wordtriez 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,771 @@
1
+ /*
2
+ * This file is part of hat-trie.
3
+ *
4
+ * Copyright (c) 2011 by Daniel C. Jones <dcjones@cs.washington.edu>
5
+ *
6
+ */
7
+
8
+ #include "hat-trie.h"
9
+ #include "ahtable.h"
10
+ #include "misc.h"
11
+ #include "pstdint.h"
12
+ #include <assert.h>
13
+ #include <string.h>
14
+
15
+ #define HT_UNUSED(x) x=x
16
+
17
+ /* maximum number of keys that may be stored in a bucket before it is burst */
18
+ static const size_t MAX_BUCKET_SIZE = 16384;
19
+ #define NODE_MAXCHAR 0xff // 0x7f for 7-bit ASCII
20
+ #define NODE_CHILDS (NODE_MAXCHAR+1)
21
+
22
+ static const uint8_t NODE_TYPE_TRIE = 0x1;
23
+ static const uint8_t NODE_TYPE_PURE_BUCKET = 0x2;
24
+ static const uint8_t NODE_TYPE_HYBRID_BUCKET = 0x4;
25
+ static const uint8_t NODE_HAS_VAL = 0x8;
26
+
27
+
28
+ struct trie_node_t_;
29
+
30
+ /* Node's may be trie nodes or buckets. This union allows us to keep
31
+ * non-specific pointer. */
32
+ typedef union node_ptr_
33
+ {
34
+ ahtable_t* b;
35
+ struct trie_node_t_* t;
36
+ uint8_t* flag;
37
+ } node_ptr;
38
+
39
+
40
+ typedef struct trie_node_t_
41
+ {
42
+ uint8_t flag;
43
+
44
+ /* the value for the key that is consumed on a trie node */
45
+ value_t val;
46
+
47
+ /* Map a character to either a trie_node_t or a ahtable_t. The first byte
48
+ * must be examined to determine which. */
49
+ node_ptr xs[NODE_CHILDS];
50
+
51
+ } trie_node_t;
52
+
53
+ struct hattrie_t_
54
+ {
55
+ node_ptr root; // root node
56
+ size_t m; // number of stored keys
57
+ };
58
+
59
+ /* Create a new trie node with all pointer pointing to the given child (which
60
+ * can be NULL). */
61
+ static trie_node_t* alloc_trie_node(hattrie_t* T, node_ptr child)
62
+ {
63
+ trie_node_t* node = malloc_or_die(sizeof(trie_node_t));
64
+ node->flag = NODE_TYPE_TRIE;
65
+ node->val = 0;
66
+
67
+ /* pass T to allow custom allocator for trie. */
68
+ HT_UNUSED(T); /* unused now */
69
+
70
+ size_t i;
71
+ for (i = 0; i < NODE_CHILDS; ++i) node->xs[i] = child;
72
+ return node;
73
+ }
74
+
75
+ /* iterate trie nodes until string is consumed or bucket is found */
76
+ static node_ptr hattrie_consume(node_ptr *p, const char **k, size_t *l, unsigned brk)
77
+ {
78
+ node_ptr node = p->t->xs[(unsigned char) **k];
79
+ while (*node.flag & NODE_TYPE_TRIE && *l > brk) {
80
+ ++*k;
81
+ --*l;
82
+ *p = node;
83
+ node = node.t->xs[(unsigned char) **k];
84
+ }
85
+
86
+ /* copy and writeback variables if it's faster */
87
+
88
+ assert(*p->flag & NODE_TYPE_TRIE);
89
+ return node;
90
+ }
91
+
92
+ /* use node value and return pointer to it */
93
+ static inline value_t* hattrie_useval(hattrie_t *T, node_ptr n)
94
+ {
95
+ if (!(n.t->flag & NODE_HAS_VAL)) {
96
+ n.t->flag |= NODE_HAS_VAL;
97
+ ++T->m;
98
+ }
99
+ return &n.t->val;
100
+ }
101
+
102
+ /* clear node value if exists */
103
+ static inline int hattrie_clrval(hattrie_t *T, node_ptr n)
104
+ {
105
+ if (n.t->flag & NODE_HAS_VAL) {
106
+ n.t->flag &= ~NODE_HAS_VAL;
107
+ n.t->val = 0;
108
+ --T->m;
109
+ return 0;
110
+ }
111
+ return -1;
112
+ }
113
+
114
+ /* find node in trie */
115
+ static node_ptr hattrie_find(hattrie_t* T, const char **key, size_t *len, int* found)
116
+ {
117
+ *found = 1;
118
+ node_ptr parent = T->root;
119
+ assert(*parent.flag & NODE_TYPE_TRIE);
120
+
121
+ if (*len == 0) return parent;
122
+
123
+ node_ptr node = hattrie_consume(&parent, key, len, 1);
124
+
125
+ /* if the trie node consumes value, use it */
126
+ if (*node.flag & NODE_TYPE_TRIE) {
127
+ if (!(node.t->flag & NODE_HAS_VAL)) {
128
+ *found = 0;
129
+ }
130
+ *key += 1;
131
+ *len -= 1;
132
+ return node;
133
+ }
134
+
135
+ /* pure bucket holds only key suffixes, skip current char */
136
+ if (*node.flag & NODE_TYPE_PURE_BUCKET) {
137
+ *key += 1;
138
+ *len -= 1;
139
+ }
140
+
141
+ /* do not scan bucket, it's not needed for this operation */
142
+ return node;
143
+ }
144
+
145
+ hattrie_t* hattrie_create()
146
+ {
147
+ hattrie_t* T = malloc_or_die(sizeof(hattrie_t));
148
+ T->m = 0;
149
+
150
+ node_ptr node;
151
+ node.b = ahtable_create();
152
+ node.b->flag = NODE_TYPE_HYBRID_BUCKET;
153
+ node.b->c0 = 0x00;
154
+ node.b->c1 = NODE_MAXCHAR;
155
+ T->root.t = alloc_trie_node(T, node);
156
+
157
+ return T;
158
+ }
159
+
160
+
161
+ static void hattrie_free_node(node_ptr node)
162
+ {
163
+ if (*node.flag & NODE_TYPE_TRIE) {
164
+ size_t i;
165
+ for (i = 0; i < NODE_CHILDS; ++i) {
166
+ if (i > 0 && node.t->xs[i].t == node.t->xs[i - 1].t) continue;
167
+
168
+ /* XXX: recursion might not be the best choice here. It is possible
169
+ * to build a very deep trie. */
170
+ if (node.t->xs[i].t) hattrie_free_node(node.t->xs[i]);
171
+ }
172
+ free(node.t);
173
+ }
174
+ else {
175
+ ahtable_free(node.b);
176
+ }
177
+ }
178
+
179
+
180
+ void hattrie_free(hattrie_t* T)
181
+ {
182
+ hattrie_free_node(T->root);
183
+ free(T);
184
+ }
185
+
186
+
187
+ size_t hattrie_size(hattrie_t* T)
188
+ {
189
+ return T->m;
190
+ }
191
+
192
+
193
+ /* Perform one split operation on the given node with the given parent.
194
+ */
195
+ static void hattrie_split(hattrie_t* T, node_ptr parent, node_ptr node)
196
+ {
197
+ /* only buckets may be split */
198
+ assert(*node.flag & NODE_TYPE_PURE_BUCKET ||
199
+ *node.flag & NODE_TYPE_HYBRID_BUCKET);
200
+
201
+ assert(*parent.flag & NODE_TYPE_TRIE);
202
+
203
+ if (*node.flag & NODE_TYPE_PURE_BUCKET) {
204
+ /* turn the pure bucket into a hybrid bucket */
205
+ parent.t->xs[node.b->c0].t = alloc_trie_node(T, node);
206
+
207
+ /* if the bucket had an empty key, move it to the new trie node */
208
+ value_t* val = ahtable_tryget(node.b, NULL, 0);
209
+ if (val) {
210
+ parent.t->xs[node.b->c0].t->val = *val;
211
+ parent.t->xs[node.b->c0].t->flag |= NODE_HAS_VAL;
212
+ *val = 0;
213
+ ahtable_del(node.b, NULL, 0);
214
+ }
215
+
216
+ node.b->c0 = 0x00;
217
+ node.b->c1 = NODE_MAXCHAR;
218
+ node.b->flag = NODE_TYPE_HYBRID_BUCKET;
219
+
220
+ return;
221
+ }
222
+
223
+ /* This is a hybrid bucket. Perform a proper split. */
224
+
225
+ /* count the number of occourances of every leading character */
226
+ unsigned int cs[NODE_CHILDS]; // occurance count for leading chars
227
+ memset(cs, 0, NODE_CHILDS * sizeof(unsigned int));
228
+ size_t len;
229
+ const char* key;
230
+
231
+ ahtable_iter_t* i = ahtable_iter_begin(node.b, false);
232
+ while (!ahtable_iter_finished(i)) {
233
+ key = ahtable_iter_key(i, &len);
234
+ assert(len > 0);
235
+ cs[(unsigned char) key[0]] += 1;
236
+ ahtable_iter_next(i);
237
+ }
238
+ ahtable_iter_free(i);
239
+
240
+ /* choose a split point */
241
+ unsigned int left_m, right_m, all_m;
242
+ unsigned char j = node.b->c0;
243
+ all_m = ahtable_size(node.b);
244
+ left_m = cs[j];
245
+ right_m = all_m - left_m;
246
+ int d;
247
+
248
+ while (j + 1 < node.b->c1) {
249
+ d = abs((int) (left_m + cs[j + 1]) - (int) (right_m - cs[j + 1]));
250
+ if (d <= abs(left_m - right_m) && left_m + cs[j + 1] < all_m) {
251
+ j += 1;
252
+ left_m += cs[j];
253
+ right_m -= cs[j];
254
+ }
255
+ else break;
256
+ }
257
+
258
+ /* now split into two node cooresponding to ranges [0, j] and
259
+ * [j + 1, NODE_MAXCHAR], respectively. */
260
+
261
+
262
+ /* create new left and right nodes */
263
+
264
+ /* TODO: Add a special case if either node is a hybrid bucket containing all
265
+ * the keys. In such a case, do not build a new table, just use the old one.
266
+ * */
267
+ size_t num_slots;
268
+
269
+
270
+ for (num_slots = ahtable_initial_size;
271
+ (double) left_m > ahtable_max_load_factor * (double) num_slots;
272
+ num_slots *= 2);
273
+
274
+ node_ptr left, right;
275
+ left.b = ahtable_create_n(num_slots);
276
+ left.b->c0 = node.b->c0;
277
+ left.b->c1 = j;
278
+ left.b->flag = left.b->c0 == left.b->c1 ?
279
+ NODE_TYPE_PURE_BUCKET : NODE_TYPE_HYBRID_BUCKET;
280
+
281
+
282
+ for (num_slots = ahtable_initial_size;
283
+ (double) right_m > ahtable_max_load_factor * (double) num_slots;
284
+ num_slots *= 2);
285
+
286
+ right.b = ahtable_create_n(num_slots);
287
+ right.b->c0 = j + 1;
288
+ right.b->c1 = node.b->c1;
289
+ right.b->flag = right.b->c0 == right.b->c1 ?
290
+ NODE_TYPE_PURE_BUCKET : NODE_TYPE_HYBRID_BUCKET;
291
+
292
+
293
+ /* update the parent's pointer */
294
+
295
+ unsigned int c;
296
+ for (c = node.b->c0; c <= j; ++c) parent.t->xs[c] = left;
297
+ for (; c <= node.b->c1; ++c) parent.t->xs[c] = right;
298
+
299
+
300
+
301
+ /* distribute keys to the new left or right node */
302
+ value_t* u;
303
+ value_t* v;
304
+ i = ahtable_iter_begin(node.b, false);
305
+ while (!ahtable_iter_finished(i)) {
306
+ key = ahtable_iter_key(i, &len);
307
+ u = ahtable_iter_val(i);
308
+ assert(len > 0);
309
+
310
+ /* left */
311
+ if ((unsigned char) key[0] <= j) {
312
+ if (*left.flag & NODE_TYPE_PURE_BUCKET) {
313
+ v = ahtable_get(left.b, key + 1, len - 1);
314
+ }
315
+ else {
316
+ v = ahtable_get(left.b, key, len);
317
+ }
318
+ *v = *u;
319
+ }
320
+
321
+ /* right */
322
+ else {
323
+ if (*right.flag & NODE_TYPE_PURE_BUCKET) {
324
+ v = ahtable_get(right.b, key + 1, len - 1);
325
+ }
326
+ else {
327
+ v = ahtable_get(right.b, key, len);
328
+ }
329
+ *v = *u;
330
+ }
331
+
332
+ ahtable_iter_next(i);
333
+ }
334
+
335
+ ahtable_iter_free(i);
336
+ ahtable_free(node.b);
337
+ }
338
+
339
+ value_t* hattrie_get(hattrie_t* T, const char* key, size_t len)
340
+ {
341
+ node_ptr parent = T->root;
342
+ assert(*parent.flag & NODE_TYPE_TRIE);
343
+
344
+ if (len == 0) return &parent.t->val;
345
+
346
+ /* consume all trie nodes, now parent must be trie and child anything */
347
+ node_ptr node = hattrie_consume(&parent, &key, &len, 0);
348
+ assert(*parent.flag & NODE_TYPE_TRIE);
349
+
350
+ /* if the key has been consumed on a trie node, use its value */
351
+ if (len == 0) {
352
+ if (*node.flag & NODE_TYPE_TRIE) {
353
+ return hattrie_useval(T, node);
354
+ }
355
+ else if (*node.flag & NODE_TYPE_HYBRID_BUCKET) {
356
+ return hattrie_useval(T, parent);
357
+ }
358
+ }
359
+
360
+
361
+ /* preemptively split the bucket if it is full */
362
+ while (ahtable_size(node.b) >= MAX_BUCKET_SIZE) {
363
+ hattrie_split(T, parent, node);
364
+
365
+ /* after the split, the node pointer is invalidated, so we search from
366
+ * the parent again. */
367
+ node = hattrie_consume(&parent, &key, &len, 0);
368
+
369
+ /* if the key has been consumed on a trie node, use its value */
370
+ if (len == 0) {
371
+ if (*node.flag & NODE_TYPE_TRIE) {
372
+ return hattrie_useval(T, node);
373
+ }
374
+ else if (*node.flag & NODE_TYPE_HYBRID_BUCKET) {
375
+ return hattrie_useval(T, parent);
376
+ }
377
+ }
378
+ }
379
+
380
+ assert(*node.flag & NODE_TYPE_PURE_BUCKET || *node.flag & NODE_TYPE_HYBRID_BUCKET);
381
+
382
+ assert(len > 0);
383
+ size_t m_old = node.b->m;
384
+ value_t* val;
385
+ if (*node.flag & NODE_TYPE_PURE_BUCKET) {
386
+ val = ahtable_get(node.b, key + 1, len - 1);
387
+ }
388
+ else {
389
+ val = ahtable_get(node.b, key, len);
390
+ }
391
+ T->m += (node.b->m - m_old);
392
+
393
+ return val;
394
+ }
395
+
396
+
397
+ value_t* hattrie_tryget(hattrie_t* T, const char* key, size_t len)
398
+ {
399
+ /* find node for given key */
400
+ int found;
401
+ node_ptr node = hattrie_find(T, &key, &len, &found);
402
+ if (!found) {
403
+ return NULL;
404
+ }
405
+
406
+ /* if the trie node consumes value, use it */
407
+ if (*node.flag & NODE_TYPE_TRIE) {
408
+ return &node.t->val;
409
+ }
410
+
411
+ return ahtable_tryget(node.b, key, len);
412
+ }
413
+
414
+
415
+ void hattrie_walk (hattrie_t* T, const char* key, size_t len, void* user_data, hattrie_walk_cb cb) {
416
+ unsigned char* k = (unsigned char*)key;
417
+ node_ptr node = T->root;
418
+ size_t i, j;
419
+ ahtable_iter_t* it;
420
+
421
+ /* go down until a bucket is reached */
422
+ for (i = 0; i < len; i++, k++) {
423
+ if (!(*node.flag & NODE_TYPE_TRIE))
424
+ break;
425
+ node = node.t->xs[*k];
426
+ if (*node.flag & NODE_HAS_VAL) {
427
+ if (hattrie_walk_stop == cb(key, i, &node.t->val, user_data))
428
+ return;
429
+ }
430
+ }
431
+ if (i == len)
432
+ return;
433
+
434
+ assert(i);
435
+ if (*node.flag & NODE_TYPE_HYBRID_BUCKET) {
436
+ i--;
437
+ k--;
438
+ } else {
439
+ assert(*node.flag & NODE_TYPE_PURE_BUCKET);
440
+ }
441
+
442
+ /* dict order ensured short => long */
443
+ it = ahtable_iter_begin(node.b, true);
444
+ for(; !ahtable_iter_finished(it); ahtable_iter_next(it)) {
445
+ size_t stored_len;
446
+ unsigned char* stored_key = (unsigned char*)ahtable_iter_key(it, &stored_len);
447
+ int matched = 1;
448
+ if (stored_len + i > len) {
449
+ continue;
450
+ }
451
+ for (j = 0; j < stored_len; j++) {
452
+ if (stored_key[j] != k[j]) {
453
+ matched = 0;
454
+ break;
455
+ }
456
+ }
457
+ if (matched) {
458
+ value_t* val = ahtable_iter_val(it);
459
+ if (hattrie_walk_stop == cb(key, i + stored_len, val, user_data)) {
460
+ ahtable_iter_free(it);
461
+ return;
462
+ }
463
+ }
464
+ }
465
+ ahtable_iter_free(it);
466
+ }
467
+
468
+
469
+ int hattrie_del(hattrie_t* T, const char* key, size_t len)
470
+ {
471
+ node_ptr parent = T->root;
472
+ assert(*parent.flag & NODE_TYPE_TRIE);
473
+
474
+ /* find node for deletion */
475
+ int found;
476
+ node_ptr node = hattrie_find(T, &key, &len, &found);
477
+ if (!found) {
478
+ return -1;
479
+ }
480
+
481
+ /* if consumed on a trie node, clear the value */
482
+ if (*node.flag & NODE_TYPE_TRIE) {
483
+ return hattrie_clrval(T, node);
484
+ }
485
+
486
+ /* remove from bucket */
487
+ size_t m_old = ahtable_size(node.b);
488
+ int ret = ahtable_del(node.b, key, len);
489
+ T->m -= (m_old - ahtable_size(node.b));
490
+
491
+ /* merge empty buckets */
492
+ /*! \todo */
493
+
494
+ return ret;
495
+ }
496
+
497
+
498
+ /* plan for iteration:
499
+ * This is tricky, as we have no parent pointers currently, and I would like to
500
+ * avoid adding them. That means maintaining a stack
501
+ *
502
+ */
503
+
504
+ typedef struct hattrie_node_stack_t_
505
+ {
506
+ unsigned char c;
507
+ size_t level;
508
+
509
+ node_ptr node;
510
+ struct hattrie_node_stack_t_* next;
511
+
512
+ } hattrie_node_stack_t;
513
+
514
+
515
+ struct hattrie_iter_t_
516
+ {
517
+ char* key;
518
+ size_t keysize; // space reserved for the key
519
+ size_t level;
520
+
521
+ /* keep track of keys stored in trie nodes */
522
+ bool has_nil_key;
523
+ value_t nil_val;
524
+
525
+ const hattrie_t* T;
526
+ bool sorted;
527
+ ahtable_iter_t* i;
528
+ hattrie_node_stack_t* stack;
529
+
530
+ // subtree inside a table
531
+ // store remaining prefix for filtering nodes not matching it
532
+ char* prefix;
533
+ size_t prefix_len;
534
+ };
535
+
536
+
537
+ static void hattrie_iter_pushchar(hattrie_iter_t* i, size_t level, char c)
538
+ {
539
+ if (i->keysize < level) {
540
+ i->keysize *= 2;
541
+ i->key = realloc_or_die(i->key, i->keysize * sizeof(char));
542
+ }
543
+
544
+ if (level > 0) {
545
+ i->key[level - 1] = c;
546
+ }
547
+
548
+ i->level = level;
549
+ }
550
+
551
+
552
+ static void hattrie_iter_nextnode(hattrie_iter_t* i)
553
+ {
554
+ if (i->stack == NULL) return;
555
+
556
+ /* pop the stack */
557
+ node_ptr node;
558
+ hattrie_node_stack_t* next;
559
+ unsigned char c;
560
+ size_t level;
561
+
562
+ node = i->stack->node;
563
+ next = i->stack->next;
564
+ c = i->stack->c;
565
+ level = i->stack->level;
566
+
567
+ free(i->stack);
568
+ i->stack = next;
569
+
570
+ if (*node.flag & NODE_TYPE_TRIE) {
571
+ hattrie_iter_pushchar(i, level, c);
572
+
573
+ if(node.t->flag & NODE_HAS_VAL) {
574
+ i->has_nil_key = true;
575
+ i->nil_val = node.t->val;
576
+ }
577
+
578
+ /* push all child nodes from right to left */
579
+ int j;
580
+ for (j = NODE_MAXCHAR; j >= 0; --j) {
581
+
582
+ /* skip repeated pointers to hybrid bucket */
583
+ if (j < NODE_MAXCHAR && node.t->xs[j].t == node.t->xs[j + 1].t) continue;
584
+
585
+ // push stack
586
+ next = i->stack;
587
+ i->stack = malloc_or_die(sizeof(hattrie_node_stack_t));
588
+ i->stack->node = node.t->xs[j];
589
+ i->stack->next = next;
590
+ i->stack->level = level + 1;
591
+ i->stack->c = (unsigned char) j;
592
+ }
593
+ }
594
+ else {
595
+ if (*node.flag & NODE_TYPE_PURE_BUCKET) {
596
+ hattrie_iter_pushchar(i, level, c);
597
+ }
598
+ else if (level) {
599
+ i->level = level - 1;
600
+ }
601
+ i->i = ahtable_iter_begin(node.b, i->sorted);
602
+
603
+ }
604
+ }
605
+
606
+
607
+ /** next non-nil-key node
608
+ * TODO pick a better name
609
+ */
610
+ static void hattrie_iter_step(hattrie_iter_t* i)
611
+ {
612
+ while (((i->i == NULL || ahtable_iter_finished(i->i)) && !i->has_nil_key) &&
613
+ i->stack != NULL ) {
614
+
615
+ ahtable_iter_free(i->i);
616
+ i->i = NULL;
617
+ hattrie_iter_nextnode(i);
618
+ }
619
+
620
+ if (i->i != NULL && ahtable_iter_finished(i->i)) {
621
+ ahtable_iter_free(i->i);
622
+ i->i = NULL;
623
+ }
624
+ }
625
+
626
+ static bool hattrie_iter_prefix_not_match(hattrie_iter_t* i)
627
+ {
628
+ if (hattrie_iter_finished(i)) {
629
+ return false; // can not advance the iter
630
+ }
631
+ if (i->level >= i->prefix_len) {
632
+ return memcmp(i->key, i->prefix, i->prefix_len);
633
+ } else if (i->has_nil_key) {
634
+ return true; // subkey too short
635
+ }
636
+
637
+ size_t sublen;
638
+ const char* subkey;
639
+ subkey = ahtable_iter_key(i->i, &sublen);
640
+ if (i->level + sublen < i->prefix_len) {
641
+ return true; // subkey too short
642
+ }
643
+ return memcmp(i->key, i->prefix, i->level) ||
644
+ memcmp(subkey, i->prefix + i->level, (i->prefix_len - i->level));
645
+ }
646
+
647
+
648
+ hattrie_iter_t* hattrie_iter_begin(const hattrie_t* T, bool sorted)
649
+ {
650
+ return hattrie_iter_with_prefix(T, sorted, NULL, 0);
651
+ }
652
+
653
+
654
+ hattrie_iter_t* hattrie_iter_with_prefix(const hattrie_t* T, bool sorted, const char* prefix, size_t prefix_len)
655
+ {
656
+ int found;
657
+ node_ptr node = hattrie_find((hattrie_t*)T, &prefix, &prefix_len, &found);
658
+
659
+ hattrie_iter_t* i = malloc_or_die(sizeof(hattrie_iter_t));
660
+ i->T = T;
661
+ i->sorted = sorted;
662
+ i->i = NULL;
663
+ i->keysize = 16;
664
+ i->key = malloc_or_die(i->keysize * sizeof(char));
665
+ i->level = 0;
666
+ i->has_nil_key = false;
667
+ i->nil_val = 0;
668
+
669
+ i->prefix_len = prefix_len;
670
+ if (prefix_len) {
671
+ i->prefix = (char*)malloc_or_die(prefix_len);
672
+ memcpy(i->prefix, prefix, prefix_len);
673
+ } else {
674
+ i->prefix = NULL;
675
+ }
676
+
677
+ i->stack = malloc_or_die(sizeof(hattrie_node_stack_t));
678
+ i->stack->next = NULL;
679
+ i->stack->node = node;
680
+ i->stack->c = '\0';
681
+ i->stack->level = 0;
682
+
683
+ hattrie_iter_step(i);
684
+ if (i->prefix_len && hattrie_iter_prefix_not_match(i)) {
685
+ hattrie_iter_next(i);
686
+ }
687
+
688
+ return i;
689
+ }
690
+
691
+
692
+ void hattrie_iter_next(hattrie_iter_t* i)
693
+ {
694
+ do {
695
+ if (hattrie_iter_finished(i)) return;
696
+
697
+ if (i->i != NULL && !ahtable_iter_finished(i->i)) {
698
+ ahtable_iter_next(i->i);
699
+ }
700
+ else if (i->has_nil_key) {
701
+ i->has_nil_key = false;
702
+ i->nil_val = 0;
703
+ hattrie_iter_nextnode(i);
704
+ }
705
+
706
+ hattrie_iter_step(i);
707
+ } while (i->prefix_len && hattrie_iter_prefix_not_match(i));
708
+ }
709
+
710
+
711
+ bool hattrie_iter_finished(hattrie_iter_t* i)
712
+ {
713
+ return i->stack == NULL && i->i == NULL && !i->has_nil_key;
714
+ }
715
+
716
+
717
+ void hattrie_iter_free(hattrie_iter_t* i)
718
+ {
719
+ if (i == NULL) return;
720
+ if (i->i) ahtable_iter_free(i->i);
721
+
722
+ hattrie_node_stack_t* next;
723
+ while (i->stack) {
724
+ next = i->stack->next;
725
+ free(i->stack);
726
+ i->stack = next;
727
+ }
728
+
729
+ if (i->prefix_len) {
730
+ free(i->prefix);
731
+ }
732
+
733
+ free(i->key);
734
+ free(i);
735
+ }
736
+
737
+
738
+ const char* hattrie_iter_key(hattrie_iter_t* i, size_t* len)
739
+ {
740
+ if (hattrie_iter_finished(i)) return NULL;
741
+
742
+ size_t sublen;
743
+ const char* subkey;
744
+
745
+ if (i->has_nil_key) {
746
+ subkey = NULL;
747
+ sublen = 0;
748
+ }
749
+ else subkey = ahtable_iter_key(i->i, &sublen);
750
+
751
+ if (i->keysize < i->level + sublen + 1) {
752
+ while (i->keysize < i->level + sublen + 1) i->keysize *= 2;
753
+ i->key = realloc_or_die(i->key, i->keysize * sizeof(char));
754
+ }
755
+
756
+ memcpy(i->key + i->level, subkey, sublen);
757
+ i->key[i->level + sublen] = '\0';
758
+
759
+ *len = i->level + sublen - i->prefix_len;
760
+ return i->key + i->prefix_len;
761
+ }
762
+
763
+
764
+ value_t* hattrie_iter_val(hattrie_iter_t* i)
765
+ {
766
+ if (i->has_nil_key) return &i->nil_val;
767
+
768
+ if (hattrie_iter_finished(i)) return NULL;
769
+
770
+ return ahtable_iter_val(i->i);
771
+ }