]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/util/rbtree.c
Fix multiple vulnerabilities in unbound.
[FreeBSD/FreeBSD.git] / contrib / unbound / util / rbtree.c
1 /*
2  * rbtree.c -- generic red black tree
3  *
4  * Copyright (c) 2001-2007, NLnet Labs. All rights reserved.
5  * 
6  * This software is open source.
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  * 
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  * 
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  */
36
37 /**
38  * \file
39  * Implementation of a redblack tree.
40  */
41
42 #include "config.h"
43 #include "log.h"
44 #include "fptr_wlist.h"
45 #include "util/rbtree.h"
46
47 /** Node colour black */
48 #define BLACK   0
49 /** Node colour red */
50 #define RED     1
51
52 /** the NULL node, global alloc */
53 rbnode_type     rbtree_null_node = {
54         RBTREE_NULL,            /* Parent.  */
55         RBTREE_NULL,            /* Left.  */
56         RBTREE_NULL,            /* Right.  */
57         NULL,                   /* Key.  */
58         BLACK                   /* Color.  */
59 };
60
61 /** rotate subtree left (to preserve redblack property) */
62 static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node);
63 /** rotate subtree right (to preserve redblack property) */
64 static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node);
65 /** Fixup node colours when insert happened */
66 static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node);
67 /** Fixup node colours when delete happened */
68 static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child,
69         rbnode_type* child_parent);
70
71 /*
72  * Creates a new red black tree, initializes and returns a pointer to it.
73  *
74  * Return NULL on failure.
75  *
76  */
77 rbtree_type *
78 rbtree_create (int (*cmpf)(const void *, const void *))
79 {
80         rbtree_type *rbtree;
81
82         /* Allocate memory for it */
83         rbtree = (rbtree_type *) malloc(sizeof(rbtree_type));
84         if (!rbtree) {
85                 return NULL;
86         }
87
88         /* Initialize it */
89         rbtree_init(rbtree, cmpf);
90
91         return rbtree;
92 }
93
94 void 
95 rbtree_init(rbtree_type *rbtree, int (*cmpf)(const void *, const void *))
96 {
97         /* Initialize it */
98         rbtree->root = RBTREE_NULL;
99         rbtree->count = 0;
100         rbtree->cmp = cmpf;
101 }
102
103 /*
104  * Rotates the node to the left.
105  *
106  */
107 static void
108 rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node)
109 {
110         rbnode_type *right = node->right;
111         node->right = right->left;
112         if (right->left != RBTREE_NULL)
113                 right->left->parent = node;
114
115         right->parent = node->parent;
116
117         if (node->parent != RBTREE_NULL) {
118                 if (node == node->parent->left) {
119                         node->parent->left = right;
120                 } else  {
121                         node->parent->right = right;
122                 }
123         } else {
124                 rbtree->root = right;
125         }
126         right->left = node;
127         node->parent = right;
128 }
129
130 /*
131  * Rotates the node to the right.
132  *
133  */
134 static void
135 rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node)
136 {
137         rbnode_type *left = node->left;
138         node->left = left->right;
139         if (left->right != RBTREE_NULL)
140                 left->right->parent = node;
141
142         left->parent = node->parent;
143
144         if (node->parent != RBTREE_NULL) {
145                 if (node == node->parent->right) {
146                         node->parent->right = left;
147                 } else  {
148                         node->parent->left = left;
149                 }
150         } else {
151                 rbtree->root = left;
152         }
153         left->right = node;
154         node->parent = left;
155 }
156
157 static void
158 rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node)
159 {
160         rbnode_type     *uncle;
161
162         /* While not at the root and need fixing... */
163         while (node != rbtree->root && node->parent->color == RED) {
164                 /* If our parent is left child of our grandparent... */
165                 if (node->parent == node->parent->parent->left) {
166                         uncle = node->parent->parent->right;
167
168                         /* If our uncle is red... */
169                         if (uncle->color == RED) {
170                                 /* Paint the parent and the uncle black... */
171                                 node->parent->color = BLACK;
172                                 uncle->color = BLACK;
173
174                                 /* And the grandparent red... */
175                                 node->parent->parent->color = RED;
176
177                                 /* And continue fixing the grandparent */
178                                 node = node->parent->parent;
179                         } else {                                /* Our uncle is black... */
180                                 /* Are we the right child? */
181                                 if (node == node->parent->right) {
182                                         node = node->parent;
183                                         rbtree_rotate_left(rbtree, node);
184                                 }
185                                 /* Now we're the left child, repaint and rotate... */
186                                 node->parent->color = BLACK;
187                                 node->parent->parent->color = RED;
188                                 rbtree_rotate_right(rbtree, node->parent->parent);
189                         }
190                 } else {
191                         uncle = node->parent->parent->left;
192
193                         /* If our uncle is red... */
194                         if (uncle->color == RED) {
195                                 /* Paint the parent and the uncle black... */
196                                 node->parent->color = BLACK;
197                                 uncle->color = BLACK;
198
199                                 /* And the grandparent red... */
200                                 node->parent->parent->color = RED;
201
202                                 /* And continue fixing the grandparent */
203                                 node = node->parent->parent;
204                         } else {                                /* Our uncle is black... */
205                                 /* Are we the right child? */
206                                 if (node == node->parent->left) {
207                                         node = node->parent;
208                                         rbtree_rotate_right(rbtree, node);
209                                 }
210                                 /* Now we're the right child, repaint and rotate... */
211                                 node->parent->color = BLACK;
212                                 node->parent->parent->color = RED;
213                                 rbtree_rotate_left(rbtree, node->parent->parent);
214                         }
215                 }
216         }
217         rbtree->root->color = BLACK;
218 }
219
220
221 /*
222  * Inserts a node into a red black tree.
223  *
224  * Returns NULL on failure or the pointer to the newly added node
225  * otherwise.
226  */
227 rbnode_type *
228 rbtree_insert (rbtree_type *rbtree, rbnode_type *data)
229 {
230         /* XXX Not necessary, but keeps compiler quiet... */
231         int r = 0;
232
233         /* We start at the root of the tree */
234         rbnode_type     *node = rbtree->root;
235         rbnode_type     *parent = RBTREE_NULL;
236
237         fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
238         /* Lets find the new parent... */
239         while (node != RBTREE_NULL) {
240                 /* Compare two keys, do we have a duplicate? */
241                 if ((r = rbtree->cmp(data->key, node->key)) == 0) {
242                         return NULL;
243                 }
244                 parent = node;
245
246                 if (r < 0) {
247                         node = node->left;
248                 } else {
249                         node = node->right;
250                 }
251         }
252
253         /* Initialize the new node */
254         data->parent = parent;
255         data->left = data->right = RBTREE_NULL;
256         data->color = RED;
257         rbtree->count++;
258
259         /* Insert it into the tree... */
260         if (parent != RBTREE_NULL) {
261                 if (r < 0) {
262                         parent->left = data;
263                 } else {
264                         parent->right = data;
265                 }
266         } else {
267                 rbtree->root = data;
268         }
269
270         /* Fix up the red-black properties... */
271         rbtree_insert_fixup(rbtree, data);
272
273         return data;
274 }
275
276 /*
277  * Searches the red black tree, returns the data if key is found or NULL otherwise.
278  *
279  */
280 rbnode_type *
281 rbtree_search (rbtree_type *rbtree, const void *key)
282 {
283         rbnode_type *node;
284
285         if (rbtree_find_less_equal(rbtree, key, &node)) {
286                 return node;
287         } else {
288                 return NULL;
289         }
290 }
291
292 /** helpers for delete: swap node colours */
293 static void swap_int8(uint8_t* x, uint8_t* y) 
294
295         uint8_t t = *x; *x = *y; *y = t; 
296 }
297
298 /** helpers for delete: swap node pointers */
299 static void swap_np(rbnode_type** x, rbnode_type** y) 
300 {
301         rbnode_type* t = *x; *x = *y; *y = t; 
302 }
303
304 /** Update parent pointers of child trees of 'parent' */
305 static void change_parent_ptr(rbtree_type* rbtree, rbnode_type* parent,
306         rbnode_type* old, rbnode_type* new)
307 {
308         if(parent == RBTREE_NULL)
309         {
310                 log_assert(rbtree->root == old);
311                 if(rbtree->root == old) rbtree->root = new;
312                 return;
313         }
314         log_assert(parent->left == old || parent->right == old
315                 || parent->left == new || parent->right == new);
316         if(parent->left == old) parent->left = new;
317         if(parent->right == old) parent->right = new;
318 }
319 /** Update parent pointer of a node 'child' */
320 static void change_child_ptr(rbnode_type* child, rbnode_type* old,
321         rbnode_type* new)
322 {
323         if(child == RBTREE_NULL) return;
324         log_assert(child->parent == old || child->parent == new);
325         if(child->parent == old) child->parent = new;
326 }
327
328 rbnode_type* 
329 rbtree_delete(rbtree_type *rbtree, const void *key)
330 {
331         rbnode_type *to_delete;
332         rbnode_type *child;
333         if((to_delete = rbtree_search(rbtree, key)) == 0) return 0;
334         rbtree->count--;
335
336         /* make sure we have at most one non-leaf child */
337         if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL)
338         {
339                 /* swap with smallest from right subtree (or largest from left) */
340                 rbnode_type *smright = to_delete->right;
341                 while(smright->left != RBTREE_NULL)
342                         smright = smright->left;
343                 /* swap the smright and to_delete elements in the tree,
344                  * but the rbnode_type is first part of user data struct
345                  * so cannot just swap the keys and data pointers. Instead
346                  * readjust the pointers left,right,parent */
347
348                 /* swap colors - colors are tied to the position in the tree */
349                 swap_int8(&to_delete->color, &smright->color);
350
351                 /* swap child pointers in parents of smright/to_delete */
352                 change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
353                 if(to_delete->right != smright)
354                         change_parent_ptr(rbtree, smright->parent, smright, to_delete);
355
356                 /* swap parent pointers in children of smright/to_delete */
357                 change_child_ptr(smright->left, smright, to_delete);
358                 change_child_ptr(smright->left, smright, to_delete);
359                 change_child_ptr(smright->right, smright, to_delete);
360                 change_child_ptr(smright->right, smright, to_delete);
361                 change_child_ptr(to_delete->left, to_delete, smright);
362                 if(to_delete->right != smright)
363                         change_child_ptr(to_delete->right, to_delete, smright);
364                 if(to_delete->right == smright)
365                 {
366                         /* set up so after swap they work */
367                         to_delete->right = to_delete;
368                         smright->parent = smright;
369                 }
370
371                 /* swap pointers in to_delete/smright nodes */
372                 swap_np(&to_delete->parent, &smright->parent);
373                 swap_np(&to_delete->left, &smright->left);
374                 swap_np(&to_delete->right, &smright->right);
375
376                 /* now delete to_delete (which is at the location where the smright previously was) */
377         }
378         log_assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
379
380         if(to_delete->left != RBTREE_NULL) child = to_delete->left;
381         else child = to_delete->right;
382
383         /* unlink to_delete from the tree, replace to_delete with child */
384         change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
385         change_child_ptr(child, to_delete, to_delete->parent);
386
387         if(to_delete->color == RED)
388         {
389                 /* if node is red then the child (black) can be swapped in */
390         }
391         else if(child->color == RED)
392         {
393                 /* change child to BLACK, removing a RED node is no problem */
394                 if(child!=RBTREE_NULL) child->color = BLACK;
395         }
396         else rbtree_delete_fixup(rbtree, child, to_delete->parent);
397
398         /* unlink completely */
399         to_delete->parent = RBTREE_NULL;
400         to_delete->left = RBTREE_NULL;
401         to_delete->right = RBTREE_NULL;
402         to_delete->color = BLACK;
403         return to_delete;
404 }
405
406 static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child,
407         rbnode_type* child_parent)
408 {
409         rbnode_type* sibling;
410         int go_up = 1;
411
412         /* determine sibling to the node that is one-black short */
413         if(child_parent->right == child) sibling = child_parent->left;
414         else sibling = child_parent->right;
415
416         while(go_up)
417         {
418                 if(child_parent == RBTREE_NULL)
419                 {
420                         /* removed parent==black from root, every path, so ok */
421                         return;
422                 }
423
424                 if(sibling->color == RED)
425                 {       /* rotate to get a black sibling */
426                         child_parent->color = RED;
427                         sibling->color = BLACK;
428                         if(child_parent->right == child)
429                                 rbtree_rotate_right(rbtree, child_parent);
430                         else    rbtree_rotate_left(rbtree, child_parent);
431                         /* new sibling after rotation */
432                         if(child_parent->right == child) sibling = child_parent->left;
433                         else sibling = child_parent->right;
434                 }
435
436                 if(child_parent->color == BLACK 
437                         && sibling->color == BLACK
438                         && sibling->left->color == BLACK
439                         && sibling->right->color == BLACK)
440                 {       /* fixup local with recolor of sibling */
441                         if(sibling != RBTREE_NULL)
442                                 sibling->color = RED;
443
444                         child = child_parent;
445                         child_parent = child_parent->parent;
446                         /* prepare to go up, new sibling */
447                         if(child_parent->right == child) sibling = child_parent->left;
448                         else sibling = child_parent->right;
449                 }
450                 else go_up = 0;
451         }
452
453         if(child_parent->color == RED
454                 && sibling->color == BLACK
455                 && sibling->left->color == BLACK
456                 && sibling->right->color == BLACK) 
457         {
458                 /* move red to sibling to rebalance */
459                 if(sibling != RBTREE_NULL)
460                         sibling->color = RED;
461                 child_parent->color = BLACK;
462                 return;
463         }
464         log_assert(sibling != RBTREE_NULL);
465
466         /* get a new sibling, by rotating at sibling. See which child
467            of sibling is red */
468         if(child_parent->right == child
469                 && sibling->color == BLACK
470                 && sibling->right->color == RED
471                 && sibling->left->color == BLACK)
472         {
473                 sibling->color = RED;
474                 sibling->right->color = BLACK;
475                 rbtree_rotate_left(rbtree, sibling);
476                 /* new sibling after rotation */
477                 if(child_parent->right == child) sibling = child_parent->left;
478                 else sibling = child_parent->right;
479         }
480         else if(child_parent->left == child
481                 && sibling->color == BLACK
482                 && sibling->left->color == RED
483                 && sibling->right->color == BLACK)
484         {
485                 sibling->color = RED;
486                 sibling->left->color = BLACK;
487                 rbtree_rotate_right(rbtree, sibling);
488                 /* new sibling after rotation */
489                 if(child_parent->right == child) sibling = child_parent->left;
490                 else sibling = child_parent->right;
491         }
492
493         /* now we have a black sibling with a red child. rotate and exchange colors. */
494         sibling->color = child_parent->color;
495         child_parent->color = BLACK;
496         if(child_parent->right == child)
497         {
498                 log_assert(sibling->left->color == RED);
499                 sibling->left->color = BLACK;
500                 rbtree_rotate_right(rbtree, child_parent);
501         }
502         else
503         {
504                 log_assert(sibling->right->color == RED);
505                 sibling->right->color = BLACK;
506                 rbtree_rotate_left(rbtree, child_parent);
507         }
508 }
509
510 int
511 rbtree_find_less_equal(rbtree_type *rbtree, const void *key,
512         rbnode_type **result)
513 {
514         int r;
515         rbnode_type *node;
516
517         log_assert(result);
518         
519         /* We start at root... */
520         node = rbtree->root;
521
522         *result = NULL;
523         fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
524
525         /* While there are children... */
526         while (node != RBTREE_NULL) {
527                 r = rbtree->cmp(key, node->key);
528                 if (r == 0) {
529                         /* Exact match */
530                         *result = node;
531                         return 1;
532                 } 
533                 if (r < 0) {
534                         node = node->left;
535                 } else {
536                         /* Temporary match */
537                         *result = node;
538                         node = node->right;
539                 }
540         }
541         return 0;
542 }
543
544 /*
545  * Finds the first element in the red black tree
546  *
547  */
548 rbnode_type *
549 rbtree_first (rbtree_type *rbtree)
550 {
551         rbnode_type *node;
552
553         for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left);
554         return node;
555 }
556
557 rbnode_type *
558 rbtree_last (rbtree_type *rbtree)
559 {
560         rbnode_type *node;
561
562         for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right);
563         return node;
564 }
565
566 /*
567  * Returns the next node...
568  *
569  */
570 rbnode_type *
571 rbtree_next (rbnode_type *node)
572 {
573         rbnode_type *parent;
574
575         if (node->right != RBTREE_NULL) {
576                 /* One right, then keep on going left... */
577                 for (node = node->right; node->left != RBTREE_NULL; node = node->left);
578         } else {
579                 parent = node->parent;
580                 while (parent != RBTREE_NULL && node == parent->right) {
581                         node = parent;
582                         parent = parent->parent;
583                 }
584                 node = parent;
585         }
586         return node;
587 }
588
589 rbnode_type *
590 rbtree_previous(rbnode_type *node)
591 {
592         rbnode_type *parent;
593
594         if (node->left != RBTREE_NULL) {
595                 /* One left, then keep on going right... */
596                 for (node = node->left; node->right != RBTREE_NULL; node = node->right);
597         } else {
598                 parent = node->parent;
599                 while (parent != RBTREE_NULL && node == parent->left) {
600                         node = parent;
601                         parent = parent->parent;
602                 }
603                 node = parent;
604         }
605         return node;
606 }
607
608 /** recursive descent traverse */
609 static void 
610 traverse_post(void (*func)(rbnode_type*, void*), void* arg, rbnode_type* node)
611 {
612         if(!node || node == RBTREE_NULL)
613                 return;
614         /* recurse */
615         traverse_post(func, arg, node->left);
616         traverse_post(func, arg, node->right);
617         /* call user func */
618         (*func)(node, arg);
619 }
620
621 void 
622 traverse_postorder(rbtree_type* tree, void (*func)(rbnode_type*, void*),
623         void* arg)
624 {
625         traverse_post(func, arg, tree->root);
626 }