xref: /openbsd/usr.sbin/unbound/util/rbtree.c (revision 5af055cd)
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, initializes 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 }
621