Line | Branch | Exec | Source |
---|---|---|---|
1 | /* GATE PROJECT LICENSE: | ||
2 | +----------------------------------------------------------------------------+ | ||
3 | | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> | | ||
4 | | All rights reserved. | | ||
5 | | | | ||
6 | | Redistribution and use in source and binary forms, with or without | | ||
7 | | modification, are permitted provided that the following conditions are met:| | ||
8 | | | | ||
9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
10 | | this list of conditions and the following disclaimer. | | ||
11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
12 | | notice, this list of conditions and the following disclaimer in the | | ||
13 | | documentation and/or other materials provided with the distribution. | | ||
14 | | | | ||
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
26 | +----------------------------------------------------------------------------+ | ||
27 | */ | ||
28 | |||
29 | #include "gate/maps.h" | ||
30 | #include "gate/debugging.h" | ||
31 | #include "gate/memalloc.h" | ||
32 | #include "gate/arrays.h" | ||
33 | |||
34 | /* based on https://en.wikipedia.org/wiki/Red%E2%80%93black_tree */ | ||
35 | |||
36 | 302766 | static gate_treenode_t* gate_treenode_parent(gate_treenode_t* node) | |
37 | { | ||
38 | 302766 | return node->parent; | |
39 | } | ||
40 | |||
41 | /* | ||
42 | static gate_treenode_t* gate_treenode_grandparent(gate_treenode_t* node) | ||
43 | { | ||
44 | gate_treenode_t* parent = gate_treenode_parent(node); | ||
45 | if(parent == NULL) | ||
46 | { | ||
47 | return NULL; | ||
48 | } | ||
49 | else | ||
50 | { | ||
51 | return gate_treenode_parent(node); | ||
52 | } | ||
53 | } | ||
54 | */ | ||
55 | 102593 | static gate_treenode_t* gate_treenode_sibling(gate_treenode_t* node) | |
56 | { | ||
57 | 102593 | gate_treenode_t* parent = gate_treenode_parent(node); | |
58 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 102585 times.
|
102593 | if (parent == NULL) |
59 | { | ||
60 | 8 | return NULL; | |
61 | } | ||
62 |
2/2✓ Branch 0 taken 49451 times.
✓ Branch 1 taken 53134 times.
|
102585 | else if (node == parent->left) |
63 | { | ||
64 | 49451 | return parent->right; | |
65 | } | ||
66 |
1/2✓ Branch 0 taken 53134 times.
✗ Branch 1 not taken.
|
53134 | else if (node == parent->right) |
67 | { | ||
68 | 53134 | return parent->left; | |
69 | } | ||
70 | else | ||
71 | { | ||
72 | ✗ | GATE_DEBUG_BREAKPOINT; | |
73 | ✗ | return NULL; | |
74 | } | ||
75 | } | ||
76 | |||
77 | 42495 | static gate_treenode_t* gate_treenode_uncle(gate_treenode_t* node) | |
78 | { | ||
79 | 42495 | gate_treenode_t* parent = gate_treenode_parent(node); | |
80 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42495 times.
|
42495 | if (parent == NULL) |
81 | { | ||
82 | ✗ | return NULL; | |
83 | } | ||
84 | 42495 | return gate_treenode_sibling(parent); | |
85 | } | ||
86 | |||
87 | /* | ||
88 | static gate_bool_t gate_treenode_isleaf(gate_treenode_t* node) | ||
89 | { | ||
90 | return (node->left == NULL) && (node->right == NULL); | ||
91 | } | ||
92 | */ | ||
93 | |||
94 | 23574 | static void gate_treenode_rotate_left(gate_treenode_t** root, gate_treenode_t* node) | |
95 | { | ||
96 | 23574 | gate_treenode_t* nnew = node->right; | |
97 | 23574 | gate_treenode_t* parent = gate_treenode_parent(node); | |
98 | 23574 | GATE_DEBUG_ASSERT(nnew != NULL); | |
99 | 23574 | node->right = nnew->left; | |
100 | 23574 | nnew->left = node; | |
101 | 23574 | node->parent = nnew; | |
102 | |||
103 |
2/2✓ Branch 0 taken 5204 times.
✓ Branch 1 taken 18370 times.
|
23574 | if (node->right != NULL) |
104 | { | ||
105 | 5204 | node->right->parent = node; | |
106 | } | ||
107 |
2/2✓ Branch 0 taken 23402 times.
✓ Branch 1 taken 172 times.
|
23574 | if (parent != NULL) |
108 | { | ||
109 |
2/2✓ Branch 0 taken 14606 times.
✓ Branch 1 taken 8796 times.
|
23402 | if (node == parent->left) |
110 | { | ||
111 | 14606 | parent->left = nnew; | |
112 | } | ||
113 |
1/2✓ Branch 0 taken 8796 times.
✗ Branch 1 not taken.
|
8796 | else if (node == parent->right) |
114 | { | ||
115 | 8796 | parent->right = nnew; | |
116 | } | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | 172 | *root = nnew; | |
121 | } | ||
122 | 23574 | nnew->parent = parent; | |
123 | 23574 | } | |
124 | |||
125 | 27964 | static void gate_treenode_rotate_right(gate_treenode_t** root, gate_treenode_t* node) | |
126 | { | ||
127 | 27964 | gate_treenode_t* nnew = node->left; | |
128 | 27964 | gate_treenode_t* parent = gate_treenode_parent(node); | |
129 | 27964 | GATE_DEBUG_ASSERT(nnew != NULL); | |
130 | 27964 | node->left = nnew->right; | |
131 | 27964 | nnew->right = node; | |
132 | 27964 | node->parent = nnew; | |
133 |
2/2✓ Branch 0 taken 5511 times.
✓ Branch 1 taken 22453 times.
|
27964 | if (node->left != NULL) |
134 | { | ||
135 | 5511 | node->left->parent = node; | |
136 | } | ||
137 |
2/2✓ Branch 0 taken 27806 times.
✓ Branch 1 taken 158 times.
|
27964 | if (parent != NULL) |
138 | { | ||
139 |
2/2✓ Branch 0 taken 8636 times.
✓ Branch 1 taken 19170 times.
|
27806 | if (node == parent->left) |
140 | { | ||
141 | 8636 | parent->left = nnew; | |
142 | } | ||
143 |
1/2✓ Branch 0 taken 19170 times.
✗ Branch 1 not taken.
|
19170 | else if (node == parent->right) |
144 | { | ||
145 | 19170 | parent->right = nnew; | |
146 | } | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | 158 | *root = nnew; | |
151 | } | ||
152 | 27964 | nnew->parent = parent; | |
153 | 27964 | } | |
154 | |||
155 | 154515 | static gate_bool_t is_black(gate_treenode_t* node) | |
156 | { | ||
157 |
4/4✓ Branch 0 taken 141655 times.
✓ Branch 1 taken 12860 times.
✓ Branch 2 taken 76991 times.
✓ Branch 3 taken 64664 times.
|
154515 | return (node == NULL) || (node->red == false); |
158 | } | ||
159 | 76670 | static gate_bool_t is_red(gate_treenode_t* node) | |
160 | { | ||
161 |
4/4✓ Branch 0 taken 69569 times.
✓ Branch 1 taken 7101 times.
✓ Branch 2 taken 44538 times.
✓ Branch 3 taken 25031 times.
|
76670 | return (node == NULL) ? false : node->red; |
162 | } | ||
163 | |||
164 | 82730 | void gate_treenode_insert_repair_tree(gate_treenode_t** root, gate_treenode_t* node) | |
165 | { | ||
166 | 82730 | gate_treenode_t* parent = gate_treenode_parent(node); | |
167 | gate_treenode_t* uncle; | ||
168 | gate_treenode_t* grandparent; | ||
169 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 82630 times.
|
82730 | if (parent == NULL) |
170 | { | ||
171 | /* case 1: element is root */ | ||
172 | 100 | node->red = false; | |
173 | } | ||
174 |
2/2✓ Branch 1 taken 42495 times.
✓ Branch 2 taken 40135 times.
|
82630 | else if (is_black(parent)) |
175 | { | ||
176 | /* case 2: parent is BLACK -> nothing to do */ | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | /* case 3: parent is RED */ | ||
181 | 42495 | uncle = gate_treenode_uncle(node); | |
182 |
4/4✓ Branch 0 taken 27276 times.
✓ Branch 1 taken 15219 times.
✓ Branch 3 taken 19077 times.
✓ Branch 4 taken 8199 times.
|
42495 | if ((uncle != NULL) && is_red(uncle)) |
183 | { | ||
184 | /*uncle is RED */ | ||
185 | 19077 | parent->red = false; | |
186 | 19077 | uncle->red = false; | |
187 | 19077 | parent->parent->red = true; | |
188 | |||
189 | 19077 | gate_treenode_insert_repair_tree(root, parent->parent); | |
190 | } | ||
191 | else | ||
192 | { | ||
193 | /* case 4: uncle is BLACK */ | ||
194 | 23418 | grandparent = parent->parent; | |
195 |
2/2✓ Branch 0 taken 23410 times.
✓ Branch 1 taken 8 times.
|
23418 | if (grandparent != NULL) |
196 | { | ||
197 |
4/4✓ Branch 0 taken 15787 times.
✓ Branch 1 taken 7623 times.
✓ Branch 2 taken 5351 times.
✓ Branch 3 taken 10436 times.
|
23410 | if ((grandparent->left != NULL) && (node == grandparent->left->right)) |
198 | { | ||
199 | 5351 | gate_treenode_rotate_left(root, parent); | |
200 | 5351 | node = node->left; | |
201 | } | ||
202 |
4/4✓ Branch 0 taken 13659 times.
✓ Branch 1 taken 4400 times.
✓ Branch 2 taken 6347 times.
✓ Branch 3 taken 7312 times.
|
18059 | else if ((grandparent->right != NULL) && (node == grandparent->right->left)) |
203 | { | ||
204 | 6347 | gate_treenode_rotate_right(root, parent); | |
205 | 6347 | node = node->right; | |
206 | } | ||
207 | |||
208 | /* case 4, part 2 */ | ||
209 | 23410 | parent = gate_treenode_parent(node); | |
210 | 23410 | grandparent = parent->parent; | |
211 | |||
212 |
2/2✓ Branch 0 taken 12599 times.
✓ Branch 1 taken 10811 times.
|
23410 | if (node == parent->left) |
213 | { | ||
214 | 12599 | gate_treenode_rotate_right(root, grandparent); | |
215 | } | ||
216 | else | ||
217 | { | ||
218 | 10811 | gate_treenode_rotate_left(root, grandparent); | |
219 | |||
220 | } | ||
221 | 23410 | parent->red = false; | |
222 | 23410 | grandparent->red = true; | |
223 | } | ||
224 | } | ||
225 | } | ||
226 | 82730 | } | |
227 | |||
228 | 256347 | gate_treenode_t* gate_treenode_find(gate_treenode_t* root, gate_comparer_t comparer, void const* key, gate_treenode_t** ptr_last_parent) | |
229 | { | ||
230 | gate_treenode_t* current; | ||
231 | gate_intptr_t diff; | ||
232 | |||
233 | 256347 | current = root; | |
234 | 256347 | root = NULL; | |
235 | |||
236 |
2/2✓ Branch 0 taken 4494598 times.
✓ Branch 1 taken 126680 times.
|
4621278 | while (current != NULL) |
237 | { | ||
238 | 4494598 | diff = comparer(key, current->mapping.key); | |
239 | |||
240 |
2/2✓ Branch 0 taken 1767586 times.
✓ Branch 1 taken 2727012 times.
|
4494598 | if (diff < 0) |
241 | { | ||
242 | 1767586 | root = current; | |
243 | 1767586 | current = current->left; | |
244 | } | ||
245 |
2/2✓ Branch 0 taken 2597345 times.
✓ Branch 1 taken 129667 times.
|
2727012 | else if (diff > 0) |
246 | { | ||
247 | 2597345 | root = current; | |
248 | 2597345 | current = current->right; | |
249 | } | ||
250 | else /* if(diff == 0) */ | ||
251 | { | ||
252 | 129667 | break; | |
253 | } | ||
254 | } | ||
255 |
1/2✓ Branch 0 taken 256347 times.
✗ Branch 1 not taken.
|
256347 | if (ptr_last_parent != NULL) |
256 | { | ||
257 | 256347 | *ptr_last_parent = root; | |
258 | } | ||
259 | 256347 | return current; | |
260 | } | ||
261 | |||
262 | |||
263 | /* | ||
264 | static void gate_treenode_replace_node(gate_treenode_t* node, gate_treenode_t* child) | ||
265 | { | ||
266 | child->parent = node->parent; | ||
267 | if(node == node->parent->left) | ||
268 | { | ||
269 | node->parent->left = child; | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | node->parent->right = child; | ||
274 | } | ||
275 | } | ||
276 | */ | ||
277 | |||
278 | 26330 | static void gate_treenode_delete_repair_tree(gate_treenode_t** root, gate_treenode_t* node) | |
279 | { | ||
280 | gate_treenode_t* sibling; | ||
281 | |||
282 | /* case 1 */ | ||
283 |
2/2✓ Branch 0 taken 232 times.
✓ Branch 1 taken 26098 times.
|
26330 | if (node->parent == NULL) |
284 | { | ||
285 | /* node is root -> nothing to do */ | ||
286 | 232 | return; | |
287 | } | ||
288 | |||
289 | /* case 2 */ | ||
290 | 26098 | sibling = gate_treenode_sibling(node); | |
291 | |||
292 |
2/2✓ Branch 1 taken 5790 times.
✓ Branch 2 taken 20308 times.
|
26098 | if (is_red(sibling)) |
293 | { | ||
294 | 5790 | node->parent->red = true; | |
295 | 5790 | sibling->red = false; | |
296 |
2/2✓ Branch 0 taken 2319 times.
✓ Branch 1 taken 3471 times.
|
5790 | if (node == node->parent->left) |
297 | { | ||
298 | 2319 | gate_treenode_rotate_left(root, node->parent); | |
299 | } | ||
300 | else | ||
301 | { | ||
302 | 3471 | gate_treenode_rotate_right(root, node->parent); | |
303 | } | ||
304 | } | ||
305 | |||
306 | /* update sibling for case 3 */ | ||
307 | 26098 | sibling = gate_treenode_sibling(node); | |
308 |
2/2✓ Branch 0 taken 10768 times.
✓ Branch 1 taken 15330 times.
|
26098 | if (sibling == NULL) |
309 | { | ||
310 | 10768 | return; | |
311 | } | ||
312 | |||
313 | /* case 3 */ | ||
314 |
5/6✓ Branch 1 taken 6299 times.
✓ Branch 2 taken 9031 times.
✓ Branch 4 taken 6299 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3868 times.
✓ Branch 7 taken 2431 times.
|
21629 | if (is_black(node->parent) && is_black(sibling) && |
315 |
2/2✓ Branch 2 taken 2710 times.
✓ Branch 3 taken 1158 times.
|
10167 | is_black(sibling->left) && is_black(sibling->right)) |
316 | { | ||
317 | 2710 | sibling->red = true; | |
318 | 2710 | gate_treenode_delete_repair_tree(root, node->parent); | |
319 | 2710 | return; | |
320 | } | ||
321 | |||
322 | /* case 4 */ | ||
323 |
6/6✓ Branch 1 taken 9031 times.
✓ Branch 2 taken 3589 times.
✓ Branch 4 taken 8995 times.
✓ Branch 5 taken 36 times.
✓ Branch 6 taken 6223 times.
✓ Branch 7 taken 2772 times.
|
21615 | if (is_red(node->parent) && is_black(sibling) && |
324 |
2/2✓ Branch 2 taken 4682 times.
✓ Branch 3 taken 1541 times.
|
15218 | is_black(sibling->left) && is_black(sibling->right) |
325 | ) | ||
326 | { | ||
327 | 4682 | sibling->red = true; | |
328 | 4682 | node->parent->red = false; | |
329 | 4682 | return; | |
330 | } | ||
331 | |||
332 | /* case 5*/ | ||
333 |
2/2✓ Branch 1 taken 7902 times.
✓ Branch 2 taken 36 times.
|
7938 | if (is_black(sibling)) |
334 | { | ||
335 |
5/6✓ Branch 0 taken 3758 times.
✓ Branch 1 taken 4144 times.
✓ Branch 3 taken 1403 times.
✓ Branch 4 taken 2355 times.
✓ Branch 6 taken 1403 times.
✗ Branch 7 not taken.
|
7902 | if ((node == node->parent->left) && is_black(sibling->right) && is_red(sibling->left)) |
336 | { | ||
337 | 1403 | sibling->red = true; | |
338 | 1403 | sibling->left->red = false; | |
339 | 1403 | gate_treenode_rotate_right(root, sibling); | |
340 | } | ||
341 |
5/6✓ Branch 0 taken 4144 times.
✓ Branch 1 taken 2355 times.
✓ Branch 3 taken 1335 times.
✓ Branch 4 taken 2809 times.
✓ Branch 6 taken 1335 times.
✗ Branch 7 not taken.
|
6499 | else if ((node == node->parent->right) && is_black(sibling->left) && is_red(sibling->right)) |
342 | { | ||
343 | 1335 | sibling->red = true; | |
344 | 1335 | sibling->right->red = false; | |
345 | 1335 | gate_treenode_rotate_left(root, sibling); | |
346 | } | ||
347 | |||
348 | /* update sibling for case 6 */ | ||
349 | 7902 | sibling = gate_treenode_sibling(node); | |
350 | } | ||
351 | |||
352 | /* case 6 */ | ||
353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7938 times.
|
7938 | if (sibling == NULL) |
354 | { | ||
355 | ✗ | return; | |
356 | } | ||
357 | |||
358 | 7938 | sibling->red = node->parent->red; | |
359 | 7938 | node->parent->red = false; | |
360 |
2/2✓ Branch 0 taken 3762 times.
✓ Branch 1 taken 4176 times.
|
7938 | if (node == node->parent->left) |
361 | { | ||
362 |
2/2✓ Branch 1 taken 3758 times.
✓ Branch 2 taken 4 times.
|
3762 | if (is_red(sibling->right)) |
363 | { | ||
364 | 3758 | sibling->right->red = false; | |
365 | 3758 | gate_treenode_rotate_left(root, node->parent); | |
366 | } | ||
367 | } | ||
368 |
1/2✓ Branch 0 taken 4176 times.
✗ Branch 1 not taken.
|
4176 | else if (node == node->parent->right) |
369 | { | ||
370 |
2/2✓ Branch 1 taken 4144 times.
✓ Branch 2 taken 32 times.
|
4176 | if (is_red(sibling->left)) |
371 | { | ||
372 | 4144 | sibling->left->red = false; | |
373 | 4144 | gate_treenode_rotate_right(root, node->parent); | |
374 | } | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | ✗ | GATE_DEBUG_BREAKPOINT; | |
379 | } | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | static void gate_treenode_delete_one_child(gate_treenode_t** root, gate_treenode_t* node) | ||
384 | { | ||
385 | gate_treenode_t* child = gate_treenode_isleaf(node->right) ? node->left : node->right; | ||
386 | |||
387 | gate_treenode_replace_node(node, child); | ||
388 | |||
389 | if(!node->red) | ||
390 | { | ||
391 | if(child->red) | ||
392 | { | ||
393 | child->red = false; | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | gate_treenode_delete_repair_tree(root, child); | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | */ | ||
402 | |||
403 | 292727 | gate_treenode_t* gate_treenode_minimum(gate_treenode_t* node) | |
404 | { | ||
405 | 292727 | gate_treenode_t* ret = node; | |
406 |
2/2✓ Branch 0 taken 272899 times.
✓ Branch 1 taken 292727 times.
|
565626 | while (ret->left != NULL) |
407 | { | ||
408 | 272899 | ret = ret->left; | |
409 | } | ||
410 | 292727 | return ret; | |
411 | } | ||
412 | 21804 | gate_treenode_t* gate_treenode_maximum(gate_treenode_t* node) | |
413 | { | ||
414 | 21804 | gate_treenode_t* ret = node; | |
415 |
2/2✓ Branch 0 taken 20631 times.
✓ Branch 1 taken 21804 times.
|
42435 | while (ret->right != NULL) |
416 | { | ||
417 | 20631 | ret = ret->right; | |
418 | } | ||
419 | 21804 | return ret; | |
420 | } | ||
421 | |||
422 | 62959 | void gate_treenode_remove_repair_tree(gate_treenode_t** root, gate_treenode_t* node) | |
423 | { | ||
424 | gate_treenode_t* replacement; | ||
425 | 125918 | gate_treenode_t** ptr_parent = (node->parent == NULL) | |
426 | ? root | ||
427 |
4/4✓ Branch 0 taken 62709 times.
✓ Branch 1 taken 250 times.
✓ Branch 2 taken 29694 times.
✓ Branch 3 taken 33015 times.
|
62959 | : ((node == node->parent->left) ? &node->parent->left : &node->parent->right); |
428 | |||
429 | |||
430 | |||
431 |
4/4✓ Branch 0 taken 33969 times.
✓ Branch 1 taken 28990 times.
✓ Branch 2 taken 22625 times.
✓ Branch 3 taken 11344 times.
|
62959 | if ((node->left == NULL) && (node->right == NULL)) |
432 | { | ||
433 | /* no children */ | ||
434 | 22625 | *ptr_parent = NULL; | |
435 | } | ||
436 |
4/4✓ Branch 0 taken 28990 times.
✓ Branch 1 taken 11344 times.
✓ Branch 2 taken 21804 times.
✓ Branch 3 taken 7186 times.
|
40334 | else if ((node->left != NULL) && (node->right != NULL)) |
437 | { | ||
438 | /* two children */ | ||
439 | 21804 | replacement = gate_treenode_maximum(node->left); | |
440 | |||
441 | 21804 | replacement->right = node->right; | |
442 | 21804 | replacement->parent->right = replacement->left; | |
443 |
2/2✓ Branch 0 taken 5692 times.
✓ Branch 1 taken 16112 times.
|
21804 | if (replacement->left != NULL) |
444 | { | ||
445 | 5692 | replacement->left->parent = replacement->parent; | |
446 | } | ||
447 |
2/2✓ Branch 0 taken 9151 times.
✓ Branch 1 taken 12653 times.
|
21804 | if (replacement != node->left) |
448 | { | ||
449 | 9151 | replacement->left = node->left; | |
450 | } | ||
451 | |||
452 | 21804 | replacement->parent = node->parent; | |
453 | 21804 | *ptr_parent = replacement; | |
454 | |||
455 |
2/2✓ Branch 0 taken 13186 times.
✓ Branch 1 taken 8618 times.
|
21804 | if (replacement->left != NULL) |
456 | { | ||
457 | 13186 | replacement->left->parent = replacement; | |
458 | } | ||
459 |
1/2✓ Branch 0 taken 21804 times.
✗ Branch 1 not taken.
|
21804 | if (replacement->right != NULL) |
460 | { | ||
461 | 21804 | replacement->right->parent = replacement; | |
462 | } | ||
463 | |||
464 |
2/2✓ Branch 0 taken 15718 times.
✓ Branch 1 taken 6086 times.
|
37522 | if (node->red == false) |
465 | { | ||
466 |
2/2✓ Branch 0 taken 10628 times.
✓ Branch 1 taken 5090 times.
|
15718 | if (replacement->red == true) |
467 | { | ||
468 | 10628 | replacement->red = false; | |
469 | } | ||
470 | else | ||
471 | { | ||
472 | 5090 | gate_treenode_delete_repair_tree(root, replacement); | |
473 | } | ||
474 | } | ||
475 | } | ||
476 |
2/2✓ Branch 0 taken 7186 times.
✓ Branch 1 taken 11344 times.
|
18530 | else if ((node->left != NULL)) |
477 | { | ||
478 | /* one child on left side */ | ||
479 | 7186 | *ptr_parent = node->left; | |
480 | 7186 | node->left->parent = node->parent; | |
481 | 7186 | gate_treenode_delete_repair_tree(root, node->left); | |
482 | } | ||
483 | else | ||
484 | { | ||
485 | /* one child on right side */ | ||
486 | 11344 | *ptr_parent = node->right; | |
487 | 11344 | node->right->parent = node->parent; | |
488 | 11344 | gate_treenode_delete_repair_tree(root, node->right); | |
489 | } | ||
490 | 62959 | } | |
491 | |||
492 | ✗ | gate_treenode_t* gate_treenode_next(gate_treenode_t* node) | |
493 | { | ||
494 | for (;;) | ||
495 | { | ||
496 | ✗ | if (node->right != NULL) | |
497 | { | ||
498 | ✗ | return gate_treenode_minimum(node->right); | |
499 | } | ||
500 | else | ||
501 | { | ||
502 | ✗ | if (node->parent == NULL) | |
503 | { | ||
504 | ✗ | return NULL; | |
505 | } | ||
506 | ✗ | if (node == node->parent->left) | |
507 | { | ||
508 | ✗ | return node->parent; | |
509 | } | ||
510 | ✗ | node = node->parent; | |
511 | } | ||
512 | } | ||
513 | } | ||
514 | ✗ | gate_treenode_t* gate_treenode_prev(gate_treenode_t* node) | |
515 | { | ||
516 | for (;;) | ||
517 | { | ||
518 | ✗ | if (node->left != NULL) | |
519 | { | ||
520 | ✗ | return gate_treenode_maximum(node->left); | |
521 | } | ||
522 | else | ||
523 | { | ||
524 | ✗ | if (node->parent == NULL) | |
525 | { | ||
526 | ✗ | return NULL; | |
527 | } | ||
528 | ✗ | if (node == node->parent->right) | |
529 | { | ||
530 | ✗ | return node->parent; | |
531 | } | ||
532 | ✗ | node = node->parent; | |
533 | } | ||
534 | } | ||
535 | } | ||
536 | |||
537 | |||
538 | |||
539 | |||
540 | |||
541 | |||
542 | |||
543 | |||
544 | |||
545 | |||
546 | |||
547 | |||
548 | |||
549 | |||
550 | |||
551 | |||
552 | |||
553 | /************************ | ||
554 | * MAP implementation * | ||
555 | ************************/ | ||
556 | |||
557 | ✗ | gate_result_t gate_map_copy_constructor(void* dest, void const* src) | |
558 | { | ||
559 | ✗ | if (NULL == gate_map_copy((gate_map_t*)dest, (gate_map_t const*)src)) | |
560 | { | ||
561 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
562 | } | ||
563 | else | ||
564 | { | ||
565 | ✗ | return GATE_RESULT_OK; | |
566 | } | ||
567 | } | ||
568 | |||
569 | ✗ | void gate_map_destructor(void* dest) | |
570 | { | ||
571 | ✗ | gate_map_destroy((gate_map_t*)dest); | |
572 | ✗ | } | |
573 | |||
574 | |||
575 | 68 | gate_map_t* gate_map_create(gate_map_t* m, gate_comparer_t key_comparer, | |
576 | gate_size_t key_size, gate_mem_copyctor_t key_ctor, gate_mem_dtor_t key_dtor, | ||
577 | gate_size_t value_size, gate_mem_copyctor_t value_ctor, gate_mem_dtor_t value_dtor | ||
578 | ) | ||
579 | { | ||
580 | 68 | m->item_count = 0; | |
581 | 68 | m->key_comparer = key_comparer; | |
582 | |||
583 | 68 | m->key_size = key_size; | |
584 | 68 | m->key_constructor = key_ctor; | |
585 | 68 | m->key_destructor = key_dtor; | |
586 | |||
587 | 68 | m->value_size = value_size; | |
588 | 68 | m->value_constructor = value_ctor; | |
589 | 68 | m->value_destructor = value_dtor; | |
590 | |||
591 | 68 | m->root = NULL; | |
592 | |||
593 | 68 | return m; | |
594 | } | ||
595 | |||
596 | 63661 | static gate_treenode_t* gate_map_create_node(gate_map_t* m, void const* key, void const* value) | |
597 | { | ||
598 | 63661 | gate_size_t keysize = gate_mem_align_size(m->key_size); | |
599 | 63661 | gate_size_t valuesize = gate_mem_align_size(m->value_size); | |
600 | 63661 | gate_treenode_t* ret = (gate_treenode_t*)gate_mem_alloc(sizeof(gate_treenode_t) + keysize + valuesize); | |
601 | char* keyptr; | ||
602 | 63661 | char* ptr = NULL; | |
603 | gate_result_t result; | ||
604 | |||
605 |
1/2✓ Branch 0 taken 63661 times.
✗ Branch 1 not taken.
|
63661 | if (ret != NULL) |
606 | { | ||
607 | do | ||
608 | { | ||
609 | 63661 | ptr = (char*)ret; | |
610 | 63661 | ret->red = true; | |
611 | 63661 | ret->parent = NULL; | |
612 | 63661 | ret->left = NULL; | |
613 | 63661 | ret->right = NULL; | |
614 | 63661 | keyptr = ptr + sizeof(gate_treenode_t); | |
615 | 63661 | ret->mapping.key = keyptr; | |
616 | 63661 | ret->mapping.value = ptr + (sizeof(gate_treenode_t) + keysize); | |
617 |
2/2✓ Branch 0 taken 699 times.
✓ Branch 1 taken 62962 times.
|
63661 | if (m->key_constructor != NULL) |
618 | { | ||
619 | 699 | result = m->key_constructor(keyptr, key); | |
620 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 699 times.
|
699 | if (GATE_FAILED(result)) |
621 | { | ||
622 | /* key construction failed */ | ||
623 | ✗ | ret = NULL; | |
624 | ✗ | break; | |
625 | } | ||
626 | } | ||
627 | else | ||
628 | { | ||
629 | 62962 | gate_mem_copy(keyptr, key, m->key_size); | |
630 | } | ||
631 | |||
632 |
2/2✓ Branch 0 taken 701 times.
✓ Branch 1 taken 62960 times.
|
63661 | if (m->value_constructor != NULL) |
633 | { | ||
634 | 701 | result = m->value_constructor(ret->mapping.value, value); | |
635 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 701 times.
|
701 | if (GATE_FAILED(result)) |
636 | { | ||
637 | /* value construction failed */ | ||
638 | ✗ | if (m->key_destructor != NULL) | |
639 | { | ||
640 | ✗ | m->key_destructor(keyptr); | |
641 | } | ||
642 | ✗ | ret = NULL; | |
643 | ✗ | break; | |
644 | } | ||
645 | } | ||
646 | else | ||
647 | { | ||
648 |
2/2✓ Branch 0 taken 62958 times.
✓ Branch 1 taken 2 times.
|
62960 | if (m->value_size != 0) |
649 | { | ||
650 | 62958 | gate_mem_copy(ret->mapping.value, value, m->value_size); | |
651 | } | ||
652 | } | ||
653 | |||
654 | /* all succeeded, no cleanup required */ | ||
655 | 63661 | ptr = NULL; | |
656 | } while (0); | ||
657 | } | ||
658 | |||
659 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63661 times.
|
63661 | if (ptr != NULL) |
660 | { | ||
661 | ✗ | gate_mem_dealloc(ptr); | |
662 | } | ||
663 | |||
664 | 63661 | return ret; | |
665 | } | ||
666 | 63661 | static void gate_map_delete_node(gate_map_t* m, gate_treenode_t* node) | |
667 | { | ||
668 |
2/2✓ Branch 0 taken 701 times.
✓ Branch 1 taken 62960 times.
|
63661 | if (m->value_destructor != NULL) |
669 | { | ||
670 | 701 | m->value_destructor(node->mapping.value); | |
671 | } | ||
672 |
2/2✓ Branch 0 taken 699 times.
✓ Branch 1 taken 62962 times.
|
63661 | if (m->key_destructor != NULL) |
673 | { | ||
674 | 699 | m->key_destructor((void*)node->mapping.key); | |
675 | } | ||
676 | 63661 | gate_mem_dealloc(node); | |
677 | 63661 | } | |
678 | |||
679 | 1485 | static void gate_map_delete_nodes(gate_map_t* m, gate_treenode_t* node) | |
680 | { | ||
681 |
2/2✓ Branch 0 taken 702 times.
✓ Branch 1 taken 783 times.
|
1485 | if (node != NULL) |
682 | { | ||
683 | 702 | gate_map_delete_nodes(m, node->left); | |
684 | 702 | gate_map_delete_nodes(m, node->right); | |
685 | 702 | gate_map_delete_node(m, node); | |
686 | } | ||
687 | 1485 | } | |
688 | |||
689 | 81 | void gate_map_clear(gate_map_t* m) | |
690 | { | ||
691 | 81 | gate_treenode_t* node = m->root; | |
692 | 81 | m->root = NULL; | |
693 | 81 | m->item_count = 0; | |
694 | 81 | gate_map_delete_nodes(m, node); | |
695 | 81 | } | |
696 | |||
697 | 73 | void gate_map_destroy(gate_map_t* m) | |
698 | { | ||
699 | 73 | gate_map_clear(m); | |
700 | 73 | gate_mem_clear(m, sizeof(gate_map_t)); | |
701 | 73 | } | |
702 | |||
703 | 2006 | gate_size_t gate_map_count(gate_map_t const* m) | |
704 | { | ||
705 | 2006 | return m->item_count; | |
706 | } | ||
707 | |||
708 | ✗ | gate_size_t gate_map_merge(gate_map_t* m, gate_map_t const* with) | |
709 | { | ||
710 | ✗ | gate_size_t count = 0; | |
711 | ✗ | gate_map_iterator_t iter = gate_map_first(with); | |
712 | ✗ | while (gate_map_iterator_valid(iter)) | |
713 | { | ||
714 | ✗ | if (gate_map_iterator_valid(gate_map_add(m, iter->mapping.key, iter->mapping.value))) | |
715 | { | ||
716 | ✗ | ++count; | |
717 | } | ||
718 | ✗ | iter = gate_map_iterator_next(iter); | |
719 | } | ||
720 | ✗ | return count; | |
721 | } | ||
722 | ✗ | gate_size_t gate_map_remove_keys(gate_map_t* m, gate_map_t const* keys) | |
723 | { | ||
724 | ✗ | gate_size_t count = 0; | |
725 | ✗ | gate_map_iterator_t iter = gate_map_first(keys); | |
726 | ✗ | while (gate_map_iterator_valid(iter)) | |
727 | { | ||
728 | ✗ | if (gate_map_remove(m, iter->mapping.key)) | |
729 | { | ||
730 | ✗ | ++count; | |
731 | } | ||
732 | ✗ | iter = gate_map_iterator_next(iter); | |
733 | } | ||
734 | ✗ | return count; | |
735 | } | ||
736 | |||
737 | |||
738 | 8 | static gate_bool_t gate_map_clone_node(gate_map_t* m, gate_treenode_t const* src, gate_treenode_t** dst) | |
739 | { | ||
740 | 8 | gate_treenode_t* newnode = gate_map_create_node(m, src->mapping.key, src->mapping.value); | |
741 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (newnode == NULL) |
742 | { | ||
743 | ✗ | return false; | |
744 | } | ||
745 | 8 | newnode->red = src->red; | |
746 | 8 | *dst = newnode; | |
747 | |||
748 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if (src->left != NULL) |
749 | { | ||
750 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (!gate_map_clone_node(m, src->left, &newnode->left)) |
751 | { | ||
752 | ✗ | return false; | |
753 | } | ||
754 | 2 | newnode->left->parent = newnode; | |
755 | } | ||
756 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if (src->right != NULL) |
757 | { | ||
758 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (!gate_map_clone_node(m, src->right, &newnode->right)) |
759 | { | ||
760 | ✗ | return false; | |
761 | } | ||
762 | 2 | newnode->right->parent = newnode; | |
763 | } | ||
764 | 8 | return true; | |
765 | } | ||
766 | |||
767 | 11 | gate_map_t* gate_map_copy(gate_map_t* dst, gate_map_t const* src) | |
768 | { | ||
769 | 11 | dst->item_count = src->item_count; | |
770 | 11 | dst->key_comparer = src->key_comparer; | |
771 | |||
772 | 11 | dst->key_size = src->key_size; | |
773 | 11 | dst->key_constructor = src->key_constructor; | |
774 | 11 | dst->key_destructor = src->key_destructor; | |
775 | |||
776 | 11 | dst->value_size = src->value_size; | |
777 | 11 | dst->value_constructor = src->value_constructor; | |
778 | 11 | dst->value_destructor = src->value_destructor; | |
779 | |||
780 | 11 | dst->root = NULL; | |
781 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
|
11 | if (src->root != NULL) |
782 | { | ||
783 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if (!gate_map_clone_node(dst, src->root, &dst->root)) |
784 | { | ||
785 | /* cloning failed */ | ||
786 | ✗ | gate_map_destroy(dst); | |
787 | ✗ | return NULL; | |
788 | } | ||
789 | } | ||
790 | 11 | return dst; | |
791 | } | ||
792 | |||
793 | |||
794 | 126222 | gate_map_iterator_t gate_map_add(gate_map_t* m, void const* key, void const* value) | |
795 | { | ||
796 | 126222 | gate_treenode_t* parentnode = NULL; | |
797 | 126222 | gate_treenode_t* node = NULL; | |
798 | gate_intptr_t cmp; | ||
799 | gate_result_t result; | ||
800 | |||
801 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 126189 times.
|
126222 | if (m->root == NULL) |
802 | { | ||
803 | 33 | node = gate_map_create_node(m, key, value); | |
804 | 33 | m->root = node; | |
805 | 33 | gate_treenode_insert_repair_tree(&m->root, node); | |
806 | 33 | ++m->item_count; | |
807 | } | ||
808 | else | ||
809 | { | ||
810 | 126189 | node = gate_treenode_find(m->root, m->key_comparer, key, &parentnode); | |
811 |
2/2✓ Branch 0 taken 62569 times.
✓ Branch 1 taken 63620 times.
|
126189 | if (node != NULL) |
812 | { | ||
813 | /* item found -> overwrite value */ | ||
814 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 62552 times.
|
62569 | if (m->value_destructor != NULL) |
815 | { | ||
816 | 17 | m->value_destructor(node->mapping.value); | |
817 | } | ||
818 |
2/2✓ Branch 0 taken 62552 times.
✓ Branch 1 taken 17 times.
|
62569 | if (m->value_constructor == NULL) |
819 | { | ||
820 |
1/2✓ Branch 0 taken 62552 times.
✗ Branch 1 not taken.
|
62552 | if (m->value_size != 0) |
821 | { | ||
822 | 62552 | gate_mem_copy(node->mapping.value, value, m->value_size); | |
823 | } | ||
824 | else | ||
825 | { | ||
826 | ✗ | node->mapping.value = NULL; | |
827 | } | ||
828 | } | ||
829 | else | ||
830 | { | ||
831 | 17 | result = m->value_constructor(node->mapping.value, value); | |
832 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (GATE_FAILED(result)) |
833 | { | ||
834 | /* construction failed -> we cannot recover from this error */ | ||
835 | ✗ | gate_mem_clear(node->mapping.value, m->value_size); | |
836 | ✗ | gate_map_remove(m, key); | |
837 | ✗ | node = NULL; | |
838 | } | ||
839 | } | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | 63620 | node = gate_map_create_node(m, key, value); | |
844 | 63620 | cmp = m->key_comparer(key, parentnode->mapping.key); | |
845 |
2/2✓ Branch 0 taken 38645 times.
✓ Branch 1 taken 24975 times.
|
63620 | if (cmp < 0) |
846 | { | ||
847 | 38645 | parentnode->left = node; | |
848 | } | ||
849 | else | ||
850 | { | ||
851 | 24975 | GATE_DEBUG_ASSERT(cmp > 0); | |
852 | 24975 | parentnode->right = node; | |
853 | } | ||
854 | 63620 | node->parent = parentnode; | |
855 | 63620 | gate_treenode_insert_repair_tree(&m->root, node); | |
856 | 63620 | ++m->item_count; | |
857 | } | ||
858 | } | ||
859 | 126222 | return node; | |
860 | } | ||
861 | 126011 | gate_bool_t gate_map_remove(gate_map_t* m, void const* key) | |
862 | { | ||
863 | gate_bool_t ret; | ||
864 | 126011 | gate_treenode_t* parentnode = NULL; | |
865 | 126011 | gate_treenode_t* node = gate_treenode_find(m->root, m->key_comparer, key, &parentnode); | |
866 |
2/2✓ Branch 0 taken 63052 times.
✓ Branch 1 taken 62959 times.
|
126011 | if (node == NULL) |
867 | { | ||
868 | 63052 | ret = false; | |
869 | } | ||
870 | else | ||
871 | { | ||
872 | 62959 | gate_treenode_remove_repair_tree(&m->root, node); | |
873 | |||
874 | 62959 | gate_map_delete_node(m, node); | |
875 | 62959 | --m->item_count; | |
876 | 62959 | ret = true; | |
877 | } | ||
878 | 126011 | return ret; | |
879 | } | ||
880 | |||
881 | 2 | gate_bool_t gate_map_is_empty(gate_map_t const* m) | |
882 | { | ||
883 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | return (m == NULL) ? true : (m->item_count == 0); |
884 | } | ||
885 | |||
886 | 2076 | gate_map_iterator_t gate_map_get(gate_map_t const* m, void const* key) | |
887 | { | ||
888 | 2076 | gate_treenode_t* parentnode = NULL; | |
889 | 2076 | gate_treenode_t* node = gate_treenode_find(m->root, m->key_comparer, key, &parentnode); | |
890 | 2076 | return node; | |
891 | } | ||
892 | |||
893 | |||
894 | 2035 | gate_map_iterator_t gate_map_first(gate_map_t const* m) | |
895 | { | ||
896 |
2/2✓ Branch 0 taken 2019 times.
✓ Branch 1 taken 16 times.
|
2035 | return (m->root == NULL) ? NULL : gate_treenode_minimum(m->root); |
897 | } | ||
898 | ✗ | gate_map_iterator_t gate_map_last(gate_map_t const* m) | |
899 | { | ||
900 | ✗ | return (m->root == NULL) ? NULL : gate_treenode_maximum(m->root); | |
901 | } | ||
902 | 565625 | gate_map_iterator_t gate_map_iterator_next(gate_map_iterator_t iterator) | |
903 | { | ||
904 |
1/2✓ Branch 0 taken 565625 times.
✗ Branch 1 not taken.
|
565625 | if (iterator != NULL) |
905 | { | ||
906 |
2/2✓ Branch 0 taken 290708 times.
✓ Branch 1 taken 274917 times.
|
565625 | if (iterator->right != NULL) |
907 | { | ||
908 | 290708 | iterator = gate_treenode_minimum(iterator->right); | |
909 | } | ||
910 | else | ||
911 | { | ||
912 | for (;;) | ||
913 | { | ||
914 |
2/2✓ Branch 0 taken 2018 times.
✓ Branch 1 taken 563607 times.
|
565625 | if (iterator->parent == NULL) |
915 | { | ||
916 | 2018 | iterator = NULL; | |
917 | 2018 | break; | |
918 | } | ||
919 |
2/2✓ Branch 0 taken 272899 times.
✓ Branch 1 taken 290708 times.
|
563607 | if (iterator == iterator->parent->left) |
920 | { | ||
921 | 272899 | iterator = iterator->parent; | |
922 | 272899 | break; | |
923 | } | ||
924 | 290708 | iterator = iterator->parent; | |
925 | } | ||
926 | } | ||
927 | } | ||
928 | 565625 | return iterator; | |
929 | } | ||
930 | ✗ | gate_map_iterator_t gate_map_iterator_prev(gate_map_iterator_t iterator) | |
931 | { | ||
932 | ✗ | if (iterator != NULL) | |
933 | { | ||
934 | ✗ | if (iterator->left != NULL) | |
935 | { | ||
936 | ✗ | iterator = gate_treenode_maximum(iterator->left); | |
937 | } | ||
938 | else | ||
939 | { | ||
940 | for (;;) | ||
941 | { | ||
942 | ✗ | if (iterator->parent == NULL) | |
943 | { | ||
944 | ✗ | iterator = NULL; | |
945 | ✗ | break; | |
946 | } | ||
947 | ✗ | if (iterator == iterator->parent->right) | |
948 | { | ||
949 | ✗ | iterator = iterator->parent; | |
950 | ✗ | break; | |
951 | } | ||
952 | ✗ | iterator = iterator->parent; | |
953 | } | ||
954 | } | ||
955 | } | ||
956 | ✗ | return iterator; | |
957 | } | ||
958 | |||
959 | 501005 | gate_bool_t gate_map_iterator_equals(gate_map_iterator_t iter1, gate_map_iterator_t iter2) | |
960 | { | ||
961 | 501005 | return iter1 == iter2; | |
962 | } | ||
963 | 2 | gate_map_iterator_t gate_map_end(gate_map_t const* m) | |
964 | { | ||
965 | (void)m; | ||
966 | 2 | return NULL; | |
967 | } | ||
968 | 1069790 | gate_bool_t gate_map_iterator_valid(gate_map_iterator_t iterator) | |
969 | { | ||
970 | 1069790 | return iterator != NULL; | |
971 | } | ||
972 | |||
973 | |||
974 | 2071 | void* gate_map_get_value(gate_map_t const* m, void const* key) | |
975 | { | ||
976 | 2071 | gate_treenode_t* parentnode = NULL; | |
977 | 2071 | gate_treenode_t* node = gate_treenode_find(m->root, m->key_comparer, key, &parentnode); | |
978 |
2/2✓ Branch 0 taken 2068 times.
✓ Branch 1 taken 3 times.
|
2071 | if (node != NULL) |
979 | { | ||
980 | 2068 | return node->mapping.value; | |
981 | } | ||
982 | 3 | return NULL; | |
983 | } | ||
984 | |||
985 | 315526 | void const* gate_map_iterator_key(gate_map_iterator_t iterator) | |
986 | { | ||
987 |
1/2✓ Branch 0 taken 315526 times.
✗ Branch 1 not taken.
|
315526 | if (iterator != NULL) |
988 | { | ||
989 | 315526 | return (void const*)iterator->mapping.key; | |
990 | } | ||
991 | else | ||
992 | { | ||
993 | ✗ | return NULL; | |
994 | } | ||
995 | } | ||
996 | 23 | void* gate_map_iterator_value(gate_map_iterator_t iterator) | |
997 | { | ||
998 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (iterator != NULL) |
999 | { | ||
1000 | 23 | return (void*)iterator->mapping.value; | |
1001 | } | ||
1002 | else | ||
1003 | { | ||
1004 | ✗ | return NULL; | |
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | |||
1009 | ✗ | static gate_bool_t gate_map_enumerate_is_valid(gate_enumerator_t const* enumerator) | |
1010 | { | ||
1011 | ✗ | return gate_map_iterator_valid((gate_map_iterator_t)enumerator->current_position); | |
1012 | } | ||
1013 | ✗ | static gate_bool_t gate_map_enumerate_next(gate_enumerator_t* enumerator) | |
1014 | { | ||
1015 | ✗ | if (enumerator->current_position) | |
1016 | { | ||
1017 | ✗ | enumerator->current_position = (void*)gate_map_iterator_next((gate_map_iterator_t)enumerator->current_position); | |
1018 | ✗ | return gate_map_iterator_valid((gate_map_iterator_t)enumerator->current_position); | |
1019 | } | ||
1020 | else | ||
1021 | { | ||
1022 | ✗ | return false; | |
1023 | } | ||
1024 | } | ||
1025 | ✗ | static void const* gate_map_enumerate_get(gate_enumerator_t const* enumerator) | |
1026 | { | ||
1027 | ✗ | gate_map_iterator_t iter = (gate_map_iterator_t)enumerator->current_position; | |
1028 | ✗ | return &iter->mapping; | |
1029 | } | ||
1030 | |||
1031 | ✗ | gate_enumerator_t* gate_map_enumerate(gate_map_t const* m, gate_enumerator_t* enumerator) | |
1032 | { | ||
1033 | ✗ | enumerator->is_valid = &gate_map_enumerate_is_valid; | |
1034 | ✗ | enumerator->next = &gate_map_enumerate_next; | |
1035 | ✗ | enumerator->get = &gate_map_enumerate_get; | |
1036 | |||
1037 | ✗ | enumerator->ptr_origin = (void*)m; | |
1038 | ✗ | enumerator->current_position = (void*)gate_map_first(m); | |
1039 | ✗ | enumerator->end_position = (void*)gate_map_end(m); | |
1040 | ✗ | return enumerator; | |
1041 | } | ||
1042 | |||
1043 | |||
1044 | |||
1045 | |||
1046 | |||
1047 | /********************************* | ||
1048 | * Sequence map implementation * | ||
1049 | *********************************/ | ||
1050 | |||
1051 | 28 | gate_result_t gate_flatmap_copy_constructor(void* dest, void const* src) | |
1052 | { | ||
1053 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
|
28 | if (NULL == gate_flatmap_copy(dest, src)) |
1054 | { | ||
1055 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
1056 | } | ||
1057 | else | ||
1058 | { | ||
1059 | 28 | return GATE_RESULT_OK; | |
1060 | } | ||
1061 | } | ||
1062 | 28 | void gate_flatmap_destructor(void* dest) | |
1063 | { | ||
1064 | 28 | gate_flatmap_destroy(dest); | |
1065 | 28 | } | |
1066 | |||
1067 | |||
1068 | 1317 | static gate_mapping_t* gate_flatmap_entry_create(gate_flatmap_t* m, void const* key, void const* value) | |
1069 | { | ||
1070 | 1317 | gate_mapping_t* ret = NULL; | |
1071 | 1317 | gate_mapping_t* entry_block = NULL; | |
1072 | 1317 | char* key_block = NULL; | |
1073 | 1317 | char* value_block = NULL; | |
1074 | gate_result_t result; | ||
1075 | |||
1076 | do | ||
1077 | { | ||
1078 | 1317 | entry_block = (gate_mapping_t*)gate_mem_alloc(m->item_size); | |
1079 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1317 times.
|
1317 | if (entry_block == NULL) |
1080 | { | ||
1081 | ✗ | break; | |
1082 | } | ||
1083 | 1317 | gate_mem_clear(entry_block, m->item_size); | |
1084 | |||
1085 | 1317 | key_block = ((char*)entry_block) + m->item_key_offset; | |
1086 | 1317 | value_block = ((char*)entry_block) + m->item_value_offset; | |
1087 | |||
1088 | 1317 | result = gate_mem_copy_construct(key_block, key, m->key_size, m->key_constructor); | |
1089 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1317 times.
|
1317 | if (GATE_FAILED(result)) |
1090 | { | ||
1091 | /* failed to allocate key */ | ||
1092 | ✗ | break; | |
1093 | } | ||
1094 | |||
1095 | 1317 | result = gate_mem_copy_construct(value_block, value, m->value_size, m->value_constructor); | |
1096 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1317 times.
|
1317 | if (GATE_FAILED(result)) |
1097 | { | ||
1098 | /* failed to allocate value */ | ||
1099 | ✗ | gate_mem_destruct(key_block, m->key_destructor); | |
1100 | ✗ | break; | |
1101 | } | ||
1102 | 1317 | entry_block->key = key_block; | |
1103 | 1317 | entry_block->value = value_block; | |
1104 | |||
1105 | 1317 | ret = entry_block; | |
1106 | 1317 | entry_block = NULL; | |
1107 | |||
1108 | } while (0); | ||
1109 | |||
1110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1317 times.
|
1317 | if (entry_block != NULL) |
1111 | { | ||
1112 | ✗ | gate_mem_dealloc(entry_block); | |
1113 | } | ||
1114 | |||
1115 | 1317 | return ret; | |
1116 | } | ||
1117 | |||
1118 | 1317 | static void gate_flatmap_entry_destroy(gate_flatmap_t* m, gate_mapping_t* entry) | |
1119 | { | ||
1120 | 1317 | void* key_block = (void*)entry->key; | |
1121 | 1317 | void* value_block = entry->value; | |
1122 | |||
1123 | 1317 | gate_mem_destruct(key_block, m->key_destructor); | |
1124 | 1317 | gate_mem_destruct(value_block, m->value_destructor); | |
1125 | 1317 | gate_mem_dealloc(entry); | |
1126 | 1317 | } | |
1127 | |||
1128 | |||
1129 | 629 | gate_flatmap_t* gate_flatmap_create(gate_flatmap_t* m, | |
1130 | gate_comparer_t key_comparer, gate_size_t key_size, gate_mem_copyctor_t key_ctor, gate_mem_dtor_t key_dtor, | ||
1131 | gate_size_t value_size, gate_mem_copyctor_t value_ctor, gate_mem_dtor_t value_dtor) | ||
1132 | { | ||
1133 | 629 | gate_flatmap_t* ret = NULL; | |
1134 | do | ||
1135 | { | ||
1136 | 629 | gate_mem_clear(m, sizeof(gate_flatmap_t)); | |
1137 | |||
1138 | 629 | m->key_comparer = key_comparer; | |
1139 | 629 | m->key_size = key_size; | |
1140 | 629 | m->key_constructor = key_ctor; | |
1141 | 629 | m->key_destructor = key_dtor; | |
1142 | |||
1143 | 629 | m->value_size = value_size; | |
1144 | 629 | m->value_constructor = value_ctor; | |
1145 | 629 | m->value_destructor = value_dtor; | |
1146 | |||
1147 | 629 | m->item_key_offset = gate_mem_align_size(sizeof(gate_mapping_t)); | |
1148 | 629 | m->item_value_offset = m->item_key_offset + gate_mem_align_size(key_size); | |
1149 | 629 | m->item_size = m->item_value_offset + gate_mem_align_size(value_size); | |
1150 | |||
1151 | 629 | m->item_capacity = 0; | |
1152 | 629 | m->item_count = 0; | |
1153 | 629 | m->items = NULL; | |
1154 | |||
1155 | 629 | ret = m; | |
1156 | } while (0); | ||
1157 | 629 | return ret; | |
1158 | } | ||
1159 | |||
1160 | 595 | static gate_mapping_t** gate_flatmap_reserve(gate_flatmap_t* m, gate_size_t new_capacity) | |
1161 | { | ||
1162 | gate_mapping_t** new_contents; | ||
1163 | gate_size_t new_size; | ||
1164 |
1/2✓ Branch 0 taken 595 times.
✗ Branch 1 not taken.
|
595 | if (new_capacity > m->item_capacity) |
1165 | { | ||
1166 | 595 | new_size = sizeof(gate_mapping_t*) * new_capacity; | |
1167 | 595 | new_contents = (gate_mapping_t**)gate_mem_alloc(new_size); | |
1168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 595 times.
|
595 | if (new_contents == NULL) |
1169 | { | ||
1170 | ✗ | return NULL; | |
1171 | } | ||
1172 | 595 | gate_mem_clear(new_contents, new_size); | |
1173 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 585 times.
|
595 | if (m->items) |
1174 | { | ||
1175 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (m->item_count > 0) |
1176 | { | ||
1177 | 10 | gate_mem_copy(new_contents, m->items, sizeof(gate_mapping_t*) * m->item_count); | |
1178 | } | ||
1179 | 10 | gate_mem_dealloc(m->items); | |
1180 | } | ||
1181 | 595 | m->items = new_contents; | |
1182 | 595 | m->item_capacity = new_capacity; | |
1183 | } | ||
1184 | 595 | return m->items; | |
1185 | } | ||
1186 | |||
1187 | 1314 | static gate_mapping_t** gate_flatmap_new_entry_slot(gate_flatmap_t* m) | |
1188 | { | ||
1189 | gate_size_t new_capacity; | ||
1190 | |||
1191 |
2/2✓ Branch 0 taken 130 times.
✓ Branch 1 taken 1184 times.
|
1314 | if (m->item_count >= m->item_capacity) |
1192 | { | ||
1193 | 130 | new_capacity = m->item_count + 4 + m->item_count / 2; | |
1194 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 130 times.
|
130 | if (NULL == gate_flatmap_reserve(m, new_capacity)) |
1195 | { | ||
1196 | ✗ | return NULL; | |
1197 | } | ||
1198 | } | ||
1199 | 1314 | return &m->items[m->item_count]; | |
1200 | } | ||
1201 | |||
1202 | 501 | gate_flatmap_t* gate_flatmap_copy(gate_flatmap_t* dst, gate_flatmap_t const* src) | |
1203 | { | ||
1204 | 501 | gate_flatmap_t* ret = NULL; | |
1205 | gate_flatmap_iterator_t iter; | ||
1206 | void const* ptr_key; | ||
1207 | void const* ptr_value; | ||
1208 | 501 | int failed = 0; | |
1209 | |||
1210 | do | ||
1211 | { | ||
1212 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 501 times.
|
501 | if (NULL == gate_flatmap_create(dst, src->key_comparer, |
1213 | src->key_size, src->key_constructor, src->key_destructor, | ||
1214 | src->value_size, src->value_constructor, src->value_destructor)) | ||
1215 | { | ||
1216 | ✗ | dst = NULL; | |
1217 | ✗ | break; | |
1218 | } | ||
1219 | |||
1220 |
2/2✓ Branch 0 taken 465 times.
✓ Branch 1 taken 36 times.
|
501 | if (src->item_count > 0) |
1221 | { | ||
1222 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 465 times.
|
465 | if (NULL == gate_flatmap_reserve(dst, src->item_count)) |
1223 | { | ||
1224 | ✗ | break; | |
1225 | } | ||
1226 | 465 | iter = gate_flatmap_first(src); | |
1227 |
2/2✓ Branch 1 taken 1028 times.
✓ Branch 2 taken 465 times.
|
1493 | while (gate_flatmap_iterator_valid(src, iter)) |
1228 | { | ||
1229 | 1028 | ptr_key = gate_flatmap_iterator_key(iter); | |
1230 | 1028 | ptr_value = gate_flatmap_iterator_value(iter); | |
1231 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1028 times.
|
1028 | if (NULL == gate_flatmap_add(dst, ptr_key, ptr_value)) |
1232 | { | ||
1233 | ✗ | ++failed; | |
1234 | ✗ | break; | |
1235 | } | ||
1236 | 1028 | iter = gate_flatmap_iterator_next(iter); | |
1237 | } | ||
1238 | } | ||
1239 | |||
1240 |
1/2✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
|
501 | if (!failed) |
1241 | { | ||
1242 | 501 | ret = dst; | |
1243 | 501 | dst = NULL; | |
1244 | } | ||
1245 | |||
1246 | |||
1247 | } while (0); | ||
1248 | |||
1249 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 501 times.
|
501 | if (dst != NULL) |
1250 | { | ||
1251 | ✗ | gate_flatmap_destroy(dst); | |
1252 | } | ||
1253 | |||
1254 | 501 | return ret; | |
1255 | } | ||
1256 | |||
1257 | 601 | void gate_flatmap_destroy(gate_flatmap_t* m) | |
1258 | { | ||
1259 | 601 | gate_flatmap_clear(m); | |
1260 |
2/2✓ Branch 0 taken 585 times.
✓ Branch 1 taken 16 times.
|
601 | if (m->items) |
1261 | { | ||
1262 | 585 | gate_mem_dealloc(m->items); | |
1263 | } | ||
1264 | 601 | m->items = NULL; | |
1265 | 601 | m->item_capacity = 0; | |
1266 | /*gate_mem_clear(m, sizeof(gate_flatmap_t));*/ | ||
1267 | 601 | } | |
1268 | |||
1269 | 20 | gate_size_t gate_flatmap_count(gate_flatmap_t const* m) | |
1270 | { | ||
1271 | 20 | return m->item_count; | |
1272 | } | ||
1273 | |||
1274 | |||
1275 | 1317 | gate_flatmap_iterator_t gate_flatmap_add(gate_flatmap_t* m, void const* key, void const* value) | |
1276 | { | ||
1277 | 1317 | gate_flatmap_iterator_t ret = NULL; | |
1278 | gate_mapping_t** slot; | ||
1279 | 1317 | gate_mapping_t* new_entry = NULL; | |
1280 | |||
1281 | do | ||
1282 | { | ||
1283 | 1317 | new_entry = gate_flatmap_entry_create(m, key, value); | |
1284 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1317 times.
|
1317 | if (new_entry == NULL) |
1285 | { | ||
1286 | ✗ | break; | |
1287 | } | ||
1288 | |||
1289 | 1317 | slot = (gate_mapping_t**)gate_flatmap_get(m, key); | |
1290 |
2/2✓ Branch 0 taken 1314 times.
✓ Branch 1 taken 3 times.
|
1317 | if (slot == NULL) |
1291 | { | ||
1292 | 1314 | slot = gate_flatmap_new_entry_slot(m); | |
1293 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1314 times.
|
1314 | if (slot == NULL) |
1294 | { | ||
1295 | ✗ | break; | |
1296 | } | ||
1297 | 1314 | *slot = new_entry; | |
1298 | 1314 | ++m->item_count; | |
1299 | } | ||
1300 | else | ||
1301 | { | ||
1302 | 3 | gate_flatmap_entry_destroy(m, *slot); | |
1303 | 3 | *slot = new_entry; | |
1304 | } | ||
1305 | |||
1306 | 1317 | new_entry = NULL; | |
1307 | 1317 | ret = (gate_flatmap_iterator_t)slot; | |
1308 | } while (0); | ||
1309 | |||
1310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1317 times.
|
1317 | if (new_entry != NULL) |
1311 | { | ||
1312 | ✗ | gate_flatmap_entry_destroy(m, new_entry); | |
1313 | } | ||
1314 | 1317 | return ret; | |
1315 | } | ||
1316 | |||
1317 | |||
1318 | 6 | gate_bool_t gate_flatmap_remove(gate_flatmap_t* m, void const* key) | |
1319 | { | ||
1320 | 6 | gate_bool_t ret = false; | |
1321 | 6 | gate_flatmap_iterator_t entry = gate_flatmap_get(m, key); | |
1322 | 6 | gate_flatmap_iterator_t first_entry = gate_flatmap_first(m); | |
1323 | gate_size_t index; | ||
1324 | |||
1325 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
6 | if (entry != NULL) |
1326 | { | ||
1327 | 5 | index = entry - first_entry; | |
1328 | 5 | gate_flatmap_entry_destroy(m, *(void**)entry); | |
1329 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5 | if (index + 1 < m->item_count) |
1330 | { | ||
1331 | 2 | gate_mem_move((void*)entry, entry + 1, (m->item_count - index - 1) * sizeof(gate_mapping_t*)); | |
1332 | } | ||
1333 | 5 | --m->item_count; | |
1334 | 5 | m->items[m->item_count] = NULL; | |
1335 | 5 | ret = true; | |
1336 | } | ||
1337 | 6 | return ret; | |
1338 | } | ||
1339 | |||
1340 | ✗ | gate_bool_t gate_flatmap_is_empty(gate_flatmap_t const* m) | |
1341 | { | ||
1342 | ✗ | return m->item_count == 0; | |
1343 | } | ||
1344 | |||
1345 | 601 | void gate_flatmap_clear(gate_flatmap_t* m) | |
1346 | { | ||
1347 | 601 | gate_mapping_t** ptr = m->items; | |
1348 | 601 | gate_size_t count = m->item_count; | |
1349 |
2/2✓ Branch 0 taken 585 times.
✓ Branch 1 taken 16 times.
|
601 | if (m->item_capacity != 0) |
1350 | { | ||
1351 |
2/2✓ Branch 0 taken 1309 times.
✓ Branch 1 taken 585 times.
|
1894 | while (count-- != 0) |
1352 | { | ||
1353 | 1309 | gate_flatmap_entry_destroy(m, *ptr); | |
1354 | 1309 | ++ptr; | |
1355 | } | ||
1356 | 585 | gate_mem_clear(m->items, m->item_capacity * sizeof(gate_mapping_t*)); | |
1357 | 585 | m->item_count = 0; | |
1358 | } | ||
1359 | 601 | } | |
1360 | |||
1361 | ✗ | gate_size_t gate_flatmap_merge(gate_flatmap_t* m, gate_flatmap_t const* with) | |
1362 | { | ||
1363 | ✗ | gate_size_t merged_items = 0; | |
1364 | ✗ | gate_flatmap_iterator_t ptr = (gate_flatmap_iterator_t)with->items; | |
1365 | ✗ | gate_size_t count = with->item_count; | |
1366 | void const* current_key; | ||
1367 | void const* current_value; | ||
1368 | |||
1369 | ✗ | if ((with->key_size == m->key_size) && (with->value_size == m->value_size)) | |
1370 | { | ||
1371 | ✗ | while (count-- != 0) | |
1372 | { | ||
1373 | ✗ | current_key = gate_flatmap_iterator_key(ptr); | |
1374 | ✗ | current_value = gate_flatmap_iterator_value(ptr); | |
1375 | ✗ | if (NULL != gate_flatmap_add(m, current_key, current_value)) | |
1376 | { | ||
1377 | ✗ | ++merged_items; | |
1378 | } | ||
1379 | ✗ | ++ptr; | |
1380 | } | ||
1381 | } | ||
1382 | ✗ | return merged_items; | |
1383 | } | ||
1384 | |||
1385 | ✗ | gate_size_t gate_flatmap_remove_keys(gate_flatmap_t* m, gate_flatmap_t const* keys) | |
1386 | { | ||
1387 | ✗ | gate_size_t removed_items = 0; | |
1388 | ✗ | gate_flatmap_iterator_t ptr = (gate_flatmap_iterator_t)keys->items; | |
1389 | ✗ | gate_size_t count = keys->item_count; | |
1390 | void const* current_key; | ||
1391 | |||
1392 | ✗ | if (keys->key_size == m->key_size) | |
1393 | { | ||
1394 | ✗ | while (count-- != 0) | |
1395 | { | ||
1396 | ✗ | current_key = gate_flatmap_iterator_key(ptr); | |
1397 | ✗ | if (gate_flatmap_remove(m, current_key)) | |
1398 | { | ||
1399 | ✗ | ++removed_items; | |
1400 | } | ||
1401 | ✗ | ++ptr; | |
1402 | } | ||
1403 | } | ||
1404 | ✗ | return removed_items; | |
1405 | |||
1406 | } | ||
1407 | |||
1408 | 1909 | gate_flatmap_iterator_t gate_flatmap_get(gate_flatmap_t const* m, void const* key) | |
1409 | { | ||
1410 | void const* ptr_key; | ||
1411 | 1909 | gate_flatmap_iterator_t iter = (gate_flatmap_iterator_t)m->items; | |
1412 | 1909 | gate_size_t count = m->item_count; | |
1413 | |||
1414 |
2/2✓ Branch 0 taken 2114 times.
✓ Branch 1 taken 1343 times.
|
3457 | while (count-- != 0) |
1415 | { | ||
1416 | 2114 | ptr_key = gate_flatmap_iterator_key(iter); | |
1417 |
1/2✓ Branch 0 taken 2114 times.
✗ Branch 1 not taken.
|
2114 | if (ptr_key) |
1418 | { | ||
1419 |
2/2✓ Branch 1 taken 566 times.
✓ Branch 2 taken 1548 times.
|
2114 | if (0 == gate_compare_types(ptr_key, key, m->key_size, m->key_comparer)) |
1420 | { | ||
1421 | /* current iterator matches given key */ | ||
1422 | 566 | return iter; | |
1423 | } | ||
1424 | } | ||
1425 | 1548 | ++iter; | |
1426 | } | ||
1427 | 1343 | return NULL; | |
1428 | } | ||
1429 | |||
1430 | 2839 | gate_flatmap_iterator_t gate_flatmap_first(gate_flatmap_t const* m) | |
1431 | { | ||
1432 |
1/2✓ Branch 0 taken 2839 times.
✗ Branch 1 not taken.
|
2839 | if (m->item_count != 0) |
1433 | { | ||
1434 | 2839 | return (gate_flatmap_iterator_t)m->items; | |
1435 | } | ||
1436 | ✗ | return NULL; | |
1437 | } | ||
1438 | |||
1439 | 2339 | gate_flatmap_iterator_t gate_flatmap_last(gate_flatmap_t const* m) | |
1440 | { | ||
1441 |
1/2✓ Branch 0 taken 2339 times.
✗ Branch 1 not taken.
|
2339 | if (m->item_count != 0) |
1442 | { | ||
1443 | 2339 | return (gate_flatmap_iterator_t)&m->items[m->item_count - 1]; | |
1444 | } | ||
1445 | ✗ | return NULL; | |
1446 | } | ||
1447 | |||
1448 | 1 | gate_flatmap_iterator_t gate_flatmap_end(gate_flatmap_t const* m) | |
1449 | { | ||
1450 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (m->item_count != 0) |
1451 | { | ||
1452 | 1 | return (gate_flatmap_iterator_t)&m->items[m->item_count]; | |
1453 | } | ||
1454 | ✗ | return NULL; | |
1455 | } | ||
1456 | |||
1457 | 1098 | gate_flatmap_iterator_t gate_flatmap_iterator_next(gate_flatmap_iterator_t iterator) | |
1458 | { | ||
1459 |
1/2✓ Branch 0 taken 1098 times.
✗ Branch 1 not taken.
|
1098 | if (iterator) |
1460 | { | ||
1461 | 1098 | ++iterator; | |
1462 | } | ||
1463 | 1098 | return iterator; | |
1464 | } | ||
1465 | |||
1466 | ✗ | gate_flatmap_iterator_t gate_flatmap_iterator_prev(gate_flatmap_iterator_t iterator) | |
1467 | { | ||
1468 | ✗ | if (iterator) | |
1469 | { | ||
1470 | ✗ | --iterator; | |
1471 | } | ||
1472 | ✗ | return iterator; | |
1473 | } | ||
1474 | |||
1475 | ✗ | gate_bool_t gate_flatmap_iterator_equals(gate_flatmap_iterator_t iter1, gate_flatmap_iterator_t iter2) | |
1476 | { | ||
1477 | ✗ | return iter1 == iter2; | |
1478 | } | ||
1479 | |||
1480 | 2367 | gate_bool_t gate_flatmap_iterator_valid(gate_flatmap_t const* m, gate_flatmap_iterator_t iterator) | |
1481 | { | ||
1482 |
2/2✓ Branch 0 taken 2339 times.
✓ Branch 1 taken 28 times.
|
2367 | if (iterator) |
1483 | { | ||
1484 |
3/4✓ Branch 1 taken 2339 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1845 times.
✓ Branch 5 taken 494 times.
|
2339 | return ((iterator >= gate_flatmap_first(m)) && (iterator <= gate_flatmap_last(m))); |
1485 | } | ||
1486 | 28 | return false; | |
1487 | } | ||
1488 | |||
1489 | |||
1490 | ✗ | static gate_bool_t gate_flatmap_enumerate_is_valid(gate_enumerator_t const* enumerator) | |
1491 | { | ||
1492 | ✗ | return gate_flatmap_iterator_valid((gate_flatmap_t*)enumerator->ptr_origin, | |
1493 | ✗ | (gate_flatmap_iterator_t)enumerator->current_position); | |
1494 | } | ||
1495 | ✗ | static gate_bool_t gate_flatmap_enumerate_next(gate_enumerator_t* enumerator) | |
1496 | { | ||
1497 | ✗ | if (enumerator->current_position != NULL) | |
1498 | { | ||
1499 | ✗ | enumerator->current_position = | |
1500 | ✗ | (void*)gate_flatmap_iterator_next((gate_flatmap_iterator_t)enumerator->current_position); | |
1501 | ✗ | return gate_flatmap_iterator_valid((gate_flatmap_t*)enumerator->ptr_origin, | |
1502 | ✗ | (gate_flatmap_iterator_t)enumerator->current_position); | |
1503 | } | ||
1504 | else | ||
1505 | { | ||
1506 | ✗ | return false; | |
1507 | } | ||
1508 | } | ||
1509 | ✗ | static void const* gate_flatmap_enumerate_get(gate_enumerator_t const* enumerator) | |
1510 | { | ||
1511 | ✗ | return (void const*)enumerator->current_position; | |
1512 | } | ||
1513 | |||
1514 | 1 | gate_enumerator_t* gate_flatmap_enumerate(gate_flatmap_t const* m, gate_enumerator_t* enumerator) | |
1515 | { | ||
1516 | 1 | enumerator->is_valid = &gate_flatmap_enumerate_is_valid; | |
1517 | 1 | enumerator->next = &gate_flatmap_enumerate_next; | |
1518 | 1 | enumerator->get = &gate_flatmap_enumerate_get; | |
1519 | |||
1520 | 1 | enumerator->ptr_origin = (void*)m; | |
1521 | 1 | enumerator->current_position = (void*)gate_flatmap_first(m); | |
1522 | 1 | enumerator->end_position = (void*)gate_flatmap_end(m); | |
1523 | 1 | return enumerator; | |
1524 | } | ||
1525 | |||
1526 | ✗ | void* gate_flatmap_get_value(gate_flatmap_t* m, void const* key) | |
1527 | { | ||
1528 | ✗ | void* ret = NULL; | |
1529 | ✗ | gate_flatmap_iterator_t iter = gate_flatmap_get(m, key); | |
1530 | ✗ | if (iter != NULL) | |
1531 | { | ||
1532 | ✗ | return gate_flatmap_iterator_value(iter); | |
1533 | } | ||
1534 | ✗ | return ret; | |
1535 | } | ||
1536 | |||
1537 | 3212 | void const* gate_flatmap_iterator_key(gate_flatmap_iterator_t iterator) | |
1538 | { | ||
1539 |
2/4✓ Branch 0 taken 3212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3212 times.
✗ Branch 3 not taken.
|
3212 | if (iterator && *iterator) |
1540 | { | ||
1541 | 3212 | return (*iterator)->key; | |
1542 | } | ||
1543 | ✗ | return NULL; | |
1544 | } | ||
1545 | 1837 | void* gate_flatmap_iterator_value(gate_flatmap_iterator_t iterator) | |
1546 | { | ||
1547 |
2/4✓ Branch 0 taken 1837 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1837 times.
✗ Branch 3 not taken.
|
1837 | if (iterator && *iterator) |
1548 | { | ||
1549 | 1837 | return (*iterator)->value; | |
1550 | } | ||
1551 | ✗ | return NULL; | |
1552 | } | ||
1553 | |||
1554 | |||
1555 | |||
1556 | |||
1557 | |||
1558 | /*************************************** | ||
1559 | * Unordered hash map implementation * | ||
1560 | ***************************************/ | ||
1561 | |||
1562 | ✗ | static gate_size_t gate_hashmap_get_bucket_index(gate_hashmap_t const* m, void const* key) | |
1563 | { | ||
1564 | ✗ | gate_hash_code_t hash = m->hash_generator(key); | |
1565 | ✗ | gate_size_t bucket_index = (gate_size_t)hash % (gate_size_t)m->bucket_count; | |
1566 | ✗ | return bucket_index; | |
1567 | } | ||
1568 | |||
1569 | ✗ | static gate_size_t gate_hashmap_get_aligned_sized(gate_size_t sz) | |
1570 | { | ||
1571 | ✗ | gate_size_t diff = sz % sizeof(gate_c_maxalign_t); | |
1572 | ✗ | if (diff != 0) | |
1573 | { | ||
1574 | ✗ | sz += (sizeof(gate_c_maxalign_t) - diff); | |
1575 | } | ||
1576 | ✗ | return sz; | |
1577 | } | ||
1578 | |||
1579 | typedef struct gate_hashmap_entry_impl_class | ||
1580 | { | ||
1581 | gate_mapping_t base; | ||
1582 | gate_c_maxalign_t data_area; | ||
1583 | } gate_hashmap_entry_impl_t; | ||
1584 | |||
1585 | ✗ | static gate_mapping_t* gate_hashmap_create_entry(gate_hashmap_t const* m, void const* key, void const* value) | |
1586 | { | ||
1587 | gate_result_t result; | ||
1588 | ✗ | gate_size_t key_size = gate_hashmap_get_aligned_sized(m->key_size); | |
1589 | ✗ | gate_size_t value_size = gate_hashmap_get_aligned_sized(m->value_size); | |
1590 | ✗ | gate_size_t entry_size = sizeof(gate_hashmap_entry_impl_t) - sizeof(gate_c_maxalign_t) + key_size + value_size; | |
1591 | ✗ | gate_hashmap_entry_impl_t* ptr_entry = (gate_hashmap_entry_impl_t*)gate_mem_alloc(entry_size); | |
1592 | char* ptr; | ||
1593 | |||
1594 | ✗ | if (NULL == ptr_entry) | |
1595 | { | ||
1596 | ✗ | return NULL; | |
1597 | } | ||
1598 | ✗ | ptr = (char*)&ptr_entry->data_area; | |
1599 | ✗ | ptr_entry->base.key = ptr; | |
1600 | ✗ | ptr_entry->base.value = (ptr + value_size); | |
1601 | |||
1602 | ✗ | result = gate_mem_copy_construct(ptr, key, m->key_size, m->key_constructor); | |
1603 | ✗ | if (GATE_FAILED(result)) | |
1604 | { | ||
1605 | ✗ | gate_mem_dealloc(ptr_entry); | |
1606 | ✗ | return NULL; | |
1607 | } | ||
1608 | ✗ | result = gate_mem_copy_construct(ptr_entry->base.value, value, m->value_size, m->value_constructor); | |
1609 | ✗ | if (GATE_FAILED(result)) | |
1610 | { | ||
1611 | ✗ | gate_mem_destruct(ptr, m->key_destructor); | |
1612 | ✗ | gate_mem_dealloc(ptr_entry); | |
1613 | ✗ | return NULL; | |
1614 | } | ||
1615 | ✗ | return &ptr_entry->base; | |
1616 | } | ||
1617 | ✗ | static void gate_hashmap_destroy_entry(gate_hashmap_t const* m, gate_mapping_t* entry) | |
1618 | { | ||
1619 | ✗ | if (entry->key) | |
1620 | { | ||
1621 | ✗ | gate_mem_destruct((char*)entry->key, m->key_destructor); | |
1622 | } | ||
1623 | ✗ | if (entry->value) | |
1624 | { | ||
1625 | ✗ | gate_mem_destruct((char*)entry->value, m->value_destructor); | |
1626 | } | ||
1627 | ✗ | gate_mem_dealloc(entry); | |
1628 | ✗ | } | |
1629 | |||
1630 | ✗ | static gate_bool_t gate_hashmap_resolve_key(gate_hashmap_t const* m, void const* key, gate_size_t* bucket_index, gate_size_t* entry_index) | |
1631 | { | ||
1632 | ✗ | gate_size_t index = gate_hashmap_get_bucket_index(m, key); | |
1633 | ✗ | gate_hashmap_bucket_t const* bucket = m->buckets[index]; | |
1634 | gate_mapping_t const* ptr_entry; | ||
1635 | gate_size_t count; | ||
1636 | gate_intptr_t comp; | ||
1637 | |||
1638 | ✗ | *bucket_index = index; | |
1639 | ✗ | if (bucket != NULL) | |
1640 | { | ||
1641 | ✗ | count = bucket->size; | |
1642 | ✗ | for (index = 0; index != count; ++index) | |
1643 | { | ||
1644 | ✗ | ptr_entry = bucket->entries[index]; | |
1645 | ✗ | comp = gate_compare_types(ptr_entry->key, key, m->key_size, m->key_comparer); | |
1646 | ✗ | if (0 == comp) | |
1647 | { | ||
1648 | ✗ | *entry_index = index; | |
1649 | ✗ | return true; | |
1650 | } | ||
1651 | } | ||
1652 | } | ||
1653 | ✗ | return false; | |
1654 | } | ||
1655 | |||
1656 | ✗ | static gate_hashmap_bucket_t* gate_hashmap_create_bucket(gate_hashmap_t* m, gate_size_t entry_count) | |
1657 | { | ||
1658 | ✗ | gate_size_t bucket_size = sizeof(gate_hashmap_bucket_t) + sizeof(gate_mapping_t*) * (entry_count - 1); | |
1659 | ✗ | gate_hashmap_bucket_t* bucket = gate_mem_alloc(bucket_size); | |
1660 | (void)m; | ||
1661 | ✗ | if (NULL != bucket) | |
1662 | { | ||
1663 | ✗ | gate_mem_clear(bucket, bucket_size); | |
1664 | ✗ | bucket->capacity = entry_count; | |
1665 | ✗ | bucket->size = 0; | |
1666 | } | ||
1667 | ✗ | return bucket; | |
1668 | } | ||
1669 | |||
1670 | ✗ | static gate_result_t gate_hashmap_insert_entry(gate_hashmap_t* m, gate_mapping_t* insert_entry) | |
1671 | { | ||
1672 | ✗ | gate_size_t index = gate_hashmap_get_bucket_index(m, insert_entry->key); | |
1673 | ✗ | gate_hashmap_bucket_t* bucket = m->buckets[index]; | |
1674 | ✗ | gate_hashmap_bucket_t* new_bucket = NULL; | |
1675 | gate_mapping_t* ptr_entry; | ||
1676 | gate_size_t new_capacity; | ||
1677 | gate_size_t count; | ||
1678 | gate_intptr_t comp; | ||
1679 | |||
1680 | ✗ | if (bucket == NULL) | |
1681 | { | ||
1682 | ✗ | bucket = gate_hashmap_create_bucket(m, 8); | |
1683 | ✗ | if (bucket == NULL) | |
1684 | { | ||
1685 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
1686 | } | ||
1687 | else | ||
1688 | { | ||
1689 | ✗ | m->buckets[index] = bucket; | |
1690 | } | ||
1691 | } | ||
1692 | |||
1693 | ✗ | count = bucket->size; | |
1694 | ✗ | for (index = 0; index != count; ++index) | |
1695 | { | ||
1696 | ✗ | ptr_entry = bucket->entries[index]; | |
1697 | ✗ | comp = gate_compare_types(ptr_entry->key, insert_entry->key, m->key_size, m->key_comparer); | |
1698 | ✗ | if (0 == comp) | |
1699 | { | ||
1700 | /* replace existing entry */ | ||
1701 | ✗ | gate_hashmap_destroy_entry(m, ptr_entry); | |
1702 | ✗ | bucket->entries[index] = insert_entry; | |
1703 | ✗ | return GATE_RESULT_OK; | |
1704 | } | ||
1705 | } | ||
1706 | ✗ | if (bucket->size >= bucket->capacity) | |
1707 | { | ||
1708 | /* create new bucket with greater array size */ | ||
1709 | ✗ | new_capacity = bucket->size + 4 + bucket->size / 2; | |
1710 | ✗ | new_bucket = gate_hashmap_create_bucket(m, new_capacity); | |
1711 | ✗ | if (new_bucket == NULL) | |
1712 | { | ||
1713 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
1714 | } | ||
1715 | ✗ | gate_mem_copy(&new_bucket->entries[0], &bucket->entries[0], sizeof(gate_mapping_t*) * bucket->size); | |
1716 | ✗ | new_bucket->size = bucket->size; | |
1717 | ✗ | m->buckets[index] = new_bucket; | |
1718 | ✗ | gate_mem_dealloc(bucket); | |
1719 | ✗ | bucket = new_bucket; | |
1720 | } | ||
1721 | |||
1722 | /* add new entry to bucket */ | ||
1723 | ✗ | bucket->entries[bucket->size] = insert_entry; | |
1724 | ✗ | ++bucket->size; | |
1725 | ✗ | ++m->entry_count; | |
1726 | ✗ | return GATE_RESULT_OK; | |
1727 | |||
1728 | } | ||
1729 | |||
1730 | ✗ | static gate_result_t gate_hashmap_insert(gate_hashmap_t* m, void const* key, void const* value) | |
1731 | { | ||
1732 | ✗ | gate_result_t ret = GATE_RESULT_FAILED; | |
1733 | ✗ | gate_mapping_t* new_entry = gate_hashmap_create_entry(m, key, value); | |
1734 | ✗ | if (NULL == new_entry) | |
1735 | { | ||
1736 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
1737 | } | ||
1738 | else | ||
1739 | { | ||
1740 | ✗ | ret = gate_hashmap_insert_entry(m, new_entry); | |
1741 | ✗ | if (GATE_FAILED(ret)) | |
1742 | { | ||
1743 | ✗ | gate_hashmap_destroy_entry(m, new_entry); | |
1744 | } | ||
1745 | } | ||
1746 | ✗ | return ret; | |
1747 | } | ||
1748 | |||
1749 | |||
1750 | //static gate_hashmap_bucket_t* gate_hashmap_access | ||
1751 | |||
1752 | ✗ | gate_hashmap_t* gate_hashmap_create(gate_hashmap_t* m, gate_comparer_t key_comparer, gate_type_hash_generator_t hash_function, | |
1753 | gate_size_t key_size, gate_mem_copyctor_t key_ctor, gate_mem_dtor_t key_dtor, | ||
1754 | gate_size_t value_size, gate_mem_copyctor_t value_ctor, gate_mem_dtor_t value_dtor) | ||
1755 | { | ||
1756 | ✗ | gate_mem_clear(m, sizeof(gate_hashmap_t)); | |
1757 | ✗ | m->key_comparer = key_comparer; | |
1758 | ✗ | m->hash_generator = hash_function; | |
1759 | |||
1760 | ✗ | m->key_size = key_size; | |
1761 | ✗ | m->key_constructor = key_ctor; | |
1762 | ✗ | m->key_destructor = key_dtor; | |
1763 | |||
1764 | ✗ | m->value_size = value_size; | |
1765 | ✗ | m->value_constructor = value_ctor; | |
1766 | ✗ | m->value_destructor = value_dtor; | |
1767 | |||
1768 | ✗ | m->entry_count = 0; | |
1769 | ✗ | m->bucket_count = 0; | |
1770 | ✗ | m->buckets = NULL; | |
1771 | ✗ | return m; | |
1772 | } | ||
1773 | ✗ | gate_hashmap_t* gate_hashmap_copy(gate_hashmap_t* dst, gate_hashmap_t const* src) | |
1774 | { | ||
1775 | gate_hashmap_iterator_t iter; | ||
1776 | gate_result_t result; | ||
1777 | void const* ptr_key; | ||
1778 | void const* ptr_value; | ||
1779 | |||
1780 | ✗ | if (NULL == gate_hashmap_create(dst, src->key_comparer, src->hash_generator, | |
1781 | src->key_size, src->key_constructor, src->key_destructor, | ||
1782 | src->value_size, src->value_constructor, src->value_destructor)) | ||
1783 | { | ||
1784 | ✗ | return NULL; | |
1785 | } | ||
1786 | |||
1787 | ✗ | for (iter = gate_hashmap_first(src); gate_hashmap_iterator_valid(iter); iter = gate_hashmap_iterator_next(iter)) | |
1788 | { | ||
1789 | ✗ | ptr_key = gate_hashmap_iterator_key(iter); | |
1790 | ✗ | ptr_value = gate_hashmap_iterator_value(iter); | |
1791 | ✗ | result = gate_hashmap_insert(dst, ptr_key, ptr_value); | |
1792 | ✗ | if (GATE_FAILED(result)) | |
1793 | { | ||
1794 | ✗ | gate_hashmap_destroy(dst); | |
1795 | ✗ | return NULL; | |
1796 | } | ||
1797 | } | ||
1798 | ✗ | return dst; | |
1799 | } | ||
1800 | ✗ | void gate_hashmap_destroy(gate_hashmap_t* m) | |
1801 | { | ||
1802 | ✗ | gate_hashmap_clear(m); | |
1803 | ✗ | gate_mem_dealloc(m->buckets); | |
1804 | ✗ | m->buckets = NULL; | |
1805 | ✗ | m->bucket_count = 0; | |
1806 | ✗ | } | |
1807 | ✗ | gate_size_t gate_hashmap_count(gate_hashmap_t const* m) | |
1808 | { | ||
1809 | ✗ | return m->entry_count; | |
1810 | } | ||
1811 | |||
1812 | static gate_size_t const bucket_thresholds[] = { | ||
1813 | 16777216, | ||
1814 | 1048576, | ||
1815 | 65536, | ||
1816 | 4096, | ||
1817 | 64 | ||
1818 | }; | ||
1819 | |||
1820 | static gate_size_t const bucket_thresholds_count = (sizeof(bucket_thresholds) / sizeof(bucket_thresholds[0])); | ||
1821 | |||
1822 | |||
1823 | ✗ | static void gate_hashmap_detach_all_entries(gate_hashmap_t* m) | |
1824 | { | ||
1825 | gate_size_t buck_index, entry_index; | ||
1826 | gate_hashmap_bucket_t* ptr_bucket; | ||
1827 | |||
1828 | ✗ | for (buck_index = 0; buck_index < m->bucket_count; ++buck_index) | |
1829 | { | ||
1830 | ✗ | ptr_bucket = m->buckets[buck_index]; | |
1831 | ✗ | if (ptr_bucket) | |
1832 | { | ||
1833 | ✗ | for (entry_index = 0; entry_index < ptr_bucket->size; ++entry_index) | |
1834 | { | ||
1835 | ✗ | ptr_bucket->entries[entry_index] = NULL; | |
1836 | } | ||
1837 | ✗ | ptr_bucket->size = 0; | |
1838 | } | ||
1839 | } | ||
1840 | ✗ | m->entry_count = 0; | |
1841 | ✗ | } | |
1842 | |||
1843 | ✗ | static gate_result_t gate_hashmap_update_bucket_count(gate_hashmap_t* m) | |
1844 | { | ||
1845 | gate_size_t index; | ||
1846 | ✗ | gate_size_t new_bucket_count = 0; | |
1847 | gate_hashmap_t new_hashmap; | ||
1848 | gate_size_t buck_index, entry_index; | ||
1849 | gate_hashmap_bucket_t* ptr_bucket; | ||
1850 | gate_mapping_t* ptr_entry; | ||
1851 | gate_result_t result; | ||
1852 | gate_size_t sz; | ||
1853 | |||
1854 | ✗ | for (index = 0; index != bucket_thresholds_count; ++index) | |
1855 | { | ||
1856 | ✗ | if (m->entry_count >= bucket_thresholds[index]) | |
1857 | { | ||
1858 | ✗ | new_bucket_count = bucket_thresholds[index]; | |
1859 | ✗ | break; | |
1860 | } | ||
1861 | } | ||
1862 | ✗ | if (new_bucket_count == 0) | |
1863 | { | ||
1864 | ✗ | new_bucket_count = bucket_thresholds[bucket_thresholds_count - 1]; | |
1865 | } | ||
1866 | ✗ | if (m->bucket_count < new_bucket_count) | |
1867 | { | ||
1868 | ✗ | gate_mem_copy(&new_hashmap, m, sizeof(gate_hashmap_t)); | |
1869 | |||
1870 | ✗ | new_hashmap.bucket_count = new_bucket_count; | |
1871 | ✗ | new_hashmap.entry_count = 0; | |
1872 | ✗ | sz = sizeof(gate_hashmap_bucket_t*) * new_bucket_count; | |
1873 | ✗ | new_hashmap.buckets = (gate_hashmap_bucket_t**)gate_mem_alloc(sz); | |
1874 | ✗ | if (NULL == new_hashmap.buckets) | |
1875 | { | ||
1876 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
1877 | } | ||
1878 | ✗ | gate_mem_clear(new_hashmap.buckets, sz); | |
1879 | |||
1880 | ✗ | for (buck_index = 0; buck_index < m->bucket_count; ++buck_index) | |
1881 | { | ||
1882 | ✗ | ptr_bucket = m->buckets[buck_index]; | |
1883 | ✗ | if (ptr_bucket) | |
1884 | { | ||
1885 | ✗ | for (entry_index = 0; entry_index < ptr_bucket->size; ++entry_index) | |
1886 | { | ||
1887 | ✗ | ptr_entry = ptr_bucket->entries[entry_index]; | |
1888 | /* attach existing entries to new hashmap */ | ||
1889 | ✗ | result = gate_hashmap_insert_entry(&new_hashmap, ptr_entry); | |
1890 | ✗ | if (GATE_FAILED(result)) | |
1891 | { | ||
1892 | /* remove attached entries from new hashmap */ | ||
1893 | ✗ | gate_hashmap_detach_all_entries(&new_hashmap); | |
1894 | ✗ | gate_hashmap_destroy(&new_hashmap); | |
1895 | ✗ | return result; | |
1896 | } | ||
1897 | } | ||
1898 | } | ||
1899 | } | ||
1900 | /* all entries were transfered to new_hashmap */ | ||
1901 | |||
1902 | ✗ | gate_hashmap_detach_all_entries(m); /* remove old hashmap's entry references */ | |
1903 | ✗ | gate_mem_copy(m, &new_hashmap, sizeof(gate_hashmap_t)); | |
1904 | ✗ | gate_mem_clear(&new_hashmap, sizeof(gate_hashmap_t)); | |
1905 | } | ||
1906 | ✗ | return GATE_RESULT_OK; | |
1907 | } | ||
1908 | |||
1909 | ✗ | gate_hashmap_iterator_t gate_hashmap_add(gate_hashmap_t* m, void const* key, void const* value) | |
1910 | { | ||
1911 | ✗ | gate_hashmap_iterator_t end = gate_hashmap_end(m); | |
1912 | gate_hashmap_iterator_t ret; | ||
1913 | gate_bool_t found; | ||
1914 | gate_result_t result; | ||
1915 | |||
1916 | do | ||
1917 | { | ||
1918 | ✗ | if (m->entry_count >= m->bucket_count) | |
1919 | { | ||
1920 | ✗ | result = gate_hashmap_update_bucket_count(m); | |
1921 | ✗ | if (GATE_FAILED(result)) | |
1922 | { | ||
1923 | ✗ | ret = end; | |
1924 | ✗ | break; | |
1925 | } | ||
1926 | } | ||
1927 | |||
1928 | ✗ | result = gate_hashmap_insert(m, key, value); | |
1929 | ✗ | if (GATE_FAILED(result)) | |
1930 | { | ||
1931 | ✗ | ret = end; | |
1932 | ✗ | break; | |
1933 | } | ||
1934 | |||
1935 | ✗ | ret.hashmap = m; | |
1936 | ✗ | found = gate_hashmap_resolve_key(m, key, &ret.bucket_index, &ret.entry_index); | |
1937 | ✗ | if (!found) | |
1938 | { | ||
1939 | ✗ | ret = end; | |
1940 | } | ||
1941 | |||
1942 | } while (0); | ||
1943 | |||
1944 | ✗ | return ret; | |
1945 | } | ||
1946 | ✗ | gate_bool_t gate_hashmap_remove(gate_hashmap_t* m, void const* key) | |
1947 | { | ||
1948 | ✗ | gate_bool_t removed = false; | |
1949 | gate_size_t bucket; | ||
1950 | gate_size_t entry; | ||
1951 | ✗ | gate_bool_t resolved = gate_hashmap_resolve_key(m, key, &bucket, &entry); | |
1952 | gate_hashmap_bucket_t* ptr_bucket; | ||
1953 | ✗ | if (resolved) | |
1954 | { | ||
1955 | ✗ | ptr_bucket = m->buckets[bucket]; | |
1956 | ✗ | gate_hashmap_destroy_entry(m, ptr_bucket->entries[entry]); | |
1957 | ✗ | --ptr_bucket->size; | |
1958 | ✗ | if (entry < ptr_bucket->size) | |
1959 | { | ||
1960 | ✗ | ptr_bucket->entries[entry] = ptr_bucket->entries[ptr_bucket->size]; | |
1961 | ✗ | ptr_bucket->entries[ptr_bucket->size] = NULL; | |
1962 | } | ||
1963 | else | ||
1964 | { | ||
1965 | ✗ | ptr_bucket->entries[entry] = NULL; | |
1966 | } | ||
1967 | ✗ | --m->entry_count; | |
1968 | ✗ | removed = true; | |
1969 | } | ||
1970 | ✗ | return removed; | |
1971 | } | ||
1972 | ✗ | gate_bool_t gate_hashmap_is_empty(gate_hashmap_t const* m) | |
1973 | { | ||
1974 | ✗ | return m->entry_count == 0; | |
1975 | } | ||
1976 | ✗ | void gate_hashmap_clear(gate_hashmap_t* m) | |
1977 | { | ||
1978 | gate_size_t bucket; | ||
1979 | gate_size_t entry; | ||
1980 | gate_hashmap_bucket_t* ptr_bucket; | ||
1981 | gate_mapping_t* ptr_entry; | ||
1982 | |||
1983 | ✗ | for (bucket = 0; bucket < m->bucket_count; ++bucket) | |
1984 | { | ||
1985 | ✗ | ptr_bucket = m->buckets[bucket]; | |
1986 | ✗ | if (ptr_bucket) | |
1987 | { | ||
1988 | ✗ | for (entry = 0; entry != ptr_bucket->size; ++entry) | |
1989 | { | ||
1990 | ✗ | ptr_entry = ptr_bucket->entries[entry]; | |
1991 | ✗ | GATE_DEBUG_ASSERT(ptr_entry != NULL); | |
1992 | ✗ | gate_hashmap_destroy_entry(m, ptr_entry); | |
1993 | } | ||
1994 | ✗ | gate_mem_dealloc(ptr_bucket); | |
1995 | ✗ | m->buckets[bucket] = NULL; | |
1996 | } | ||
1997 | } | ||
1998 | ✗ | m->entry_count = 0; | |
1999 | ✗ | } | |
2000 | ✗ | gate_size_t gate_hashmap_merge(gate_hashmap_t* m, gate_hashmap_t const* with) | |
2001 | { | ||
2002 | ✗ | gate_hashmap_iterator_t iter = gate_hashmap_first(with); | |
2003 | ✗ | gate_size_t ret = 0; | |
2004 | void const* ptr_key; | ||
2005 | void const* ptr_value; | ||
2006 | |||
2007 | ✗ | while (gate_hashmap_iterator_valid(iter)) | |
2008 | { | ||
2009 | ✗ | ptr_key = gate_hashmap_iterator_key(iter); | |
2010 | ✗ | ptr_value = gate_hashmap_iterator_value(iter); | |
2011 | ✗ | if (gate_hashmap_iterator_valid(gate_hashmap_add(m, ptr_key, ptr_value))) | |
2012 | { | ||
2013 | ✗ | ++ret; | |
2014 | } | ||
2015 | } | ||
2016 | ✗ | return ret; | |
2017 | } | ||
2018 | ✗ | gate_size_t gate_hashmap_remove_keys(gate_hashmap_t* m, gate_hashmap_t const* keys) | |
2019 | { | ||
2020 | ✗ | gate_hashmap_iterator_t iter = gate_hashmap_first(keys); | |
2021 | ✗ | gate_size_t ret = 0; | |
2022 | void const* ptr_key; | ||
2023 | |||
2024 | ✗ | while (gate_hashmap_iterator_valid(iter)) | |
2025 | { | ||
2026 | ✗ | ptr_key = gate_hashmap_iterator_key(iter); | |
2027 | ✗ | if (gate_hashmap_remove(m, ptr_key)) | |
2028 | { | ||
2029 | ✗ | ++ret; | |
2030 | } | ||
2031 | } | ||
2032 | ✗ | return ret; | |
2033 | } | ||
2034 | |||
2035 | ✗ | gate_hashmap_iterator_t gate_hashmap_get(gate_hashmap_t const* m, void const* key) | |
2036 | { | ||
2037 | gate_hashmap_iterator_t iter; | ||
2038 | ✗ | gate_bool_t found = gate_hashmap_resolve_key(m, key, &iter.bucket_index, &iter.entry_index); | |
2039 | ✗ | if (found) | |
2040 | { | ||
2041 | ✗ | iter.hashmap = m; | |
2042 | } | ||
2043 | else | ||
2044 | { | ||
2045 | ✗ | iter = gate_hashmap_end(m); | |
2046 | } | ||
2047 | ✗ | return iter; | |
2048 | } | ||
2049 | ✗ | gate_hashmap_iterator_t gate_hashmap_first(gate_hashmap_t const* m) | |
2050 | { | ||
2051 | gate_size_t bucket; | ||
2052 | gate_hashmap_iterator_t new_iter; | ||
2053 | |||
2054 | ✗ | for (bucket = 0; bucket < m->bucket_count; ++bucket) | |
2055 | { | ||
2056 | ✗ | if (m->buckets[bucket]) | |
2057 | { | ||
2058 | ✗ | if (m->buckets[bucket]->size > 0) | |
2059 | { | ||
2060 | ✗ | new_iter.hashmap = m; | |
2061 | ✗ | new_iter.bucket_index = bucket; | |
2062 | ✗ | new_iter.entry_index = 0; | |
2063 | ✗ | GATE_DEBUG_ASSERT(m->buckets[new_iter.bucket_index]->entries[new_iter.entry_index] != NULL); | |
2064 | ✗ | return new_iter; | |
2065 | } | ||
2066 | } | ||
2067 | } | ||
2068 | ✗ | return gate_hashmap_end(m); | |
2069 | } | ||
2070 | ✗ | gate_hashmap_iterator_t gate_hashmap_last(gate_hashmap_t const* m) | |
2071 | { | ||
2072 | gate_size_t bucket; | ||
2073 | gate_hashmap_iterator_t new_iter; | ||
2074 | |||
2075 | ✗ | for (bucket = m->bucket_count; bucket > 0; ) | |
2076 | { | ||
2077 | ✗ | --bucket; | |
2078 | ✗ | if (m->buckets[bucket]) | |
2079 | { | ||
2080 | ✗ | if (m->buckets[bucket]->size > 0) | |
2081 | { | ||
2082 | ✗ | new_iter.hashmap = m; | |
2083 | ✗ | new_iter.bucket_index = bucket; | |
2084 | ✗ | new_iter.entry_index = m->buckets[bucket]->size - 1; | |
2085 | ✗ | GATE_DEBUG_ASSERT(m->buckets[new_iter.bucket_index]->entries[new_iter.entry_index] != NULL); | |
2086 | ✗ | return new_iter; | |
2087 | } | ||
2088 | } | ||
2089 | } | ||
2090 | ✗ | return gate_hashmap_end(m); | |
2091 | |||
2092 | } | ||
2093 | ✗ | gate_hashmap_iterator_t gate_hashmap_end(gate_hashmap_t const* m) | |
2094 | { | ||
2095 | gate_hashmap_iterator_t iter; | ||
2096 | ✗ | iter.hashmap = m; | |
2097 | ✗ | iter.bucket_index = (gate_size_t)(-1); | |
2098 | ✗ | iter.entry_index = (gate_size_t)(-1); | |
2099 | ✗ | return iter; | |
2100 | } | ||
2101 | ✗ | gate_hashmap_iterator_t gate_hashmap_iterator_next(gate_hashmap_iterator_t iterator) | |
2102 | { | ||
2103 | gate_size_t bucket; | ||
2104 | ✗ | gate_hashmap_t const* m = iterator.hashmap; | |
2105 | gate_hashmap_iterator_t new_iter; | ||
2106 | |||
2107 | ✗ | if (gate_hashmap_iterator_valid(iterator)) | |
2108 | { | ||
2109 | ✗ | bucket = iterator.bucket_index; | |
2110 | ✗ | if (iterator.entry_index + 1 < m->buckets[bucket]->size) | |
2111 | { | ||
2112 | ✗ | new_iter.hashmap = m; | |
2113 | ✗ | new_iter.bucket_index = bucket; | |
2114 | ✗ | new_iter.entry_index = iterator.entry_index + 1; | |
2115 | ✗ | GATE_DEBUG_ASSERT(m->buckets[new_iter.bucket_index]->entries[new_iter.entry_index] != NULL); | |
2116 | ✗ | return new_iter; | |
2117 | } | ||
2118 | ✗ | for (bucket = iterator.bucket_index + 1; bucket < m->bucket_count; ++bucket) | |
2119 | { | ||
2120 | ✗ | if (m->buckets[bucket]) | |
2121 | { | ||
2122 | ✗ | if (m->buckets[bucket]->size > 0) | |
2123 | { | ||
2124 | ✗ | new_iter.hashmap = m; | |
2125 | ✗ | new_iter.bucket_index = bucket; | |
2126 | ✗ | new_iter.entry_index = 0; | |
2127 | ✗ | GATE_DEBUG_ASSERT(m->buckets[new_iter.bucket_index]->entries[new_iter.entry_index] != NULL); | |
2128 | ✗ | return new_iter; | |
2129 | } | ||
2130 | } | ||
2131 | } | ||
2132 | } | ||
2133 | ✗ | return gate_hashmap_end(m); | |
2134 | } | ||
2135 | ✗ | gate_hashmap_iterator_t gate_hashmap_iterator_prev(gate_hashmap_iterator_t iterator) | |
2136 | { | ||
2137 | gate_size_t bucket; | ||
2138 | ✗ | gate_hashmap_t const* m = iterator.hashmap; | |
2139 | gate_hashmap_iterator_t new_iter; | ||
2140 | |||
2141 | ✗ | if (gate_hashmap_iterator_valid(iterator)) | |
2142 | { | ||
2143 | ✗ | if (iterator.entry_index > 0) | |
2144 | { | ||
2145 | ✗ | new_iter.hashmap = m; | |
2146 | ✗ | new_iter.bucket_index = iterator.bucket_index; | |
2147 | ✗ | new_iter.entry_index = iterator.entry_index - 1; | |
2148 | ✗ | GATE_DEBUG_ASSERT(m->buckets[new_iter.bucket_index]->entries[new_iter.entry_index] != NULL); | |
2149 | ✗ | return new_iter; | |
2150 | } | ||
2151 | |||
2152 | ✗ | bucket = iterator.bucket_index; | |
2153 | ✗ | while (bucket > 0) | |
2154 | { | ||
2155 | ✗ | --bucket; | |
2156 | ✗ | if (m->buckets[bucket]->size > 0) | |
2157 | { | ||
2158 | ✗ | new_iter.hashmap = m; | |
2159 | ✗ | new_iter.bucket_index = bucket; | |
2160 | ✗ | new_iter.entry_index = m->buckets[bucket]->size - 1; | |
2161 | ✗ | GATE_DEBUG_ASSERT(m->buckets[new_iter.bucket_index]->entries[new_iter.entry_index] != NULL); | |
2162 | ✗ | return new_iter; | |
2163 | } | ||
2164 | } | ||
2165 | } | ||
2166 | ✗ | return gate_hashmap_end(m); | |
2167 | } | ||
2168 | ✗ | gate_bool_t gate_hashmap_iterator_equals(gate_hashmap_iterator_t iter1, gate_hashmap_iterator_t iter2) | |
2169 | { | ||
2170 | ✗ | return (iter1.hashmap == iter2.hashmap) | |
2171 | ✗ | && (iter1.bucket_index == iter2.bucket_index) | |
2172 | ✗ | && (iter1.entry_index == iter2.entry_index) | |
2173 | ; | ||
2174 | } | ||
2175 | ✗ | gate_bool_t gate_hashmap_iterator_valid(gate_hashmap_iterator_t iterator) | |
2176 | { | ||
2177 | ✗ | if (!iterator.hashmap) | |
2178 | { | ||
2179 | ✗ | return false; | |
2180 | } | ||
2181 | ✗ | if (iterator.bucket_index >= iterator.hashmap->bucket_count) | |
2182 | { | ||
2183 | ✗ | return false; | |
2184 | } | ||
2185 | ✗ | if (iterator.entry_index >= iterator.hashmap->buckets[iterator.bucket_index]->size) | |
2186 | { | ||
2187 | ✗ | return false; | |
2188 | } | ||
2189 | ✗ | return NULL != iterator.hashmap->buckets[iterator.bucket_index]->entries[iterator.entry_index]; | |
2190 | } | ||
2191 | |||
2192 | |||
2193 | ✗ | static gate_bool_t gate_hashmap_enum_is_valid(gate_enumerator_t const* enumerator) | |
2194 | { | ||
2195 | ✗ | gate_hashmap_iterator_t* ptr_iter = (gate_hashmap_iterator_t*)&enumerator->handles[0]; | |
2196 | ✗ | return gate_hashmap_iterator_valid(*ptr_iter); | |
2197 | } | ||
2198 | ✗ | static gate_bool_t gate_hashmap_enum_next(gate_enumerator_t* enumerator) | |
2199 | { | ||
2200 | ✗ | gate_hashmap_iterator_t* ptr_iter = (gate_hashmap_iterator_t*)&enumerator->handles[0]; | |
2201 | gate_hashmap_iterator_t next_iter; | ||
2202 | ✗ | if (gate_hashmap_iterator_valid(*ptr_iter)) | |
2203 | { | ||
2204 | ✗ | next_iter = gate_hashmap_iterator_next(*ptr_iter); | |
2205 | ✗ | gate_mem_copy(&enumerator->handles[0], &next_iter, sizeof(gate_hashmap_iterator_t)); | |
2206 | ✗ | if (gate_hashmap_iterator_valid(next_iter)) | |
2207 | { | ||
2208 | ✗ | enumerator->current_position = next_iter.hashmap->buckets[next_iter.bucket_index]->entries[next_iter.entry_index]; | |
2209 | ✗ | return true; | |
2210 | } | ||
2211 | else | ||
2212 | { | ||
2213 | ✗ | enumerator->current_position = NULL; | |
2214 | ✗ | return false; | |
2215 | } | ||
2216 | } | ||
2217 | else | ||
2218 | { | ||
2219 | ✗ | return false; | |
2220 | } | ||
2221 | } | ||
2222 | ✗ | static void const* gate_hashmap_enum_get(gate_enumerator_t const* enumerator) | |
2223 | { | ||
2224 | ✗ | gate_mapping_t const* ptr_iter = (gate_mapping_t const*)enumerator->current_position; | |
2225 | ✗ | return ptr_iter; | |
2226 | } | ||
2227 | |||
2228 | ✗ | gate_enumerator_t* gate_hashmap_enumerate(gate_hashmap_t const* m, gate_enumerator_t* enumerator) | |
2229 | { | ||
2230 | ✗ | gate_enumerator_t* ret = NULL; | |
2231 | ✗ | gate_hashmap_iterator_t iter = gate_hashmap_first(m); | |
2232 | ✗ | gate_mem_clear(enumerator, sizeof(gate_enumerator_t)); | |
2233 | ✗ | enumerator->ptr_origin = m; | |
2234 | ✗ | enumerator->is_valid = &gate_hashmap_enum_is_valid; | |
2235 | ✗ | enumerator->next = &gate_hashmap_enum_next; | |
2236 | ✗ | enumerator->get = &gate_hashmap_enum_get; | |
2237 | ✗ | GATE_DEBUG_ASSERT(sizeof(enumerator->handles) >= sizeof(iter)); | |
2238 | ✗ | gate_mem_copy(&enumerator->handles[0], &iter, sizeof(gate_hashmap_iterator_t)); | |
2239 | ✗ | if (gate_hashmap_iterator_valid(iter)) | |
2240 | { | ||
2241 | ✗ | enumerator->current_position = m->buckets[iter.bucket_index]->entries[iter.entry_index]; | |
2242 | } | ||
2243 | ✗ | ret = enumerator; | |
2244 | ✗ | return ret; | |
2245 | } | ||
2246 | ✗ | void* gate_hashmap_get_value(gate_hashmap_t const* m, void const* key) | |
2247 | { | ||
2248 | gate_size_t bucket_index; | ||
2249 | gate_size_t entry_index; | ||
2250 | gate_bool_t found; | ||
2251 | ✗ | found = gate_hashmap_resolve_key(m, key, &bucket_index, &entry_index); | |
2252 | ✗ | if (found) | |
2253 | { | ||
2254 | ✗ | return m->buckets[bucket_index]->entries[entry_index]->value; | |
2255 | } | ||
2256 | else | ||
2257 | { | ||
2258 | ✗ | return NULL; | |
2259 | } | ||
2260 | } | ||
2261 | ✗ | void const* gate_hashmap_iterator_key(gate_hashmap_iterator_t iterator) | |
2262 | { | ||
2263 | ✗ | return iterator.hashmap->buckets[iterator.bucket_index]->entries[iterator.entry_index]->key; | |
2264 | } | ||
2265 | ✗ | void* gate_hashmap_iterator_value(gate_hashmap_iterator_t iterator) | |
2266 | { | ||
2267 | ✗ | return iterator.hashmap->buckets[iterator.bucket_index]->entries[iterator.entry_index]->value; | |
2268 | } | ||
2269 |