xref: /openbsd-src/usr.sbin/unbound/util/rbtree.c (revision 77079be7e74cd516ce5a60021c2a03ba383e594d)
1933707f3Ssthen /*
2933707f3Ssthen  * rbtree.c -- generic red black tree
3933707f3Ssthen  *
4933707f3Ssthen  * Copyright (c) 2001-2007, NLnet Labs. All rights reserved.
5933707f3Ssthen  *
6933707f3Ssthen  * This software is open source.
7933707f3Ssthen  *
8933707f3Ssthen  * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen  * modification, are permitted provided that the following conditions
10933707f3Ssthen  * are met:
11933707f3Ssthen  *
12933707f3Ssthen  * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen  * this list of conditions and the following disclaimer.
14933707f3Ssthen  *
15933707f3Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen  * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen  * and/or other materials provided with the distribution.
18933707f3Ssthen  *
19933707f3Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen  * be used to endorse or promote products derived from this software without
21933707f3Ssthen  * specific prior written permission.
22933707f3Ssthen  *
23933707f3Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  *
35933707f3Ssthen  */
36933707f3Ssthen 
37933707f3Ssthen /**
38933707f3Ssthen  * \file
39933707f3Ssthen  * Implementation of a redblack tree.
40933707f3Ssthen  */
41933707f3Ssthen 
42933707f3Ssthen #include "config.h"
43933707f3Ssthen #include "log.h"
44933707f3Ssthen #include "fptr_wlist.h"
45933707f3Ssthen #include "util/rbtree.h"
46933707f3Ssthen 
47933707f3Ssthen /** Node colour black */
48933707f3Ssthen #define	BLACK	0
49933707f3Ssthen /** Node colour red */
50933707f3Ssthen #define	RED	1
51933707f3Ssthen 
52933707f3Ssthen /** the NULL node, global alloc */
53*77079be7Ssthen rbnode_type	rbtree_null_node = {
54933707f3Ssthen 	RBTREE_NULL,		/* Parent.  */
55933707f3Ssthen 	RBTREE_NULL,		/* Left.  */
56933707f3Ssthen 	RBTREE_NULL,		/* Right.  */
57933707f3Ssthen 	NULL,			/* Key.  */
58933707f3Ssthen 	BLACK			/* Color.  */
59933707f3Ssthen };
60933707f3Ssthen 
61933707f3Ssthen /** rotate subtree left (to preserve redblack property) */
62*77079be7Ssthen static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node);
63933707f3Ssthen /** rotate subtree right (to preserve redblack property) */
64*77079be7Ssthen static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node);
65933707f3Ssthen /** Fixup node colours when insert happened */
66*77079be7Ssthen static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node);
67933707f3Ssthen /** Fixup node colours when delete happened */
68*77079be7Ssthen static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child,
69*77079be7Ssthen 	rbnode_type* child_parent);
70933707f3Ssthen 
71933707f3Ssthen /*
724bfc71b0Ssthen  * Creates a new red black tree, initializes and returns a pointer to it.
73933707f3Ssthen  *
74933707f3Ssthen  * Return NULL on failure.
75933707f3Ssthen  *
76933707f3Ssthen  */
77*77079be7Ssthen rbtree_type *
rbtree_create(int (* cmpf)(const void *,const void *))78933707f3Ssthen rbtree_create (int (*cmpf)(const void *, const void *))
79933707f3Ssthen {
80*77079be7Ssthen 	rbtree_type *rbtree;
81933707f3Ssthen 
82933707f3Ssthen 	/* Allocate memory for it */
83*77079be7Ssthen 	rbtree = (rbtree_type *) malloc(sizeof(rbtree_type));
84933707f3Ssthen 	if (!rbtree) {
85933707f3Ssthen 		return NULL;
86933707f3Ssthen 	}
87933707f3Ssthen 
88933707f3Ssthen 	/* Initialize it */
89933707f3Ssthen 	rbtree_init(rbtree, cmpf);
90933707f3Ssthen 
91933707f3Ssthen 	return rbtree;
92933707f3Ssthen }
93933707f3Ssthen 
94933707f3Ssthen void
rbtree_init(rbtree_type * rbtree,int (* cmpf)(const void *,const void *))95*77079be7Ssthen rbtree_init(rbtree_type *rbtree, int (*cmpf)(const void *, const void *))
96933707f3Ssthen {
97933707f3Ssthen 	/* Initialize it */
98933707f3Ssthen 	rbtree->root = RBTREE_NULL;
99933707f3Ssthen 	rbtree->count = 0;
100933707f3Ssthen 	rbtree->cmp = cmpf;
101933707f3Ssthen }
102933707f3Ssthen 
103933707f3Ssthen /*
104933707f3Ssthen  * Rotates the node to the left.
105933707f3Ssthen  *
106933707f3Ssthen  */
107933707f3Ssthen static void
rbtree_rotate_left(rbtree_type * rbtree,rbnode_type * node)108*77079be7Ssthen rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node)
109933707f3Ssthen {
110*77079be7Ssthen 	rbnode_type *right = node->right;
111933707f3Ssthen 	node->right = right->left;
112933707f3Ssthen 	if (right->left != RBTREE_NULL)
113933707f3Ssthen 		right->left->parent = node;
114933707f3Ssthen 
115933707f3Ssthen 	right->parent = node->parent;
116933707f3Ssthen 
117933707f3Ssthen 	if (node->parent != RBTREE_NULL) {
118933707f3Ssthen 		if (node == node->parent->left) {
119933707f3Ssthen 			node->parent->left = right;
120933707f3Ssthen 		} else  {
121933707f3Ssthen 			node->parent->right = right;
122933707f3Ssthen 		}
123933707f3Ssthen 	} else {
124933707f3Ssthen 		rbtree->root = right;
125933707f3Ssthen 	}
126933707f3Ssthen 	right->left = node;
127933707f3Ssthen 	node->parent = right;
128933707f3Ssthen }
129933707f3Ssthen 
130933707f3Ssthen /*
131933707f3Ssthen  * Rotates the node to the right.
132933707f3Ssthen  *
133933707f3Ssthen  */
134933707f3Ssthen static void
rbtree_rotate_right(rbtree_type * rbtree,rbnode_type * node)135*77079be7Ssthen rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node)
136933707f3Ssthen {
137*77079be7Ssthen 	rbnode_type *left = node->left;
138933707f3Ssthen 	node->left = left->right;
139933707f3Ssthen 	if (left->right != RBTREE_NULL)
140933707f3Ssthen 		left->right->parent = node;
141933707f3Ssthen 
142933707f3Ssthen 	left->parent = node->parent;
143933707f3Ssthen 
144933707f3Ssthen 	if (node->parent != RBTREE_NULL) {
145933707f3Ssthen 		if (node == node->parent->right) {
146933707f3Ssthen 			node->parent->right = left;
147933707f3Ssthen 		} else  {
148933707f3Ssthen 			node->parent->left = left;
149933707f3Ssthen 		}
150933707f3Ssthen 	} else {
151933707f3Ssthen 		rbtree->root = left;
152933707f3Ssthen 	}
153933707f3Ssthen 	left->right = node;
154933707f3Ssthen 	node->parent = left;
155933707f3Ssthen }
156933707f3Ssthen 
157933707f3Ssthen static void
rbtree_insert_fixup(rbtree_type * rbtree,rbnode_type * node)158*77079be7Ssthen rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node)
159933707f3Ssthen {
160*77079be7Ssthen 	rbnode_type	*uncle;
161933707f3Ssthen 
162933707f3Ssthen 	/* While not at the root and need fixing... */
163933707f3Ssthen 	while (node != rbtree->root && node->parent->color == RED) {
164933707f3Ssthen 		/* If our parent is left child of our grandparent... */
165933707f3Ssthen 		if (node->parent == node->parent->parent->left) {
166933707f3Ssthen 			uncle = node->parent->parent->right;
167933707f3Ssthen 
168933707f3Ssthen 			/* If our uncle is red... */
169933707f3Ssthen 			if (uncle->color == RED) {
170933707f3Ssthen 				/* Paint the parent and the uncle black... */
171933707f3Ssthen 				node->parent->color = BLACK;
172933707f3Ssthen 				uncle->color = BLACK;
173933707f3Ssthen 
174933707f3Ssthen 				/* And the grandparent red... */
175933707f3Ssthen 				node->parent->parent->color = RED;
176933707f3Ssthen 
177933707f3Ssthen 				/* And continue fixing the grandparent */
178933707f3Ssthen 				node = node->parent->parent;
179933707f3Ssthen 			} else {				/* Our uncle is black... */
180933707f3Ssthen 				/* Are we the right child? */
181933707f3Ssthen 				if (node == node->parent->right) {
182933707f3Ssthen 					node = node->parent;
183933707f3Ssthen 					rbtree_rotate_left(rbtree, node);
184933707f3Ssthen 				}
185933707f3Ssthen 				/* Now we're the left child, repaint and rotate... */
186933707f3Ssthen 				node->parent->color = BLACK;
187933707f3Ssthen 				node->parent->parent->color = RED;
188933707f3Ssthen 				rbtree_rotate_right(rbtree, node->parent->parent);
189933707f3Ssthen 			}
190933707f3Ssthen 		} else {
191933707f3Ssthen 			uncle = node->parent->parent->left;
192933707f3Ssthen 
193933707f3Ssthen 			/* If our uncle is red... */
194933707f3Ssthen 			if (uncle->color == RED) {
195933707f3Ssthen 				/* Paint the parent and the uncle black... */
196933707f3Ssthen 				node->parent->color = BLACK;
197933707f3Ssthen 				uncle->color = BLACK;
198933707f3Ssthen 
199933707f3Ssthen 				/* And the grandparent red... */
200933707f3Ssthen 				node->parent->parent->color = RED;
201933707f3Ssthen 
202933707f3Ssthen 				/* And continue fixing the grandparent */
203933707f3Ssthen 				node = node->parent->parent;
204933707f3Ssthen 			} else {				/* Our uncle is black... */
205933707f3Ssthen 				/* Are we the right child? */
206933707f3Ssthen 				if (node == node->parent->left) {
207933707f3Ssthen 					node = node->parent;
208933707f3Ssthen 					rbtree_rotate_right(rbtree, node);
209933707f3Ssthen 				}
210933707f3Ssthen 				/* Now we're the right child, repaint and rotate... */
211933707f3Ssthen 				node->parent->color = BLACK;
212933707f3Ssthen 				node->parent->parent->color = RED;
213933707f3Ssthen 				rbtree_rotate_left(rbtree, node->parent->parent);
214933707f3Ssthen 			}
215933707f3Ssthen 		}
216933707f3Ssthen 	}
217933707f3Ssthen 	rbtree->root->color = BLACK;
218933707f3Ssthen }
219933707f3Ssthen 
220933707f3Ssthen 
221933707f3Ssthen /*
222933707f3Ssthen  * Inserts a node into a red black tree.
223933707f3Ssthen  *
224933707f3Ssthen  * Returns NULL on failure or the pointer to the newly added node
225933707f3Ssthen  * otherwise.
226933707f3Ssthen  */
227*77079be7Ssthen rbnode_type *
rbtree_insert(rbtree_type * rbtree,rbnode_type * data)228*77079be7Ssthen rbtree_insert (rbtree_type *rbtree, rbnode_type *data)
229933707f3Ssthen {
230933707f3Ssthen 	/* XXX Not necessary, but keeps compiler quiet... */
231933707f3Ssthen 	int r = 0;
232933707f3Ssthen 
233933707f3Ssthen 	/* We start at the root of the tree */
234*77079be7Ssthen 	rbnode_type	*node = rbtree->root;
235*77079be7Ssthen 	rbnode_type	*parent = RBTREE_NULL;
236933707f3Ssthen 
237933707f3Ssthen 	fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
238933707f3Ssthen 	/* Lets find the new parent... */
239933707f3Ssthen 	while (node != RBTREE_NULL) {
240933707f3Ssthen 		/* Compare two keys, do we have a duplicate? */
241933707f3Ssthen 		if ((r = rbtree->cmp(data->key, node->key)) == 0) {
242933707f3Ssthen 			return NULL;
243933707f3Ssthen 		}
244933707f3Ssthen 		parent = node;
245933707f3Ssthen 
246933707f3Ssthen 		if (r < 0) {
247933707f3Ssthen 			node = node->left;
248933707f3Ssthen 		} else {
249933707f3Ssthen 			node = node->right;
250933707f3Ssthen 		}
251933707f3Ssthen 	}
252933707f3Ssthen 
253933707f3Ssthen 	/* Initialize the new node */
254933707f3Ssthen 	data->parent = parent;
255933707f3Ssthen 	data->left = data->right = RBTREE_NULL;
256933707f3Ssthen 	data->color = RED;
257933707f3Ssthen 	rbtree->count++;
258933707f3Ssthen 
259933707f3Ssthen 	/* Insert it into the tree... */
260933707f3Ssthen 	if (parent != RBTREE_NULL) {
261933707f3Ssthen 		if (r < 0) {
262933707f3Ssthen 			parent->left = data;
263933707f3Ssthen 		} else {
264933707f3Ssthen 			parent->right = data;
265933707f3Ssthen 		}
266933707f3Ssthen 	} else {
267933707f3Ssthen 		rbtree->root = data;
268933707f3Ssthen 	}
269933707f3Ssthen 
270933707f3Ssthen 	/* Fix up the red-black properties... */
271933707f3Ssthen 	rbtree_insert_fixup(rbtree, data);
272933707f3Ssthen 
273933707f3Ssthen 	return data;
274933707f3Ssthen }
275933707f3Ssthen 
276933707f3Ssthen /*
277933707f3Ssthen  * Searches the red black tree, returns the data if key is found or NULL otherwise.
278933707f3Ssthen  *
279933707f3Ssthen  */
280*77079be7Ssthen rbnode_type *
rbtree_search(rbtree_type * rbtree,const void * key)281*77079be7Ssthen rbtree_search (rbtree_type *rbtree, const void *key)
282933707f3Ssthen {
283*77079be7Ssthen 	rbnode_type *node;
284933707f3Ssthen 
285933707f3Ssthen 	if (rbtree_find_less_equal(rbtree, key, &node)) {
286933707f3Ssthen 		return node;
287933707f3Ssthen 	} else {
288933707f3Ssthen 		return NULL;
289933707f3Ssthen 	}
290933707f3Ssthen }
291933707f3Ssthen 
292933707f3Ssthen /** helpers for delete: swap node colours */
swap_int8(uint8_t * x,uint8_t * y)293933707f3Ssthen static void swap_int8(uint8_t* x, uint8_t* y)
294933707f3Ssthen {
295933707f3Ssthen 	uint8_t t = *x; *x = *y; *y = t;
296933707f3Ssthen }
297933707f3Ssthen 
298933707f3Ssthen /** helpers for delete: swap node pointers */
swap_np(rbnode_type ** x,rbnode_type ** y)299*77079be7Ssthen static void swap_np(rbnode_type** x, rbnode_type** y)
300933707f3Ssthen {
301*77079be7Ssthen 	rbnode_type* t = *x; *x = *y; *y = t;
302933707f3Ssthen }
303933707f3Ssthen 
304933707f3Ssthen /** Update parent pointers of child trees of 'parent' */
change_parent_ptr(rbtree_type * rbtree,rbnode_type * parent,rbnode_type * old,rbnode_type * new)305*77079be7Ssthen static void change_parent_ptr(rbtree_type* rbtree, rbnode_type* parent,
306*77079be7Ssthen 	rbnode_type* old, rbnode_type* new)
307933707f3Ssthen {
308933707f3Ssthen 	if(parent == RBTREE_NULL)
309933707f3Ssthen 	{
310933707f3Ssthen 		log_assert(rbtree->root == old);
311933707f3Ssthen 		if(rbtree->root == old) rbtree->root = new;
312933707f3Ssthen 		return;
313933707f3Ssthen 	}
314933707f3Ssthen 	log_assert(parent->left == old || parent->right == old
315933707f3Ssthen 		|| parent->left == new || parent->right == new);
316933707f3Ssthen 	if(parent->left == old) parent->left = new;
317933707f3Ssthen 	if(parent->right == old) parent->right = new;
318933707f3Ssthen }
319933707f3Ssthen /** Update parent pointer of a node 'child' */
change_child_ptr(rbnode_type * child,rbnode_type * old,rbnode_type * new)320*77079be7Ssthen static void change_child_ptr(rbnode_type* child, rbnode_type* old,
321*77079be7Ssthen 	rbnode_type* new)
322933707f3Ssthen {
323933707f3Ssthen 	if(child == RBTREE_NULL) return;
324933707f3Ssthen 	log_assert(child->parent == old || child->parent == new);
325933707f3Ssthen 	if(child->parent == old) child->parent = new;
326933707f3Ssthen }
327933707f3Ssthen 
328*77079be7Ssthen rbnode_type*
rbtree_delete(rbtree_type * rbtree,const void * key)329*77079be7Ssthen rbtree_delete(rbtree_type *rbtree, const void *key)
330933707f3Ssthen {
331*77079be7Ssthen 	rbnode_type *to_delete;
332*77079be7Ssthen 	rbnode_type *child;
333933707f3Ssthen 	if((to_delete = rbtree_search(rbtree, key)) == 0) return 0;
334933707f3Ssthen 	rbtree->count--;
335933707f3Ssthen 
336933707f3Ssthen 	/* make sure we have at most one non-leaf child */
337933707f3Ssthen 	if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL)
338933707f3Ssthen 	{
339933707f3Ssthen 		/* swap with smallest from right subtree (or largest from left) */
340*77079be7Ssthen 		rbnode_type *smright = to_delete->right;
341933707f3Ssthen 		while(smright->left != RBTREE_NULL)
342933707f3Ssthen 			smright = smright->left;
343933707f3Ssthen 		/* swap the smright and to_delete elements in the tree,
344*77079be7Ssthen 		 * but the rbnode_type is first part of user data struct
345933707f3Ssthen 		 * so cannot just swap the keys and data pointers. Instead
346933707f3Ssthen 		 * readjust the pointers left,right,parent */
347933707f3Ssthen 
348933707f3Ssthen 		/* swap colors - colors are tied to the position in the tree */
349933707f3Ssthen 		swap_int8(&to_delete->color, &smright->color);
350933707f3Ssthen 
351933707f3Ssthen 		/* swap child pointers in parents of smright/to_delete */
352933707f3Ssthen 		change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
353933707f3Ssthen 		if(to_delete->right != smright)
354933707f3Ssthen 			change_parent_ptr(rbtree, smright->parent, smright, to_delete);
355933707f3Ssthen 
356933707f3Ssthen 		/* swap parent pointers in children of smright/to_delete */
357933707f3Ssthen 		change_child_ptr(smright->left, smright, to_delete);
358933707f3Ssthen 		change_child_ptr(smright->left, smright, to_delete);
359933707f3Ssthen 		change_child_ptr(smright->right, smright, to_delete);
360933707f3Ssthen 		change_child_ptr(smright->right, smright, to_delete);
361933707f3Ssthen 		change_child_ptr(to_delete->left, to_delete, smright);
362933707f3Ssthen 		if(to_delete->right != smright)
363933707f3Ssthen 			change_child_ptr(to_delete->right, to_delete, smright);
364933707f3Ssthen 		if(to_delete->right == smright)
365933707f3Ssthen 		{
366933707f3Ssthen 			/* set up so after swap they work */
367933707f3Ssthen 			to_delete->right = to_delete;
368933707f3Ssthen 			smright->parent = smright;
369933707f3Ssthen 		}
370933707f3Ssthen 
371933707f3Ssthen 		/* swap pointers in to_delete/smright nodes */
372933707f3Ssthen 		swap_np(&to_delete->parent, &smright->parent);
373933707f3Ssthen 		swap_np(&to_delete->left, &smright->left);
374933707f3Ssthen 		swap_np(&to_delete->right, &smright->right);
375933707f3Ssthen 
376933707f3Ssthen 		/* now delete to_delete (which is at the location where the smright previously was) */
377933707f3Ssthen 	}
378933707f3Ssthen 	log_assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
379933707f3Ssthen 
380933707f3Ssthen 	if(to_delete->left != RBTREE_NULL) child = to_delete->left;
381933707f3Ssthen 	else child = to_delete->right;
382933707f3Ssthen 
383933707f3Ssthen 	/* unlink to_delete from the tree, replace to_delete with child */
384933707f3Ssthen 	change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
385933707f3Ssthen 	change_child_ptr(child, to_delete, to_delete->parent);
386933707f3Ssthen 
387933707f3Ssthen 	if(to_delete->color == RED)
388933707f3Ssthen 	{
389933707f3Ssthen 		/* if node is red then the child (black) can be swapped in */
390933707f3Ssthen 	}
391933707f3Ssthen 	else if(child->color == RED)
392933707f3Ssthen 	{
393933707f3Ssthen 		/* change child to BLACK, removing a RED node is no problem */
394933707f3Ssthen 		if(child!=RBTREE_NULL) child->color = BLACK;
395933707f3Ssthen 	}
396933707f3Ssthen 	else rbtree_delete_fixup(rbtree, child, to_delete->parent);
397933707f3Ssthen 
398933707f3Ssthen 	/* unlink completely */
399933707f3Ssthen 	to_delete->parent = RBTREE_NULL;
400933707f3Ssthen 	to_delete->left = RBTREE_NULL;
401933707f3Ssthen 	to_delete->right = RBTREE_NULL;
402933707f3Ssthen 	to_delete->color = BLACK;
403933707f3Ssthen 	return to_delete;
404933707f3Ssthen }
405933707f3Ssthen 
rbtree_delete_fixup(rbtree_type * rbtree,rbnode_type * child,rbnode_type * child_parent)406*77079be7Ssthen static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child,
407*77079be7Ssthen 	rbnode_type* child_parent)
408933707f3Ssthen {
409*77079be7Ssthen 	rbnode_type* sibling;
410933707f3Ssthen 	int go_up = 1;
411933707f3Ssthen 
412933707f3Ssthen 	/* determine sibling to the node that is one-black short */
413933707f3Ssthen 	if(child_parent->right == child) sibling = child_parent->left;
414933707f3Ssthen 	else sibling = child_parent->right;
415933707f3Ssthen 
416933707f3Ssthen 	while(go_up)
417933707f3Ssthen 	{
418933707f3Ssthen 		if(child_parent == RBTREE_NULL)
419933707f3Ssthen 		{
420933707f3Ssthen 			/* removed parent==black from root, every path, so ok */
421933707f3Ssthen 			return;
422933707f3Ssthen 		}
423933707f3Ssthen 
424933707f3Ssthen 		if(sibling->color == RED)
425933707f3Ssthen 		{	/* rotate to get a black sibling */
426933707f3Ssthen 			child_parent->color = RED;
427933707f3Ssthen 			sibling->color = BLACK;
428933707f3Ssthen 			if(child_parent->right == child)
429933707f3Ssthen 				rbtree_rotate_right(rbtree, child_parent);
430933707f3Ssthen 			else	rbtree_rotate_left(rbtree, child_parent);
431933707f3Ssthen 			/* new sibling after rotation */
432933707f3Ssthen 			if(child_parent->right == child) sibling = child_parent->left;
433933707f3Ssthen 			else sibling = child_parent->right;
434933707f3Ssthen 		}
435933707f3Ssthen 
436933707f3Ssthen 		if(child_parent->color == BLACK
437933707f3Ssthen 			&& sibling->color == BLACK
438933707f3Ssthen 			&& sibling->left->color == BLACK
439933707f3Ssthen 			&& sibling->right->color == BLACK)
440933707f3Ssthen 		{	/* fixup local with recolor of sibling */
441933707f3Ssthen 			if(sibling != RBTREE_NULL)
442933707f3Ssthen 				sibling->color = RED;
443933707f3Ssthen 
444933707f3Ssthen 			child = child_parent;
445933707f3Ssthen 			child_parent = child_parent->parent;
446933707f3Ssthen 			/* prepare to go up, new sibling */
447933707f3Ssthen 			if(child_parent->right == child) sibling = child_parent->left;
448933707f3Ssthen 			else sibling = child_parent->right;
449933707f3Ssthen 		}
450933707f3Ssthen 		else go_up = 0;
451933707f3Ssthen 	}
452933707f3Ssthen 
453933707f3Ssthen 	if(child_parent->color == RED
454933707f3Ssthen 		&& sibling->color == BLACK
455933707f3Ssthen 		&& sibling->left->color == BLACK
456933707f3Ssthen 		&& sibling->right->color == BLACK)
457933707f3Ssthen 	{
458933707f3Ssthen 		/* move red to sibling to rebalance */
459933707f3Ssthen 		if(sibling != RBTREE_NULL)
460933707f3Ssthen 			sibling->color = RED;
461933707f3Ssthen 		child_parent->color = BLACK;
462933707f3Ssthen 		return;
463933707f3Ssthen 	}
464933707f3Ssthen 	log_assert(sibling != RBTREE_NULL);
465933707f3Ssthen 
466933707f3Ssthen 	/* get a new sibling, by rotating at sibling. See which child
467933707f3Ssthen 	   of sibling is red */
468933707f3Ssthen 	if(child_parent->right == child
469933707f3Ssthen 		&& sibling->color == BLACK
470933707f3Ssthen 		&& sibling->right->color == RED
471933707f3Ssthen 		&& sibling->left->color == BLACK)
472933707f3Ssthen 	{
473933707f3Ssthen 		sibling->color = RED;
474933707f3Ssthen 		sibling->right->color = BLACK;
475933707f3Ssthen 		rbtree_rotate_left(rbtree, sibling);
476933707f3Ssthen 		/* new sibling after rotation */
477933707f3Ssthen 		if(child_parent->right == child) sibling = child_parent->left;
478933707f3Ssthen 		else sibling = child_parent->right;
479933707f3Ssthen 	}
480933707f3Ssthen 	else if(child_parent->left == child
481933707f3Ssthen 		&& sibling->color == BLACK
482933707f3Ssthen 		&& sibling->left->color == RED
483933707f3Ssthen 		&& sibling->right->color == BLACK)
484933707f3Ssthen 	{
485933707f3Ssthen 		sibling->color = RED;
486933707f3Ssthen 		sibling->left->color = BLACK;
487933707f3Ssthen 		rbtree_rotate_right(rbtree, sibling);
488933707f3Ssthen 		/* new sibling after rotation */
489933707f3Ssthen 		if(child_parent->right == child) sibling = child_parent->left;
490933707f3Ssthen 		else sibling = child_parent->right;
491933707f3Ssthen 	}
492933707f3Ssthen 
493933707f3Ssthen 	/* now we have a black sibling with a red child. rotate and exchange colors. */
494933707f3Ssthen 	sibling->color = child_parent->color;
495933707f3Ssthen 	child_parent->color = BLACK;
496933707f3Ssthen 	if(child_parent->right == child)
497933707f3Ssthen 	{
498933707f3Ssthen 		log_assert(sibling->left->color == RED);
499933707f3Ssthen 		sibling->left->color = BLACK;
500933707f3Ssthen 		rbtree_rotate_right(rbtree, child_parent);
501933707f3Ssthen 	}
502933707f3Ssthen 	else
503933707f3Ssthen 	{
504933707f3Ssthen 		log_assert(sibling->right->color == RED);
505933707f3Ssthen 		sibling->right->color = BLACK;
506933707f3Ssthen 		rbtree_rotate_left(rbtree, child_parent);
507933707f3Ssthen 	}
508933707f3Ssthen }
509933707f3Ssthen 
510933707f3Ssthen int
rbtree_find_less_equal(rbtree_type * rbtree,const void * key,rbnode_type ** result)511*77079be7Ssthen rbtree_find_less_equal(rbtree_type *rbtree, const void *key,
512*77079be7Ssthen 	rbnode_type **result)
513933707f3Ssthen {
514933707f3Ssthen 	int r;
515*77079be7Ssthen 	rbnode_type *node;
516933707f3Ssthen 
517933707f3Ssthen 	log_assert(result);
518933707f3Ssthen 
519933707f3Ssthen 	/* We start at root... */
520933707f3Ssthen 	node = rbtree->root;
521933707f3Ssthen 
522933707f3Ssthen 	*result = NULL;
523933707f3Ssthen 	fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
524933707f3Ssthen 
525933707f3Ssthen 	/* While there are children... */
526933707f3Ssthen 	while (node != RBTREE_NULL) {
527933707f3Ssthen 		r = rbtree->cmp(key, node->key);
528933707f3Ssthen 		if (r == 0) {
529933707f3Ssthen 			/* Exact match */
530933707f3Ssthen 			*result = node;
531933707f3Ssthen 			return 1;
532933707f3Ssthen 		}
533933707f3Ssthen 		if (r < 0) {
534933707f3Ssthen 			node = node->left;
535933707f3Ssthen 		} else {
536933707f3Ssthen 			/* Temporary match */
537933707f3Ssthen 			*result = node;
538933707f3Ssthen 			node = node->right;
539933707f3Ssthen 		}
540933707f3Ssthen 	}
541933707f3Ssthen 	return 0;
542933707f3Ssthen }
543933707f3Ssthen 
544933707f3Ssthen /*
545933707f3Ssthen  * Finds the first element in the red black tree
546933707f3Ssthen  *
547933707f3Ssthen  */
548*77079be7Ssthen rbnode_type *
rbtree_first(rbtree_type * rbtree)549*77079be7Ssthen rbtree_first (rbtree_type *rbtree)
550933707f3Ssthen {
551*77079be7Ssthen 	rbnode_type *node;
552933707f3Ssthen 
553933707f3Ssthen 	for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left);
554933707f3Ssthen 	return node;
555933707f3Ssthen }
556933707f3Ssthen 
557*77079be7Ssthen rbnode_type *
rbtree_last(rbtree_type * rbtree)558*77079be7Ssthen rbtree_last (rbtree_type *rbtree)
559933707f3Ssthen {
560*77079be7Ssthen 	rbnode_type *node;
561933707f3Ssthen 
562933707f3Ssthen 	for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right);
563933707f3Ssthen 	return node;
564933707f3Ssthen }
565933707f3Ssthen 
566933707f3Ssthen /*
567933707f3Ssthen  * Returns the next node...
568933707f3Ssthen  *
569933707f3Ssthen  */
570*77079be7Ssthen rbnode_type *
rbtree_next(rbnode_type * node)571*77079be7Ssthen rbtree_next (rbnode_type *node)
572933707f3Ssthen {
573*77079be7Ssthen 	rbnode_type *parent;
574933707f3Ssthen 
575933707f3Ssthen 	if (node->right != RBTREE_NULL) {
576933707f3Ssthen 		/* One right, then keep on going left... */
577933707f3Ssthen 		for (node = node->right; node->left != RBTREE_NULL; node = node->left);
578933707f3Ssthen 	} else {
579933707f3Ssthen 		parent = node->parent;
580933707f3Ssthen 		while (parent != RBTREE_NULL && node == parent->right) {
581933707f3Ssthen 			node = parent;
582933707f3Ssthen 			parent = parent->parent;
583933707f3Ssthen 		}
584933707f3Ssthen 		node = parent;
585933707f3Ssthen 	}
586933707f3Ssthen 	return node;
587933707f3Ssthen }
588933707f3Ssthen 
589*77079be7Ssthen rbnode_type *
rbtree_previous(rbnode_type * node)590*77079be7Ssthen rbtree_previous(rbnode_type *node)
591933707f3Ssthen {
592*77079be7Ssthen 	rbnode_type *parent;
593933707f3Ssthen 
594933707f3Ssthen 	if (node->left != RBTREE_NULL) {
595933707f3Ssthen 		/* One left, then keep on going right... */
596933707f3Ssthen 		for (node = node->left; node->right != RBTREE_NULL; node = node->right);
597933707f3Ssthen 	} else {
598933707f3Ssthen 		parent = node->parent;
599933707f3Ssthen 		while (parent != RBTREE_NULL && node == parent->left) {
600933707f3Ssthen 			node = parent;
601933707f3Ssthen 			parent = parent->parent;
602933707f3Ssthen 		}
603933707f3Ssthen 		node = parent;
604933707f3Ssthen 	}
605933707f3Ssthen 	return node;
606933707f3Ssthen }
607933707f3Ssthen 
608933707f3Ssthen /** recursive descent traverse */
609933707f3Ssthen static void
traverse_post(void (* func)(rbnode_type *,void *),void * arg,rbnode_type * node)610*77079be7Ssthen traverse_post(void (*func)(rbnode_type*, void*), void* arg, rbnode_type* node)
611933707f3Ssthen {
612933707f3Ssthen 	if(!node || node == RBTREE_NULL)
613933707f3Ssthen 		return;
614933707f3Ssthen 	/* recurse */
615933707f3Ssthen 	traverse_post(func, arg, node->left);
616933707f3Ssthen 	traverse_post(func, arg, node->right);
617933707f3Ssthen 	/* call user func */
618933707f3Ssthen 	(*func)(node, arg);
619933707f3Ssthen }
620933707f3Ssthen 
621933707f3Ssthen void
traverse_postorder(rbtree_type * tree,void (* func)(rbnode_type *,void *),void * arg)622*77079be7Ssthen traverse_postorder(rbtree_type* tree, void (*func)(rbnode_type*, void*),
623*77079be7Ssthen 	void* arg)
624933707f3Ssthen {
625933707f3Ssthen 	traverse_post(func, arg, tree->root);
626933707f3Ssthen }
627