xref: /openbsd-src/usr.sbin/nsd/rbtree.c (revision fe5fe5f6cfa8bb64bb38bafa85c14c1d131dfe6d)
162ac0c33Sjakob /*
262ac0c33Sjakob  * rbtree.c -- generic red black tree
362ac0c33Sjakob  *
4d3fecca9Ssthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
10aee1b7aaSsthen #include "config.h"
1162ac0c33Sjakob 
1262ac0c33Sjakob #include <assert.h>
1362ac0c33Sjakob #include <stdlib.h>
1462ac0c33Sjakob 
1562ac0c33Sjakob #include "rbtree.h"
1662ac0c33Sjakob 
1762ac0c33Sjakob #define	BLACK	0
1862ac0c33Sjakob #define	RED	1
1962ac0c33Sjakob 
20*fe5fe5f6Sflorian rbnode_type	rbtree_null_node = {
2162ac0c33Sjakob 	RBTREE_NULL,		/* Parent.  */
2262ac0c33Sjakob 	RBTREE_NULL,		/* Left.  */
2362ac0c33Sjakob 	RBTREE_NULL,		/* Right.  */
2462ac0c33Sjakob 	NULL,			/* Key.  */
2562ac0c33Sjakob 	BLACK			/* Color.  */
2662ac0c33Sjakob };
2762ac0c33Sjakob 
28*fe5fe5f6Sflorian static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node);
29*fe5fe5f6Sflorian static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node);
30*fe5fe5f6Sflorian static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node);
31*fe5fe5f6Sflorian static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, rbnode_type* child_parent);
3262ac0c33Sjakob 
3362ac0c33Sjakob /*
342fd875a4Ssthen  * Creates a new red black tree, initializes and returns a pointer to it.
3562ac0c33Sjakob  *
3662ac0c33Sjakob  * Return NULL on failure.
3762ac0c33Sjakob  *
3862ac0c33Sjakob  */
39*fe5fe5f6Sflorian rbtree_type *
rbtree_create(region_type * region,int (* cmpf)(const void *,const void *))4062ac0c33Sjakob rbtree_create (region_type *region, int (*cmpf)(const void *, const void *))
4162ac0c33Sjakob {
42*fe5fe5f6Sflorian 	rbtree_type *rbtree;
4362ac0c33Sjakob 
4462ac0c33Sjakob 	/* Allocate memory for it */
45*fe5fe5f6Sflorian 	rbtree = (rbtree_type *) region_alloc(region, sizeof(rbtree_type));
4662ac0c33Sjakob 	if (!rbtree) {
4762ac0c33Sjakob 		return NULL;
4862ac0c33Sjakob 	}
4962ac0c33Sjakob 
5062ac0c33Sjakob 	/* Initialize it */
5162ac0c33Sjakob 	rbtree->root = RBTREE_NULL;
5262ac0c33Sjakob 	rbtree->count = 0;
5362ac0c33Sjakob 	rbtree->region = region;
5462ac0c33Sjakob 	rbtree->cmp = cmpf;
5562ac0c33Sjakob 
5662ac0c33Sjakob 	return rbtree;
5762ac0c33Sjakob }
5862ac0c33Sjakob 
5962ac0c33Sjakob /*
6062ac0c33Sjakob  * Rotates the node to the left.
6162ac0c33Sjakob  *
6262ac0c33Sjakob  */
6362ac0c33Sjakob static void
rbtree_rotate_left(rbtree_type * rbtree,rbnode_type * node)64*fe5fe5f6Sflorian rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node)
6562ac0c33Sjakob {
66*fe5fe5f6Sflorian 	rbnode_type *right = node->right;
6762ac0c33Sjakob 	node->right = right->left;
6862ac0c33Sjakob 	if (right->left != RBTREE_NULL)
6962ac0c33Sjakob 		right->left->parent = node;
7062ac0c33Sjakob 
7162ac0c33Sjakob 	right->parent = node->parent;
7262ac0c33Sjakob 
7362ac0c33Sjakob 	if (node->parent != RBTREE_NULL) {
7462ac0c33Sjakob 		if (node == node->parent->left) {
7562ac0c33Sjakob 			node->parent->left = right;
7662ac0c33Sjakob 		} else  {
7762ac0c33Sjakob 			node->parent->right = right;
7862ac0c33Sjakob 		}
7962ac0c33Sjakob 	} else {
8062ac0c33Sjakob 		rbtree->root = right;
8162ac0c33Sjakob 	}
8262ac0c33Sjakob 	right->left = node;
8362ac0c33Sjakob 	node->parent = right;
8462ac0c33Sjakob }
8562ac0c33Sjakob 
8662ac0c33Sjakob /*
8762ac0c33Sjakob  * Rotates the node to the right.
8862ac0c33Sjakob  *
8962ac0c33Sjakob  */
9062ac0c33Sjakob static void
rbtree_rotate_right(rbtree_type * rbtree,rbnode_type * node)91*fe5fe5f6Sflorian rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node)
9262ac0c33Sjakob {
93*fe5fe5f6Sflorian 	rbnode_type *left = node->left;
9462ac0c33Sjakob 	node->left = left->right;
9562ac0c33Sjakob 	if (left->right != RBTREE_NULL)
9662ac0c33Sjakob 		left->right->parent = node;
9762ac0c33Sjakob 
9862ac0c33Sjakob 	left->parent = node->parent;
9962ac0c33Sjakob 
10062ac0c33Sjakob 	if (node->parent != RBTREE_NULL) {
10162ac0c33Sjakob 		if (node == node->parent->right) {
10262ac0c33Sjakob 			node->parent->right = left;
10362ac0c33Sjakob 		} else  {
10462ac0c33Sjakob 			node->parent->left = left;
10562ac0c33Sjakob 		}
10662ac0c33Sjakob 	} else {
10762ac0c33Sjakob 		rbtree->root = left;
10862ac0c33Sjakob 	}
10962ac0c33Sjakob 	left->right = node;
11062ac0c33Sjakob 	node->parent = left;
11162ac0c33Sjakob }
11262ac0c33Sjakob 
11362ac0c33Sjakob static void
rbtree_insert_fixup(rbtree_type * rbtree,rbnode_type * node)114*fe5fe5f6Sflorian rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node)
11562ac0c33Sjakob {
116*fe5fe5f6Sflorian 	rbnode_type	*uncle;
11762ac0c33Sjakob 
11862ac0c33Sjakob 	/* While not at the root and need fixing... */
11962ac0c33Sjakob 	while (node != rbtree->root && node->parent->color == RED) {
12062ac0c33Sjakob 		/* If our parent is left child of our grandparent... */
12162ac0c33Sjakob 		if (node->parent == node->parent->parent->left) {
12262ac0c33Sjakob 			uncle = node->parent->parent->right;
12362ac0c33Sjakob 
12462ac0c33Sjakob 			/* If our uncle is red... */
12562ac0c33Sjakob 			if (uncle->color == RED) {
12662ac0c33Sjakob 				/* Paint the parent and the uncle black... */
12762ac0c33Sjakob 				node->parent->color = BLACK;
12862ac0c33Sjakob 				uncle->color = BLACK;
12962ac0c33Sjakob 
13062ac0c33Sjakob 				/* And the grandparent red... */
13162ac0c33Sjakob 				node->parent->parent->color = RED;
13262ac0c33Sjakob 
13362ac0c33Sjakob 				/* And continue fixing the grandparent */
13462ac0c33Sjakob 				node = node->parent->parent;
13562ac0c33Sjakob 			} else {				/* Our uncle is black... */
13662ac0c33Sjakob 				/* Are we the right child? */
13762ac0c33Sjakob 				if (node == node->parent->right) {
13862ac0c33Sjakob 					node = node->parent;
13962ac0c33Sjakob 					rbtree_rotate_left(rbtree, node);
14062ac0c33Sjakob 				}
14162ac0c33Sjakob 				/* Now we're the left child, repaint and rotate... */
14262ac0c33Sjakob 				node->parent->color = BLACK;
14362ac0c33Sjakob 				node->parent->parent->color = RED;
14462ac0c33Sjakob 				rbtree_rotate_right(rbtree, node->parent->parent);
14562ac0c33Sjakob 			}
14662ac0c33Sjakob 		} else {
14762ac0c33Sjakob 			uncle = node->parent->parent->left;
14862ac0c33Sjakob 
14962ac0c33Sjakob 			/* If our uncle is red... */
15062ac0c33Sjakob 			if (uncle->color == RED) {
15162ac0c33Sjakob 				/* Paint the parent and the uncle black... */
15262ac0c33Sjakob 				node->parent->color = BLACK;
15362ac0c33Sjakob 				uncle->color = BLACK;
15462ac0c33Sjakob 
15562ac0c33Sjakob 				/* And the grandparent red... */
15662ac0c33Sjakob 				node->parent->parent->color = RED;
15762ac0c33Sjakob 
15862ac0c33Sjakob 				/* And continue fixing the grandparent */
15962ac0c33Sjakob 				node = node->parent->parent;
16062ac0c33Sjakob 			} else {				/* Our uncle is black... */
16162ac0c33Sjakob 				/* Are we the right child? */
16262ac0c33Sjakob 				if (node == node->parent->left) {
16362ac0c33Sjakob 					node = node->parent;
16462ac0c33Sjakob 					rbtree_rotate_right(rbtree, node);
16562ac0c33Sjakob 				}
16662ac0c33Sjakob 				/* Now we're the right child, repaint and rotate... */
16762ac0c33Sjakob 				node->parent->color = BLACK;
16862ac0c33Sjakob 				node->parent->parent->color = RED;
16962ac0c33Sjakob 				rbtree_rotate_left(rbtree, node->parent->parent);
17062ac0c33Sjakob 			}
17162ac0c33Sjakob 		}
17262ac0c33Sjakob 	}
17362ac0c33Sjakob 	rbtree->root->color = BLACK;
17462ac0c33Sjakob }
17562ac0c33Sjakob 
17662ac0c33Sjakob 
17762ac0c33Sjakob /*
17862ac0c33Sjakob  * Inserts a node into a red black tree.
17962ac0c33Sjakob  *
18062ac0c33Sjakob  * Returns NULL on failure or the pointer to the newly added node
18162ac0c33Sjakob  * otherwise.
18262ac0c33Sjakob  */
183*fe5fe5f6Sflorian rbnode_type *
rbtree_insert(rbtree_type * rbtree,rbnode_type * data)184*fe5fe5f6Sflorian rbtree_insert (rbtree_type *rbtree, rbnode_type *data)
18562ac0c33Sjakob {
18662ac0c33Sjakob 	/* XXX Not necessary, but keeps compiler quiet... */
18762ac0c33Sjakob 	int r = 0;
18862ac0c33Sjakob 
18962ac0c33Sjakob 	/* We start at the root of the tree */
190*fe5fe5f6Sflorian 	rbnode_type	*node = rbtree->root;
191*fe5fe5f6Sflorian 	rbnode_type	*parent = RBTREE_NULL;
19262ac0c33Sjakob 
19362ac0c33Sjakob 	/* Lets find the new parent... */
19462ac0c33Sjakob 	while (node != RBTREE_NULL) {
19562ac0c33Sjakob 		/* Compare two keys, do we have a duplicate? */
19662ac0c33Sjakob 		if ((r = rbtree->cmp(data->key, node->key)) == 0) {
19762ac0c33Sjakob 			return NULL;
19862ac0c33Sjakob 		}
19962ac0c33Sjakob 		parent = node;
20062ac0c33Sjakob 
20162ac0c33Sjakob 		if (r < 0) {
20262ac0c33Sjakob 			node = node->left;
20362ac0c33Sjakob 		} else {
20462ac0c33Sjakob 			node = node->right;
20562ac0c33Sjakob 		}
20662ac0c33Sjakob 	}
20762ac0c33Sjakob 
20862ac0c33Sjakob 	/* Initialize the new node */
20962ac0c33Sjakob 	data->parent = parent;
21062ac0c33Sjakob 	data->left = data->right = RBTREE_NULL;
21162ac0c33Sjakob 	data->color = RED;
21262ac0c33Sjakob 	rbtree->count++;
21362ac0c33Sjakob 
21462ac0c33Sjakob 	/* Insert it into the tree... */
21562ac0c33Sjakob 	if (parent != RBTREE_NULL) {
21662ac0c33Sjakob 		if (r < 0) {
21762ac0c33Sjakob 			parent->left = data;
21862ac0c33Sjakob 		} else {
21962ac0c33Sjakob 			parent->right = data;
22062ac0c33Sjakob 		}
22162ac0c33Sjakob 	} else {
22262ac0c33Sjakob 		rbtree->root = data;
22362ac0c33Sjakob 	}
22462ac0c33Sjakob 
22562ac0c33Sjakob 	/* Fix up the red-black properties... */
22662ac0c33Sjakob 	rbtree_insert_fixup(rbtree, data);
22762ac0c33Sjakob 
22862ac0c33Sjakob 	return data;
22962ac0c33Sjakob }
23062ac0c33Sjakob 
23162ac0c33Sjakob /*
23262ac0c33Sjakob  * Searches the red black tree, returns the data if key is found or NULL otherwise.
23362ac0c33Sjakob  *
23462ac0c33Sjakob  */
235*fe5fe5f6Sflorian rbnode_type *
rbtree_search(rbtree_type * rbtree,const void * key)236*fe5fe5f6Sflorian rbtree_search (rbtree_type *rbtree, const void *key)
23762ac0c33Sjakob {
238*fe5fe5f6Sflorian 	rbnode_type *node;
23962ac0c33Sjakob 
24062ac0c33Sjakob 	if (rbtree_find_less_equal(rbtree, key, &node)) {
24162ac0c33Sjakob 		return node;
24262ac0c33Sjakob 	} else {
24362ac0c33Sjakob 		return NULL;
24462ac0c33Sjakob 	}
24562ac0c33Sjakob }
24662ac0c33Sjakob 
24762ac0c33Sjakob /* helpers for delete */
swap_int8(uint8_t * x,uint8_t * y)24862ac0c33Sjakob static void swap_int8(uint8_t* x, uint8_t* y)
24962ac0c33Sjakob {
25062ac0c33Sjakob 	uint8_t t = *x; *x = *y; *y = t;
25162ac0c33Sjakob }
25262ac0c33Sjakob 
swap_np(rbnode_type ** x,rbnode_type ** y)253*fe5fe5f6Sflorian static void swap_np(rbnode_type** x, rbnode_type** y)
25462ac0c33Sjakob {
255*fe5fe5f6Sflorian 	rbnode_type* t = *x; *x = *y; *y = t;
25662ac0c33Sjakob }
25762ac0c33Sjakob 
change_parent_ptr(rbtree_type * rbtree,rbnode_type * parent,rbnode_type * old,rbnode_type * new)258*fe5fe5f6Sflorian static void change_parent_ptr(rbtree_type* rbtree, rbnode_type* parent, rbnode_type* old, rbnode_type* new)
25962ac0c33Sjakob {
26062ac0c33Sjakob 	if(parent == RBTREE_NULL)
26162ac0c33Sjakob 	{
26262ac0c33Sjakob 		assert(rbtree->root == old);
26362ac0c33Sjakob 		if(rbtree->root == old) rbtree->root = new;
26462ac0c33Sjakob 		return;
26562ac0c33Sjakob 	}
26662ac0c33Sjakob 	assert(parent->left == old || parent->right == old
26762ac0c33Sjakob 		|| parent->left == new || parent->right == new);
26862ac0c33Sjakob 	if(parent->left == old) parent->left = new;
26962ac0c33Sjakob 	if(parent->right == old) parent->right = new;
27062ac0c33Sjakob }
change_child_ptr(rbnode_type * child,rbnode_type * old,rbnode_type * new)271*fe5fe5f6Sflorian static void change_child_ptr(rbnode_type* child, rbnode_type* old, rbnode_type* new)
27262ac0c33Sjakob {
27362ac0c33Sjakob 	if(child == RBTREE_NULL) return;
27462ac0c33Sjakob 	assert(child->parent == old || child->parent == new);
27562ac0c33Sjakob 	if(child->parent == old) child->parent = new;
27662ac0c33Sjakob }
27762ac0c33Sjakob 
278*fe5fe5f6Sflorian rbnode_type*
rbtree_delete(rbtree_type * rbtree,const void * key)279*fe5fe5f6Sflorian rbtree_delete(rbtree_type *rbtree, const void *key)
28062ac0c33Sjakob {
281*fe5fe5f6Sflorian 	rbnode_type *to_delete;
282*fe5fe5f6Sflorian 	rbnode_type *child;
28362ac0c33Sjakob 	if((to_delete = rbtree_search(rbtree, key)) == 0) return 0;
28462ac0c33Sjakob 	rbtree->count--;
28562ac0c33Sjakob 
28662ac0c33Sjakob 	/* make sure we have at most one non-leaf child */
28762ac0c33Sjakob 	if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL)
28862ac0c33Sjakob 	{
28962ac0c33Sjakob 		/* swap with smallest from right subtree (or largest from left) */
290*fe5fe5f6Sflorian 		rbnode_type *smright = to_delete->right;
29162ac0c33Sjakob 		while(smright->left != RBTREE_NULL)
29262ac0c33Sjakob 			smright = smright->left;
29362ac0c33Sjakob 		/* swap the smright and to_delete elements in the tree,
294*fe5fe5f6Sflorian 		 * but the rbnode_type is first part of user data struct
29562ac0c33Sjakob 		 * so cannot just swap the keys and data pointers. Instead
29662ac0c33Sjakob 		 * readjust the pointers left,right,parent */
29762ac0c33Sjakob 
29862ac0c33Sjakob 		/* swap colors - colors are tied to the position in the tree */
29962ac0c33Sjakob 		swap_int8(&to_delete->color, &smright->color);
30062ac0c33Sjakob 
30162ac0c33Sjakob 		/* swap child pointers in parents of smright/to_delete */
30262ac0c33Sjakob 		change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
30362ac0c33Sjakob 		if(to_delete->right != smright)
30462ac0c33Sjakob 			change_parent_ptr(rbtree, smright->parent, smright, to_delete);
30562ac0c33Sjakob 
30662ac0c33Sjakob 		/* swap parent pointers in children of smright/to_delete */
30762ac0c33Sjakob 		change_child_ptr(smright->left, smright, to_delete);
30862ac0c33Sjakob 		change_child_ptr(smright->left, smright, to_delete);
30962ac0c33Sjakob 		change_child_ptr(smright->right, smright, to_delete);
31062ac0c33Sjakob 		change_child_ptr(smright->right, smright, to_delete);
31162ac0c33Sjakob 		change_child_ptr(to_delete->left, to_delete, smright);
31262ac0c33Sjakob 		if(to_delete->right != smright)
31362ac0c33Sjakob 			change_child_ptr(to_delete->right, to_delete, smright);
31462ac0c33Sjakob 		if(to_delete->right == smright)
31562ac0c33Sjakob 		{
31662ac0c33Sjakob 			/* set up so after swap they work */
31762ac0c33Sjakob 			to_delete->right = to_delete;
31862ac0c33Sjakob 			smright->parent = smright;
31962ac0c33Sjakob 		}
32062ac0c33Sjakob 
32162ac0c33Sjakob 		/* swap pointers in to_delete/smright nodes */
32262ac0c33Sjakob 		swap_np(&to_delete->parent, &smright->parent);
32362ac0c33Sjakob 		swap_np(&to_delete->left, &smright->left);
32462ac0c33Sjakob 		swap_np(&to_delete->right, &smright->right);
32562ac0c33Sjakob 
32662ac0c33Sjakob 		/* now delete to_delete (which is at the location where the smright previously was) */
32762ac0c33Sjakob 	}
32862ac0c33Sjakob 	assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
32962ac0c33Sjakob 
33062ac0c33Sjakob 	if(to_delete->left != RBTREE_NULL) child = to_delete->left;
33162ac0c33Sjakob 	else child = to_delete->right;
33262ac0c33Sjakob 
33362ac0c33Sjakob 	/* unlink to_delete from the tree, replace to_delete with child */
33462ac0c33Sjakob 	change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
33562ac0c33Sjakob 	change_child_ptr(child, to_delete, to_delete->parent);
33662ac0c33Sjakob 
33762ac0c33Sjakob 	if(to_delete->color == RED)
33862ac0c33Sjakob 	{
33962ac0c33Sjakob 		/* if node is red then the child (black) can be swapped in */
34062ac0c33Sjakob 	}
34162ac0c33Sjakob 	else if(child->color == RED)
34262ac0c33Sjakob 	{
34362ac0c33Sjakob 		/* change child to BLACK, removing a RED node is no problem */
34462ac0c33Sjakob 		if(child!=RBTREE_NULL) child->color = BLACK;
34562ac0c33Sjakob 	}
34662ac0c33Sjakob 	else rbtree_delete_fixup(rbtree, child, to_delete->parent);
34762ac0c33Sjakob 
34862ac0c33Sjakob 	/* unlink completely */
34962ac0c33Sjakob 	to_delete->parent = RBTREE_NULL;
35062ac0c33Sjakob 	to_delete->left = RBTREE_NULL;
35162ac0c33Sjakob 	to_delete->right = RBTREE_NULL;
35262ac0c33Sjakob 	to_delete->color = BLACK;
35362ac0c33Sjakob 	return to_delete;
35462ac0c33Sjakob }
35562ac0c33Sjakob 
rbtree_delete_fixup(rbtree_type * rbtree,rbnode_type * child,rbnode_type * child_parent)356*fe5fe5f6Sflorian static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, rbnode_type* child_parent)
35762ac0c33Sjakob {
358*fe5fe5f6Sflorian 	rbnode_type* sibling;
35962ac0c33Sjakob 	int go_up = 1;
36062ac0c33Sjakob 
36162ac0c33Sjakob 	/* determine sibling to the node that is one-black short */
36262ac0c33Sjakob 	if(child_parent->right == child) sibling = child_parent->left;
36362ac0c33Sjakob 	else sibling = child_parent->right;
36462ac0c33Sjakob 
36562ac0c33Sjakob 	while(go_up)
36662ac0c33Sjakob 	{
36762ac0c33Sjakob 		if(child_parent == RBTREE_NULL)
36862ac0c33Sjakob 		{
36962ac0c33Sjakob 			/* removed parent==black from root, every path, so ok */
37062ac0c33Sjakob 			return;
37162ac0c33Sjakob 		}
37262ac0c33Sjakob 
37362ac0c33Sjakob 		if(sibling->color == RED)
37462ac0c33Sjakob 		{	/* rotate to get a black sibling */
37562ac0c33Sjakob 			child_parent->color = RED;
37662ac0c33Sjakob 			sibling->color = BLACK;
37762ac0c33Sjakob 			if(child_parent->right == child)
37862ac0c33Sjakob 				rbtree_rotate_right(rbtree, child_parent);
37962ac0c33Sjakob 			else	rbtree_rotate_left(rbtree, child_parent);
38062ac0c33Sjakob 			/* new sibling after rotation */
38162ac0c33Sjakob 			if(child_parent->right == child) sibling = child_parent->left;
38262ac0c33Sjakob 			else sibling = child_parent->right;
38362ac0c33Sjakob 		}
38462ac0c33Sjakob 
38562ac0c33Sjakob 		if(child_parent->color == BLACK
38662ac0c33Sjakob 			&& sibling->color == BLACK
38762ac0c33Sjakob 			&& sibling->left->color == BLACK
38862ac0c33Sjakob 			&& sibling->right->color == BLACK)
38962ac0c33Sjakob 		{	/* fixup local with recolor of sibling */
39062ac0c33Sjakob 			if(sibling != RBTREE_NULL)
39162ac0c33Sjakob 				sibling->color = RED;
39262ac0c33Sjakob 
39362ac0c33Sjakob 			child = child_parent;
39462ac0c33Sjakob 			child_parent = child_parent->parent;
39562ac0c33Sjakob 			/* prepare to go up, new sibling */
39662ac0c33Sjakob 			if(child_parent->right == child) sibling = child_parent->left;
39762ac0c33Sjakob 			else sibling = child_parent->right;
39862ac0c33Sjakob 		}
39962ac0c33Sjakob 		else go_up = 0;
40062ac0c33Sjakob 	}
40162ac0c33Sjakob 
40262ac0c33Sjakob 	if(child_parent->color == RED
40362ac0c33Sjakob 		&& sibling->color == BLACK
40462ac0c33Sjakob 		&& sibling->left->color == BLACK
40562ac0c33Sjakob 		&& sibling->right->color == BLACK)
40662ac0c33Sjakob 	{
40762ac0c33Sjakob 		/* move red to sibling to rebalance */
40862ac0c33Sjakob 		if(sibling != RBTREE_NULL)
40962ac0c33Sjakob 			sibling->color = RED;
41062ac0c33Sjakob 		child_parent->color = BLACK;
41162ac0c33Sjakob 		return;
41262ac0c33Sjakob 	}
41362ac0c33Sjakob 	assert(sibling != RBTREE_NULL);
41462ac0c33Sjakob 
41562ac0c33Sjakob 	/* get a new sibling, by rotating at sibling. See which child
41662ac0c33Sjakob 	   of sibling is red */
41762ac0c33Sjakob 	if(child_parent->right == child
41862ac0c33Sjakob 		&& sibling->color == BLACK
41962ac0c33Sjakob 		&& sibling->right->color == RED
42062ac0c33Sjakob 		&& sibling->left->color == BLACK)
42162ac0c33Sjakob 	{
42262ac0c33Sjakob 		sibling->color = RED;
42362ac0c33Sjakob 		sibling->right->color = BLACK;
42462ac0c33Sjakob 		rbtree_rotate_left(rbtree, sibling);
42562ac0c33Sjakob 		/* new sibling after rotation */
42662ac0c33Sjakob 		if(child_parent->right == child) sibling = child_parent->left;
42762ac0c33Sjakob 		else sibling = child_parent->right;
42862ac0c33Sjakob 	}
42962ac0c33Sjakob 	else if(child_parent->left == child
43062ac0c33Sjakob 		&& sibling->color == BLACK
43162ac0c33Sjakob 		&& sibling->left->color == RED
43262ac0c33Sjakob 		&& sibling->right->color == BLACK)
43362ac0c33Sjakob 	{
43462ac0c33Sjakob 		sibling->color = RED;
43562ac0c33Sjakob 		sibling->left->color = BLACK;
43662ac0c33Sjakob 		rbtree_rotate_right(rbtree, sibling);
43762ac0c33Sjakob 		/* new sibling after rotation */
43862ac0c33Sjakob 		if(child_parent->right == child) sibling = child_parent->left;
43962ac0c33Sjakob 		else sibling = child_parent->right;
44062ac0c33Sjakob 	}
44162ac0c33Sjakob 
44262ac0c33Sjakob 	/* now we have a black sibling with a red child. rotate and exchange colors. */
44362ac0c33Sjakob 	sibling->color = child_parent->color;
44462ac0c33Sjakob 	child_parent->color = BLACK;
44562ac0c33Sjakob 	if(child_parent->right == child)
44662ac0c33Sjakob 	{
44762ac0c33Sjakob 		assert(sibling->left->color == RED);
44862ac0c33Sjakob 		sibling->left->color = BLACK;
44962ac0c33Sjakob 		rbtree_rotate_right(rbtree, child_parent);
45062ac0c33Sjakob 	}
45162ac0c33Sjakob 	else
45262ac0c33Sjakob 	{
45362ac0c33Sjakob 		assert(sibling->right->color == RED);
45462ac0c33Sjakob 		sibling->right->color = BLACK;
45562ac0c33Sjakob 		rbtree_rotate_left(rbtree, child_parent);
45662ac0c33Sjakob 	}
45762ac0c33Sjakob }
45862ac0c33Sjakob 
45962ac0c33Sjakob int
rbtree_find_less_equal(rbtree_type * rbtree,const void * key,rbnode_type ** result)460*fe5fe5f6Sflorian rbtree_find_less_equal(rbtree_type *rbtree, const void *key, rbnode_type **result)
46162ac0c33Sjakob {
46262ac0c33Sjakob 	int r;
463*fe5fe5f6Sflorian 	rbnode_type *node;
46462ac0c33Sjakob 
46562ac0c33Sjakob 	assert(result);
46662ac0c33Sjakob 
46762ac0c33Sjakob 	/* We start at root... */
46862ac0c33Sjakob 	node = rbtree->root;
46962ac0c33Sjakob 
47062ac0c33Sjakob 	*result = NULL;
47162ac0c33Sjakob 
47262ac0c33Sjakob 	/* While there are children... */
47362ac0c33Sjakob 	while (node != RBTREE_NULL) {
47462ac0c33Sjakob 		r = rbtree->cmp(key, node->key);
47562ac0c33Sjakob 		if (r == 0) {
47662ac0c33Sjakob 			/* Exact match */
47762ac0c33Sjakob 			*result = node;
47862ac0c33Sjakob 			return 1;
47962ac0c33Sjakob 		}
48062ac0c33Sjakob 		if (r < 0) {
48162ac0c33Sjakob 			node = node->left;
48262ac0c33Sjakob 		} else {
48362ac0c33Sjakob 			/* Temporary match */
48462ac0c33Sjakob 			*result = node;
48562ac0c33Sjakob 			node = node->right;
48662ac0c33Sjakob 		}
48762ac0c33Sjakob 	}
48862ac0c33Sjakob 	return 0;
48962ac0c33Sjakob }
49062ac0c33Sjakob 
49162ac0c33Sjakob /*
49262ac0c33Sjakob  * Finds the first element in the red black tree
49362ac0c33Sjakob  *
49462ac0c33Sjakob  */
495*fe5fe5f6Sflorian rbnode_type *
rbtree_first(rbtree_type * rbtree)496*fe5fe5f6Sflorian rbtree_first (rbtree_type *rbtree)
49762ac0c33Sjakob {
498*fe5fe5f6Sflorian 	rbnode_type *node;
49962ac0c33Sjakob 
50062ac0c33Sjakob 	for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left);
50162ac0c33Sjakob 	return node;
50262ac0c33Sjakob }
50362ac0c33Sjakob 
504*fe5fe5f6Sflorian rbnode_type *
rbtree_last(rbtree_type * rbtree)505*fe5fe5f6Sflorian rbtree_last (rbtree_type *rbtree)
50662ac0c33Sjakob {
507*fe5fe5f6Sflorian 	rbnode_type *node;
50862ac0c33Sjakob 
50962ac0c33Sjakob 	for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right);
51062ac0c33Sjakob 	return node;
51162ac0c33Sjakob }
51262ac0c33Sjakob 
51362ac0c33Sjakob /*
51462ac0c33Sjakob  * Returns the next node...
51562ac0c33Sjakob  *
51662ac0c33Sjakob  */
517*fe5fe5f6Sflorian rbnode_type *
rbtree_next(rbnode_type * node)518*fe5fe5f6Sflorian rbtree_next (rbnode_type *node)
51962ac0c33Sjakob {
520*fe5fe5f6Sflorian 	rbnode_type *parent;
52162ac0c33Sjakob 
52262ac0c33Sjakob 	if (node->right != RBTREE_NULL) {
52362ac0c33Sjakob 		/* One right, then keep on going left... */
52462ac0c33Sjakob 		for (node = node->right; node->left != RBTREE_NULL; node = node->left);
52562ac0c33Sjakob 	} else {
52662ac0c33Sjakob 		parent = node->parent;
52762ac0c33Sjakob 		while (parent != RBTREE_NULL && node == parent->right) {
52862ac0c33Sjakob 			node = parent;
52962ac0c33Sjakob 			parent = parent->parent;
53062ac0c33Sjakob 		}
53162ac0c33Sjakob 		node = parent;
53262ac0c33Sjakob 	}
53362ac0c33Sjakob 	return node;
53462ac0c33Sjakob }
53562ac0c33Sjakob 
536*fe5fe5f6Sflorian rbnode_type *
rbtree_previous(rbnode_type * node)537*fe5fe5f6Sflorian rbtree_previous(rbnode_type *node)
53862ac0c33Sjakob {
539*fe5fe5f6Sflorian 	rbnode_type *parent;
54062ac0c33Sjakob 
54162ac0c33Sjakob 	if (node->left != RBTREE_NULL) {
54262ac0c33Sjakob 		/* One left, then keep on going right... */
54362ac0c33Sjakob 		for (node = node->left; node->right != RBTREE_NULL; node = node->right);
54462ac0c33Sjakob 	} else {
54562ac0c33Sjakob 		parent = node->parent;
54662ac0c33Sjakob 		while (parent != RBTREE_NULL && node == parent->left) {
54762ac0c33Sjakob 			node = parent;
54862ac0c33Sjakob 			parent = parent->parent;
54962ac0c33Sjakob 		}
55062ac0c33Sjakob 		node = parent;
55162ac0c33Sjakob 	}
55262ac0c33Sjakob 	return node;
55362ac0c33Sjakob }
554