Line | Count | Source |
1 | | /** |
2 | | * @file set.c |
3 | | * @author Radek Krejci <rkrejci@cesnet.cz> |
4 | | * @brief Generic set routines implementations |
5 | | * |
6 | | * Copyright (c) 2015 - 2018 CESNET, z.s.p.o. |
7 | | * |
8 | | * This source code is licensed under BSD 3-Clause License (the "License"). |
9 | | * You may not use this file except in compliance with the License. |
10 | | * You may obtain a copy of the License at |
11 | | * |
12 | | * https://opensource.org/licenses/BSD-3-Clause |
13 | | */ |
14 | | |
15 | | #include "common.h" |
16 | | |
17 | | #include <stdint.h> |
18 | | #include <stdlib.h> |
19 | | #include <string.h> |
20 | | |
21 | | #include "log.h" |
22 | | #include "set.h" |
23 | | |
24 | | API LY_ERR |
25 | | ly_set_new(struct ly_set **set_p) |
26 | 0 | { |
27 | 0 | LY_CHECK_ARG_RET(NULL, set_p, LY_EINVAL); |
28 | |
|
29 | 0 | *set_p = calloc(1, sizeof **set_p); |
30 | 0 | LY_CHECK_ERR_RET(!(*set_p), LOGMEM(NULL), LY_EMEM); |
31 | |
|
32 | 0 | return LY_SUCCESS; |
33 | 0 | } |
34 | | |
35 | | API void |
36 | | ly_set_clean(struct ly_set *set, void (*destructor)(void *obj)) |
37 | 0 | { |
38 | 0 | uint32_t u; |
39 | |
|
40 | 0 | if (!set) { |
41 | 0 | return; |
42 | 0 | } |
43 | | |
44 | 0 | if (destructor) { |
45 | 0 | for (u = 0; u < set->count; ++u) { |
46 | 0 | destructor(set->objs[u]); |
47 | 0 | } |
48 | 0 | } |
49 | 0 | set->count = 0; |
50 | 0 | } |
51 | | |
52 | | API void |
53 | | ly_set_erase(struct ly_set *set, void (*destructor)(void *obj)) |
54 | 0 | { |
55 | 0 | if (!set) { |
56 | 0 | return; |
57 | 0 | } |
58 | | |
59 | 0 | ly_set_clean(set, destructor); |
60 | |
|
61 | 0 | free(set->objs); |
62 | 0 | set->size = 0; |
63 | 0 | set->objs = NULL; |
64 | 0 | } |
65 | | |
66 | | API void |
67 | | ly_set_free(struct ly_set *set, void (*destructor)(void *obj)) |
68 | 0 | { |
69 | 0 | if (!set) { |
70 | 0 | return; |
71 | 0 | } |
72 | | |
73 | 0 | ly_set_erase(set, destructor); |
74 | |
|
75 | 0 | free(set); |
76 | 0 | } |
77 | | |
78 | | API ly_bool |
79 | | ly_set_contains(const struct ly_set *set, void *object, uint32_t *index_p) |
80 | 0 | { |
81 | 0 | LY_CHECK_ARG_RET(NULL, set, 0); |
82 | |
|
83 | 0 | for (uint32_t i = 0; i < set->count; i++) { |
84 | 0 | if (set->objs[i] == object) { |
85 | | /* object found */ |
86 | 0 | if (index_p) { |
87 | 0 | *index_p = i; |
88 | 0 | } |
89 | 0 | return 1; |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | | /* object not found */ |
94 | 0 | return 0; |
95 | 0 | } |
96 | | |
97 | | API LY_ERR |
98 | | ly_set_dup(const struct ly_set *set, void *(*duplicator)(void *obj), struct ly_set **newset_p) |
99 | 0 | { |
100 | 0 | struct ly_set *newset; |
101 | 0 | uint32_t u; |
102 | |
|
103 | 0 | LY_CHECK_ARG_RET(NULL, set, newset_p, LY_EINVAL); |
104 | |
|
105 | 0 | newset = malloc(sizeof *newset); |
106 | 0 | LY_CHECK_ERR_RET(!newset, LOGMEM(NULL), LY_EMEM); |
107 | 0 | newset->count = set->count; |
108 | 0 | newset->size = set->count; /* optimize the size */ |
109 | 0 | newset->objs = malloc(newset->size * sizeof *(newset->objs)); |
110 | 0 | LY_CHECK_ERR_RET(!newset->objs, LOGMEM(NULL); free(newset), LY_EMEM); |
111 | 0 | if (duplicator) { |
112 | 0 | for (u = 0; u < set->count; ++u) { |
113 | 0 | newset->objs[u] = duplicator(set->objs[u]); |
114 | 0 | } |
115 | 0 | } else { |
116 | 0 | memcpy(newset->objs, set->objs, newset->size * sizeof *(newset->objs)); |
117 | 0 | } |
118 | |
|
119 | 0 | *newset_p = newset; |
120 | 0 | return LY_SUCCESS; |
121 | 0 | } |
122 | | |
123 | | API LY_ERR |
124 | | ly_set_add(struct ly_set *set, void *object, ly_bool list, uint32_t *index_p) |
125 | 0 | { |
126 | 0 | void **new; |
127 | |
|
128 | 0 | LY_CHECK_ARG_RET(NULL, set, LY_EINVAL); |
129 | |
|
130 | 0 | if (!list) { |
131 | | /* search for duplication */ |
132 | 0 | for (uint32_t i = 0; i < set->count; i++) { |
133 | 0 | if (set->objs[i] == object) { |
134 | | /* already in set */ |
135 | 0 | if (index_p) { |
136 | 0 | *index_p = i; |
137 | 0 | } |
138 | 0 | return LY_SUCCESS; |
139 | 0 | } |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | 0 | if (set->size == set->count) { |
144 | 0 | #define SET_SIZE_STEP 8 |
145 | 0 | new = realloc(set->objs, (set->size + SET_SIZE_STEP) * sizeof *(set->objs)); |
146 | 0 | LY_CHECK_ERR_RET(!new, LOGMEM(NULL), LY_EMEM); |
147 | 0 | set->size += SET_SIZE_STEP; |
148 | 0 | set->objs = new; |
149 | 0 | #undef SET_SIZE_STEP |
150 | 0 | } |
151 | | |
152 | 0 | if (index_p) { |
153 | 0 | *index_p = set->count; |
154 | 0 | } |
155 | 0 | set->objs[set->count++] = object; |
156 | |
|
157 | 0 | return LY_SUCCESS; |
158 | 0 | } |
159 | | |
160 | | API LY_ERR |
161 | | ly_set_merge(struct ly_set *trg, const struct ly_set *src, ly_bool list, void *(*duplicator)(void *obj)) |
162 | 0 | { |
163 | 0 | uint32_t u; |
164 | 0 | void *obj; |
165 | |
|
166 | 0 | LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL); |
167 | |
|
168 | 0 | if (!src) { |
169 | | /* nothing to do */ |
170 | 0 | return LY_SUCCESS; |
171 | 0 | } |
172 | | |
173 | 0 | for (u = 0; u < src->count; ++u) { |
174 | 0 | if (duplicator) { |
175 | 0 | obj = duplicator(src->objs[u]); |
176 | 0 | } else { |
177 | 0 | obj = src->objs[u]; |
178 | 0 | } |
179 | 0 | LY_CHECK_RET(ly_set_add(trg, obj, list, NULL)); |
180 | 0 | } |
181 | | |
182 | 0 | return LY_SUCCESS; |
183 | 0 | } |
184 | | |
185 | | API LY_ERR |
186 | | ly_set_rm_index(struct ly_set *set, uint32_t index, void (*destructor)(void *obj)) |
187 | 0 | { |
188 | 0 | LY_CHECK_ARG_RET(NULL, set, LY_EINVAL); |
189 | 0 | LY_CHECK_ERR_RET(index >= set->count, LOGARG(NULL, index), LY_EINVAL); |
190 | |
|
191 | 0 | if (destructor) { |
192 | 0 | destructor(set->objs[index]); |
193 | 0 | } |
194 | 0 | if (index == set->count - 1) { |
195 | | /* removing last item in set */ |
196 | 0 | set->objs[index] = NULL; |
197 | 0 | } else { |
198 | | /* removing item somewhere in a middle, so put there the last item */ |
199 | 0 | set->objs[index] = set->objs[set->count - 1]; |
200 | 0 | set->objs[set->count - 1] = NULL; |
201 | 0 | } |
202 | 0 | set->count--; |
203 | |
|
204 | 0 | return LY_SUCCESS; |
205 | 0 | } |
206 | | |
207 | | API LY_ERR |
208 | | ly_set_rm(struct ly_set *set, void *object, void (*destructor)(void *obj)) |
209 | 0 | { |
210 | 0 | uint32_t i; |
211 | |
|
212 | 0 | LY_CHECK_ARG_RET(NULL, set, object, LY_EINVAL); |
213 | | |
214 | | /* get index */ |
215 | 0 | for (i = 0; i < set->count; i++) { |
216 | 0 | if (set->objs[i] == object) { |
217 | 0 | break; |
218 | 0 | } |
219 | 0 | } |
220 | 0 | LY_CHECK_ERR_RET((i == set->count), LOGARG(NULL, object), LY_EINVAL); /* object is not in set */ |
221 | |
|
222 | 0 | return ly_set_rm_index(set, i, destructor); |
223 | 0 | } |