]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/unbound/util/rbtree.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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_t        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_t *rbtree, rbnode_t *node);
63 /** rotate subtree right (to preserve redblack property) */
64 static void rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node);
65 /** Fixup node colours when insert happened */
66 static void rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node);
67 /** Fixup node colours when delete happened */
68 static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent);
69
70 /*
71  * Creates a new red black tree, intializes and returns a pointer to it.
72  *
73  * Return NULL on failure.
74  *
75  */
76 rbtree_t *
77 rbtree_create (int (*cmpf)(const void *, const void *))
78 {
79         rbtree_t *rbtree;
80
81         /* Allocate memory for it */
82         rbtree = (rbtree_t *) malloc(sizeof(rbtree_t));
83         if (!rbtree) {
84                 return NULL;
85         }
86
87         /* Initialize it */
88         rbtree_init(rbtree, cmpf);
89
90         return rbtree;
91 }
92
93 void 
94 rbtree_init(rbtree_t *rbtree, int (*cmpf)(const void *, const void *))
95 {
96         /* Initialize it */
97         rbtree->root = RBTREE_NULL;
98         rbtree->count = 0;
99         rbtree->cmp = cmpf;
100 }
101
102 /*
103  * Rotates the node to the left.
104  *
105  */
106 static void
107 rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node)
108 {
109         rbnode_t *right = node->right;
110         node->right = right->left;
111         if (right->left != RBTREE_NULL)
112                 right->left->parent = node;
113
114         right->parent = node->parent;
115
116         if (node->parent != RBTREE_NULL) {
117                 if (node == node->parent->left) {
118                         node->parent->left = right;
119                 } else  {
120                         node->parent->right = right;
121                 }
122         } else {
123                 rbtree->root = right;
124         }
125         right->left = node;
126         node->parent = right;
127 }
128
129 /*
130  * Rotates the node to the right.
131  *
132  */
133 static void
134 rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node)
135 {
136         rbnode_t *left = node->left;
137         node->left = left->right;
138         if (left->right != RBTREE_NULL)
139                 left->right->parent = node;
140
141         left->parent = node->parent;
142
143         if (node->parent != RBTREE_NULL) {
144                 if (node == node->parent->right) {
145                         node->parent->right = left;
146                 } else  {
147                         node->parent->left = left;
148                 }
149         } else {
150                 rbtree->root = left;
151         }
152         left->right = node;
153         node->parent = left;
154 }
155
156 static void
157 rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node)
158 {
159         rbnode_t        *uncle;
160
161         /* While not at the root and need fixing... */
162         while (node != rbtree->root && node->parent->color == RED) {
163                 /* If our parent is left child of our grandparent... */
164                 if (node->parent == node->parent->parent->left) {
165                         uncle = node->parent->parent->right;
166
167                         /* If our uncle is red... */
168                         if (uncle->color == RED) {
169                                 /* Paint the parent and the uncle black... */
170                                 node->parent->color = BLACK;
171                                 uncle->color = BLACK;
172
173                                 /* And the grandparent red... */
174                                 node->parent->parent->color = RED;
175
176                                 /* And continue fixing the grandparent */
177                                 node = node->parent->parent;
178                         } else {                                /* Our uncle is black... */
179                                 /* Are we the right child? */
180                                 if (node == node->parent->right) {
181                                         node = node->parent;
182                                         rbtree_rotate_left(rbtree, node);
183                                 }
184                                 /* Now we're the left child, repaint and rotate... */
185                                 node->parent->color = BLACK;
186                                 node->parent->parent->color = RED;
187                                 rbtree_rotate_right(rbtree, node->parent->parent);
188                         }
189                 } else {
190                         uncle = node->parent->parent->left;
191
192                         /* If our uncle is red... */
193                         if (uncle->color == RED) {
194                                 /* Paint the parent and the uncle black... */
195                                 node->parent->color = BLACK;
196                                 uncle->color = BLACK;
197
198                                 /* And the grandparent red... */
199                                 node->parent->parent->color = RED;
200
201                                 /* And continue fixing the grandparent */
202                                 node = node->parent->parent;
203                         } else {                                /* Our uncle is black... */
204                                 /* Are we the right child? */
205                                 if (node == node->parent->left) {
206                                         node = node->parent;
207                                         rbtree_rotate_right(rbtree, node);
208                                 }
209                                 /* Now we're the right child, repaint and rotate... */
210                                 node->parent->color = BLACK;
211                                 node->parent->parent->color = RED;
212                                 rbtree_rotate_left(rbtree, node->parent->parent);
213                         }
214                 }
215         }
216         rbtree->root->color = BLACK;
217 }
218
219
220 /*
221  * Inserts a node into a red black tree.
222  *
223  * Returns NULL on failure or the pointer to the newly added node
224  * otherwise.
225  */
226 rbnode_t *
227 rbtree_insert (rbtree_t *rbtree, rbnode_t *data)
228 {
229         /* XXX Not necessary, but keeps compiler quiet... */
230         int r = 0;
231
232         /* We start at the root of the tree */
233         rbnode_t        *node = rbtree->root;
234         rbnode_t        *parent = RBTREE_NULL;
235
236         fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
237         /* Lets find the new parent... */
238         while (node != RBTREE_NULL) {
239                 /* Compare two keys, do we have a duplicate? */
240                 if ((r = rbtree->cmp(data->key, node->key)) == 0) {
241                         return NULL;
242                 }
243                 parent = node;
244
245                 if (r < 0) {
246                         node = node->left;
247                 } else {
248                         node = node->right;
249                 }
250         }
251
252         /* Initialize the new node */
253         data->parent = parent;
254         data->left = data->right = RBTREE_NULL;
255         data->color = RED;
256         rbtree->count++;
257
258         /* Insert it into the tree... */
259         if (parent != RBTREE_NULL) {
260                 if (r < 0) {
261                         parent->left = data;
262                 } else {
263                         parent->right = data;
264                 }
265         } else {
266                 rbtree->root = data;
267         }
268
269         /* Fix up the red-black properties... */
270         rbtree_insert_fixup(rbtree, data);
271
272         return data;
273 }
274
275 /*
276  * Searches the red black tree, returns the data if key is found or NULL otherwise.
277  *
278  */
279 rbnode_t *
280 rbtree_search (rbtree_t *rbtree, const void *key)
281 {
282         rbnode_t *node;
283
284         if (rbtree_find_less_equal(rbtree, key, &node)) {
285                 return node;
286         } else {
287                 return NULL;
288         }
289 }
290
291 /** helpers for delete: swap node colours */
292 static void swap_int8(uint8_t* x, uint8_t* y) 
293
294         uint8_t t = *x; *x = *y; *y = t; 
295 }
296
297 /** helpers for delete: swap node pointers */
298 static void swap_np(rbnode_t** x, rbnode_t** y) 
299 {
300         rbnode_t* t = *x; *x = *y; *y = t; 
301 }
302
303 /** Update parent pointers of child trees of 'parent' */
304 static void change_parent_ptr(rbtree_t* rbtree, rbnode_t* parent, rbnode_t* old, rbnode_t* new)
305 {
306         if(parent == RBTREE_NULL)
307         {
308                 log_assert(rbtree->root == old);
309                 if(rbtree->root == old) rbtree->root = new;
310                 return;
311         }
312         log_assert(parent->left == old || parent->right == old
313                 || parent->left == new || parent->right == new);
314         if(parent->left == old) parent->left = new;
315         if(parent->right == old) parent->right = new;
316 }
317 /** Update parent pointer of a node 'child' */
318 static void change_child_ptr(rbnode_t* child, rbnode_t* old, rbnode_t* new)
319 {
320         if(child == RBTREE_NULL) return;
321         log_assert(child->parent == old || child->parent == new);
322         if(child->parent == old) child->parent = new;
323 }
324
325 rbnode_t* 
326 rbtree_delete(rbtree_t *rbtree, const void *key)
327 {
328         rbnode_t *to_delete;
329         rbnode_t *child;
330         if((to_delete = rbtree_search(rbtree, key)) == 0) return 0;
331         rbtree->count--;
332
333         /* make sure we have at most one non-leaf child */
334         if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL)
335         {
336                 /* swap with smallest from right subtree (or largest from left) */
337                 rbnode_t *smright = to_delete->right;
338                 while(smright->left != RBTREE_NULL)
339                         smright = smright->left;
340                 /* swap the smright and to_delete elements in the tree,
341                  * but the rbnode_t is first part of user data struct
342                  * so cannot just swap the keys and data pointers. Instead
343                  * readjust the pointers left,right,parent */
344
345                 /* swap colors - colors are tied to the position in the tree */
346                 swap_int8(&to_delete->color, &smright->color);
347
348                 /* swap child pointers in parents of smright/to_delete */
349                 change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
350                 if(to_delete->right != smright)
351                         change_parent_ptr(rbtree, smright->parent, smright, to_delete);
352
353                 /* swap parent pointers in children of smright/to_delete */
354                 change_child_ptr(smright->left, smright, to_delete);
355                 change_child_ptr(smright->left, smright, to_delete);
356                 change_child_ptr(smright->right, smright, to_delete);
357                 change_child_ptr(smright->right, smright, to_delete);
358                 change_child_ptr(to_delete->left, to_delete, smright);
359                 if(to_delete->right != smright)
360                         change_child_ptr(to_delete->right, to_delete, smright);
361                 if(to_delete->right == smright)
362                 {
363                         /* set up so after swap they work */
364                         to_delete->right = to_delete;
365                         smright->parent = smright;
366                 }
367
368                 /* swap pointers in to_delete/smright nodes */
369                 swap_np(&to_delete->parent, &smright->parent);
370                 swap_np(&to_delete->left, &smright->left);
371                 swap_np(&to_delete->right, &smright->right);
372
373                 /* now delete to_delete (which is at the location where the smright previously was) */
374         }
375         log_assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
376
377         if(to_delete->left != RBTREE_NULL) child = to_delete->left;
378         else child = to_delete->right;
379
380         /* unlink to_delete from the tree, replace to_delete with child */
381         change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
382         change_child_ptr(child, to_delete, to_delete->parent);
383
384         if(to_delete->color == RED)
385         {
386                 /* if node is red then the child (black) can be swapped in */
387         }
388         else if(child->color == RED)
389         {
390                 /* change child to BLACK, removing a RED node is no problem */
391                 if(child!=RBTREE_NULL) child->color = BLACK;
392         }
393         else rbtree_delete_fixup(rbtree, child, to_delete->parent);
394
395         /* unlink completely */
396         to_delete->parent = RBTREE_NULL;
397         to_delete->left = RBTREE_NULL;
398         to_delete->right = RBTREE_NULL;
399         to_delete->color = BLACK;
400         return to_delete;
401 }
402
403 static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent)
404 {
405         rbnode_t* sibling;
406         int go_up = 1;
407
408         /* determine sibling to the node that is one-black short */
409         if(child_parent->right == child) sibling = child_parent->left;
410         else sibling = child_parent->right;
411
412         while(go_up)
413         {
414                 if(child_parent == RBTREE_NULL)
415                 {
416                         /* removed parent==black from root, every path, so ok */
417                         return;
418                 }
419
420                 if(sibling->color == RED)
421                 {       /* rotate to get a black sibling */
422                         child_parent->color = RED;
423                         sibling->color = BLACK;
424                         if(child_parent->right == child)
425                                 rbtree_rotate_right(rbtree, child_parent);
426                         else    rbtree_rotate_left(rbtree, child_parent);
427                         /* new sibling after rotation */
428                         if(child_parent->right == child) sibling = child_parent->left;
429                         else sibling = child_parent->right;
430                 }
431
432                 if(child_parent->color == BLACK 
433                         && sibling->color == BLACK
434                         && sibling->left->color == BLACK
435                         && sibling->right->color == BLACK)
436                 {       /* fixup local with recolor of sibling */
437                         if(sibling != RBTREE_NULL)
438                                 sibling->color = RED;
439
440                         child = child_parent;
441                         child_parent = child_parent->parent;
442                         /* prepare to go up, new sibling */
443                         if(child_parent->right == child) sibling = child_parent->left;
444                         else sibling = child_parent->right;
445                 }
446                 else go_up = 0;
447         }
448
449         if(child_parent->color == RED
450                 && sibling->color == BLACK
451                 && sibling->left->color == BLACK
452                 && sibling->right->color == BLACK) 
453         {
454                 /* move red to sibling to rebalance */
455                 if(sibling != RBTREE_NULL)
456                         sibling->color = RED;
457                 child_parent->color = BLACK;
458                 return;
459         }
460         log_assert(sibling != RBTREE_NULL);
461
462         /* get a new sibling, by rotating at sibling. See which child
463            of sibling is red */
464         if(child_parent->right == child
465                 && sibling->color == BLACK
466                 && sibling->right->color == RED
467                 && sibling->left->color == BLACK)
468         {
469                 sibling->color = RED;
470                 sibling->right->color = BLACK;
471                 rbtree_rotate_left(rbtree, sibling);
472                 /* new sibling after rotation */
473                 if(child_parent->right == child) sibling = child_parent->left;
474                 else sibling = child_parent->right;
475         }
476         else if(child_parent->left == child
477                 && sibling->color == BLACK
478                 && sibling->left->color == RED
479                 && sibling->right->color == BLACK)
480         {
481                 sibling->color = RED;
482                 sibling->left->color = BLACK;
483                 rbtree_rotate_right(rbtree, sibling);
484                 /* new sibling after rotation */
485                 if(child_parent->right == child) sibling = child_parent->left;
486                 else sibling = child_parent->right;
487         }
488
489         /* now we have a black sibling with a red child. rotate and exchange colors. */
490         sibling->color = child_parent->color;
491         child_parent->color = BLACK;
492         if(child_parent->right == child)
493         {
494                 log_assert(sibling->left->color == RED);
495                 sibling->left->color = BLACK;
496                 rbtree_rotate_right(rbtree, child_parent);
497         }
498         else
499         {
500                 log_assert(sibling->right->color == RED);
501                 sibling->right->color = BLACK;
502                 rbtree_rotate_left(rbtree, child_parent);
503         }
504 }
505
506 int
507 rbtree_find_less_equal(rbtree_t *rbtree, const void *key, rbnode_t **result)
508 {
509         int r;
510         rbnode_t *node;
511
512         log_assert(result);
513         
514         /* We start at root... */
515         node = rbtree->root;
516
517         *result = NULL;
518         fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
519
520         /* While there are children... */
521         while (node != RBTREE_NULL) {
522                 r = rbtree->cmp(key, node->key);
523                 if (r == 0) {
524                         /* Exact match */
525                         *result = node;
526                         return 1;
527                 } 
528                 if (r < 0) {
529                         node = node->left;
530                 } else {
531                         /* Temporary match */
532                         *result = node;
533                         node = node->right;
534                 }
535         }
536         return 0;
537 }
538
539 /*
540  * Finds the first element in the red black tree
541  *
542  */
543 rbnode_t *
544 rbtree_first (rbtree_t *rbtree)
545 {
546         rbnode_t *node;
547
548         for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left);
549         return node;
550 }
551
552 rbnode_t *
553 rbtree_last (rbtree_t *rbtree)
554 {
555         rbnode_t *node;
556
557         for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right);
558         return node;
559 }
560
561 /*
562  * Returns the next node...
563  *
564  */
565 rbnode_t *
566 rbtree_next (rbnode_t *node)
567 {
568         rbnode_t *parent;
569
570         if (node->right != RBTREE_NULL) {
571                 /* One right, then keep on going left... */
572                 for (node = node->right; node->left != RBTREE_NULL; node = node->left);
573         } else {
574                 parent = node->parent;
575                 while (parent != RBTREE_NULL && node == parent->right) {
576                         node = parent;
577                         parent = parent->parent;
578                 }
579                 node = parent;
580         }
581         return node;
582 }
583
584 rbnode_t *
585 rbtree_previous(rbnode_t *node)
586 {
587         rbnode_t *parent;
588
589         if (node->left != RBTREE_NULL) {
590                 /* One left, then keep on going right... */
591                 for (node = node->left; node->right != RBTREE_NULL; node = node->right);
592         } else {
593                 parent = node->parent;
594                 while (parent != RBTREE_NULL && node == parent->left) {
595                         node = parent;
596                         parent = parent->parent;
597                 }
598                 node = parent;
599         }
600         return node;
601 }
602
603 /** recursive descent traverse */
604 static void 
605 traverse_post(void (*func)(rbnode_t*, void*), void* arg, rbnode_t* node)
606 {
607         if(!node || node == RBTREE_NULL)
608                 return;
609         /* recurse */
610         traverse_post(func, arg, node->left);
611         traverse_post(func, arg, node->right);
612         /* call user func */
613         (*func)(node, arg);
614 }
615
616 void 
617 traverse_postorder(rbtree_t* tree, void (*func)(rbnode_t*, void*), void* arg)
618 {
619         traverse_post(func, arg, tree->root);
620 }