xref: /dflybsd-src/contrib/ldns/rbtree.c (revision 7733acb50455a11cc2ee36edd926ff0fa3361e9a)
1825eb42bSJan Lentfer /*
2825eb42bSJan Lentfer  * rbtree.c -- generic red black tree
3825eb42bSJan Lentfer  *
4825eb42bSJan Lentfer  * Taken from Unbound, modified for ldns
5825eb42bSJan Lentfer  *
6825eb42bSJan Lentfer  * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
7825eb42bSJan Lentfer  *
8825eb42bSJan Lentfer  * This software is open source.
9825eb42bSJan Lentfer  *
10825eb42bSJan Lentfer  * Redistribution and use in source and binary forms, with or without
11825eb42bSJan Lentfer  * modification, are permitted provided that the following conditions
12825eb42bSJan Lentfer  * are met:
13825eb42bSJan Lentfer  *
14825eb42bSJan Lentfer  * Redistributions of source code must retain the above copyright notice,
15825eb42bSJan Lentfer  * this list of conditions and the following disclaimer.
16825eb42bSJan Lentfer  *
17825eb42bSJan Lentfer  * Redistributions in binary form must reproduce the above copyright notice,
18825eb42bSJan Lentfer  * this list of conditions and the following disclaimer in the documentation
19825eb42bSJan Lentfer  * and/or other materials provided with the distribution.
20825eb42bSJan Lentfer  *
21825eb42bSJan Lentfer  * Neither the name of the NLNET LABS nor the names of its contributors may
22825eb42bSJan Lentfer  * be used to endorse or promote products derived from this software without
23825eb42bSJan Lentfer  * specific prior written permission.
24825eb42bSJan Lentfer  *
25825eb42bSJan Lentfer  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
265340022aSzrj  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
275340022aSzrj  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
285340022aSzrj  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
295340022aSzrj  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
305340022aSzrj  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
315340022aSzrj  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
325340022aSzrj  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
335340022aSzrj  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
345340022aSzrj  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
355340022aSzrj  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36825eb42bSJan Lentfer  *
37825eb42bSJan Lentfer  */
38825eb42bSJan Lentfer 
39825eb42bSJan Lentfer /**
40825eb42bSJan Lentfer  * \file
41825eb42bSJan Lentfer  * Implementation of a redblack tree.
42825eb42bSJan Lentfer  */
43825eb42bSJan Lentfer 
44825eb42bSJan Lentfer #include <ldns/config.h>
45825eb42bSJan Lentfer #include <ldns/rbtree.h>
46d1b2b5caSJohn Marino #include <ldns/util.h>
47825eb42bSJan Lentfer #include <stdlib.h>
48825eb42bSJan Lentfer 
49825eb42bSJan Lentfer /** Node colour black */
50825eb42bSJan Lentfer #define	BLACK	0
51825eb42bSJan Lentfer /** Node colour red */
52825eb42bSJan Lentfer #define	RED	1
53825eb42bSJan Lentfer 
54825eb42bSJan Lentfer /** the NULL node, global alloc */
55825eb42bSJan Lentfer ldns_rbnode_t	ldns_rbtree_null_node = {
56825eb42bSJan Lentfer 	LDNS_RBTREE_NULL,	/* Parent.  */
57825eb42bSJan Lentfer 	LDNS_RBTREE_NULL,	/* Left.  */
58825eb42bSJan Lentfer 	LDNS_RBTREE_NULL,	/* Right.  */
59825eb42bSJan Lentfer 	NULL,			/* Key.  */
60825eb42bSJan Lentfer 	NULL,               /* Data. */
61825eb42bSJan Lentfer 	BLACK		     /* Color.  */
62825eb42bSJan Lentfer };
63825eb42bSJan Lentfer 
64825eb42bSJan Lentfer /** rotate subtree left (to preserve redblack property) */
65825eb42bSJan Lentfer static void ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
66825eb42bSJan Lentfer /** rotate subtree right (to preserve redblack property) */
67825eb42bSJan Lentfer static void ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
68825eb42bSJan Lentfer /** Fixup node colours when insert happened */
69825eb42bSJan Lentfer static void ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
70825eb42bSJan Lentfer /** Fixup node colours when delete happened */
71825eb42bSJan Lentfer static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent);
72825eb42bSJan Lentfer 
73825eb42bSJan Lentfer /*
74*ee791febSAntonio Huete Jimenez  * Creates a new red black tree, initializes and returns a pointer to it.
75825eb42bSJan Lentfer  *
76825eb42bSJan Lentfer  * Return NULL on failure.
77825eb42bSJan Lentfer  *
78825eb42bSJan Lentfer  */
79825eb42bSJan Lentfer ldns_rbtree_t *
ldns_rbtree_create(int (* cmpf)(const void *,const void *))80825eb42bSJan Lentfer ldns_rbtree_create (int (*cmpf)(const void *, const void *))
81825eb42bSJan Lentfer {
82825eb42bSJan Lentfer 	ldns_rbtree_t *rbtree;
83825eb42bSJan Lentfer 
84825eb42bSJan Lentfer 	/* Allocate memory for it */
85d1b2b5caSJohn Marino 	rbtree = (ldns_rbtree_t *) LDNS_MALLOC(ldns_rbtree_t);
86825eb42bSJan Lentfer 	if (!rbtree) {
87825eb42bSJan Lentfer 		return NULL;
88825eb42bSJan Lentfer 	}
89825eb42bSJan Lentfer 
90825eb42bSJan Lentfer 	/* Initialize it */
91825eb42bSJan Lentfer 	ldns_rbtree_init(rbtree, cmpf);
92825eb42bSJan Lentfer 
93825eb42bSJan Lentfer 	return rbtree;
94825eb42bSJan Lentfer }
95825eb42bSJan Lentfer 
96825eb42bSJan Lentfer void
ldns_rbtree_init(ldns_rbtree_t * rbtree,int (* cmpf)(const void *,const void *))97825eb42bSJan Lentfer ldns_rbtree_init(ldns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *))
98825eb42bSJan Lentfer {
99825eb42bSJan Lentfer 	/* Initialize it */
100825eb42bSJan Lentfer 	rbtree->root = LDNS_RBTREE_NULL;
101825eb42bSJan Lentfer 	rbtree->count = 0;
102825eb42bSJan Lentfer 	rbtree->cmp = cmpf;
103825eb42bSJan Lentfer }
104825eb42bSJan Lentfer 
105825eb42bSJan Lentfer void
ldns_rbtree_free(ldns_rbtree_t * rbtree)106825eb42bSJan Lentfer ldns_rbtree_free(ldns_rbtree_t *rbtree)
107825eb42bSJan Lentfer {
108d1b2b5caSJohn Marino 	LDNS_FREE(rbtree);
109825eb42bSJan Lentfer }
110825eb42bSJan Lentfer 
111825eb42bSJan Lentfer /*
112825eb42bSJan Lentfer  * Rotates the node to the left.
113825eb42bSJan Lentfer  *
114825eb42bSJan Lentfer  */
115825eb42bSJan Lentfer static void
ldns_rbtree_rotate_left(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)116825eb42bSJan Lentfer ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
117825eb42bSJan Lentfer {
118825eb42bSJan Lentfer 	ldns_rbnode_t *right = node->right;
119825eb42bSJan Lentfer 	node->right = right->left;
120825eb42bSJan Lentfer 	if (right->left != LDNS_RBTREE_NULL)
121825eb42bSJan Lentfer 		right->left->parent = node;
122825eb42bSJan Lentfer 
123825eb42bSJan Lentfer 	right->parent = node->parent;
124825eb42bSJan Lentfer 
125825eb42bSJan Lentfer 	if (node->parent != LDNS_RBTREE_NULL) {
126825eb42bSJan Lentfer 		if (node == node->parent->left) {
127825eb42bSJan Lentfer 			node->parent->left = right;
128825eb42bSJan Lentfer 		} else  {
129825eb42bSJan Lentfer 			node->parent->right = right;
130825eb42bSJan Lentfer 		}
131825eb42bSJan Lentfer 	} else {
132825eb42bSJan Lentfer 		rbtree->root = right;
133825eb42bSJan Lentfer 	}
134825eb42bSJan Lentfer 	right->left = node;
135825eb42bSJan Lentfer 	node->parent = right;
136825eb42bSJan Lentfer }
137825eb42bSJan Lentfer 
138825eb42bSJan Lentfer /*
139825eb42bSJan Lentfer  * Rotates the node to the right.
140825eb42bSJan Lentfer  *
141825eb42bSJan Lentfer  */
142825eb42bSJan Lentfer static void
ldns_rbtree_rotate_right(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)143825eb42bSJan Lentfer ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
144825eb42bSJan Lentfer {
145825eb42bSJan Lentfer 	ldns_rbnode_t *left = node->left;
146825eb42bSJan Lentfer 	node->left = left->right;
147825eb42bSJan Lentfer 	if (left->right != LDNS_RBTREE_NULL)
148825eb42bSJan Lentfer 		left->right->parent = node;
149825eb42bSJan Lentfer 
150825eb42bSJan Lentfer 	left->parent = node->parent;
151825eb42bSJan Lentfer 
152825eb42bSJan Lentfer 	if (node->parent != LDNS_RBTREE_NULL) {
153825eb42bSJan Lentfer 		if (node == node->parent->right) {
154825eb42bSJan Lentfer 			node->parent->right = left;
155825eb42bSJan Lentfer 		} else  {
156825eb42bSJan Lentfer 			node->parent->left = left;
157825eb42bSJan Lentfer 		}
158825eb42bSJan Lentfer 	} else {
159825eb42bSJan Lentfer 		rbtree->root = left;
160825eb42bSJan Lentfer 	}
161825eb42bSJan Lentfer 	left->right = node;
162825eb42bSJan Lentfer 	node->parent = left;
163825eb42bSJan Lentfer }
164825eb42bSJan Lentfer 
165825eb42bSJan Lentfer static void
ldns_rbtree_insert_fixup(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)166825eb42bSJan Lentfer ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
167825eb42bSJan Lentfer {
168825eb42bSJan Lentfer 	ldns_rbnode_t	*uncle;
169825eb42bSJan Lentfer 
170825eb42bSJan Lentfer 	/* While not at the root and need fixing... */
171825eb42bSJan Lentfer 	while (node != rbtree->root && node->parent->color == RED) {
172825eb42bSJan Lentfer 		/* If our parent is left child of our grandparent... */
173825eb42bSJan Lentfer 		if (node->parent == node->parent->parent->left) {
174825eb42bSJan Lentfer 			uncle = node->parent->parent->right;
175825eb42bSJan Lentfer 
176825eb42bSJan Lentfer 			/* If our uncle is red... */
177825eb42bSJan Lentfer 			if (uncle->color == RED) {
178825eb42bSJan Lentfer 				/* Paint the parent and the uncle black... */
179825eb42bSJan Lentfer 				node->parent->color = BLACK;
180825eb42bSJan Lentfer 				uncle->color = BLACK;
181825eb42bSJan Lentfer 
182825eb42bSJan Lentfer 				/* And the grandparent red... */
183825eb42bSJan Lentfer 				node->parent->parent->color = RED;
184825eb42bSJan Lentfer 
185825eb42bSJan Lentfer 				/* And continue fixing the grandparent */
186825eb42bSJan Lentfer 				node = node->parent->parent;
187825eb42bSJan Lentfer 			} else {				/* Our uncle is black... */
188825eb42bSJan Lentfer 				/* Are we the right child? */
189825eb42bSJan Lentfer 				if (node == node->parent->right) {
190825eb42bSJan Lentfer 					node = node->parent;
191825eb42bSJan Lentfer 					ldns_rbtree_rotate_left(rbtree, node);
192825eb42bSJan Lentfer 				}
193825eb42bSJan Lentfer 				/* Now we're the left child, repaint and rotate... */
194825eb42bSJan Lentfer 				node->parent->color = BLACK;
195825eb42bSJan Lentfer 				node->parent->parent->color = RED;
196825eb42bSJan Lentfer 				ldns_rbtree_rotate_right(rbtree, node->parent->parent);
197825eb42bSJan Lentfer 			}
198825eb42bSJan Lentfer 		} else {
199825eb42bSJan Lentfer 			uncle = node->parent->parent->left;
200825eb42bSJan Lentfer 
201825eb42bSJan Lentfer 			/* If our uncle is red... */
202825eb42bSJan Lentfer 			if (uncle->color == RED) {
203825eb42bSJan Lentfer 				/* Paint the parent and the uncle black... */
204825eb42bSJan Lentfer 				node->parent->color = BLACK;
205825eb42bSJan Lentfer 				uncle->color = BLACK;
206825eb42bSJan Lentfer 
207825eb42bSJan Lentfer 				/* And the grandparent red... */
208825eb42bSJan Lentfer 				node->parent->parent->color = RED;
209825eb42bSJan Lentfer 
210825eb42bSJan Lentfer 				/* And continue fixing the grandparent */
211825eb42bSJan Lentfer 				node = node->parent->parent;
212825eb42bSJan Lentfer 			} else {				/* Our uncle is black... */
213825eb42bSJan Lentfer 				/* Are we the right child? */
214825eb42bSJan Lentfer 				if (node == node->parent->left) {
215825eb42bSJan Lentfer 					node = node->parent;
216825eb42bSJan Lentfer 					ldns_rbtree_rotate_right(rbtree, node);
217825eb42bSJan Lentfer 				}
218825eb42bSJan Lentfer 				/* Now we're the right child, repaint and rotate... */
219825eb42bSJan Lentfer 				node->parent->color = BLACK;
220825eb42bSJan Lentfer 				node->parent->parent->color = RED;
221825eb42bSJan Lentfer 				ldns_rbtree_rotate_left(rbtree, node->parent->parent);
222825eb42bSJan Lentfer 			}
223825eb42bSJan Lentfer 		}
224825eb42bSJan Lentfer 	}
225825eb42bSJan Lentfer 	rbtree->root->color = BLACK;
226825eb42bSJan Lentfer }
227825eb42bSJan Lentfer 
228825eb42bSJan Lentfer void
ldns_rbtree_insert_vref(ldns_rbnode_t * data,void * rbtree)229825eb42bSJan Lentfer ldns_rbtree_insert_vref(ldns_rbnode_t *data, void *rbtree)
230825eb42bSJan Lentfer {
231825eb42bSJan Lentfer 	(void) ldns_rbtree_insert((ldns_rbtree_t *) rbtree,
232825eb42bSJan Lentfer 						 data);
233825eb42bSJan Lentfer }
234825eb42bSJan Lentfer 
235825eb42bSJan Lentfer /*
236825eb42bSJan Lentfer  * Inserts a node into a red black tree.
237825eb42bSJan Lentfer  *
238825eb42bSJan Lentfer  * Returns NULL on failure or the pointer to the newly added node
239825eb42bSJan Lentfer  * otherwise.
240825eb42bSJan Lentfer  */
241825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_insert(ldns_rbtree_t * rbtree,ldns_rbnode_t * data)242825eb42bSJan Lentfer ldns_rbtree_insert (ldns_rbtree_t *rbtree, ldns_rbnode_t *data)
243825eb42bSJan Lentfer {
244825eb42bSJan Lentfer 	/* XXX Not necessary, but keeps compiler quiet... */
245825eb42bSJan Lentfer 	int r = 0;
246825eb42bSJan Lentfer 
247825eb42bSJan Lentfer 	/* We start at the root of the tree */
248825eb42bSJan Lentfer 	ldns_rbnode_t	*node = rbtree->root;
249825eb42bSJan Lentfer 	ldns_rbnode_t	*parent = LDNS_RBTREE_NULL;
250825eb42bSJan Lentfer 
251825eb42bSJan Lentfer 	/* Lets find the new parent... */
252825eb42bSJan Lentfer 	while (node != LDNS_RBTREE_NULL) {
253825eb42bSJan Lentfer 		/* Compare two keys, do we have a duplicate? */
254825eb42bSJan Lentfer 		if ((r = rbtree->cmp(data->key, node->key)) == 0) {
255825eb42bSJan Lentfer 			return NULL;
256825eb42bSJan Lentfer 		}
257825eb42bSJan Lentfer 		parent = node;
258825eb42bSJan Lentfer 
259825eb42bSJan Lentfer 		if (r < 0) {
260825eb42bSJan Lentfer 			node = node->left;
261825eb42bSJan Lentfer 		} else {
262825eb42bSJan Lentfer 			node = node->right;
263825eb42bSJan Lentfer 		}
264825eb42bSJan Lentfer 	}
265825eb42bSJan Lentfer 
266825eb42bSJan Lentfer 	/* Initialize the new node */
267825eb42bSJan Lentfer 	data->parent = parent;
268825eb42bSJan Lentfer 	data->left = data->right = LDNS_RBTREE_NULL;
269825eb42bSJan Lentfer 	data->color = RED;
270825eb42bSJan Lentfer 	rbtree->count++;
271825eb42bSJan Lentfer 
272825eb42bSJan Lentfer 	/* Insert it into the tree... */
273825eb42bSJan Lentfer 	if (parent != LDNS_RBTREE_NULL) {
274825eb42bSJan Lentfer 		if (r < 0) {
275825eb42bSJan Lentfer 			parent->left = data;
276825eb42bSJan Lentfer 		} else {
277825eb42bSJan Lentfer 			parent->right = data;
278825eb42bSJan Lentfer 		}
279825eb42bSJan Lentfer 	} else {
280825eb42bSJan Lentfer 		rbtree->root = data;
281825eb42bSJan Lentfer 	}
282825eb42bSJan Lentfer 
283825eb42bSJan Lentfer 	/* Fix up the red-black properties... */
284825eb42bSJan Lentfer 	ldns_rbtree_insert_fixup(rbtree, data);
285825eb42bSJan Lentfer 
286825eb42bSJan Lentfer 	return data;
287825eb42bSJan Lentfer }
288825eb42bSJan Lentfer 
289825eb42bSJan Lentfer /*
290825eb42bSJan Lentfer  * Searches the red black tree, returns the data if key is found or NULL otherwise.
291825eb42bSJan Lentfer  *
292825eb42bSJan Lentfer  */
293825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_search(ldns_rbtree_t * rbtree,const void * key)294825eb42bSJan Lentfer ldns_rbtree_search (ldns_rbtree_t *rbtree, const void *key)
295825eb42bSJan Lentfer {
296825eb42bSJan Lentfer 	ldns_rbnode_t *node;
297825eb42bSJan Lentfer 
298825eb42bSJan Lentfer 	if (ldns_rbtree_find_less_equal(rbtree, key, &node)) {
299825eb42bSJan Lentfer 		return node;
300825eb42bSJan Lentfer 	} else {
301825eb42bSJan Lentfer 		return NULL;
302825eb42bSJan Lentfer 	}
303825eb42bSJan Lentfer }
304825eb42bSJan Lentfer 
305825eb42bSJan Lentfer /** helpers for delete: swap node colours */
swap_int8(uint8_t * x,uint8_t * y)306825eb42bSJan Lentfer static void swap_int8(uint8_t* x, uint8_t* y)
307825eb42bSJan Lentfer {
308825eb42bSJan Lentfer 	uint8_t t = *x; *x = *y; *y = t;
309825eb42bSJan Lentfer }
310825eb42bSJan Lentfer 
311825eb42bSJan Lentfer /** helpers for delete: swap node pointers */
swap_np(ldns_rbnode_t ** x,ldns_rbnode_t ** y)312825eb42bSJan Lentfer static void swap_np(ldns_rbnode_t** x, ldns_rbnode_t** y)
313825eb42bSJan Lentfer {
314825eb42bSJan Lentfer 	ldns_rbnode_t* t = *x; *x = *y; *y = t;
315825eb42bSJan Lentfer }
316825eb42bSJan Lentfer 
317825eb42bSJan Lentfer /** Update parent pointers of child trees of 'parent' */
change_parent_ptr(ldns_rbtree_t * rbtree,ldns_rbnode_t * parent,ldns_rbnode_t * old,ldns_rbnode_t * new)318825eb42bSJan Lentfer static void change_parent_ptr(ldns_rbtree_t* rbtree, ldns_rbnode_t* parent, ldns_rbnode_t* old, ldns_rbnode_t* new)
319825eb42bSJan Lentfer {
320825eb42bSJan Lentfer 	if(parent == LDNS_RBTREE_NULL)
321825eb42bSJan Lentfer 	{
322825eb42bSJan Lentfer 		if(rbtree->root == old) rbtree->root = new;
323825eb42bSJan Lentfer 		return;
324825eb42bSJan Lentfer 	}
325825eb42bSJan Lentfer 	if(parent->left == old) parent->left = new;
326825eb42bSJan Lentfer 	if(parent->right == old) parent->right = new;
327825eb42bSJan Lentfer }
328825eb42bSJan Lentfer /** Update parent pointer of a node 'child' */
change_child_ptr(ldns_rbnode_t * child,ldns_rbnode_t * old,ldns_rbnode_t * new)329825eb42bSJan Lentfer static void change_child_ptr(ldns_rbnode_t* child, ldns_rbnode_t* old, ldns_rbnode_t* new)
330825eb42bSJan Lentfer {
331825eb42bSJan Lentfer 	if(child == LDNS_RBTREE_NULL) return;
332825eb42bSJan Lentfer 	if(child->parent == old) child->parent = new;
333825eb42bSJan Lentfer }
334825eb42bSJan Lentfer 
335825eb42bSJan Lentfer ldns_rbnode_t*
ldns_rbtree_delete(ldns_rbtree_t * rbtree,const void * key)336825eb42bSJan Lentfer ldns_rbtree_delete(ldns_rbtree_t *rbtree, const void *key)
337825eb42bSJan Lentfer {
338825eb42bSJan Lentfer 	ldns_rbnode_t *to_delete;
339825eb42bSJan Lentfer 	ldns_rbnode_t *child;
340825eb42bSJan Lentfer 	if((to_delete = ldns_rbtree_search(rbtree, key)) == 0) return 0;
341825eb42bSJan Lentfer 	rbtree->count--;
342825eb42bSJan Lentfer 
343825eb42bSJan Lentfer 	/* make sure we have at most one non-leaf child */
344825eb42bSJan Lentfer 	if(to_delete->left != LDNS_RBTREE_NULL &&
345825eb42bSJan Lentfer 	   to_delete->right != LDNS_RBTREE_NULL)
346825eb42bSJan Lentfer 	{
347825eb42bSJan Lentfer 		/* swap with smallest from right subtree (or largest from left) */
348825eb42bSJan Lentfer 		ldns_rbnode_t *smright = to_delete->right;
349825eb42bSJan Lentfer 		while(smright->left != LDNS_RBTREE_NULL)
350825eb42bSJan Lentfer 			smright = smright->left;
351825eb42bSJan Lentfer 		/* swap the smright and to_delete elements in the tree,
352825eb42bSJan Lentfer 		 * but the ldns_rbnode_t is first part of user data struct
353825eb42bSJan Lentfer 		 * so cannot just swap the keys and data pointers. Instead
354825eb42bSJan Lentfer 		 * readjust the pointers left,right,parent */
355825eb42bSJan Lentfer 
356825eb42bSJan Lentfer 		/* swap colors - colors are tied to the position in the tree */
357825eb42bSJan Lentfer 		swap_int8(&to_delete->color, &smright->color);
358825eb42bSJan Lentfer 
359825eb42bSJan Lentfer 		/* swap child pointers in parents of smright/to_delete */
360825eb42bSJan Lentfer 		change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
361825eb42bSJan Lentfer 		if(to_delete->right != smright)
362825eb42bSJan Lentfer 			change_parent_ptr(rbtree, smright->parent, smright, to_delete);
363825eb42bSJan Lentfer 
364825eb42bSJan Lentfer 		/* swap parent pointers in children of smright/to_delete */
365825eb42bSJan Lentfer 		change_child_ptr(smright->left, smright, to_delete);
366825eb42bSJan Lentfer 		change_child_ptr(smright->left, smright, to_delete);
367825eb42bSJan Lentfer 		change_child_ptr(smright->right, smright, to_delete);
368825eb42bSJan Lentfer 		change_child_ptr(smright->right, smright, to_delete);
369825eb42bSJan Lentfer 		change_child_ptr(to_delete->left, to_delete, smright);
370825eb42bSJan Lentfer 		if(to_delete->right != smright)
371825eb42bSJan Lentfer 			change_child_ptr(to_delete->right, to_delete, smright);
372825eb42bSJan Lentfer 		if(to_delete->right == smright)
373825eb42bSJan Lentfer 		{
374825eb42bSJan Lentfer 			/* set up so after swap they work */
375825eb42bSJan Lentfer 			to_delete->right = to_delete;
376825eb42bSJan Lentfer 			smright->parent = smright;
377825eb42bSJan Lentfer 		}
378825eb42bSJan Lentfer 
379825eb42bSJan Lentfer 		/* swap pointers in to_delete/smright nodes */
380825eb42bSJan Lentfer 		swap_np(&to_delete->parent, &smright->parent);
381825eb42bSJan Lentfer 		swap_np(&to_delete->left, &smright->left);
382825eb42bSJan Lentfer 		swap_np(&to_delete->right, &smright->right);
383825eb42bSJan Lentfer 
384825eb42bSJan Lentfer 		/* now delete to_delete (which is at the location where the smright previously was) */
385825eb42bSJan Lentfer 	}
386825eb42bSJan Lentfer 
387825eb42bSJan Lentfer 	if(to_delete->left != LDNS_RBTREE_NULL) child = to_delete->left;
388825eb42bSJan Lentfer 	else child = to_delete->right;
389825eb42bSJan Lentfer 
390825eb42bSJan Lentfer 	/* unlink to_delete from the tree, replace to_delete with child */
391825eb42bSJan Lentfer 	change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
392825eb42bSJan Lentfer 	change_child_ptr(child, to_delete, to_delete->parent);
393825eb42bSJan Lentfer 
394825eb42bSJan Lentfer 	if(to_delete->color == RED)
395825eb42bSJan Lentfer 	{
396825eb42bSJan Lentfer 		/* if node is red then the child (black) can be swapped in */
397825eb42bSJan Lentfer 	}
398825eb42bSJan Lentfer 	else if(child->color == RED)
399825eb42bSJan Lentfer 	{
400825eb42bSJan Lentfer 		/* change child to BLACK, removing a RED node is no problem */
401825eb42bSJan Lentfer 		if(child!=LDNS_RBTREE_NULL) child->color = BLACK;
402825eb42bSJan Lentfer 	}
403825eb42bSJan Lentfer 	else ldns_rbtree_delete_fixup(rbtree, child, to_delete->parent);
404825eb42bSJan Lentfer 
405825eb42bSJan Lentfer 	/* unlink completely */
406825eb42bSJan Lentfer 	to_delete->parent = LDNS_RBTREE_NULL;
407825eb42bSJan Lentfer 	to_delete->left = LDNS_RBTREE_NULL;
408825eb42bSJan Lentfer 	to_delete->right = LDNS_RBTREE_NULL;
409825eb42bSJan Lentfer 	to_delete->color = BLACK;
410825eb42bSJan Lentfer 	return to_delete;
411825eb42bSJan Lentfer }
412825eb42bSJan Lentfer 
ldns_rbtree_delete_fixup(ldns_rbtree_t * rbtree,ldns_rbnode_t * child,ldns_rbnode_t * child_parent)413825eb42bSJan Lentfer static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent)
414825eb42bSJan Lentfer {
415825eb42bSJan Lentfer 	ldns_rbnode_t* sibling;
416825eb42bSJan Lentfer 	int go_up = 1;
417825eb42bSJan Lentfer 
418825eb42bSJan Lentfer 	/* determine sibling to the node that is one-black short */
419825eb42bSJan Lentfer 	if(child_parent->right == child) sibling = child_parent->left;
420825eb42bSJan Lentfer 	else sibling = child_parent->right;
421825eb42bSJan Lentfer 
422825eb42bSJan Lentfer 	while(go_up)
423825eb42bSJan Lentfer 	{
424825eb42bSJan Lentfer 		if(child_parent == LDNS_RBTREE_NULL)
425825eb42bSJan Lentfer 		{
426825eb42bSJan Lentfer 			/* removed parent==black from root, every path, so ok */
427825eb42bSJan Lentfer 			return;
428825eb42bSJan Lentfer 		}
429825eb42bSJan Lentfer 
430825eb42bSJan Lentfer 		if(sibling->color == RED)
431825eb42bSJan Lentfer 		{	/* rotate to get a black sibling */
432825eb42bSJan Lentfer 			child_parent->color = RED;
433825eb42bSJan Lentfer 			sibling->color = BLACK;
434825eb42bSJan Lentfer 			if(child_parent->right == child)
435825eb42bSJan Lentfer 				ldns_rbtree_rotate_right(rbtree, child_parent);
436825eb42bSJan Lentfer 			else	ldns_rbtree_rotate_left(rbtree, child_parent);
437825eb42bSJan Lentfer 			/* new sibling after rotation */
438825eb42bSJan Lentfer 			if(child_parent->right == child) sibling = child_parent->left;
439825eb42bSJan Lentfer 			else sibling = child_parent->right;
440825eb42bSJan Lentfer 		}
441825eb42bSJan Lentfer 
442825eb42bSJan Lentfer 		if(child_parent->color == BLACK
443825eb42bSJan Lentfer 			&& sibling->color == BLACK
444825eb42bSJan Lentfer 			&& sibling->left->color == BLACK
445825eb42bSJan Lentfer 			&& sibling->right->color == BLACK)
446825eb42bSJan Lentfer 		{	/* fixup local with recolor of sibling */
447825eb42bSJan Lentfer 			if(sibling != LDNS_RBTREE_NULL)
448825eb42bSJan Lentfer 				sibling->color = RED;
449825eb42bSJan Lentfer 
450825eb42bSJan Lentfer 			child = child_parent;
451825eb42bSJan Lentfer 			child_parent = child_parent->parent;
452825eb42bSJan Lentfer 			/* prepare to go up, new sibling */
453825eb42bSJan Lentfer 			if(child_parent->right == child) sibling = child_parent->left;
454825eb42bSJan Lentfer 			else sibling = child_parent->right;
455825eb42bSJan Lentfer 		}
456825eb42bSJan Lentfer 		else go_up = 0;
457825eb42bSJan Lentfer 	}
458825eb42bSJan Lentfer 
459825eb42bSJan Lentfer 	if(child_parent->color == RED
460825eb42bSJan Lentfer 		&& sibling->color == BLACK
461825eb42bSJan Lentfer 		&& sibling->left->color == BLACK
462825eb42bSJan Lentfer 		&& sibling->right->color == BLACK)
463825eb42bSJan Lentfer 	{
464825eb42bSJan Lentfer 		/* move red to sibling to rebalance */
465825eb42bSJan Lentfer 		if(sibling != LDNS_RBTREE_NULL)
466825eb42bSJan Lentfer 			sibling->color = RED;
467825eb42bSJan Lentfer 		child_parent->color = BLACK;
468825eb42bSJan Lentfer 		return;
469825eb42bSJan Lentfer 	}
470825eb42bSJan Lentfer 
471825eb42bSJan Lentfer 	/* get a new sibling, by rotating at sibling. See which child
472825eb42bSJan Lentfer 	   of sibling is red */
473825eb42bSJan Lentfer 	if(child_parent->right == child
474825eb42bSJan Lentfer 		&& sibling->color == BLACK
475825eb42bSJan Lentfer 		&& sibling->right->color == RED
476825eb42bSJan Lentfer 		&& sibling->left->color == BLACK)
477825eb42bSJan Lentfer 	{
478825eb42bSJan Lentfer 		sibling->color = RED;
479825eb42bSJan Lentfer 		sibling->right->color = BLACK;
480825eb42bSJan Lentfer 		ldns_rbtree_rotate_left(rbtree, sibling);
481825eb42bSJan Lentfer 		/* new sibling after rotation */
482825eb42bSJan Lentfer 		if(child_parent->right == child) sibling = child_parent->left;
483825eb42bSJan Lentfer 		else sibling = child_parent->right;
484825eb42bSJan Lentfer 	}
485825eb42bSJan Lentfer 	else if(child_parent->left == child
486825eb42bSJan Lentfer 		&& sibling->color == BLACK
487825eb42bSJan Lentfer 		&& sibling->left->color == RED
488825eb42bSJan Lentfer 		&& sibling->right->color == BLACK)
489825eb42bSJan Lentfer 	{
490825eb42bSJan Lentfer 		sibling->color = RED;
491825eb42bSJan Lentfer 		sibling->left->color = BLACK;
492825eb42bSJan Lentfer 		ldns_rbtree_rotate_right(rbtree, sibling);
493825eb42bSJan Lentfer 		/* new sibling after rotation */
494825eb42bSJan Lentfer 		if(child_parent->right == child) sibling = child_parent->left;
495825eb42bSJan Lentfer 		else sibling = child_parent->right;
496825eb42bSJan Lentfer 	}
497825eb42bSJan Lentfer 
498825eb42bSJan Lentfer 	/* now we have a black sibling with a red child. rotate and exchange colors. */
499825eb42bSJan Lentfer 	sibling->color = child_parent->color;
500825eb42bSJan Lentfer 	child_parent->color = BLACK;
501825eb42bSJan Lentfer 	if(child_parent->right == child)
502825eb42bSJan Lentfer 	{
503825eb42bSJan Lentfer 		sibling->left->color = BLACK;
504825eb42bSJan Lentfer 		ldns_rbtree_rotate_right(rbtree, child_parent);
505825eb42bSJan Lentfer 	}
506825eb42bSJan Lentfer 	else
507825eb42bSJan Lentfer 	{
508825eb42bSJan Lentfer 		sibling->right->color = BLACK;
509825eb42bSJan Lentfer 		ldns_rbtree_rotate_left(rbtree, child_parent);
510825eb42bSJan Lentfer 	}
511825eb42bSJan Lentfer }
512825eb42bSJan Lentfer 
513825eb42bSJan Lentfer int
ldns_rbtree_find_less_equal(ldns_rbtree_t * rbtree,const void * key,ldns_rbnode_t ** result)514825eb42bSJan Lentfer ldns_rbtree_find_less_equal(ldns_rbtree_t *rbtree, const void *key, ldns_rbnode_t **result)
515825eb42bSJan Lentfer {
516825eb42bSJan Lentfer 	int r;
517825eb42bSJan Lentfer 	ldns_rbnode_t *node;
518825eb42bSJan Lentfer 
519825eb42bSJan Lentfer 	/* We start at root... */
520825eb42bSJan Lentfer 	node = rbtree->root;
521825eb42bSJan Lentfer 
522825eb42bSJan Lentfer 	*result = NULL;
523825eb42bSJan Lentfer 
524825eb42bSJan Lentfer 	/* While there are children... */
525825eb42bSJan Lentfer 	while (node != LDNS_RBTREE_NULL) {
526825eb42bSJan Lentfer 		r = rbtree->cmp(key, node->key);
527825eb42bSJan Lentfer 		if (r == 0) {
528825eb42bSJan Lentfer 			/* Exact match */
529825eb42bSJan Lentfer 			*result = node;
530825eb42bSJan Lentfer 			return 1;
531825eb42bSJan Lentfer 		}
532825eb42bSJan Lentfer 		if (r < 0) {
533825eb42bSJan Lentfer 			node = node->left;
534825eb42bSJan Lentfer 		} else {
535825eb42bSJan Lentfer 			/* Temporary match */
536825eb42bSJan Lentfer 			*result = node;
537825eb42bSJan Lentfer 			node = node->right;
538825eb42bSJan Lentfer 		}
539825eb42bSJan Lentfer 	}
540825eb42bSJan Lentfer 	return 0;
541825eb42bSJan Lentfer }
542825eb42bSJan Lentfer 
543825eb42bSJan Lentfer /*
544825eb42bSJan Lentfer  * Finds the first element in the red black tree
545825eb42bSJan Lentfer  *
546825eb42bSJan Lentfer  */
547825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_first(const ldns_rbtree_t * rbtree)5485340022aSzrj ldns_rbtree_first(const ldns_rbtree_t *rbtree)
549825eb42bSJan Lentfer {
550ac996e71SJan Lentfer 	ldns_rbnode_t *node = rbtree->root;
551825eb42bSJan Lentfer 
552ac996e71SJan Lentfer 	if (rbtree->root != LDNS_RBTREE_NULL) {
553825eb42bSJan Lentfer 		for (node = rbtree->root; node->left != LDNS_RBTREE_NULL; node = node->left);
554ac996e71SJan Lentfer 	}
555825eb42bSJan Lentfer 	return node;
556825eb42bSJan Lentfer }
557825eb42bSJan Lentfer 
558825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_last(const ldns_rbtree_t * rbtree)5595340022aSzrj ldns_rbtree_last(const ldns_rbtree_t *rbtree)
560825eb42bSJan Lentfer {
561ac996e71SJan Lentfer 	ldns_rbnode_t *node = rbtree->root;
562825eb42bSJan Lentfer 
563ac996e71SJan Lentfer 	if (rbtree->root != LDNS_RBTREE_NULL) {
564825eb42bSJan Lentfer 		for (node = rbtree->root; node->right != LDNS_RBTREE_NULL; node = node->right);
565ac996e71SJan Lentfer 	}
566825eb42bSJan Lentfer 	return node;
567825eb42bSJan Lentfer }
568825eb42bSJan Lentfer 
569825eb42bSJan Lentfer /*
570825eb42bSJan Lentfer  * Returns the next node...
571825eb42bSJan Lentfer  *
572825eb42bSJan Lentfer  */
573825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_next(ldns_rbnode_t * node)574825eb42bSJan Lentfer ldns_rbtree_next(ldns_rbnode_t *node)
575825eb42bSJan Lentfer {
576825eb42bSJan Lentfer 	ldns_rbnode_t *parent;
577825eb42bSJan Lentfer 
578825eb42bSJan Lentfer 	if (node->right != LDNS_RBTREE_NULL) {
579825eb42bSJan Lentfer 		/* One right, then keep on going left... */
580825eb42bSJan Lentfer 		for (node = node->right;
581825eb42bSJan Lentfer 			node->left != LDNS_RBTREE_NULL;
582825eb42bSJan Lentfer 			node = node->left);
583825eb42bSJan Lentfer 	} else {
584825eb42bSJan Lentfer 		parent = node->parent;
585825eb42bSJan Lentfer 		while (parent != LDNS_RBTREE_NULL && node == parent->right) {
586825eb42bSJan Lentfer 			node = parent;
587825eb42bSJan Lentfer 			parent = parent->parent;
588825eb42bSJan Lentfer 		}
589825eb42bSJan Lentfer 		node = parent;
590825eb42bSJan Lentfer 	}
591825eb42bSJan Lentfer 	return node;
592825eb42bSJan Lentfer }
593825eb42bSJan Lentfer 
594825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_previous(ldns_rbnode_t * node)595825eb42bSJan Lentfer ldns_rbtree_previous(ldns_rbnode_t *node)
596825eb42bSJan Lentfer {
597825eb42bSJan Lentfer 	ldns_rbnode_t *parent;
598825eb42bSJan Lentfer 
599825eb42bSJan Lentfer 	if (node->left != LDNS_RBTREE_NULL) {
600825eb42bSJan Lentfer 		/* One left, then keep on going right... */
601825eb42bSJan Lentfer 		for (node = node->left;
602825eb42bSJan Lentfer 			node->right != LDNS_RBTREE_NULL;
603825eb42bSJan Lentfer 			node = node->right);
604825eb42bSJan Lentfer 	} else {
605825eb42bSJan Lentfer 		parent = node->parent;
606825eb42bSJan Lentfer 		while (parent != LDNS_RBTREE_NULL && node == parent->left) {
607825eb42bSJan Lentfer 			node = parent;
608825eb42bSJan Lentfer 			parent = parent->parent;
609825eb42bSJan Lentfer 		}
610825eb42bSJan Lentfer 		node = parent;
611825eb42bSJan Lentfer 	}
612825eb42bSJan Lentfer 	return node;
613825eb42bSJan Lentfer }
614825eb42bSJan Lentfer 
615825eb42bSJan Lentfer /**
616825eb42bSJan Lentfer  * split off elements number of elements from the start
617825eb42bSJan Lentfer  * of the name tree and return a new tree
618825eb42bSJan Lentfer  */
619825eb42bSJan Lentfer ldns_rbtree_t *
ldns_rbtree_split(ldns_rbtree_t * tree,size_t elements)620825eb42bSJan Lentfer ldns_rbtree_split(ldns_rbtree_t *tree,
621825eb42bSJan Lentfer 			   size_t elements)
622825eb42bSJan Lentfer {
623825eb42bSJan Lentfer 	ldns_rbtree_t *new_tree;
624825eb42bSJan Lentfer 	ldns_rbnode_t *cur_node;
625825eb42bSJan Lentfer 	ldns_rbnode_t *move_node;
626825eb42bSJan Lentfer 	size_t count = 0;
627825eb42bSJan Lentfer 
628825eb42bSJan Lentfer 	new_tree = ldns_rbtree_create(tree->cmp);
629825eb42bSJan Lentfer 
630825eb42bSJan Lentfer 	cur_node = ldns_rbtree_first(tree);
631825eb42bSJan Lentfer 	while (count < elements && cur_node != LDNS_RBTREE_NULL) {
632825eb42bSJan Lentfer 		move_node = ldns_rbtree_delete(tree, cur_node->key);
633fd185f4dSJan Lentfer 		(void)ldns_rbtree_insert(new_tree, move_node);
634825eb42bSJan Lentfer 		cur_node = ldns_rbtree_first(tree);
635825eb42bSJan Lentfer 		count++;
636825eb42bSJan Lentfer 	}
637825eb42bSJan Lentfer 
638825eb42bSJan Lentfer 	return new_tree;
639825eb42bSJan Lentfer }
640825eb42bSJan Lentfer 
641825eb42bSJan Lentfer /*
642825eb42bSJan Lentfer  * add all node from the second tree to the first (removing them from the
643825eb42bSJan Lentfer  * second), and fix up nsec(3)s if present
644825eb42bSJan Lentfer  */
645825eb42bSJan Lentfer void
ldns_rbtree_join(ldns_rbtree_t * tree1,ldns_rbtree_t * tree2)646825eb42bSJan Lentfer ldns_rbtree_join(ldns_rbtree_t *tree1, ldns_rbtree_t *tree2)
647825eb42bSJan Lentfer {
648825eb42bSJan Lentfer 	ldns_traverse_postorder(tree2, ldns_rbtree_insert_vref, tree1);
649825eb42bSJan Lentfer }
650825eb42bSJan Lentfer 
651825eb42bSJan Lentfer /** recursive descent traverse */
652825eb42bSJan Lentfer static void
traverse_post(void (* func)(ldns_rbnode_t *,void *),void * arg,ldns_rbnode_t * node)653825eb42bSJan Lentfer traverse_post(void (*func)(ldns_rbnode_t*, void*), void* arg,
654825eb42bSJan Lentfer 	ldns_rbnode_t* node)
655825eb42bSJan Lentfer {
656825eb42bSJan Lentfer 	if(!node || node == LDNS_RBTREE_NULL)
657825eb42bSJan Lentfer 		return;
658825eb42bSJan Lentfer 	/* recurse */
659825eb42bSJan Lentfer 	traverse_post(func, arg, node->left);
660825eb42bSJan Lentfer 	traverse_post(func, arg, node->right);
661825eb42bSJan Lentfer 	/* call user func */
662825eb42bSJan Lentfer 	(*func)(node, arg);
663825eb42bSJan Lentfer }
664825eb42bSJan Lentfer 
665825eb42bSJan Lentfer void
ldns_traverse_postorder(ldns_rbtree_t * tree,void (* func)(ldns_rbnode_t *,void *),void * arg)666825eb42bSJan Lentfer ldns_traverse_postorder(ldns_rbtree_t* tree,
667825eb42bSJan Lentfer 	void (*func)(ldns_rbnode_t*, void*), void* arg)
668825eb42bSJan Lentfer {
669825eb42bSJan Lentfer 	traverse_post(func, arg, tree->root);
670825eb42bSJan Lentfer }
671