xref: /freebsd/contrib/unbound/util/rbtree.c (revision 0dbdecfd4f23486da21345fe446a28a1c27db3f2)
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 }
627