source: vendor/current/ctdb/common/rb_tree.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

File size: 23.3 KB
Line 
1/*
2 a talloc based red-black tree
3
4 Copyright (C) Ronnie Sahlberg 2007
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "replace.h"
21
22#include <talloc.h>
23
24#include "lib/util/debug.h"
25
26#include "common/logging.h"
27#include "common/rb_tree.h"
28
29#define NO_MEMORY_FATAL(p) do { if (!(p)) { \
30 DEBUG(DEBUG_CRIT,("Out of memory for %s at %s\n", #p, __location__)); \
31 exit(10); \
32 }} while (0)
33
34
35static void
36tree_destructor_traverse_node(TALLOC_CTX *mem_ctx, trbt_node_t *node)
37{
38 talloc_set_destructor(node, NULL);
39 if (node->left) {
40 tree_destructor_traverse_node(mem_ctx, node->left);
41 }
42 if (node->right) {
43 tree_destructor_traverse_node(mem_ctx, node->right);
44 }
45 talloc_steal(mem_ctx, node);
46}
47
48/*
49 destroy a tree and remove all its nodes
50 */
51static int tree_destructor(trbt_tree_t *tree)
52{
53 TALLOC_CTX *tmp_ctx;
54 trbt_node_t *node;
55
56 if (tree == NULL) {
57 return 0;
58 }
59
60 node=tree->root;
61 if (node == NULL) {
62 return 0;
63 }
64
65 /* traverse the tree and remove the node destructor and steal
66 the node to the temporary context.
67 we don't want to use the existing destructor for the node
68 since that will remove the nodes one by one from the tree.
69 since the entire tree will be completely destroyed we don't care
70 if it is inconsistent or unbalanced while freeing the
71 individual nodes
72 */
73 tmp_ctx = talloc_new(NULL);
74 tree_destructor_traverse_node(tmp_ctx, node);
75 talloc_free(tmp_ctx);
76
77 return 0;
78}
79
80
81/* create a red black tree */
82trbt_tree_t *
83trbt_create(TALLOC_CTX *memctx, uint32_t flags)
84{
85 trbt_tree_t *tree;
86
87 tree = talloc_zero(memctx, trbt_tree_t);
88 NO_MEMORY_FATAL(tree);
89
90 /* If the tree is freed, we must walk over all entries and steal the
91 node from the stored data pointer and release the node.
92 Note, when we free the tree we only free the tree and not any of
93 the data stored in the tree.
94 */
95 talloc_set_destructor(tree, tree_destructor);
96 tree->flags = flags;
97
98 return tree;
99}
100
101static inline trbt_node_t *
102trbt_parent(trbt_node_t *node)
103{
104 return node->parent;
105}
106
107static inline trbt_node_t *
108trbt_grandparent(trbt_node_t *node)
109{
110 trbt_node_t *parent;
111
112 parent=trbt_parent(node);
113 if(parent){
114 return parent->parent;
115 }
116 return NULL;
117}
118
119static inline trbt_node_t *
120trbt_uncle(trbt_node_t *node)
121{
122 trbt_node_t *parent, *grandparent;
123
124 parent=trbt_parent(node);
125 if(!parent){
126 return NULL;
127 }
128 grandparent=trbt_parent(parent);
129 if(!grandparent){
130 return NULL;
131 }
132 if(parent==grandparent->left){
133 return grandparent->right;
134 }
135 return grandparent->left;
136}
137
138
139static inline void trbt_insert_case1(trbt_tree_t *tree, trbt_node_t *node);
140static inline void trbt_insert_case2(trbt_tree_t *tree, trbt_node_t *node);
141
142static inline void
143trbt_rotate_left(trbt_node_t *node)
144{
145 trbt_tree_t *tree = node->tree;
146
147 if(node->parent){
148 if(node->parent->left==node){
149 node->parent->left=node->right;
150 } else {
151 node->parent->right=node->right;
152 }
153 } else {
154 tree->root=node->right;
155 }
156 node->right->parent=node->parent;
157 node->parent=node->right;
158 node->right=node->right->left;
159 if(node->right){
160 node->right->parent=node;
161 }
162 node->parent->left=node;
163}
164
165static inline void
166trbt_rotate_right(trbt_node_t *node)
167{
168 trbt_tree_t *tree = node->tree;
169
170 if(node->parent){
171 if(node->parent->left==node){
172 node->parent->left=node->left;
173 } else {
174 node->parent->right=node->left;
175 }
176 } else {
177 tree->root=node->left;
178 }
179 node->left->parent=node->parent;
180 node->parent=node->left;
181 node->left=node->left->right;
182 if(node->left){
183 node->left->parent=node;
184 }
185 node->parent->right=node;
186}
187
188/* NULL nodes are black by definition */
189static inline int trbt_get_color(trbt_node_t *node)
190{
191 if (node==NULL) {
192 return TRBT_BLACK;
193 }
194 return node->rb_color;
195}
196static inline int trbt_get_color_left(trbt_node_t *node)
197{
198 if (node==NULL) {
199 return TRBT_BLACK;
200 }
201 if (node->left==NULL) {
202 return TRBT_BLACK;
203 }
204 return node->left->rb_color;
205}
206static inline int trbt_get_color_right(trbt_node_t *node)
207{
208 if (node==NULL) {
209 return TRBT_BLACK;
210 }
211 if (node->right==NULL) {
212 return TRBT_BLACK;
213 }
214 return node->right->rb_color;
215}
216/* setting a NULL node to black is a nop */
217static inline void trbt_set_color(trbt_node_t *node, int color)
218{
219 if (node == NULL) {
220 return;
221 }
222 node->rb_color = color;
223}
224static inline void trbt_set_color_left(trbt_node_t *node, int color)
225{
226 if (node == NULL || node->left == NULL) {
227 return;
228 }
229 node->left->rb_color = color;
230}
231static inline void trbt_set_color_right(trbt_node_t *node, int color)
232{
233 if (node == NULL || node->right == NULL) {
234 return;
235 }
236 node->right->rb_color = color;
237}
238
239static inline void
240trbt_insert_case5(trbt_tree_t *tree, trbt_node_t *node)
241{
242 trbt_node_t *grandparent;
243 trbt_node_t *parent;
244
245 parent=trbt_parent(node);
246 grandparent=trbt_parent(parent);
247 parent->rb_color=TRBT_BLACK;
248 grandparent->rb_color=TRBT_RED;
249 if( (node==parent->left) && (parent==grandparent->left) ){
250 trbt_rotate_right(grandparent);
251 } else {
252 trbt_rotate_left(grandparent);
253 }
254}
255
256static inline void
257trbt_insert_case4(trbt_tree_t *tree, trbt_node_t *node)
258{
259 trbt_node_t *grandparent;
260 trbt_node_t *parent;
261
262 parent=trbt_parent(node);
263 grandparent=trbt_parent(parent);
264 if(!grandparent){
265 return;
266 }
267 if( (node==parent->right) && (parent==grandparent->left) ){
268 trbt_rotate_left(parent);
269 node=node->left;
270 } else if( (node==parent->left) && (parent==grandparent->right) ){
271 trbt_rotate_right(parent);
272 node=node->right;
273 }
274 trbt_insert_case5(tree, node);
275}
276
277static inline void
278trbt_insert_case3(trbt_tree_t *tree, trbt_node_t *node)
279{
280 trbt_node_t *grandparent;
281 trbt_node_t *parent;
282 trbt_node_t *uncle;
283
284 uncle=trbt_uncle(node);
285 if(uncle && (uncle->rb_color==TRBT_RED)){
286 parent=trbt_parent(node);
287 parent->rb_color=TRBT_BLACK;
288 uncle->rb_color=TRBT_BLACK;
289 grandparent=trbt_grandparent(node);
290 grandparent->rb_color=TRBT_RED;
291 trbt_insert_case1(tree, grandparent);
292 } else {
293 trbt_insert_case4(tree, node);
294 }
295}
296
297static inline void
298trbt_insert_case2(trbt_tree_t *tree, trbt_node_t *node)
299{
300 trbt_node_t *parent;
301
302 parent=trbt_parent(node);
303 /* parent is always non-NULL here */
304 if(parent->rb_color==TRBT_BLACK){
305 return;
306 }
307 trbt_insert_case3(tree, node);
308}
309
310static inline void
311trbt_insert_case1(trbt_tree_t *tree, trbt_node_t *node)
312{
313 trbt_node_t *parent;
314
315 parent=trbt_parent(node);
316 if(!parent){
317 node->rb_color=TRBT_BLACK;
318 return;
319 }
320 trbt_insert_case2(tree, node);
321}
322
323static inline trbt_node_t *
324trbt_sibling(trbt_node_t *node)
325{
326 trbt_node_t *parent;
327
328 parent=trbt_parent(node);
329 if(!parent){
330 return NULL;
331 }
332
333 if (node == parent->left) {
334 return parent->right;
335 } else {
336 return parent->left;
337 }
338}
339
340static inline void
341trbt_delete_case6(trbt_node_t *node)
342{
343 trbt_node_t *sibling, *parent;
344
345 sibling = trbt_sibling(node);
346 parent = trbt_parent(node);
347
348 trbt_set_color(sibling, parent->rb_color);
349 trbt_set_color(parent, TRBT_BLACK);
350 if (node == parent->left) {
351 trbt_set_color_right(sibling, TRBT_BLACK);
352 trbt_rotate_left(parent);
353 } else {
354 trbt_set_color_left(sibling, TRBT_BLACK);
355 trbt_rotate_right(parent);
356 }
357}
358
359
360static inline void
361trbt_delete_case5(trbt_node_t *node)
362{
363 trbt_node_t *parent, *sibling;
364
365 parent = trbt_parent(node);
366 sibling = trbt_sibling(node);
367 if ( (node == parent->left)
368 &&(trbt_get_color(sibling) == TRBT_BLACK)
369 &&(trbt_get_color_left(sibling) == TRBT_RED)
370 &&(trbt_get_color_right(sibling) == TRBT_BLACK) ){
371 trbt_set_color(sibling, TRBT_RED);
372 trbt_set_color_left(sibling, TRBT_BLACK);
373 trbt_rotate_right(sibling);
374 trbt_delete_case6(node);
375 return;
376 }
377 if ( (node == parent->right)
378 &&(trbt_get_color(sibling) == TRBT_BLACK)
379 &&(trbt_get_color_right(sibling) == TRBT_RED)
380 &&(trbt_get_color_left(sibling) == TRBT_BLACK) ){
381 trbt_set_color(sibling, TRBT_RED);
382 trbt_set_color_right(sibling, TRBT_BLACK);
383 trbt_rotate_left(sibling);
384 trbt_delete_case6(node);
385 return;
386 }
387
388 trbt_delete_case6(node);
389}
390
391static inline void
392trbt_delete_case4(trbt_node_t *node)
393{
394 trbt_node_t *sibling;
395
396 sibling = trbt_sibling(node);
397 if ( (trbt_get_color(node->parent) == TRBT_RED)
398 &&(trbt_get_color(sibling) == TRBT_BLACK)
399 &&(trbt_get_color_left(sibling) == TRBT_BLACK)
400 &&(trbt_get_color_right(sibling) == TRBT_BLACK) ){
401 trbt_set_color(sibling, TRBT_RED);
402 trbt_set_color(node->parent, TRBT_BLACK);
403 } else {
404 trbt_delete_case5(node);
405 }
406}
407
408static void trbt_delete_case1(trbt_node_t *node);
409
410static inline void
411trbt_delete_case3(trbt_node_t *node)
412{
413 trbt_node_t *sibling;
414
415 sibling = trbt_sibling(node);
416 if ( (trbt_get_color(node->parent) == TRBT_BLACK)
417 &&(trbt_get_color(sibling) == TRBT_BLACK)
418 &&(trbt_get_color_left(sibling) == TRBT_BLACK)
419 &&(trbt_get_color_right(sibling) == TRBT_BLACK) ){
420 trbt_set_color(sibling, TRBT_RED);
421 trbt_delete_case1(node->parent);
422 } else {
423 trbt_delete_case4(node);
424 }
425}
426
427static inline void
428trbt_delete_case2(trbt_node_t *node)
429{
430 trbt_node_t *sibling;
431
432 sibling = trbt_sibling(node);
433 if (trbt_get_color(sibling) == TRBT_RED) {
434 trbt_set_color(node->parent, TRBT_RED);
435 trbt_set_color(sibling, TRBT_BLACK);
436 if (node == node->parent->left) {
437 trbt_rotate_left(node->parent);
438 } else {
439 trbt_rotate_right(node->parent);
440 }
441 }
442 trbt_delete_case3(node);
443}
444
445static void
446trbt_delete_case1(trbt_node_t *node)
447{
448 if (!node->parent) {
449 return;
450 } else {
451 trbt_delete_case2(node);
452 }
453}
454
455static void
456delete_node(trbt_node_t *node, bool from_destructor)
457{
458 trbt_node_t *parent, *child, dc;
459 trbt_node_t *temp = NULL;
460
461 /* This node has two child nodes, then just copy the content
462 from the next smaller node with this node and delete the
463 predecessor instead.
464 The predecessor is guaranteed to have at most one child
465 node since its right arm must be NULL
466 (It must be NULL since we are its sucessor and we are above
467 it in the tree)
468 */
469 if (node->left != NULL && node->right != NULL) {
470 /* This node has two children, just copy the data */
471 /* find the predecessor */
472 temp = node->left;
473
474 while (temp->right != NULL) {
475 temp = temp->right;
476 }
477
478 /* swap the predecessor data and key with the node to
479 be deleted.
480 */
481 node->key32 = temp->key32;
482 node->data = temp->data;
483 /* now we let node hang off the new data */
484 talloc_steal(node->data, node);
485
486 temp->data = NULL;
487 temp->key32 = -1;
488 /* then delete the temp node.
489 this node is guaranteed to have at least one leaf
490 child */
491 delete_node(temp, from_destructor);
492 goto finished;
493 }
494
495
496 /* There is at most one child to this node to be deleted */
497 child = node->left;
498 if (node->right) {
499 child = node->right;
500 }
501
502 /* If the node to be deleted did not have any child at all we
503 create a temporary dummy node for the child and mark it black.
504 Once the delete of the node is finished, we remove this dummy
505 node, which is simple to do since it is guaranteed that it will
506 still not have any children after the delete operation.
507 This is because we don't represent the leaf-nodes as actual nodes
508 in this implementation.
509 */
510 if (!child) {
511 child = &dc;
512 child->tree = node->tree;
513 child->left=NULL;
514 child->right=NULL;
515 child->rb_color=TRBT_BLACK;
516 child->data=NULL;
517 }
518
519 /* replace node with child */
520 parent = trbt_parent(node);
521 if (parent) {
522 if (parent->left == node) {
523 parent->left = child;
524 } else {
525 parent->right = child;
526 }
527 } else {
528 node->tree->root = child;
529 }
530 child->parent = node->parent;
531
532
533 if (node->rb_color == TRBT_BLACK) {
534 if (trbt_get_color(child) == TRBT_RED) {
535 child->rb_color = TRBT_BLACK;
536 } else {
537 trbt_delete_case1(child);
538 }
539 }
540
541 /* If we had to create a temporary dummy node to represent a black
542 leaf child we now has to delete it.
543 This is simple since this dummy node originally had no children
544 and we are guaranteed that it will also not have any children
545 after the node has been deleted and any possible rotations
546 have occured.
547
548 The only special case is if this was the last node of the tree
549 in which case we have to reset the root to NULL as well.
550 Othervise it is enough to just unlink the child from its new
551 parent.
552 */
553 if (child == &dc) {
554 if (child->parent == NULL) {
555 node->tree->root = NULL;
556 } else if (child == child->parent->left) {
557 child->parent->left = NULL;
558 } else {
559 child->parent->right = NULL;
560 }
561 }
562
563finished:
564 if (!from_destructor) {
565 talloc_free(node);
566 }
567
568 /* if we came from a destructor and temp!=NULL this means we
569 did the node-swap but now the tree still contains the old
570 node which was freed in the destructor. Not good.
571 */
572 if (from_destructor && temp) {
573 temp->key32 = node->key32;
574 temp->rb_color = node->rb_color;
575
576 temp->data = node->data;
577 talloc_steal(temp->data, temp);
578
579 temp->parent = node->parent;
580 if (temp->parent) {
581 if (temp->parent->left == node) {
582 temp->parent->left = temp;
583 } else {
584 temp->parent->right = temp;
585 }
586 }
587
588 temp->left = node->left;
589 if (temp->left) {
590 temp->left->parent = temp;
591 }
592 temp->right = node->right;
593 if (temp->right) {
594 temp->right->parent = temp;
595 }
596
597 if (temp->tree->root == node) {
598 temp->tree->root = temp;
599 }
600 }
601
602 if ( (node->tree->flags & TRBT_AUTOFREE)
603 && (node->tree->root == NULL) ) {
604 talloc_free(node->tree);
605 }
606
607 return;
608}
609
610/*
611 destroy a node and remove it from its tree
612 */
613static int node_destructor(trbt_node_t *node)
614{
615 delete_node(node, true);
616
617 return 0;
618}
619
620static inline trbt_node_t *
621trbt_create_node(trbt_tree_t *tree, trbt_node_t *parent, uint32_t key, void *data)
622{
623 trbt_node_t *node;
624
625 node=talloc_zero(tree, trbt_node_t);
626 NO_MEMORY_FATAL(node);
627
628 node->tree=tree;
629 node->rb_color=TRBT_BLACK;
630 node->parent=parent;
631 node->left=NULL;
632 node->right=NULL;
633 node->key32=key;
634 node->data = data;
635
636 /* let this node hang off data so that it is removed when
637 data is freed
638 */
639 talloc_steal(data, node);
640 talloc_set_destructor(node, node_destructor);
641
642 return node;
643}
644
645/* insert a new node in the tree.
646 if there is already a node with a matching key in the tree
647 we replace it with the new data and return a pointer to the old data
648 in case the caller wants to take any special action
649 */
650void *
651trbt_insert32(trbt_tree_t *tree, uint32_t key, void *data)
652{
653 trbt_node_t *node;
654
655 node=tree->root;
656
657 /* is this the first node ?*/
658 if(!node){
659 node = trbt_create_node(tree, NULL, key, data);
660
661 tree->root=node;
662 return NULL;
663 }
664
665 /* it was not the new root so walk the tree until we find where to
666 * insert this new leaf.
667 */
668 while(1){
669 /* this node already exists, replace data and return the
670 old data
671 */
672 if(key==node->key32){
673 void *old_data;
674
675 old_data = node->data;
676 node->data = data;
677 /* Let the node now be owned by the new data
678 so the node is freed when the enw data is released
679 */
680 talloc_steal(node->data, node);
681
682 return old_data;
683 }
684 if(key<node->key32) {
685 if(!node->left){
686 /* new node to the left */
687 trbt_node_t *new_node;
688
689 new_node = trbt_create_node(tree, node, key, data);
690 node->left=new_node;
691 node=new_node;
692
693 break;
694 }
695 node=node->left;
696 continue;
697 }
698 if(key>node->key32) {
699 if(!node->right){
700 /* new node to the right */
701 trbt_node_t *new_node;
702
703 new_node = trbt_create_node(tree, node, key, data);
704 node->right=new_node;
705 node=new_node;
706 break;
707 }
708 node=node->right;
709 continue;
710 }
711 }
712
713 /* node will now point to the newly created node */
714 node->rb_color=TRBT_RED;
715 trbt_insert_case1(tree, node);
716 return NULL;
717}
718
719void *
720trbt_lookup32(trbt_tree_t *tree, uint32_t key)
721{
722 trbt_node_t *node;
723
724 node=tree->root;
725
726 while(node){
727 if(key==node->key32){
728 return node->data;
729 }
730 if(key<node->key32){
731 node=node->left;
732 continue;
733 }
734 if(key>node->key32){
735 node=node->right;
736 continue;
737 }
738 }
739 return NULL;
740}
741
742
743/* This deletes a node from the tree.
744 Note that this does not release the data that the node points to
745*/
746void
747trbt_delete32(trbt_tree_t *tree, uint32_t key)
748{
749 trbt_node_t *node;
750
751 node=tree->root;
752
753 while(node){
754 if(key==node->key32){
755 delete_node(node, false);
756 return;
757 }
758 if(key<node->key32){
759 node=node->left;
760 continue;
761 }
762 if(key>node->key32){
763 node=node->right;
764 continue;
765 }
766 }
767}
768
769
770void
771trbt_insert32_callback(trbt_tree_t *tree, uint32_t key, void *(*callback)(void *param, void *data), void *param)
772{
773 trbt_node_t *node;
774
775 node=tree->root;
776
777 /* is this the first node ?*/
778 if(!node){
779 node = trbt_create_node(tree, NULL, key,
780 callback(param, NULL));
781
782 tree->root=node;
783 return;
784 }
785
786 /* it was not the new root so walk the tree until we find where to
787 * insert this new leaf.
788 */
789 while(1){
790 /* this node already exists, replace it
791 */
792 if(key==node->key32){
793 node->data = callback(param, node->data);
794 talloc_steal(node->data, node);
795
796 return;
797 }
798 if(key<node->key32) {
799 if(!node->left){
800 /* new node to the left */
801 trbt_node_t *new_node;
802
803 new_node = trbt_create_node(tree, node, key,
804 callback(param, NULL));
805 node->left=new_node;
806 node=new_node;
807
808 break;
809 }
810 node=node->left;
811 continue;
812 }
813 if(key>node->key32) {
814 if(!node->right){
815 /* new node to the right */
816 trbt_node_t *new_node;
817
818 new_node = trbt_create_node(tree, node, key,
819 callback(param, NULL));
820 node->right=new_node;
821 node=new_node;
822 break;
823 }
824 node=node->right;
825 continue;
826 }
827 }
828
829 /* node will now point to the newly created node */
830 node->rb_color=TRBT_RED;
831 trbt_insert_case1(tree, node);
832 return;
833}
834
835
836struct trbt_array_param {
837 void *(*callback)(void *param, void *data);
838 void *param;
839 uint32_t keylen;
840 uint32_t *key;
841 trbt_tree_t *tree;
842};
843static void *array_insert_callback(void *p, void *data)
844{
845 struct trbt_array_param *param = (struct trbt_array_param *)p;
846 trbt_tree_t *tree = NULL;
847
848
849 /* if keylen has reached 0 we are done and can call the users
850 callback function with the users parameters
851 */
852 if (param->keylen == 0) {
853 return param->callback(param->param, data);
854 }
855
856
857 /* keylen is not zero yes so we must create/process more subtrees */
858 /* if data is NULL this means we did not yet have a subtree here
859 and we must create one.
860 */
861 if (data == NULL) {
862 /* create a new subtree and hang it off our current tree
863 set it to autofree so that the tree is freed when
864 the last node in it has been released.
865 */
866 tree = trbt_create(param->tree, TRBT_AUTOFREE);
867 } else {
868 /* we already have a subtree for this path */
869 tree = (trbt_tree_t *)data;
870 }
871
872 trbt_insertarray32_callback(tree, param->keylen, param->key, param->callback, param->param);
873
874 /* now return either the old tree we got in *data or the new tree
875 we created to our caller so he can update his pointer in his
876 tree to point to our subtree
877 */
878 return tree;
879}
880
881
882
883/* insert into the tree using an array of uint32 as a key */
884void
885trbt_insertarray32_callback(trbt_tree_t *tree, uint32_t keylen, uint32_t *key, void *(*cb)(void *param, void *data), void *pm)
886{
887 struct trbt_array_param tap;
888
889 /* keylen-1 and key[1] since the call to insert32 will consume the
890 first part of the key.
891 */
892 tap.callback= cb;
893 tap.param = pm;
894 tap.keylen = keylen-1;
895 tap.key = &key[1];
896 tap.tree = tree;
897
898 trbt_insert32_callback(tree, key[0], array_insert_callback, &tap);
899}
900
901/* lookup the tree using an array of uint32 as a key */
902void *
903trbt_lookuparray32(trbt_tree_t *tree, uint32_t keylen, uint32_t *key)
904{
905 /* if keylen is 1 we can do a regular lookup and return this to the
906 user
907 */
908 if (keylen == 1) {
909 return trbt_lookup32(tree, key[0]);
910 }
911
912 /* we need to lookup the next subtree */
913 tree = trbt_lookup32(tree, key[0]);
914 if (tree == NULL) {
915 /* the key does not exist, return NULL */
916 return NULL;
917 }
918
919 /* now lookup the next part of the key in our new tree */
920 return trbt_lookuparray32(tree, keylen-1, &key[1]);
921}
922
923
924/* traverse a tree starting at node */
925static int
926trbt_traversearray32_node(trbt_node_t *node, uint32_t keylen,
927 int (*callback)(void *param, void *data),
928 void *param)
929{
930 trbt_node_t *left = node->left;
931 trbt_node_t *right = node->right;
932
933 if (left) {
934 int ret;
935 ret = trbt_traversearray32_node(left, keylen, callback, param);
936 if (ret != 0) {
937 return ret;
938 }
939 }
940
941 /* this is the smallest node in this subtree
942 if keylen is 0 this means we can just call the callback
943 otherwise we must pull the next subtree and traverse that one as well
944 */
945 if (keylen == 0) {
946 int ret;
947
948 ret = callback(param, node->data);
949 if (ret != 0) {
950 return ret;
951 }
952 } else {
953 int ret;
954
955 ret = trbt_traversearray32(node->data, keylen, callback, param);
956 if (ret != 0) {
957 return ret;
958 }
959 }
960
961 if (right) {
962 int ret;
963
964 ret = trbt_traversearray32_node(right, keylen, callback, param);
965 if (ret != 0) {
966 return ret;
967 }
968 }
969
970 return 0;
971}
972
973
974/* traverse the tree using an array of uint32 as a key */
975int
976trbt_traversearray32(trbt_tree_t *tree, uint32_t keylen,
977 int (*callback)(void *param, void *data),
978 void *param)
979{
980 trbt_node_t *node;
981
982 if (tree == NULL) {
983 return 0;
984 }
985
986 node=tree->root;
987 if (node == NULL) {
988 return 0;
989 }
990
991 return trbt_traversearray32_node(node, keylen-1, callback, param);
992}
993
994
995/* this function will return the first node in a tree where
996 the key is an array of uint32_t
997*/
998void *
999trbt_findfirstarray32(trbt_tree_t *tree, uint32_t keylen)
1000{
1001 trbt_node_t *node;
1002
1003 if (keylen < 1) {
1004 return NULL;
1005 }
1006
1007 if (tree == NULL) {
1008 return NULL;
1009 }
1010
1011 node=tree->root;
1012 if (node == NULL) {
1013 return NULL;
1014 }
1015
1016 while (node->left) {
1017 node = node->left;
1018 }
1019
1020 /* we found our node so return the data */
1021 if (keylen == 1) {
1022 return node->data;
1023 }
1024
1025 /* we are still traversing subtrees so find the first node in the
1026 next level of trees
1027 */
1028 return trbt_findfirstarray32(node->data, keylen-1);
1029}
1030
1031
1032#if TEST_RB_TREE
1033static void printtree(trbt_node_t *node, int levels)
1034{
1035 int i;
1036 if(node==NULL)return;
1037 printtree(node->left, levels+1);
1038
1039 for(i=0;i<levels;i++)printf(" ");
1040 printf("key:%d COLOR:%s (node:%p parent:%p left:%p right:%p)\n",node->key32,node->rb_color==TRBT_BLACK?"BLACK":"RED", node, node->parent, node->left, node->right);
1041
1042 printtree(node->right, levels+1);
1043 printf("\n");
1044}
1045
1046void print_tree(trbt_tree_t *tree)
1047{
1048 if(tree->root==NULL){
1049 printf("tree is empty\n");
1050 return;
1051 }
1052 printf("---\n");
1053 printtree(tree->root->left, 1);
1054 printf("root node key:%d COLOR:%s (node:%p left:%p right:%p)\n",tree->root->key32,tree->root->rb_color==TRBT_BLACK?"BLACK":"RED", tree->root, tree->root->left, tree->root->right);
1055 printtree(tree->root->right, 1);
1056 printf("===\n");
1057}
1058
1059void
1060test_tree(void)
1061{
1062 trbt_tree_t *tree;
1063 char *str;
1064 int i, ret;
1065 int NUM=15;
1066 int cnt=0;
1067
1068 tree=trbt_create(talloc_new(NULL), 0);
1069#if 0
1070 for(i=0;i<10;i++){
1071 printf("adding node %i\n",i);
1072 trbt_insert32(tree, i, NULL);
1073 print_tree(tree);
1074 }
1075 printf("deleting node %i\n",3);
1076 trbt_delete32(tree, 3);
1077 print_tree(tree);
1078 for(i=0;i<10;i++){
1079 printf("deleting node %i\n",i);
1080 trbt_delete32(tree, i);
1081 print_tree(tree);
1082 }
1083exit(0);
1084#endif
1085 while(++cnt){
1086 int i;
1087 printf("iteration : %d\n",cnt);
1088 i=random()%20;
1089 printf("adding node %i\n",i);
1090 trbt_insert32(tree, i, NULL);
1091 print_tree(tree);
1092
1093 i=random()%20;
1094 printf("deleting node %i\n",i);
1095 trbt_delete32(tree, i);
1096 print_tree(tree);
1097 }
1098
1099}
1100
1101#endif
Note: See TracBrowser for help on using the repository browser.