This source file includes following definitions.
- entry_type
- init_ref_counter
- inc_ref_counter
- dec_ref_counter
- create_function_table
- copy_function_table
- free_function_table
- hash_element
- compare_elements
- free_element
- init_element
- alloc_bucket
- is_shared
- trienode_count
- alloc_subtrie
- copy_entry
- replace_bucket_element
- replace_entry
- insert_entry
- remove_subtrie_entry
- remove_bucket_entry
- hamt_create
- hamt_copy
- free_bucket
- free_entry
- free_subtrie
- hamt_free
- bucket_lookup
- subtrie_lookup
- entry_lookup
- hamt_lookup
- create_populated_bucket
- create_populated_subtrie
- bucket_insert
- subtrie_insert
- entry_insert
- root_insert
- hamt_insert
- hamt_replace
- bucket_remove
- subtrie_remove
- entry_remove
- root_remove
- hamt_remove
- bucket_do_while
- subtrie_do_while
- entry_do_while
- hamt_do_while
- hamt_iterator
- hamt_iterator_free
- hamt_iterator_copy
- bit_width
- hamt_iterator_next
- hamt_insert_x
- hamt_replace_x
- hamt_remove_x
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20 #define _GL_HAMT_INLINE _GL_EXTERN_INLINE
21 #include "hamt.h"
22
23 #include <flexmember.h>
24 #include <inttypes.h>
25 #include <stdlib.h>
26 #include "count-one-bits.h"
27 #include "verify.h"
28 #include "xalloc.h"
29
30
31
32
33
34
35
36
37
38 typedef
39 #if GL_HAMT_THREAD_SAFE
40 _Atomic
41 #endif
42 size_t ref_counter;
43
44
45
46
47
48
49
50
51
52 enum entry_type
53 {
54 element_entry = 0,
55 subtrie_entry = 1,
56 bucket_entry = 2
57 };
58
59
60 static enum entry_type
61 entry_type (const Hamt_entry *entry)
62 {
63 return entry->ref_count & 3;
64 }
65
66
67
68
69
70
71 static void
72 init_ref_counter (ref_counter *counter, enum entry_type type)
73 {
74 *counter = 4 + type;
75 }
76
77
78 static void
79 inc_ref_counter (ref_counter *counter)
80 {
81 *counter += 4;
82 }
83
84
85
86 static bool
87 dec_ref_counter (ref_counter *counter)
88 {
89 *counter -= 4;
90 return *counter >= 4;
91 }
92
93
94
95
96
97
98 struct function_table
99 {
100 Hamt_hasher *hasher;
101 Hamt_comparator *comparator;
102 Hamt_freer *freer;
103 ref_counter ref_count;
104 };
105
106
107
108 struct subtrie
109 {
110 ref_counter ref_count;
111
112
113 uint32_t map;
114
115
116
117 Hamt_entry *nodes[FLEXIBLE_ARRAY_MEMBER];
118 };
119
120
121 struct bucket
122 {
123 ref_counter ref_counter;
124 size_t elt_count;
125 Hamt_entry *elts[FLEXIBLE_ARRAY_MEMBER];
126 };
127
128
129 struct hamt
130 {
131 struct function_table *functions;
132
133 Hamt_entry *root;
134 };
135
136
137
138
139
140
141 static struct function_table *
142 create_function_table (Hamt_hasher *hasher, Hamt_comparator *comparator,
143 Hamt_freer *freer)
144 {
145 struct function_table *functions = XMALLOC (struct function_table);
146 functions->hasher = hasher;
147 functions->comparator = comparator;
148 functions->freer = freer;
149 functions->ref_count = 1;
150 return functions;
151 }
152
153
154 static struct function_table *
155 copy_function_table (struct function_table *function_table)
156 {
157 ++function_table->ref_count;
158 return function_table;
159 }
160
161
162
163 static void
164 free_function_table (struct function_table *function_table)
165 {
166 if (--function_table->ref_count)
167 return;
168 free (function_table);
169 }
170
171
172
173
174
175
176 static size_t
177 hash_element (const struct function_table *functions, const Hamt_entry *elt)
178 {
179 return functions->hasher (elt);
180 }
181
182
183 static bool
184 compare_elements (const struct function_table *functions,
185 const Hamt_entry *elt1, const Hamt_entry *elt2)
186 {
187 return functions->comparator (elt1, elt2);
188 }
189
190
191 static void
192 free_element (const struct function_table *functions, Hamt_entry *elt)
193 {
194 if (dec_ref_counter (&elt->ref_count))
195 return;
196 functions->freer (elt);
197 }
198
199
200 static Hamt_entry *
201 init_element (Hamt_entry *elt)
202 {
203 init_ref_counter (&elt->ref_count, element_entry);
204 return elt;
205 }
206
207
208
209
210
211
212 static struct bucket *
213 alloc_bucket (size_t elt_count)
214 {
215 struct bucket *bucket
216 = xmalloc (FLEXSIZEOF (struct bucket, elts,
217 sizeof (Hamt_entry) * elt_count));
218 init_ref_counter (&bucket->ref_counter, bucket_entry);
219 bucket->elt_count = elt_count;
220 return bucket;
221 }
222
223
224
225
226
227
228
229
230
231
232
233 static bool
234 is_shared (const Hamt_entry *entry)
235 {
236 return entry->ref_count >= 8;
237 }
238
239
240 static int
241 trienode_count (const struct subtrie *subtrie)
242 {
243 return count_one_bits (subtrie->map);
244
245
246 }
247
248
249 static struct subtrie *
250 alloc_subtrie (int node_count)
251 {
252 struct subtrie *subtrie
253 = xmalloc (FLEXSIZEOF (struct subtrie, nodes,
254 sizeof (Hamt_entry) * node_count));
255 init_ref_counter (&subtrie->ref_count, subtrie_entry);
256 return subtrie;
257 }
258
259
260 static Hamt_entry *
261 copy_entry (Hamt_entry *entry)
262 {
263 inc_ref_counter (&entry->ref_count);
264 return entry;
265 }
266
267
268 static struct bucket *
269 replace_bucket_element (struct bucket *bucket, int j, Hamt_entry *elt)
270 {
271 int n = bucket->elt_count;
272 struct bucket *new_bucket = alloc_bucket (n);
273 for (int k = 0; k < n; ++k)
274 if (k == j)
275 new_bucket->elts[k] = elt;
276 else
277 new_bucket->elts[k] = copy_entry (bucket->elts[k]);
278 return new_bucket;
279 }
280
281
282 static struct subtrie *
283 replace_entry (struct subtrie *subtrie, int j, Hamt_entry *entry)
284 {
285 int n = trienode_count (subtrie);
286 struct subtrie *new_subtrie = alloc_subtrie (n);
287 new_subtrie->map = subtrie->map;
288 for (int k = 0; k < n; ++k)
289 if (k == j)
290 new_subtrie->nodes[k] = entry;
291 else
292 new_subtrie->nodes[k] = copy_entry (subtrie->nodes[k]);
293 return new_subtrie;
294 }
295
296
297
298 static struct subtrie *
299 insert_entry (struct subtrie *subtrie, int i, int j, Hamt_entry *entry)
300 {
301 int n = trienode_count (subtrie) + 1;
302 struct subtrie *new_subtrie = alloc_subtrie (n);
303 new_subtrie->map = subtrie->map | (1 << i);
304 for (int k = 0; k < n; ++k)
305 {
306 if (k < j)
307 new_subtrie->nodes[k] = copy_entry (subtrie->nodes[k]);
308 else if (k > j)
309 new_subtrie->nodes[k] = copy_entry (subtrie->nodes[k - 1]);
310 else
311 new_subtrie->nodes[k] = entry;
312 }
313 return new_subtrie;
314 }
315
316
317
318 static Hamt_entry *
319 remove_subtrie_entry (struct subtrie *subtrie, int i, int j)
320 {
321 int n = trienode_count (subtrie) - 1;
322 if (n == 1)
323 {
324 if (j == 0)
325 return copy_entry (subtrie->nodes[1]);
326 return copy_entry (subtrie->nodes[0]);
327 }
328 struct subtrie *new_subtrie = alloc_subtrie (n);
329 new_subtrie->map = subtrie->map & ~(1 << i);
330 for (int k = 0; k < n; ++k)
331 {
332 if (k < j)
333 new_subtrie->nodes[k] = copy_entry (subtrie->nodes[k]);
334 else if (k >= j)
335 new_subtrie->nodes[k] = copy_entry (subtrie->nodes[k + 1]);
336 }
337 return (Hamt_entry *) new_subtrie;
338 }
339
340
341 static Hamt_entry *
342 remove_bucket_entry (struct bucket *bucket, int j)
343 {
344 int n = bucket->elt_count - 1;
345 if (n == 1)
346 {
347 if (j == 0)
348 return copy_entry (bucket->elts[1]);
349 return copy_entry (bucket->elts[0]);
350 }
351 struct bucket *new_bucket = alloc_bucket (n);
352 for (int k = 0; k < n; ++k)
353 {
354 if (k < j)
355 new_bucket->elts[k] = copy_entry (bucket->elts[k]);
356 else if (k >= j)
357 new_bucket->elts[k] = copy_entry (bucket->elts[k + 1]);
358 }
359 return (Hamt_entry *) new_bucket;
360 }
361
362
363
364
365
366
367 Hamt *
368 hamt_create (Hamt_hasher *hasher, Hamt_comparator *comparator,
369 Hamt_freer *freer)
370 {
371 struct function_table *functions
372 = create_function_table (hasher, comparator, freer);
373 Hamt *hamt = XMALLOC (Hamt);
374 hamt->functions = functions;
375 hamt->root = NULL;
376 return hamt;
377 }
378
379
380 Hamt *
381 hamt_copy (Hamt *hamt)
382 {
383 Hamt *new_hamt = XMALLOC (Hamt);
384 new_hamt->functions = copy_function_table (hamt->functions);
385 new_hamt->root = hamt->root == NULL ? NULL : copy_entry (hamt->root);
386 return new_hamt;
387 }
388
389
390 static void
391 free_bucket (struct function_table const *functions, struct bucket *bucket)
392 {
393 if (dec_ref_counter (&bucket->ref_counter))
394 return;
395 size_t elt_count = bucket->elt_count;
396 Hamt_entry *const *elts = bucket->elts;
397 for (size_t i = 0; i < elt_count; ++i)
398 free_element (functions, elts[i]);
399 free (bucket);
400 }
401
402
403 static void free_subtrie (struct function_table const *functions,
404 struct subtrie *subtrie);
405
406
407 static void
408 free_entry (struct function_table const *functions, Hamt_entry *entry)
409 {
410 switch (entry_type (entry))
411 {
412 case element_entry:
413 free_element (functions, entry);
414 break;
415 case subtrie_entry:
416 free_subtrie (functions, (struct subtrie *) entry);
417 break;
418 case bucket_entry:
419 free_bucket (functions, (struct bucket *) entry);
420 break;
421 default:
422 assume (0);
423 }
424 }
425
426
427 static void
428 free_subtrie (struct function_table const *functions, struct subtrie *subtrie)
429 {
430 if (dec_ref_counter (&subtrie->ref_count))
431 return;
432 int n = trienode_count (subtrie);
433 Hamt_entry **node_ptr = subtrie->nodes;
434 for (int j = 0; j < n; ++j)
435 free_entry (functions, *node_ptr++);
436 free (subtrie);
437 }
438
439
440 void
441 hamt_free (Hamt *hamt)
442 {
443 if (hamt->root != NULL)
444 free_entry (hamt->functions, hamt->root);
445 free_function_table (hamt->functions);
446 free (hamt);
447 }
448
449
450
451
452
453
454 static Hamt_entry *
455 bucket_lookup (const struct function_table *functions,
456 const struct bucket *bucket, const void *elt)
457 {
458 size_t elt_count = bucket->elt_count;
459 Hamt_entry *const *elts = bucket->elts;
460 for (size_t i = 0; i < elt_count; ++i)
461 {
462 if (compare_elements (functions, elt, elts[i]))
463 return *elts;
464 }
465 return NULL;
466 }
467
468
469 static Hamt_entry *entry_lookup (const struct function_table *functions,
470 Hamt_entry *entry,
471 const void *elt, size_t hash);
472
473
474 static Hamt_entry *
475 subtrie_lookup (const struct function_table *functions,
476 const struct subtrie *subtrie, const void *elt,
477 size_t hash)
478 {
479 uint32_t map = subtrie->map;
480 int i = hash & 31;
481
482 if (! (map & (1 << i)))
483 return NULL;
484
485 int j = i == 0 ? 0 : count_one_bits (map << (32 - i));
486 return entry_lookup (functions, subtrie->nodes[j], elt, hash >> 5);
487 }
488
489
490 static Hamt_entry *
491 entry_lookup (const struct function_table *functions, Hamt_entry *entry,
492 const void *elt, size_t hash)
493 {
494 switch (entry_type (entry))
495 {
496 case element_entry:
497 if (compare_elements (functions, elt, entry))
498 return entry;
499 return NULL;
500 case subtrie_entry:
501 return subtrie_lookup (functions, (struct subtrie *) entry, elt, hash);
502 case bucket_entry:
503 return bucket_lookup (functions, (struct bucket *) entry, elt);
504 default:
505 assume (0);
506 }
507 }
508
509
510
511 Hamt_entry *
512 hamt_lookup (const Hamt *hamt, const void *elt)
513 {
514 if (hamt->root == NULL)
515 return NULL;
516
517 return entry_lookup (hamt->functions, hamt->root, elt,
518 hash_element (hamt->functions, elt));
519 }
520
521
522
523
524
525
526 static struct bucket *
527 create_populated_bucket (Hamt_entry *elt1, Hamt_entry *elt2)
528 {
529 struct bucket *bucket = alloc_bucket (2);
530 bucket->elts[0] = elt1;
531 bucket->elts[1] = elt2;
532 return bucket;
533 }
534
535
536
537 static Hamt_entry *
538 create_populated_subtrie (Hamt_entry *elt1, Hamt_entry *elt2, size_t hash1,
539 size_t hash2, int depth)
540 {
541 if (depth >= _GL_HAMT_MAX_DEPTH)
542 return (Hamt_entry *) create_populated_bucket (elt1, elt2);
543
544 struct subtrie *subtrie;
545 int i1 = hash1 & 31;
546 int i2 = hash2 & 31;
547 if (i1 != i2)
548 {
549 subtrie = alloc_subtrie (2);
550 subtrie->map = (1 << i1) | (1 << i2);
551 if (i1 < i2)
552 {
553 subtrie->nodes[0] = elt1;
554 subtrie->nodes[1] = elt2;
555 }
556 else
557 {
558 subtrie->nodes[0] = elt2;
559 subtrie->nodes[1] = elt1;
560 }
561 }
562 else
563 {
564 subtrie = alloc_subtrie (1);
565 subtrie->map = 1 << i1;
566 subtrie->nodes[0]
567 = create_populated_subtrie (elt1, elt2, hash1 >> 5, hash2 >> 5,
568 depth + 1);
569 }
570 return (Hamt_entry *) subtrie;
571 }
572
573
574 static struct bucket *
575 bucket_insert (const struct function_table *functions, struct bucket *bucket,
576 Hamt_entry **elt_ptr, bool replace, bool shared)
577 {
578 size_t elt_count = bucket->elt_count;
579 Hamt_entry **elts = bucket->elts;
580 for (size_t i = 0; i < elt_count; ++i)
581 {
582 if (compare_elements (functions, *elt_ptr, elts[i]))
583 {
584 if (replace)
585 {
586 if (shared)
587 {
588 struct bucket *new_bucket
589 = replace_bucket_element (bucket, i,
590 copy_entry (*elt_ptr));
591 *elt_ptr = elts[i];
592 return new_bucket;
593 }
594 free_element (functions, elts[i]);
595 elts[i] = copy_entry (*elt_ptr);
596 return bucket;
597 }
598 *elt_ptr = *elt_ptr == elts[i] ? NULL : elts[i];
599 return bucket;
600 }
601 }
602 struct bucket *new_bucket = alloc_bucket (elt_count + 1);
603 new_bucket->elts[0] = copy_entry (*elt_ptr);
604 for (size_t i = 0; i < elt_count; ++i)
605 {
606 new_bucket->elts[i + 1] = copy_entry (bucket->elts[i]);
607 }
608 if (replace)
609 *elt_ptr = NULL;
610 return new_bucket;
611 }
612
613
614 static Hamt_entry *entry_insert (const struct function_table *functions,
615 Hamt_entry *subtrie, Hamt_entry **elt_ptr,
616 size_t hash, int depth, bool replace,
617 bool shared);
618
619
620 static struct subtrie *
621 subtrie_insert (const struct function_table *functions, struct subtrie *subtrie,
622 Hamt_entry **elt_ptr, size_t hash, int depth, bool replace,
623 bool shared)
624 {
625 uint32_t map = subtrie->map;
626 int i = hash & 31;
627 int j = i == 0 ? 0 : count_one_bits (map << (32 - i));
628 if (map & (1 << i))
629 {
630 Hamt_entry *entry = subtrie->nodes[j];
631 Hamt_entry *new_entry
632 = entry_insert (functions, entry, elt_ptr, hash >> 5, depth + 1,
633 replace, shared);
634 if (new_entry != entry)
635 {
636 if (shared)
637 return replace_entry (subtrie, j, new_entry);
638 free_entry (functions, entry);
639 subtrie->nodes[j] = new_entry;
640 }
641 return subtrie;
642 }
643 Hamt_entry *entry = copy_entry (*elt_ptr);
644 if (replace)
645 *elt_ptr = NULL;
646 return insert_entry (subtrie, i, j, entry);
647 }
648
649
650
651
652
653
654
655
656 static Hamt_entry *
657 entry_insert (const struct function_table *functions, Hamt_entry *entry,
658 Hamt_entry **elt_ptr, size_t hash, int depth, bool replace,
659 bool shared)
660 {
661 shared |= is_shared (entry);
662 switch (entry_type (entry))
663 {
664 case element_entry:
665 if (compare_elements (functions, *elt_ptr, entry))
666 {
667 if (replace)
668 {
669 if (shared)
670 {
671 Hamt_entry *new_entry = copy_entry (*elt_ptr);
672 *elt_ptr = entry;
673 return new_entry;
674 }
675 return copy_entry (*elt_ptr);
676 }
677 *elt_ptr = *elt_ptr == entry ? NULL : entry;
678 return entry;
679 }
680 Hamt_entry *new_entry = copy_entry (*elt_ptr);
681 if (replace)
682 *elt_ptr = NULL;
683 return create_populated_subtrie (new_entry, copy_entry (entry), hash,
684 (hash_element (functions, entry)
685 >> (5 * depth)), depth);
686 case subtrie_entry:
687 return (Hamt_entry *)
688 subtrie_insert (functions, (struct subtrie *) entry, elt_ptr, hash,
689 depth, replace, shared);
690 case bucket_entry:
691 return (Hamt_entry *)
692 bucket_insert (functions, (struct bucket *) entry, elt_ptr, replace,
693 shared);
694 default:
695 assume (0);
696 }
697 }
698
699
700 static Hamt_entry *
701 root_insert (const struct function_table *functions, Hamt_entry *root,
702 Hamt_entry **elt_ptr, bool replace, bool shared)
703 {
704 if (root == NULL)
705 return copy_entry (*elt_ptr);
706
707 return entry_insert (functions, root, elt_ptr,
708 hash_element (functions, *elt_ptr), 0, replace, shared);
709 }
710
711
712
713
714 Hamt *
715 hamt_insert (Hamt *hamt, Hamt_entry **elt_ptr)
716 {
717 Hamt_entry *elt = *elt_ptr;
718 Hamt_entry *new_entry = root_insert (hamt->functions, hamt->root,
719 elt_ptr, false, true);
720 if (*elt_ptr == NULL)
721 *elt_ptr = elt;
722
723 if (new_entry == hamt->root)
724 return hamt;
725
726 Hamt *new_hamt = XMALLOC (Hamt);
727 new_hamt->functions = copy_function_table (hamt->functions);
728 new_hamt->root = new_entry;
729 return new_hamt;
730 }
731
732
733
734
735 Hamt *
736 hamt_replace (Hamt *hamt, Hamt_entry **elt_ptr)
737 {
738 Hamt *new_hamt = XMALLOC (Hamt);
739 new_hamt->functions = copy_function_table (hamt->functions);
740 new_hamt->root = root_insert (hamt->functions, hamt->root, elt_ptr, true,
741 true);
742 return new_hamt;
743 }
744
745
746 static Hamt_entry *
747 bucket_remove (const struct function_table *functions, struct bucket *bucket,
748 Hamt_entry **elt_ptr)
749 {
750 size_t elt_count = bucket->elt_count;
751 Hamt_entry *const *elts = bucket->elts;
752 for (size_t i = 0; i < elt_count; ++i)
753 {
754 if (compare_elements (functions, *elt_ptr, elts[i]))
755 {
756 *elt_ptr = elts[i];
757 return remove_bucket_entry (bucket, i);
758 }
759 }
760 *elt_ptr = NULL;
761 return (Hamt_entry *) bucket;
762 }
763
764
765 static Hamt_entry *entry_remove (const struct function_table *functions,
766 Hamt_entry *entry, Hamt_entry **elt_ptr,
767 size_t hash, int depth, bool shared);
768
769
770 static Hamt_entry *
771 subtrie_remove (const struct function_table *functions, struct subtrie *subtrie,
772 Hamt_entry **elt_ptr, size_t hash, int depth, bool shared)
773 {
774 uint32_t map = subtrie->map;
775 int i = hash & 31;
776 int j = i == 0 ? 0 : count_one_bits (map << (32 - i));
777 if (map & (1 << i))
778 {
779 Hamt_entry *entry = subtrie->nodes[j];
780 Hamt_entry *new_entry
781 = entry_remove (functions, entry, elt_ptr, hash >> 5, depth + 1,
782 shared);
783 if (new_entry == NULL)
784 return remove_subtrie_entry (subtrie, i, j);
785 if (new_entry != entry)
786 {
787 if (shared)
788 return (Hamt_entry *) replace_entry (subtrie, j, new_entry);
789 free_entry (functions, entry);
790 subtrie->nodes[j] = new_entry;
791 }
792 return (Hamt_entry *) subtrie;
793 }
794 *elt_ptr = NULL;
795 return (Hamt_entry *) subtrie;
796 }
797
798
799
800
801
802
803 static Hamt_entry *
804 entry_remove (const struct function_table *functions, Hamt_entry *entry,
805 Hamt_entry **elt_ptr, size_t hash, int depth, bool shared)
806 {
807 shared |= is_shared (entry);
808 switch (entry_type (entry))
809 {
810 case element_entry:
811 if (compare_elements (functions, *elt_ptr, entry))
812 {
813 *elt_ptr = entry;
814 return NULL;
815 }
816 *elt_ptr = NULL;
817 return entry;
818 case subtrie_entry:
819 return subtrie_remove (functions, (struct subtrie *) entry, elt_ptr, hash,
820 depth, shared);
821 case bucket_entry:
822 return bucket_remove (functions, (struct bucket *) entry, elt_ptr);
823 default:
824 assume (0);
825 }
826 }
827
828
829 static Hamt_entry *
830 root_remove (const struct function_table *functions, Hamt_entry *root,
831 Hamt_entry **elt_ptr, bool shared)
832 {
833 if (root == NULL)
834 return NULL;
835
836 return entry_remove (functions, root, elt_ptr,
837 hash_element (functions, *elt_ptr), 0, shared);
838 }
839
840
841
842
843 Hamt *
844 hamt_remove (Hamt *hamt, Hamt_entry **elt_ptr)
845 {
846 Hamt_entry *elt = *elt_ptr;
847 Hamt_entry *new_entry = root_remove (hamt->functions, hamt->root, elt_ptr,
848 true);
849 if (*elt_ptr == NULL)
850 *elt_ptr = elt;
851
852 if (new_entry == hamt->root)
853 return hamt;
854
855 Hamt *new_hamt = XMALLOC (Hamt);
856 new_hamt->functions = copy_function_table (hamt->functions);
857 new_hamt->root = new_entry;
858 return new_hamt;
859 }
860
861
862
863
864
865
866 static size_t
867 bucket_do_while (const struct bucket *bucket, Hamt_processor *proc, void *data,
868 bool *success)
869 {
870 size_t cnt = 0;
871 size_t elt_count = bucket->elt_count;
872 Hamt_entry *const *elts = bucket->elts;
873 for (size_t i = 0; i < elt_count; ++i)
874 {
875 *success = proc (elts[i], data);
876 if (*success == false)
877 return cnt;
878 ++cnt;
879 }
880 return cnt;
881 }
882
883
884 static size_t entry_do_while (Hamt_entry *entry, Hamt_processor *proc,
885 void *data, bool *success);
886
887
888 static size_t subtrie_do_while (const struct subtrie *subtrie,
889 Hamt_processor *proc, void *data, bool *success)
890 {
891 size_t cnt = 0;
892 int n = trienode_count (subtrie);
893 Hamt_entry *const *node_ptr = subtrie->nodes;
894 for (int j = 0; j < n; ++j)
895 {
896 cnt += entry_do_while (*node_ptr++, proc, data, success);
897 if (!success)
898 return cnt;
899 }
900 return cnt;
901 }
902
903
904 static size_t
905 entry_do_while (Hamt_entry *entry, Hamt_processor *proc, void *data,
906 bool *success)
907 {
908 switch (entry_type (entry))
909 {
910 case element_entry:
911 *success = proc (entry, data);
912 return *success ? 1 : 0;
913 case subtrie_entry:
914 return subtrie_do_while ((struct subtrie *) entry, proc, data, success);
915 case bucket_entry:
916 return bucket_do_while ((struct bucket *) entry, proc, data, success);
917 default:
918 assume (0);
919 }
920 }
921
922
923
924
925
926 size_t
927 hamt_do_while (const Hamt *hamt, Hamt_processor *proc, void *data)
928 {
929 if (hamt->root == NULL)
930 return 0;
931
932 bool success = true;
933 return entry_do_while (hamt->root, proc, data, &success);
934 }
935
936
937
938
939
940
941
942
943 Hamt_iterator
944 hamt_iterator (Hamt *hamt)
945 {
946 Hamt_iterator iter;
947 iter.hamt = hamt_copy (hamt);
948 Hamt_entry *entry = hamt->root;
949 iter.path = 0;
950 iter.position = 0;
951 if (entry == NULL)
952 {
953 iter.depth = -1;
954 return iter;
955 }
956 iter.depth = 0;
957 while (iter.entry[iter.depth] = entry, entry_type (entry) == subtrie_entry)
958 {
959 const struct subtrie *subtrie = (const struct subtrie *) entry;
960 ++iter.depth;
961 entry = subtrie->nodes[0];
962 }
963 return iter;
964 }
965
966
967 void
968 hamt_iterator_free (Hamt_iterator *iter)
969 {
970 hamt_free (iter->hamt);
971 }
972
973
974
975 Hamt_iterator
976 hamt_iterator_copy (Hamt_iterator *iter)
977 {
978 Hamt_iterator new_iter = *iter;
979 new_iter.hamt = hamt_copy (iter->hamt);
980 return new_iter;
981 }
982
983
984 static int
985 bit_width (int depth)
986 {
987 if (depth < _GL_HAMT_MAX_DEPTH - 1)
988 return 5;
989 return SIZE_WIDTH - 5 * (_GL_HAMT_MAX_DEPTH - 1);
990 }
991
992
993 bool
994 hamt_iterator_next (Hamt_iterator *iter, Hamt_entry **elt_ptr)
995 {
996 int depth = iter->depth;
997 if (depth < 0)
998 return false;
999
1000 Hamt_entry *entry = iter->entry[depth];
1001 if (entry_type (entry) == bucket_entry)
1002 {
1003 struct bucket *bucket = (struct bucket *) entry;
1004 *elt_ptr = bucket->elts[iter->position];
1005 if (++iter->position < bucket->elt_count)
1006 return true;
1007 }
1008 else
1009 *elt_ptr = entry;
1010
1011 struct subtrie *subtrie;
1012 while (iter->depth-- > 0)
1013 {
1014 int width = bit_width (iter->depth);
1015 int j = (iter->path & ((1 << width) - 1)) + 1;
1016 subtrie = (struct subtrie *) iter->entry[iter->depth];
1017 if (j < trienode_count (subtrie))
1018 {
1019 ++iter->path;
1020 while (iter->entry[++iter->depth] = subtrie->nodes[j],
1021 entry_type (iter->entry[iter->depth]) == subtrie_entry)
1022 {
1023 width = bit_width (iter->depth);
1024 iter->path <<= width;
1025 j = 0;
1026 subtrie = (struct subtrie *) iter->entry[iter->depth];
1027 }
1028 iter->position = 0;
1029 break;
1030 }
1031 iter->path >>= width;
1032 }
1033
1034 return true;
1035 }
1036
1037
1038
1039
1040
1041
1042
1043
1044 bool
1045 hamt_insert_x (Hamt *hamt, Hamt_entry **elt_ptr)
1046 {
1047 Hamt_entry *elt = *elt_ptr;
1048 Hamt_entry *old_root = hamt->root;
1049 hamt->root = root_insert (hamt->functions, old_root, elt_ptr, false, false);
1050 if (old_root != hamt->root && old_root != NULL)
1051 free_entry (hamt->functions, old_root);
1052 if (*elt_ptr == NULL)
1053 {
1054 *elt_ptr = elt;
1055 return false;
1056 }
1057 return *elt_ptr == elt;
1058 }
1059
1060
1061
1062 bool
1063 hamt_replace_x (Hamt *hamt, Hamt_entry *elt)
1064 {
1065 Hamt_entry *old_root = hamt->root;
1066 hamt->root = root_insert (hamt->functions, old_root, &elt, true, false);
1067 if (old_root != hamt->root && old_root != NULL)
1068 free_entry (hamt->functions, old_root);
1069 return elt != NULL;
1070 }
1071
1072
1073
1074
1075 bool
1076 hamt_remove_x (Hamt *hamt, Hamt_entry *elt)
1077 {
1078 Hamt_entry *old_root = hamt->root;
1079 hamt->root = root_remove (hamt->functions, old_root, &elt, false);
1080 if (old_root != hamt->root)
1081 free_entry (hamt->functions, old_root);
1082 return elt != NULL;
1083 }