]> jfr.im git - solanum.git/blame - librb/src/radixtree.c
Change struct Dictionary(*) to rb_dictionary(_\1).
[solanum.git] / librb / src / radixtree.c
CommitLineData
8e6ba6f9
AC
1/*
2 * charybdis: an advanced ircd.
a4bf26dd 3 * rb_radixtree.c: Dictionary-based information storage.
8e6ba6f9
AC
4 *
5 * Copyright (c) 2007-2016 William Pitcock <nenolod -at- dereferenced.org>
6 * Copyright (c) 2007-2016 Jilles Tjoelker <jilles -at- stack.nl>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
a4bf26dd
EM
35#include <librb_config.h>
36#include <rb_lib.h>
37#include <rb_radixtree.h>
8e6ba6f9 38
325cc939
AC
39rb_dlink_list radixtree_list = {NULL, NULL, 0};
40
8e6ba6f9
AC
41/*
42 * Patricia tree.
43 *
44 * A radix trie that avoids one-way branching and redundant nodes.
45 *
46 * To find a node, the tree is traversed starting from the root. The
47 * nibnum in each node indicates which nibble of the key needs to be
48 * tested, and the appropriate branch is taken.
49 *
50 * The nibnum values are strictly increasing while going down the tree.
51 *
52 * -- jilles
53 */
54
a4bf26dd 55union rb_radixtree_elem;
8e6ba6f9 56
a4bf26dd 57struct rb_radixtree
8e6ba6f9
AC
58{
59 void (*canonize_cb)(char *key);
a4bf26dd 60 union rb_radixtree_elem *root;
8e6ba6f9
AC
61
62 unsigned int count;
63 char *id;
325cc939
AC
64
65 rb_dlink_node node;
8e6ba6f9
AC
66};
67
68#define POINTERS_PER_NODE 16
69#define NIBBLE_VAL(key, nibnum) (((key)[(nibnum) / 2] >> ((nibnum) & 1 ? 0 : 4)) & 0xF)
70
a4bf26dd 71struct rb_radixtree_node
8e6ba6f9
AC
72{
73 /* nibble to test (nibble NUM%2 of byte NUM/2) */
74 int nibnum;
75
76 /* branches of the tree */
a4bf26dd
EM
77 union rb_radixtree_elem *down[POINTERS_PER_NODE];
78 union rb_radixtree_elem *parent;
8e6ba6f9
AC
79
80 char parent_val;
81};
82
a4bf26dd 83struct rb_radixtree_leaf
8e6ba6f9
AC
84{
85 /* -1 to indicate this is a leaf, not a node */
86 int nibnum;
87
88 /* data associated with the key */
89 void *data;
90
91 /* key (canonized copy) */
92 char *key;
a4bf26dd 93 union rb_radixtree_elem *parent;
8e6ba6f9
AC
94
95 char parent_val;
96};
97
a4bf26dd 98union rb_radixtree_elem
8e6ba6f9
AC
99{
100 int nibnum;
a4bf26dd 101 struct rb_radixtree_node node;
8e6ba6f9 102
a4bf26dd 103 struct rb_radixtree_leaf leaf;
8e6ba6f9
AC
104};
105
106#define IS_LEAF(elem) ((elem)->nibnum == -1)
107
108/* Preserve compatibility with the old mowgli_patricia.h */
109#define STATE_CUR(state) ((state)->pspare[0])
110#define STATE_NEXT(state) ((state)->pspare[1])
111
112/*
113 * first_leaf()
114 *
115 * Find the smallest leaf hanging off a subtree.
116 *
117 * Inputs:
118 * - element (may be leaf or node) heading subtree
119 *
120 * Outputs:
121 * - lowest leaf in subtree
122 *
123 * Side Effects:
124 * - none
125 */
a4bf26dd
EM
126static union rb_radixtree_elem *
127first_leaf(union rb_radixtree_elem *delem)
8e6ba6f9
AC
128{
129 int val;
130
131 while (!IS_LEAF(delem))
132 {
133 for (val = 0; val < POINTERS_PER_NODE; val++)
134 if (delem->node.down[val] != NULL)
135 {
136 delem = delem->node.down[val];
137 break;
138 }
139 }
140
141 return delem;
142}
143
8e6ba6f9 144/*
a4bf26dd 145 * rb_radixtree_create_named(const char *name,
8e6ba6f9
AC
146 * void (*canonize_cb)(char *key))
147 *
148 * Dictionary object factory.
149 *
150 * Inputs:
151 * - patricia name
152 * - function to use for canonizing keys (for example, use
153 * a function that makes the string upper case to create
154 * a patricia with case-insensitive matching)
155 *
156 * Outputs:
157 * - on success, a new patricia object.
158 *
159 * Side Effects:
160 * - if services runs out of memory and cannot allocate the object,
161 * the program will abort.
162 */
a4bf26dd
EM
163struct rb_radixtree *
164rb_radixtree_create(const char *name, void (*canonize_cb)(char *key))
8e6ba6f9 165{
a4bf26dd 166 struct rb_radixtree *dtree = (struct rb_radixtree *) rb_malloc(sizeof(struct rb_radixtree));
8e6ba6f9
AC
167
168 dtree->canonize_cb = canonize_cb;
169 dtree->id = rb_strdup(name);
170 dtree->root = NULL;
171
325cc939
AC
172 rb_dlinkAdd(dtree, &dtree->node, &radixtree_list);
173
8e6ba6f9
AC
174 return dtree;
175}
176
177/*
a4bf26dd 178 * rb_radixtree_destroy(struct rb_radixtree *dtree,
8e6ba6f9
AC
179 * void (*destroy_cb)(const char *key, void *data, void *privdata),
180 * void *privdata);
181 *
182 * Recursively destroys all nodes in a patricia tree.
183 *
184 * Inputs:
185 * - patricia tree object
186 * - optional iteration callback
187 * - optional opaque/private data to pass to callback
188 *
189 * Outputs:
190 * - nothing
191 *
192 * Side Effects:
193 * - on success, a dtree and optionally it's children are destroyed.
194 *
195 * Notes:
196 * - if this is called without a callback, the objects bound to the
197 * DTree will not be destroyed.
198 */
199void
a4bf26dd 200rb_radixtree_destroy(struct rb_radixtree *dtree, void (*destroy_cb)(const char *key, void *data, void *privdata), void *privdata)
8e6ba6f9 201{
a4bf26dd
EM
202 struct rb_radixtree_iteration_state state;
203 union rb_radixtree_elem *delem;
8e6ba6f9
AC
204
205 void *entry;
206
a4bf26dd 207 lrb_assert(dtree != NULL);
8e6ba6f9 208
a4bf26dd 209 RB_RADIXTREE_FOREACH(entry, &state, dtree)
8e6ba6f9
AC
210 {
211 delem = STATE_CUR(&state);
212
213 if (destroy_cb != NULL)
214 (*destroy_cb)(delem->leaf.key, delem->leaf.data,
215 privdata);
216
a4bf26dd 217 rb_radixtree_delete(dtree, delem->leaf.key);
8e6ba6f9
AC
218 }
219
55d5f797
AC
220 rb_dlinkDelete(&dtree->node, &radixtree_list);
221 rb_free(dtree->id);
8e6ba6f9
AC
222 rb_free(dtree);
223}
224
225/*
a4bf26dd 226 * rb_radixtree_foreach(struct rb_radixtree *dtree,
8e6ba6f9
AC
227 * int (*foreach_cb)(const char *key, void *data, void *privdata),
228 * void *privdata);
229 *
230 * Iterates over all entries in a DTree.
231 *
232 * Inputs:
233 * - patricia tree object
234 * - optional iteration callback
235 * - optional opaque/private data to pass to callback
236 *
237 * Outputs:
238 * - nothing
239 *
240 * Side Effects:
241 * - on success, a dtree is iterated
242 */
243void
a4bf26dd 244rb_radixtree_foreach(struct rb_radixtree *dtree, int (*foreach_cb)(const char *key, void *data, void *privdata), void *privdata)
8e6ba6f9 245{
a4bf26dd 246 union rb_radixtree_elem *delem, *next;
8e6ba6f9
AC
247
248 int val;
249
a4bf26dd 250 lrb_assert(dtree != NULL);
8e6ba6f9
AC
251
252 delem = dtree->root;
253
254 if (delem == NULL)
255 return;
256
257 /* Only one element in the tree */
258 if (IS_LEAF(delem))
259 {
260 if (foreach_cb != NULL)
261 (*foreach_cb)(delem->leaf.key, delem->leaf.data, privdata);
262
263 return;
264 }
265
266 val = 0;
267
268 do
269 {
270 do
271 next = delem->node.down[val++];
272 while (next == NULL && val < POINTERS_PER_NODE);
273
274 if (next != NULL)
275 {
276 if (IS_LEAF(next))
277 {
278 if (foreach_cb != NULL)
279 (*foreach_cb)(next->leaf.key, next->leaf.data, privdata);
280 }
281 else
282 {
283 delem = next;
284 val = 0;
285 }
286 }
287
288 while (val >= POINTERS_PER_NODE)
289 {
290 val = delem->node.parent_val;
291 delem = delem->node.parent;
292
293 if (delem == NULL)
294 break;
295
296 val++;
297 }
298 } while (delem != NULL);
299}
300
301/*
a4bf26dd 302 * rb_radixtree_search(struct rb_radixtree *dtree,
8e6ba6f9
AC
303 * void *(*foreach_cb)(const char *key, void *data, void *privdata),
304 * void *privdata);
305 *
306 * Searches all entries in a DTree using a custom callback.
307 *
308 * Inputs:
309 * - patricia tree object
310 * - optional iteration callback
311 * - optional opaque/private data to pass to callback
312 *
313 * Outputs:
314 * - on success, the requested object
315 * - on failure, NULL.
316 *
317 * Side Effects:
318 * - a dtree is iterated until the requested conditions are met
319 */
320void *
a4bf26dd 321rb_radixtree_search(struct rb_radixtree *dtree, void *(*foreach_cb)(const char *key, void *data, void *privdata), void *privdata)
8e6ba6f9 322{
a4bf26dd 323 union rb_radixtree_elem *delem, *next;
8e6ba6f9
AC
324
325 int val;
326 void *ret = NULL;
327
a4bf26dd 328 lrb_assert(dtree != NULL);
8e6ba6f9
AC
329
330 delem = dtree->root;
331
332 if (delem == NULL)
333 return NULL;
334
335 /* Only one element in the tree */
336 if (IS_LEAF(delem))
337 {
338 if (foreach_cb != NULL)
339 return (*foreach_cb)(delem->leaf.key, delem->leaf.data, privdata);
340
341 return NULL;
342 }
343
344 val = 0;
345
346 for (;;)
347 {
348 do
349 next = delem->node.down[val++];
350 while (next == NULL && val < POINTERS_PER_NODE);
351
352 if (next != NULL)
353 {
354 if (IS_LEAF(next))
355 {
356 if (foreach_cb != NULL)
357 ret = (*foreach_cb)(next->leaf.key, next->leaf.data, privdata);
358
359 if (ret != NULL)
360 break;
361 }
362 else
363 {
364 delem = next;
365 val = 0;
366 }
367 }
368
369 while (val >= POINTERS_PER_NODE)
370 {
371 val = delem->node.parent_val;
372 delem = delem->node.parent;
373
374 if (delem == NULL)
375 break;
376
377 val++;
378 }
379 }
380
381 return ret;
382}
383
384/*
a4bf26dd
EM
385 * rb_radixtree_foreach_start(struct rb_radixtree *dtree,
386 * struct rb_radixtree_iteration_state *state);
8e6ba6f9
AC
387 *
388 * Initializes a static DTree iterator.
389 *
390 * Inputs:
391 * - patricia tree object
392 * - static DTree iterator
393 *
394 * Outputs:
395 * - nothing
396 *
397 * Side Effects:
398 * - the static iterator, &state, is initialized.
399 */
400void
a4bf26dd 401rb_radixtree_foreach_start(struct rb_radixtree *dtree, struct rb_radixtree_iteration_state *state)
8e6ba6f9
AC
402{
403 if (dtree == NULL)
404 return;
405
a4bf26dd 406 lrb_assert(state != NULL);
8e6ba6f9
AC
407
408 if (dtree->root != NULL)
409 STATE_NEXT(state) = first_leaf(dtree->root);
410 else
411 STATE_NEXT(state) = NULL;
412
413 STATE_CUR(state) = STATE_NEXT(state);
414
415 if (STATE_NEXT(state) == NULL)
416 return;
417
418 /* make STATE_CUR point to first item and STATE_NEXT point to
419 * second item */
a4bf26dd 420 rb_radixtree_foreach_next(dtree, state);
8e6ba6f9
AC
421}
422
423/*
a4bf26dd
EM
424 * rb_radixtree_foreach_cur(struct rb_radixtree *dtree,
425 * struct rb_radixtree_iteration_state *state);
8e6ba6f9
AC
426 *
427 * Returns the data from the current node being iterated by the
428 * static iterator.
429 *
430 * Inputs:
431 * - patricia tree object
432 * - static DTree iterator
433 *
434 * Outputs:
435 * - reference to data in the current dtree node being iterated
436 *
437 * Side Effects:
438 * - none
439 */
440void *
a4bf26dd 441rb_radixtree_foreach_cur(struct rb_radixtree *dtree, struct rb_radixtree_iteration_state *state)
8e6ba6f9
AC
442{
443 if (dtree == NULL)
444 return NULL;
445
a4bf26dd 446 lrb_assert(state != NULL);
8e6ba6f9
AC
447
448 return STATE_CUR(state) != NULL ?
a4bf26dd 449 ((struct rb_radixtree_leaf *) STATE_CUR(state))->data : NULL;
8e6ba6f9
AC
450}
451
452/*
a4bf26dd
EM
453 * rb_radixtree_foreach_next(struct rb_radixtree *dtree,
454 * struct rb_radixtree_iteration_state *state);
8e6ba6f9
AC
455 *
456 * Advances a static DTree iterator.
457 *
458 * Inputs:
459 * - patricia tree object
460 * - static DTree iterator
461 *
462 * Outputs:
463 * - nothing
464 *
465 * Side Effects:
466 * - the static iterator, &state, is advanced to a new DTree node.
467 */
468void
a4bf26dd 469rb_radixtree_foreach_next(struct rb_radixtree *dtree, struct rb_radixtree_iteration_state *state)
8e6ba6f9 470{
a4bf26dd 471 struct rb_radixtree_leaf *leaf;
8e6ba6f9 472
a4bf26dd 473 union rb_radixtree_elem *delem, *next;
8e6ba6f9
AC
474
475 int val;
476
477 if (dtree == NULL)
478 return;
479
a4bf26dd 480 lrb_assert(state != NULL);
8e6ba6f9
AC
481
482 if (STATE_CUR(state) == NULL)
483 return;
484
485 STATE_CUR(state) = STATE_NEXT(state);
486
487 if (STATE_NEXT(state) == NULL)
488 return;
489
490 leaf = STATE_NEXT(state);
491 delem = leaf->parent;
492 val = leaf->parent_val;
493
494 while (delem != NULL)
495 {
496 do
497 next = delem->node.down[val++];
498 while (next == NULL && val < POINTERS_PER_NODE);
499
500 if (next != NULL)
501 {
502 if (IS_LEAF(next))
503 {
504 /* We will find the original leaf first. */
505 if (&next->leaf != leaf)
506 {
507 if (strcmp(next->leaf.key, leaf->key) < 0)
508 {
509 STATE_NEXT(state) = NULL;
510 return;
511 }
512
513 STATE_NEXT(state) = next;
514 return;
515 }
516 }
517 else
518 {
519 delem = next;
520 val = 0;
521 }
522 }
523
524 while (val >= POINTERS_PER_NODE)
525 {
526 val = delem->node.parent_val;
527 delem = delem->node.parent;
528
529 if (delem == NULL)
530 break;
531
532 val++;
533 }
534 }
535
536 STATE_NEXT(state) = NULL;
537}
538
539/*
a4bf26dd 540 * rb_radixtree_elem_find(struct rb_radixtree *dtree, const char *key)
8e6ba6f9
AC
541 *
542 * Looks up a DTree node by name.
543 *
544 * Inputs:
545 * - patricia tree object
546 * - name of node to lookup
704697b6 547 * - whether to do a direct or fuzzy match
8e6ba6f9
AC
548 *
549 * Outputs:
550 * - on success, the dtree node requested
551 * - on failure, NULL
552 *
553 * Side Effects:
554 * - none
555 */
a4bf26dd
EM
556struct rb_radixtree_leaf *
557rb_radixtree_elem_find(struct rb_radixtree *dict, const char *key, int fuzzy)
8e6ba6f9
AC
558{
559 char ckey_store[256];
560
561 char *ckey_buf = NULL;
562 const char *ckey;
a4bf26dd 563 union rb_radixtree_elem *delem;
8e6ba6f9
AC
564
565 int val, keylen;
566
a4bf26dd
EM
567 lrb_assert(dict != NULL);
568 lrb_assert(key != NULL);
8e6ba6f9
AC
569
570 keylen = strlen(key);
571
572 if (dict->canonize_cb == NULL)
573 {
574 ckey = key;
575 }
576 else
577 {
578 if (keylen >= (int) sizeof(ckey_store))
579 {
580 ckey_buf = rb_strdup(key);
581 dict->canonize_cb(ckey_buf);
582 ckey = ckey_buf;
583 }
584 else
585 {
586 rb_strlcpy(ckey_store, key, sizeof ckey_store);
587 dict->canonize_cb(ckey_store);
588 ckey = ckey_store;
589 }
590 }
591
592 delem = dict->root;
593
594 while (delem != NULL && !IS_LEAF(delem))
595 {
596 if (delem->nibnum / 2 < keylen)
597 val = NIBBLE_VAL(ckey, delem->nibnum);
598 else
599 val = 0;
600
601 delem = delem->node.down[val];
602 }
603
604 /* Now, if the key is in the tree, delem contains it. */
704697b6 605 if ((delem != NULL) && !fuzzy && strcmp(delem->leaf.key, ckey))
8e6ba6f9
AC
606 delem = NULL;
607
608 if (ckey_buf != NULL)
609 rb_free(ckey_buf);
610
611 return &delem->leaf;
612}
613
0d9a72de 614/*
a4bf26dd 615 * rb_radixtree_foreach_start_from(struct rb_radixtree *dtree, struct rb_radixtree_iteration_state *state, const char *key)
0d9a72de 616 *
a4bf26dd 617 * Starts iteration from a specified key, by wrapping rb_radixtree_elem_find().
0d9a72de
AC
618 *
619 * Inputs:
620 * - patricia tree object
621 * - iterator
622 * - key to start from
623 *
624 * Outputs:
625 * - none
626 *
627 * Side Effects:
628 * - the iterator's state is initialized at a specific point
629 */
630void
a4bf26dd 631rb_radixtree_foreach_start_from(struct rb_radixtree *dtree, struct rb_radixtree_iteration_state *state, const char *key)
0d9a72de 632{
a4bf26dd
EM
633 lrb_assert(dtree != NULL);
634 lrb_assert(state != NULL);
0d9a72de
AC
635
636 if (key != NULL)
637 {
638 STATE_CUR(state) = NULL;
a4bf26dd 639 STATE_NEXT(state) = rb_radixtree_elem_find(dtree, key, 1);
0d9a72de
AC
640
641 /* make STATE_CUR point to selected item and STATE_NEXT point to
642 * next item in the tree */
a4bf26dd 643 rb_radixtree_foreach_next(dtree, state);
0d9a72de
AC
644 }
645 else
a4bf26dd 646 rb_radixtree_foreach_start(dtree, state);
0d9a72de
AC
647}
648
8e6ba6f9 649/*
a4bf26dd 650 * rb_radixtree_add(struct rb_radixtree *dtree, const char *key, void *data)
8e6ba6f9
AC
651 *
652 * Creates a new DTree node and binds data to it.
653 *
654 * Inputs:
655 * - patricia tree object
656 * - name for new DTree node
657 * - data to bind to the new DTree node
658 *
659 * Outputs:
660 * - on success, TRUE
661 * - on failure, FALSE
662 *
663 * Side Effects:
664 * - data is inserted into the DTree.
665 */
a4bf26dd
EM
666struct rb_radixtree_leaf *
667rb_radixtree_elem_add(struct rb_radixtree *dict, const char *key, void *data)
8e6ba6f9
AC
668{
669 char *ckey;
670
a4bf26dd 671 union rb_radixtree_elem *delem, *prev, *newnode;
8e6ba6f9 672
a4bf26dd 673 union rb_radixtree_elem **place1;
8e6ba6f9
AC
674
675 int val, keylen;
676 int i, j;
677
a4bf26dd
EM
678 lrb_assert(dict != NULL);
679 lrb_assert(key != NULL);
680 lrb_assert(data != NULL);
8e6ba6f9
AC
681
682 keylen = strlen(key);
683 ckey = rb_strdup(key);
684
685 if (ckey == NULL)
686 return NULL;
687
688 if (dict->canonize_cb != NULL)
689 dict->canonize_cb(ckey);
690
691 prev = NULL;
692 val = POINTERS_PER_NODE + 2; /* trap value */
693 delem = dict->root;
694
695 while (delem != NULL && !IS_LEAF(delem))
696 {
697 prev = delem;
698
699 if (delem->nibnum / 2 < keylen)
700 val = NIBBLE_VAL(ckey, delem->nibnum);
701 else
702 val = 0;
703
704 delem = delem->node.down[val];
705 }
706
707 /* Now, if the key is in the tree, delem contains it. */
708 if ((delem != NULL) && !strcmp(delem->leaf.key, ckey))
709 {
710 rb_free(ckey);
711 return NULL;
712 }
713
714 if ((delem == NULL) && (prev != NULL))
715 /* Get a leaf to compare with. */
716 delem = first_leaf(prev);
717
718 if (delem == NULL)
719 {
a4bf26dd
EM
720 lrb_assert(prev == NULL);
721 lrb_assert(dict->count == 0);
8e6ba6f9 722 place1 = &dict->root;
a4bf26dd
EM
723 *place1 = rb_malloc(sizeof(struct rb_radixtree_leaf));
724 lrb_assert(*place1 != NULL);
8e6ba6f9
AC
725 (*place1)->nibnum = -1;
726 (*place1)->leaf.data = data;
727 (*place1)->leaf.key = ckey;
728 (*place1)->leaf.parent = prev;
729 (*place1)->leaf.parent_val = val;
730 dict->count++;
731 return &(*place1)->leaf;
732 }
733
734 /* Find the first nibble where they differ. */
735 for (i = 0; NIBBLE_VAL(ckey, i) == NIBBLE_VAL(delem->leaf.key, i); i++)
736 ;
737
738 /* Find where to insert the new node. */
739 while (prev != NULL && prev->nibnum > i)
740 {
741 val = prev->node.parent_val;
742 prev = prev->node.parent;
743 }
744
745 if ((prev == NULL) || (prev->nibnum < i))
746 {
747 /* Insert new node below prev */
a4bf26dd
EM
748 newnode = rb_malloc(sizeof(struct rb_radixtree_node));
749 lrb_assert(newnode != NULL);
8e6ba6f9
AC
750 newnode->nibnum = i;
751 newnode->node.parent = prev;
752 newnode->node.parent_val = val;
753
754 for (j = 0; j < POINTERS_PER_NODE; j++)
755 newnode->node.down[j] = NULL;
756
757 if (prev == NULL)
758 {
759 newnode->node.down[NIBBLE_VAL(delem->leaf.key, i)] = dict->root;
760
761 if (IS_LEAF(dict->root))
762 {
763 dict->root->leaf.parent = newnode;
764 dict->root->leaf.parent_val = NIBBLE_VAL(delem->leaf.key, i);
765 }
766 else
767 {
a4bf26dd 768 lrb_assert(dict->root->nibnum > i);
8e6ba6f9
AC
769 dict->root->node.parent = newnode;
770 dict->root->node.parent_val = NIBBLE_VAL(delem->leaf.key, i);
771 }
772
773 dict->root = newnode;
774 }
775 else
776 {
777 newnode->node.down[NIBBLE_VAL(delem->leaf.key, i)] = prev->node.down[val];
778
779 if (IS_LEAF(prev->node.down[val]))
780 {
781 prev->node.down[val]->leaf.parent = newnode;
782 prev->node.down[val]->leaf.parent_val = NIBBLE_VAL(delem->leaf.key, i);
783 }
784 else
785 {
786 prev->node.down[val]->node.parent = newnode;
787 prev->node.down[val]->node.parent_val = NIBBLE_VAL(delem->leaf.key, i);
788 }
789
790 prev->node.down[val] = newnode;
791 }
792 }
793 else
794 {
795 /* This nibble is already checked. */
a4bf26dd 796 lrb_assert(prev->nibnum == i);
8e6ba6f9
AC
797 newnode = prev;
798 }
799
800 val = NIBBLE_VAL(ckey, i);
801 place1 = &newnode->node.down[val];
a4bf26dd
EM
802 lrb_assert(*place1 == NULL);
803 *place1 = rb_malloc(sizeof(struct rb_radixtree_leaf));
804 lrb_assert(*place1 != NULL);
8e6ba6f9
AC
805 (*place1)->nibnum = -1;
806 (*place1)->leaf.data = data;
807 (*place1)->leaf.key = ckey;
808 (*place1)->leaf.parent = newnode;
809 (*place1)->leaf.parent_val = val;
810 dict->count++;
811 return &(*place1)->leaf;
812}
813
814int
a4bf26dd 815rb_radixtree_add(struct rb_radixtree *dict, const char *key, void *data)
8e6ba6f9 816{
a4bf26dd 817 return (rb_radixtree_elem_add(dict, key, data) != NULL);
8e6ba6f9
AC
818}
819
820/*
a4bf26dd 821 * rb_radixtree_delete(struct rb_radixtree *dtree, const char *key)
8e6ba6f9
AC
822 *
823 * Deletes data from a patricia tree.
824 *
825 * Inputs:
826 * - patricia tree object
827 * - name of DTree node to delete
828 *
829 * Outputs:
830 * - on success, the remaining data that needs to be rb_freed
831 * - on failure, NULL
832 *
833 * Side Effects:
834 * - data is removed from the DTree.
835 *
836 * Notes:
837 * - the returned data needs to be rb_freed/released manually!
838 */
839void *
a4bf26dd 840rb_radixtree_delete(struct rb_radixtree *dict, const char *key)
8e6ba6f9
AC
841{
842 void *data;
a4bf26dd 843 struct rb_radixtree_leaf *leaf;
8e6ba6f9 844
a4bf26dd 845 leaf = rb_radixtree_elem_find(dict, key, 0);
8e6ba6f9
AC
846
847 if (leaf == NULL)
848 return NULL;
849
850 data = leaf->data;
a4bf26dd 851 rb_radixtree_elem_delete(dict, leaf);
8e6ba6f9
AC
852 return data;
853}
854
855void
a4bf26dd 856rb_radixtree_elem_delete(struct rb_radixtree *dict, struct rb_radixtree_leaf *leaf)
8e6ba6f9 857{
a4bf26dd 858 union rb_radixtree_elem *delem, *prev, *next;
8e6ba6f9
AC
859
860 int val, i, used;
861
a4bf26dd
EM
862 lrb_assert(dict != NULL);
863 lrb_assert(leaf != NULL);
8e6ba6f9 864
a4bf26dd 865 delem = (union rb_radixtree_elem *) leaf;
8e6ba6f9
AC
866
867 val = delem->leaf.parent_val;
868 prev = delem->leaf.parent;
869
870 rb_free(delem->leaf.key);
871 rb_free(delem);
872
873 if (prev != NULL)
874 {
875 prev->node.down[val] = NULL;
876
877 /* Leaf is gone, now consider the node it was in. */
878 delem = prev;
879
880 used = -1;
881
882 for (i = 0; i < POINTERS_PER_NODE; i++)
883 if (delem->node.down[i] != NULL)
884 used = used == -1 ? i : -2;
885
a4bf26dd 886 lrb_assert(used == -2 || used >= 0);
8e6ba6f9
AC
887
888 if (used >= 0)
889 {
890 /* Only one pointer in this node, remove it.
891 * Replace the pointer that pointed to it by
892 * the sole pointer in it.
893 */
894 next = delem->node.down[used];
895 val = delem->node.parent_val;
896 prev = delem->node.parent;
897
898 if (prev != NULL)
899 prev->node.down[val] = next;
900 else
901 dict->root = next;
902
903 if (IS_LEAF(next))
904 next->leaf.parent = prev, next->leaf.parent_val = val;
905 else
906 next->node.parent = prev, next->node.parent_val = val;
907
908 rb_free(delem);
909 }
910 }
911 else
912 {
913 /* This was the last leaf. */
914 dict->root = NULL;
915 }
916
917 dict->count--;
918
919 if (dict->count == 0)
920 {
a4bf26dd 921 lrb_assert(dict->root == NULL);
8e6ba6f9
AC
922 dict->root = NULL;
923 }
924}
925
926/*
a4bf26dd 927 * rb_radixtree_retrieve(struct rb_radixtree *dtree, const char *key)
8e6ba6f9
AC
928 *
929 * Retrieves data from a patricia.
930 *
931 * Inputs:
932 * - patricia tree object
933 * - name of node to lookup
934 *
935 * Outputs:
936 * - on success, the data bound to the DTree node.
937 * - on failure, NULL
938 *
939 * Side Effects:
940 * - none
941 */
942void *
a4bf26dd 943rb_radixtree_retrieve(struct rb_radixtree *dtree, const char *key)
8e6ba6f9 944{
a4bf26dd 945 struct rb_radixtree_leaf *delem = rb_radixtree_elem_find(dtree, key, 0);
8e6ba6f9
AC
946
947 if (delem != NULL)
948 return delem->data;
949
950 return NULL;
951}
952
953const char *
a4bf26dd 954rb_radixtree_elem_get_key(struct rb_radixtree_leaf *leaf)
8e6ba6f9 955{
a4bf26dd 956 lrb_assert(leaf != NULL);
8e6ba6f9
AC
957
958 return leaf->key;
959}
960
961void
a4bf26dd 962rb_radixtree_elem_set_data(struct rb_radixtree_leaf *leaf, void *data)
8e6ba6f9 963{
a4bf26dd 964 lrb_assert(leaf != NULL);
8e6ba6f9
AC
965
966 leaf->data = data;
967}
968
969void *
a4bf26dd 970rb_radixtree_elem_get_data(struct rb_radixtree_leaf *leaf)
8e6ba6f9 971{
a4bf26dd 972 lrb_assert(leaf != NULL);
8e6ba6f9
AC
973
974 return leaf->data;
975}
976
977/*
a4bf26dd 978 * rb_radixtree_size(struct rb_radixtree *dict)
8e6ba6f9
AC
979 *
980 * Returns the size of a patricia.
981 *
982 * Inputs:
983 * - patricia tree object
984 *
985 * Outputs:
986 * - size of patricia
987 *
988 * Side Effects:
989 * - none
990 */
991unsigned int
a4bf26dd 992rb_radixtree_size(struct rb_radixtree *dict)
8e6ba6f9 993{
a4bf26dd 994 lrb_assert(dict != NULL);
8e6ba6f9
AC
995
996 return dict->count;
997}
998
999/* returns the sum of the depths of the subtree rooted in delem at depth depth */
1000/* there is no need for this to be recursive, but it is easier... */
1001static int
a4bf26dd 1002stats_recurse(union rb_radixtree_elem *delem, int depth, int *pmaxdepth)
8e6ba6f9
AC
1003{
1004 int result = 0;
1005 int val;
a4bf26dd 1006 union rb_radixtree_elem *next;
8e6ba6f9
AC
1007
1008 if (depth > *pmaxdepth)
1009 *pmaxdepth = depth;
1010
1011 if (depth == 0)
1012 {
1013 if (IS_LEAF(delem))
a4bf26dd 1014 lrb_assert(delem->leaf.parent == NULL);
8e6ba6f9
AC
1015
1016 else
a4bf26dd 1017 lrb_assert(delem->node.parent == NULL);
8e6ba6f9
AC
1018 }
1019
1020 if (IS_LEAF(delem))
1021 return depth;
1022
1023 for (val = 0; val < POINTERS_PER_NODE; val++)
1024 {
1025 next = delem->node.down[val];
1026
1027 if (next == NULL)
1028 continue;
1029
1030 result += stats_recurse(next, depth + 1, pmaxdepth);
1031
1032 if (IS_LEAF(next))
1033 {
a4bf26dd
EM
1034 lrb_assert(next->leaf.parent == delem);
1035 lrb_assert(next->leaf.parent_val == val);
8e6ba6f9
AC
1036 }
1037 else
1038 {
a4bf26dd
EM
1039 lrb_assert(next->node.parent == delem);
1040 lrb_assert(next->node.parent_val == val);
1041 lrb_assert(next->node.nibnum > delem->node.nibnum);
8e6ba6f9
AC
1042 }
1043 }
1044
1045 return result;
1046}
1047
1048/*
a4bf26dd 1049 * rb_radixtree_stats(struct rb_radixtree *dict, void (*cb)(const char *line, void *privdata), void *privdata)
8e6ba6f9
AC
1050 *
1051 * Returns the size of a patricia.
1052 *
1053 * Inputs:
1054 * - patricia tree object
1055 * - callback
1056 * - data for callback
1057 *
1058 * Outputs:
1059 * - none
1060 *
1061 * Side Effects:
1062 * - callback called with stats text
1063 */
1064void
a4bf26dd 1065rb_radixtree_stats(struct rb_radixtree *dict, void (*cb)(const char *line, void *privdata), void *privdata)
8e6ba6f9
AC
1066{
1067 char str[256];
1068 int sum, maxdepth;
1069
a4bf26dd 1070 lrb_assert(dict != NULL);
8e6ba6f9 1071
8e6ba6f9 1072 maxdepth = 0;
8e6ba6f9
AC
1073 if (dict->count > 0)
1074 {
1075 sum = stats_recurse(dict->root, 0, &maxdepth);
8dacf9e9 1076 snprintf(str, sizeof str, "%-30s %-15s %-10d %-10d %-10d %-10d", dict->id, "RADIX", dict->count, sum, sum / dict->count, maxdepth);
8e6ba6f9
AC
1077 }
1078 else
1079 {
8dacf9e9 1080 snprintf(str, sizeof str, "%-30s %-15s %-10s %-10s %-10s %-10s", dict->id, "RADIX", "0", "0", "0", "0");
8e6ba6f9
AC
1081 }
1082
1083 cb(str, privdata);
1084 return;
1085}
325cc939
AC
1086
1087void
a4bf26dd 1088rb_radixtree_stats_walk(void (*cb)(const char *line, void *privdata), void *privdata)
325cc939
AC
1089{
1090 rb_dlink_node *ptr;
1091
1092 RB_DLINK_FOREACH(ptr, radixtree_list.head)
1093 {
a4bf26dd 1094 rb_radixtree_stats(ptr->data, cb, privdata);
325cc939
AC
1095 }
1096}
db891ac3 1097