xref: /freebsd/contrib/ldns/rbtree.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * rbtree.c -- generic red black tree
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * Taken from Unbound, modified for ldns
57b5038d7SDag-Erling Smørgrav  *
67b5038d7SDag-Erling Smørgrav  * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
77b5038d7SDag-Erling Smørgrav  *
87b5038d7SDag-Erling Smørgrav  * This software is open source.
97b5038d7SDag-Erling Smørgrav  *
107b5038d7SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
117b5038d7SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
127b5038d7SDag-Erling Smørgrav  * are met:
137b5038d7SDag-Erling Smørgrav  *
147b5038d7SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
157b5038d7SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
167b5038d7SDag-Erling Smørgrav  *
177b5038d7SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
187b5038d7SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
197b5038d7SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
207b5038d7SDag-Erling Smørgrav  *
217b5038d7SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
227b5038d7SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
237b5038d7SDag-Erling Smørgrav  * specific prior written permission.
247b5038d7SDag-Erling Smørgrav  *
257b5038d7SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26986ba33cSDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27986ba33cSDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28986ba33cSDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29986ba33cSDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30986ba33cSDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
31986ba33cSDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32986ba33cSDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33986ba33cSDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34986ba33cSDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35986ba33cSDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
367b5038d7SDag-Erling Smørgrav  *
377b5038d7SDag-Erling Smørgrav  */
387b5038d7SDag-Erling Smørgrav 
397b5038d7SDag-Erling Smørgrav /**
407b5038d7SDag-Erling Smørgrav  * \file
417b5038d7SDag-Erling Smørgrav  * Implementation of a redblack tree.
427b5038d7SDag-Erling Smørgrav  */
437b5038d7SDag-Erling Smørgrav 
447b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
457b5038d7SDag-Erling Smørgrav #include <ldns/rbtree.h>
467b5038d7SDag-Erling Smørgrav #include <ldns/util.h>
477b5038d7SDag-Erling Smørgrav #include <stdlib.h>
487b5038d7SDag-Erling Smørgrav 
497b5038d7SDag-Erling Smørgrav /** Node colour black */
507b5038d7SDag-Erling Smørgrav #define	BLACK	0
517b5038d7SDag-Erling Smørgrav /** Node colour red */
527b5038d7SDag-Erling Smørgrav #define	RED	1
537b5038d7SDag-Erling Smørgrav 
547b5038d7SDag-Erling Smørgrav /** the NULL node, global alloc */
557b5038d7SDag-Erling Smørgrav ldns_rbnode_t	ldns_rbtree_null_node = {
567b5038d7SDag-Erling Smørgrav 	LDNS_RBTREE_NULL,	/* Parent.  */
577b5038d7SDag-Erling Smørgrav 	LDNS_RBTREE_NULL,	/* Left.  */
587b5038d7SDag-Erling Smørgrav 	LDNS_RBTREE_NULL,	/* Right.  */
597b5038d7SDag-Erling Smørgrav 	NULL,			/* Key.  */
607b5038d7SDag-Erling Smørgrav 	NULL,               /* Data. */
617b5038d7SDag-Erling Smørgrav 	BLACK		     /* Color.  */
627b5038d7SDag-Erling Smørgrav };
637b5038d7SDag-Erling Smørgrav 
647b5038d7SDag-Erling Smørgrav /** rotate subtree left (to preserve redblack property) */
657b5038d7SDag-Erling Smørgrav static void ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
667b5038d7SDag-Erling Smørgrav /** rotate subtree right (to preserve redblack property) */
677b5038d7SDag-Erling Smørgrav static void ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
687b5038d7SDag-Erling Smørgrav /** Fixup node colours when insert happened */
697b5038d7SDag-Erling Smørgrav static void ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
707b5038d7SDag-Erling Smørgrav /** Fixup node colours when delete happened */
717b5038d7SDag-Erling Smørgrav static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent);
727b5038d7SDag-Erling Smørgrav 
737b5038d7SDag-Erling Smørgrav /*
74*5afab0e5SDag-Erling Smørgrav  * Creates a new red black tree, initializes and returns a pointer to it.
757b5038d7SDag-Erling Smørgrav  *
767b5038d7SDag-Erling Smørgrav  * Return NULL on failure.
777b5038d7SDag-Erling Smørgrav  *
787b5038d7SDag-Erling Smørgrav  */
797b5038d7SDag-Erling Smørgrav ldns_rbtree_t *
ldns_rbtree_create(int (* cmpf)(const void *,const void *))807b5038d7SDag-Erling Smørgrav ldns_rbtree_create (int (*cmpf)(const void *, const void *))
817b5038d7SDag-Erling Smørgrav {
827b5038d7SDag-Erling Smørgrav 	ldns_rbtree_t *rbtree;
837b5038d7SDag-Erling Smørgrav 
847b5038d7SDag-Erling Smørgrav 	/* Allocate memory for it */
857b5038d7SDag-Erling Smørgrav 	rbtree = (ldns_rbtree_t *) LDNS_MALLOC(ldns_rbtree_t);
867b5038d7SDag-Erling Smørgrav 	if (!rbtree) {
877b5038d7SDag-Erling Smørgrav 		return NULL;
887b5038d7SDag-Erling Smørgrav 	}
897b5038d7SDag-Erling Smørgrav 
907b5038d7SDag-Erling Smørgrav 	/* Initialize it */
917b5038d7SDag-Erling Smørgrav 	ldns_rbtree_init(rbtree, cmpf);
927b5038d7SDag-Erling Smørgrav 
937b5038d7SDag-Erling Smørgrav 	return rbtree;
947b5038d7SDag-Erling Smørgrav }
957b5038d7SDag-Erling Smørgrav 
967b5038d7SDag-Erling Smørgrav void
ldns_rbtree_init(ldns_rbtree_t * rbtree,int (* cmpf)(const void *,const void *))977b5038d7SDag-Erling Smørgrav ldns_rbtree_init(ldns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *))
987b5038d7SDag-Erling Smørgrav {
997b5038d7SDag-Erling Smørgrav 	/* Initialize it */
1007b5038d7SDag-Erling Smørgrav 	rbtree->root = LDNS_RBTREE_NULL;
1017b5038d7SDag-Erling Smørgrav 	rbtree->count = 0;
1027b5038d7SDag-Erling Smørgrav 	rbtree->cmp = cmpf;
1037b5038d7SDag-Erling Smørgrav }
1047b5038d7SDag-Erling Smørgrav 
1057b5038d7SDag-Erling Smørgrav void
ldns_rbtree_free(ldns_rbtree_t * rbtree)1067b5038d7SDag-Erling Smørgrav ldns_rbtree_free(ldns_rbtree_t *rbtree)
1077b5038d7SDag-Erling Smørgrav {
1087b5038d7SDag-Erling Smørgrav 	LDNS_FREE(rbtree);
1097b5038d7SDag-Erling Smørgrav }
1107b5038d7SDag-Erling Smørgrav 
1117b5038d7SDag-Erling Smørgrav /*
1127b5038d7SDag-Erling Smørgrav  * Rotates the node to the left.
1137b5038d7SDag-Erling Smørgrav  *
1147b5038d7SDag-Erling Smørgrav  */
1157b5038d7SDag-Erling Smørgrav static void
ldns_rbtree_rotate_left(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)1167b5038d7SDag-Erling Smørgrav ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
1177b5038d7SDag-Erling Smørgrav {
1187b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *right = node->right;
1197b5038d7SDag-Erling Smørgrav 	node->right = right->left;
1207b5038d7SDag-Erling Smørgrav 	if (right->left != LDNS_RBTREE_NULL)
1217b5038d7SDag-Erling Smørgrav 		right->left->parent = node;
1227b5038d7SDag-Erling Smørgrav 
1237b5038d7SDag-Erling Smørgrav 	right->parent = node->parent;
1247b5038d7SDag-Erling Smørgrav 
1257b5038d7SDag-Erling Smørgrav 	if (node->parent != LDNS_RBTREE_NULL) {
1267b5038d7SDag-Erling Smørgrav 		if (node == node->parent->left) {
1277b5038d7SDag-Erling Smørgrav 			node->parent->left = right;
1287b5038d7SDag-Erling Smørgrav 		} else  {
1297b5038d7SDag-Erling Smørgrav 			node->parent->right = right;
1307b5038d7SDag-Erling Smørgrav 		}
1317b5038d7SDag-Erling Smørgrav 	} else {
1327b5038d7SDag-Erling Smørgrav 		rbtree->root = right;
1337b5038d7SDag-Erling Smørgrav 	}
1347b5038d7SDag-Erling Smørgrav 	right->left = node;
1357b5038d7SDag-Erling Smørgrav 	node->parent = right;
1367b5038d7SDag-Erling Smørgrav }
1377b5038d7SDag-Erling Smørgrav 
1387b5038d7SDag-Erling Smørgrav /*
1397b5038d7SDag-Erling Smørgrav  * Rotates the node to the right.
1407b5038d7SDag-Erling Smørgrav  *
1417b5038d7SDag-Erling Smørgrav  */
1427b5038d7SDag-Erling Smørgrav static void
ldns_rbtree_rotate_right(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)1437b5038d7SDag-Erling Smørgrav ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
1447b5038d7SDag-Erling Smørgrav {
1457b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *left = node->left;
1467b5038d7SDag-Erling Smørgrav 	node->left = left->right;
1477b5038d7SDag-Erling Smørgrav 	if (left->right != LDNS_RBTREE_NULL)
1487b5038d7SDag-Erling Smørgrav 		left->right->parent = node;
1497b5038d7SDag-Erling Smørgrav 
1507b5038d7SDag-Erling Smørgrav 	left->parent = node->parent;
1517b5038d7SDag-Erling Smørgrav 
1527b5038d7SDag-Erling Smørgrav 	if (node->parent != LDNS_RBTREE_NULL) {
1537b5038d7SDag-Erling Smørgrav 		if (node == node->parent->right) {
1547b5038d7SDag-Erling Smørgrav 			node->parent->right = left;
1557b5038d7SDag-Erling Smørgrav 		} else  {
1567b5038d7SDag-Erling Smørgrav 			node->parent->left = left;
1577b5038d7SDag-Erling Smørgrav 		}
1587b5038d7SDag-Erling Smørgrav 	} else {
1597b5038d7SDag-Erling Smørgrav 		rbtree->root = left;
1607b5038d7SDag-Erling Smørgrav 	}
1617b5038d7SDag-Erling Smørgrav 	left->right = node;
1627b5038d7SDag-Erling Smørgrav 	node->parent = left;
1637b5038d7SDag-Erling Smørgrav }
1647b5038d7SDag-Erling Smørgrav 
1657b5038d7SDag-Erling Smørgrav static void
ldns_rbtree_insert_fixup(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)1667b5038d7SDag-Erling Smørgrav ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
1677b5038d7SDag-Erling Smørgrav {
1687b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t	*uncle;
1697b5038d7SDag-Erling Smørgrav 
1707b5038d7SDag-Erling Smørgrav 	/* While not at the root and need fixing... */
1717b5038d7SDag-Erling Smørgrav 	while (node != rbtree->root && node->parent->color == RED) {
1727b5038d7SDag-Erling Smørgrav 		/* If our parent is left child of our grandparent... */
1737b5038d7SDag-Erling Smørgrav 		if (node->parent == node->parent->parent->left) {
1747b5038d7SDag-Erling Smørgrav 			uncle = node->parent->parent->right;
1757b5038d7SDag-Erling Smørgrav 
1767b5038d7SDag-Erling Smørgrav 			/* If our uncle is red... */
1777b5038d7SDag-Erling Smørgrav 			if (uncle->color == RED) {
1787b5038d7SDag-Erling Smørgrav 				/* Paint the parent and the uncle black... */
1797b5038d7SDag-Erling Smørgrav 				node->parent->color = BLACK;
1807b5038d7SDag-Erling Smørgrav 				uncle->color = BLACK;
1817b5038d7SDag-Erling Smørgrav 
1827b5038d7SDag-Erling Smørgrav 				/* And the grandparent red... */
1837b5038d7SDag-Erling Smørgrav 				node->parent->parent->color = RED;
1847b5038d7SDag-Erling Smørgrav 
1857b5038d7SDag-Erling Smørgrav 				/* And continue fixing the grandparent */
1867b5038d7SDag-Erling Smørgrav 				node = node->parent->parent;
1877b5038d7SDag-Erling Smørgrav 			} else {				/* Our uncle is black... */
1887b5038d7SDag-Erling Smørgrav 				/* Are we the right child? */
1897b5038d7SDag-Erling Smørgrav 				if (node == node->parent->right) {
1907b5038d7SDag-Erling Smørgrav 					node = node->parent;
1917b5038d7SDag-Erling Smørgrav 					ldns_rbtree_rotate_left(rbtree, node);
1927b5038d7SDag-Erling Smørgrav 				}
1937b5038d7SDag-Erling Smørgrav 				/* Now we're the left child, repaint and rotate... */
1947b5038d7SDag-Erling Smørgrav 				node->parent->color = BLACK;
1957b5038d7SDag-Erling Smørgrav 				node->parent->parent->color = RED;
1967b5038d7SDag-Erling Smørgrav 				ldns_rbtree_rotate_right(rbtree, node->parent->parent);
1977b5038d7SDag-Erling Smørgrav 			}
1987b5038d7SDag-Erling Smørgrav 		} else {
1997b5038d7SDag-Erling Smørgrav 			uncle = node->parent->parent->left;
2007b5038d7SDag-Erling Smørgrav 
2017b5038d7SDag-Erling Smørgrav 			/* If our uncle is red... */
2027b5038d7SDag-Erling Smørgrav 			if (uncle->color == RED) {
2037b5038d7SDag-Erling Smørgrav 				/* Paint the parent and the uncle black... */
2047b5038d7SDag-Erling Smørgrav 				node->parent->color = BLACK;
2057b5038d7SDag-Erling Smørgrav 				uncle->color = BLACK;
2067b5038d7SDag-Erling Smørgrav 
2077b5038d7SDag-Erling Smørgrav 				/* And the grandparent red... */
2087b5038d7SDag-Erling Smørgrav 				node->parent->parent->color = RED;
2097b5038d7SDag-Erling Smørgrav 
2107b5038d7SDag-Erling Smørgrav 				/* And continue fixing the grandparent */
2117b5038d7SDag-Erling Smørgrav 				node = node->parent->parent;
2127b5038d7SDag-Erling Smørgrav 			} else {				/* Our uncle is black... */
2137b5038d7SDag-Erling Smørgrav 				/* Are we the right child? */
2147b5038d7SDag-Erling Smørgrav 				if (node == node->parent->left) {
2157b5038d7SDag-Erling Smørgrav 					node = node->parent;
2167b5038d7SDag-Erling Smørgrav 					ldns_rbtree_rotate_right(rbtree, node);
2177b5038d7SDag-Erling Smørgrav 				}
2187b5038d7SDag-Erling Smørgrav 				/* Now we're the right child, repaint and rotate... */
2197b5038d7SDag-Erling Smørgrav 				node->parent->color = BLACK;
2207b5038d7SDag-Erling Smørgrav 				node->parent->parent->color = RED;
2217b5038d7SDag-Erling Smørgrav 				ldns_rbtree_rotate_left(rbtree, node->parent->parent);
2227b5038d7SDag-Erling Smørgrav 			}
2237b5038d7SDag-Erling Smørgrav 		}
2247b5038d7SDag-Erling Smørgrav 	}
2257b5038d7SDag-Erling Smørgrav 	rbtree->root->color = BLACK;
2267b5038d7SDag-Erling Smørgrav }
2277b5038d7SDag-Erling Smørgrav 
2287b5038d7SDag-Erling Smørgrav void
ldns_rbtree_insert_vref(ldns_rbnode_t * data,void * rbtree)2297b5038d7SDag-Erling Smørgrav ldns_rbtree_insert_vref(ldns_rbnode_t *data, void *rbtree)
2307b5038d7SDag-Erling Smørgrav {
2317b5038d7SDag-Erling Smørgrav 	(void) ldns_rbtree_insert((ldns_rbtree_t *) rbtree,
2327b5038d7SDag-Erling Smørgrav 						 data);
2337b5038d7SDag-Erling Smørgrav }
2347b5038d7SDag-Erling Smørgrav 
2357b5038d7SDag-Erling Smørgrav /*
2367b5038d7SDag-Erling Smørgrav  * Inserts a node into a red black tree.
2377b5038d7SDag-Erling Smørgrav  *
2387b5038d7SDag-Erling Smørgrav  * Returns NULL on failure or the pointer to the newly added node
2397b5038d7SDag-Erling Smørgrav  * otherwise.
2407b5038d7SDag-Erling Smørgrav  */
2417b5038d7SDag-Erling Smørgrav ldns_rbnode_t *
ldns_rbtree_insert(ldns_rbtree_t * rbtree,ldns_rbnode_t * data)2427b5038d7SDag-Erling Smørgrav ldns_rbtree_insert (ldns_rbtree_t *rbtree, ldns_rbnode_t *data)
2437b5038d7SDag-Erling Smørgrav {
2447b5038d7SDag-Erling Smørgrav 	/* XXX Not necessary, but keeps compiler quiet... */
2457b5038d7SDag-Erling Smørgrav 	int r = 0;
2467b5038d7SDag-Erling Smørgrav 
2477b5038d7SDag-Erling Smørgrav 	/* We start at the root of the tree */
2487b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t	*node = rbtree->root;
2497b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t	*parent = LDNS_RBTREE_NULL;
2507b5038d7SDag-Erling Smørgrav 
2517b5038d7SDag-Erling Smørgrav 	/* Lets find the new parent... */
2527b5038d7SDag-Erling Smørgrav 	while (node != LDNS_RBTREE_NULL) {
2537b5038d7SDag-Erling Smørgrav 		/* Compare two keys, do we have a duplicate? */
2547b5038d7SDag-Erling Smørgrav 		if ((r = rbtree->cmp(data->key, node->key)) == 0) {
2557b5038d7SDag-Erling Smørgrav 			return NULL;
2567b5038d7SDag-Erling Smørgrav 		}
2577b5038d7SDag-Erling Smørgrav 		parent = node;
2587b5038d7SDag-Erling Smørgrav 
2597b5038d7SDag-Erling Smørgrav 		if (r < 0) {
2607b5038d7SDag-Erling Smørgrav 			node = node->left;
2617b5038d7SDag-Erling Smørgrav 		} else {
2627b5038d7SDag-Erling Smørgrav 			node = node->right;
2637b5038d7SDag-Erling Smørgrav 		}
2647b5038d7SDag-Erling Smørgrav 	}
2657b5038d7SDag-Erling Smørgrav 
2667b5038d7SDag-Erling Smørgrav 	/* Initialize the new node */
2677b5038d7SDag-Erling Smørgrav 	data->parent = parent;
2687b5038d7SDag-Erling Smørgrav 	data->left = data->right = LDNS_RBTREE_NULL;
2697b5038d7SDag-Erling Smørgrav 	data->color = RED;
2707b5038d7SDag-Erling Smørgrav 	rbtree->count++;
2717b5038d7SDag-Erling Smørgrav 
2727b5038d7SDag-Erling Smørgrav 	/* Insert it into the tree... */
2737b5038d7SDag-Erling Smørgrav 	if (parent != LDNS_RBTREE_NULL) {
2747b5038d7SDag-Erling Smørgrav 		if (r < 0) {
2757b5038d7SDag-Erling Smørgrav 			parent->left = data;
2767b5038d7SDag-Erling Smørgrav 		} else {
2777b5038d7SDag-Erling Smørgrav 			parent->right = data;
2787b5038d7SDag-Erling Smørgrav 		}
2797b5038d7SDag-Erling Smørgrav 	} else {
2807b5038d7SDag-Erling Smørgrav 		rbtree->root = data;
2817b5038d7SDag-Erling Smørgrav 	}
2827b5038d7SDag-Erling Smørgrav 
2837b5038d7SDag-Erling Smørgrav 	/* Fix up the red-black properties... */
2847b5038d7SDag-Erling Smørgrav 	ldns_rbtree_insert_fixup(rbtree, data);
2857b5038d7SDag-Erling Smørgrav 
2867b5038d7SDag-Erling Smørgrav 	return data;
2877b5038d7SDag-Erling Smørgrav }
2887b5038d7SDag-Erling Smørgrav 
2897b5038d7SDag-Erling Smørgrav /*
2907b5038d7SDag-Erling Smørgrav  * Searches the red black tree, returns the data if key is found or NULL otherwise.
2917b5038d7SDag-Erling Smørgrav  *
2927b5038d7SDag-Erling Smørgrav  */
2937b5038d7SDag-Erling Smørgrav ldns_rbnode_t *
ldns_rbtree_search(ldns_rbtree_t * rbtree,const void * key)2947b5038d7SDag-Erling Smørgrav ldns_rbtree_search (ldns_rbtree_t *rbtree, const void *key)
2957b5038d7SDag-Erling Smørgrav {
2967b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *node;
2977b5038d7SDag-Erling Smørgrav 
2987b5038d7SDag-Erling Smørgrav 	if (ldns_rbtree_find_less_equal(rbtree, key, &node)) {
2997b5038d7SDag-Erling Smørgrav 		return node;
3007b5038d7SDag-Erling Smørgrav 	} else {
3017b5038d7SDag-Erling Smørgrav 		return NULL;
3027b5038d7SDag-Erling Smørgrav 	}
3037b5038d7SDag-Erling Smørgrav }
3047b5038d7SDag-Erling Smørgrav 
3057b5038d7SDag-Erling Smørgrav /** helpers for delete: swap node colours */
swap_int8(uint8_t * x,uint8_t * y)3067b5038d7SDag-Erling Smørgrav static void swap_int8(uint8_t* x, uint8_t* y)
3077b5038d7SDag-Erling Smørgrav {
3087b5038d7SDag-Erling Smørgrav 	uint8_t t = *x; *x = *y; *y = t;
3097b5038d7SDag-Erling Smørgrav }
3107b5038d7SDag-Erling Smørgrav 
3117b5038d7SDag-Erling Smørgrav /** helpers for delete: swap node pointers */
swap_np(ldns_rbnode_t ** x,ldns_rbnode_t ** y)3127b5038d7SDag-Erling Smørgrav static void swap_np(ldns_rbnode_t** x, ldns_rbnode_t** y)
3137b5038d7SDag-Erling Smørgrav {
3147b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t* t = *x; *x = *y; *y = t;
3157b5038d7SDag-Erling Smørgrav }
3167b5038d7SDag-Erling Smørgrav 
3177b5038d7SDag-Erling Smørgrav /** 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)3187b5038d7SDag-Erling Smørgrav static void change_parent_ptr(ldns_rbtree_t* rbtree, ldns_rbnode_t* parent, ldns_rbnode_t* old, ldns_rbnode_t* new)
3197b5038d7SDag-Erling Smørgrav {
3207b5038d7SDag-Erling Smørgrav 	if(parent == LDNS_RBTREE_NULL)
3217b5038d7SDag-Erling Smørgrav 	{
3227b5038d7SDag-Erling Smørgrav 		if(rbtree->root == old) rbtree->root = new;
3237b5038d7SDag-Erling Smørgrav 		return;
3247b5038d7SDag-Erling Smørgrav 	}
3257b5038d7SDag-Erling Smørgrav 	if(parent->left == old) parent->left = new;
3267b5038d7SDag-Erling Smørgrav 	if(parent->right == old) parent->right = new;
3277b5038d7SDag-Erling Smørgrav }
3287b5038d7SDag-Erling Smørgrav /** Update parent pointer of a node 'child' */
change_child_ptr(ldns_rbnode_t * child,ldns_rbnode_t * old,ldns_rbnode_t * new)3297b5038d7SDag-Erling Smørgrav static void change_child_ptr(ldns_rbnode_t* child, ldns_rbnode_t* old, ldns_rbnode_t* new)
3307b5038d7SDag-Erling Smørgrav {
3317b5038d7SDag-Erling Smørgrav 	if(child == LDNS_RBTREE_NULL) return;
3327b5038d7SDag-Erling Smørgrav 	if(child->parent == old) child->parent = new;
3337b5038d7SDag-Erling Smørgrav }
3347b5038d7SDag-Erling Smørgrav 
3357b5038d7SDag-Erling Smørgrav ldns_rbnode_t*
ldns_rbtree_delete(ldns_rbtree_t * rbtree,const void * key)3367b5038d7SDag-Erling Smørgrav ldns_rbtree_delete(ldns_rbtree_t *rbtree, const void *key)
3377b5038d7SDag-Erling Smørgrav {
3387b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *to_delete;
3397b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *child;
3407b5038d7SDag-Erling Smørgrav 	if((to_delete = ldns_rbtree_search(rbtree, key)) == 0) return 0;
3417b5038d7SDag-Erling Smørgrav 	rbtree->count--;
3427b5038d7SDag-Erling Smørgrav 
3437b5038d7SDag-Erling Smørgrav 	/* make sure we have at most one non-leaf child */
3447b5038d7SDag-Erling Smørgrav 	if(to_delete->left != LDNS_RBTREE_NULL &&
3457b5038d7SDag-Erling Smørgrav 	   to_delete->right != LDNS_RBTREE_NULL)
3467b5038d7SDag-Erling Smørgrav 	{
3477b5038d7SDag-Erling Smørgrav 		/* swap with smallest from right subtree (or largest from left) */
3487b5038d7SDag-Erling Smørgrav 		ldns_rbnode_t *smright = to_delete->right;
3497b5038d7SDag-Erling Smørgrav 		while(smright->left != LDNS_RBTREE_NULL)
3507b5038d7SDag-Erling Smørgrav 			smright = smright->left;
3517b5038d7SDag-Erling Smørgrav 		/* swap the smright and to_delete elements in the tree,
3527b5038d7SDag-Erling Smørgrav 		 * but the ldns_rbnode_t is first part of user data struct
3537b5038d7SDag-Erling Smørgrav 		 * so cannot just swap the keys and data pointers. Instead
3547b5038d7SDag-Erling Smørgrav 		 * readjust the pointers left,right,parent */
3557b5038d7SDag-Erling Smørgrav 
3567b5038d7SDag-Erling Smørgrav 		/* swap colors - colors are tied to the position in the tree */
3577b5038d7SDag-Erling Smørgrav 		swap_int8(&to_delete->color, &smright->color);
3587b5038d7SDag-Erling Smørgrav 
3597b5038d7SDag-Erling Smørgrav 		/* swap child pointers in parents of smright/to_delete */
3607b5038d7SDag-Erling Smørgrav 		change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
3617b5038d7SDag-Erling Smørgrav 		if(to_delete->right != smright)
3627b5038d7SDag-Erling Smørgrav 			change_parent_ptr(rbtree, smright->parent, smright, to_delete);
3637b5038d7SDag-Erling Smørgrav 
3647b5038d7SDag-Erling Smørgrav 		/* swap parent pointers in children of smright/to_delete */
3657b5038d7SDag-Erling Smørgrav 		change_child_ptr(smright->left, smright, to_delete);
3667b5038d7SDag-Erling Smørgrav 		change_child_ptr(smright->left, smright, to_delete);
3677b5038d7SDag-Erling Smørgrav 		change_child_ptr(smright->right, smright, to_delete);
3687b5038d7SDag-Erling Smørgrav 		change_child_ptr(smright->right, smright, to_delete);
3697b5038d7SDag-Erling Smørgrav 		change_child_ptr(to_delete->left, to_delete, smright);
3707b5038d7SDag-Erling Smørgrav 		if(to_delete->right != smright)
3717b5038d7SDag-Erling Smørgrav 			change_child_ptr(to_delete->right, to_delete, smright);
3727b5038d7SDag-Erling Smørgrav 		if(to_delete->right == smright)
3737b5038d7SDag-Erling Smørgrav 		{
3747b5038d7SDag-Erling Smørgrav 			/* set up so after swap they work */
3757b5038d7SDag-Erling Smørgrav 			to_delete->right = to_delete;
3767b5038d7SDag-Erling Smørgrav 			smright->parent = smright;
3777b5038d7SDag-Erling Smørgrav 		}
3787b5038d7SDag-Erling Smørgrav 
3797b5038d7SDag-Erling Smørgrav 		/* swap pointers in to_delete/smright nodes */
3807b5038d7SDag-Erling Smørgrav 		swap_np(&to_delete->parent, &smright->parent);
3817b5038d7SDag-Erling Smørgrav 		swap_np(&to_delete->left, &smright->left);
3827b5038d7SDag-Erling Smørgrav 		swap_np(&to_delete->right, &smright->right);
3837b5038d7SDag-Erling Smørgrav 
3847b5038d7SDag-Erling Smørgrav 		/* now delete to_delete (which is at the location where the smright previously was) */
3857b5038d7SDag-Erling Smørgrav 	}
3867b5038d7SDag-Erling Smørgrav 
3877b5038d7SDag-Erling Smørgrav 	if(to_delete->left != LDNS_RBTREE_NULL) child = to_delete->left;
3887b5038d7SDag-Erling Smørgrav 	else child = to_delete->right;
3897b5038d7SDag-Erling Smørgrav 
3907b5038d7SDag-Erling Smørgrav 	/* unlink to_delete from the tree, replace to_delete with child */
3917b5038d7SDag-Erling Smørgrav 	change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
3927b5038d7SDag-Erling Smørgrav 	change_child_ptr(child, to_delete, to_delete->parent);
3937b5038d7SDag-Erling Smørgrav 
3947b5038d7SDag-Erling Smørgrav 	if(to_delete->color == RED)
3957b5038d7SDag-Erling Smørgrav 	{
3967b5038d7SDag-Erling Smørgrav 		/* if node is red then the child (black) can be swapped in */
3977b5038d7SDag-Erling Smørgrav 	}
3987b5038d7SDag-Erling Smørgrav 	else if(child->color == RED)
3997b5038d7SDag-Erling Smørgrav 	{
4007b5038d7SDag-Erling Smørgrav 		/* change child to BLACK, removing a RED node is no problem */
4017b5038d7SDag-Erling Smørgrav 		if(child!=LDNS_RBTREE_NULL) child->color = BLACK;
4027b5038d7SDag-Erling Smørgrav 	}
4037b5038d7SDag-Erling Smørgrav 	else ldns_rbtree_delete_fixup(rbtree, child, to_delete->parent);
4047b5038d7SDag-Erling Smørgrav 
4057b5038d7SDag-Erling Smørgrav 	/* unlink completely */
4067b5038d7SDag-Erling Smørgrav 	to_delete->parent = LDNS_RBTREE_NULL;
4077b5038d7SDag-Erling Smørgrav 	to_delete->left = LDNS_RBTREE_NULL;
4087b5038d7SDag-Erling Smørgrav 	to_delete->right = LDNS_RBTREE_NULL;
4097b5038d7SDag-Erling Smørgrav 	to_delete->color = BLACK;
4107b5038d7SDag-Erling Smørgrav 	return to_delete;
4117b5038d7SDag-Erling Smørgrav }
4127b5038d7SDag-Erling Smørgrav 
ldns_rbtree_delete_fixup(ldns_rbtree_t * rbtree,ldns_rbnode_t * child,ldns_rbnode_t * child_parent)4137b5038d7SDag-Erling Smørgrav static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent)
4147b5038d7SDag-Erling Smørgrav {
4157b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t* sibling;
4167b5038d7SDag-Erling Smørgrav 	int go_up = 1;
4177b5038d7SDag-Erling Smørgrav 
4187b5038d7SDag-Erling Smørgrav 	/* determine sibling to the node that is one-black short */
4197b5038d7SDag-Erling Smørgrav 	if(child_parent->right == child) sibling = child_parent->left;
4207b5038d7SDag-Erling Smørgrav 	else sibling = child_parent->right;
4217b5038d7SDag-Erling Smørgrav 
4227b5038d7SDag-Erling Smørgrav 	while(go_up)
4237b5038d7SDag-Erling Smørgrav 	{
4247b5038d7SDag-Erling Smørgrav 		if(child_parent == LDNS_RBTREE_NULL)
4257b5038d7SDag-Erling Smørgrav 		{
4267b5038d7SDag-Erling Smørgrav 			/* removed parent==black from root, every path, so ok */
4277b5038d7SDag-Erling Smørgrav 			return;
4287b5038d7SDag-Erling Smørgrav 		}
4297b5038d7SDag-Erling Smørgrav 
4307b5038d7SDag-Erling Smørgrav 		if(sibling->color == RED)
4317b5038d7SDag-Erling Smørgrav 		{	/* rotate to get a black sibling */
4327b5038d7SDag-Erling Smørgrav 			child_parent->color = RED;
4337b5038d7SDag-Erling Smørgrav 			sibling->color = BLACK;
4347b5038d7SDag-Erling Smørgrav 			if(child_parent->right == child)
4357b5038d7SDag-Erling Smørgrav 				ldns_rbtree_rotate_right(rbtree, child_parent);
4367b5038d7SDag-Erling Smørgrav 			else	ldns_rbtree_rotate_left(rbtree, child_parent);
4377b5038d7SDag-Erling Smørgrav 			/* new sibling after rotation */
4387b5038d7SDag-Erling Smørgrav 			if(child_parent->right == child) sibling = child_parent->left;
4397b5038d7SDag-Erling Smørgrav 			else sibling = child_parent->right;
4407b5038d7SDag-Erling Smørgrav 		}
4417b5038d7SDag-Erling Smørgrav 
4427b5038d7SDag-Erling Smørgrav 		if(child_parent->color == BLACK
4437b5038d7SDag-Erling Smørgrav 			&& sibling->color == BLACK
4447b5038d7SDag-Erling Smørgrav 			&& sibling->left->color == BLACK
4457b5038d7SDag-Erling Smørgrav 			&& sibling->right->color == BLACK)
4467b5038d7SDag-Erling Smørgrav 		{	/* fixup local with recolor of sibling */
4477b5038d7SDag-Erling Smørgrav 			if(sibling != LDNS_RBTREE_NULL)
4487b5038d7SDag-Erling Smørgrav 				sibling->color = RED;
4497b5038d7SDag-Erling Smørgrav 
4507b5038d7SDag-Erling Smørgrav 			child = child_parent;
4517b5038d7SDag-Erling Smørgrav 			child_parent = child_parent->parent;
4527b5038d7SDag-Erling Smørgrav 			/* prepare to go up, new sibling */
4537b5038d7SDag-Erling Smørgrav 			if(child_parent->right == child) sibling = child_parent->left;
4547b5038d7SDag-Erling Smørgrav 			else sibling = child_parent->right;
4557b5038d7SDag-Erling Smørgrav 		}
4567b5038d7SDag-Erling Smørgrav 		else go_up = 0;
4577b5038d7SDag-Erling Smørgrav 	}
4587b5038d7SDag-Erling Smørgrav 
4597b5038d7SDag-Erling Smørgrav 	if(child_parent->color == RED
4607b5038d7SDag-Erling Smørgrav 		&& sibling->color == BLACK
4617b5038d7SDag-Erling Smørgrav 		&& sibling->left->color == BLACK
4627b5038d7SDag-Erling Smørgrav 		&& sibling->right->color == BLACK)
4637b5038d7SDag-Erling Smørgrav 	{
4647b5038d7SDag-Erling Smørgrav 		/* move red to sibling to rebalance */
4657b5038d7SDag-Erling Smørgrav 		if(sibling != LDNS_RBTREE_NULL)
4667b5038d7SDag-Erling Smørgrav 			sibling->color = RED;
4677b5038d7SDag-Erling Smørgrav 		child_parent->color = BLACK;
4687b5038d7SDag-Erling Smørgrav 		return;
4697b5038d7SDag-Erling Smørgrav 	}
4707b5038d7SDag-Erling Smørgrav 
4717b5038d7SDag-Erling Smørgrav 	/* get a new sibling, by rotating at sibling. See which child
4727b5038d7SDag-Erling Smørgrav 	   of sibling is red */
4737b5038d7SDag-Erling Smørgrav 	if(child_parent->right == child
4747b5038d7SDag-Erling Smørgrav 		&& sibling->color == BLACK
4757b5038d7SDag-Erling Smørgrav 		&& sibling->right->color == RED
4767b5038d7SDag-Erling Smørgrav 		&& sibling->left->color == BLACK)
4777b5038d7SDag-Erling Smørgrav 	{
4787b5038d7SDag-Erling Smørgrav 		sibling->color = RED;
4797b5038d7SDag-Erling Smørgrav 		sibling->right->color = BLACK;
4807b5038d7SDag-Erling Smørgrav 		ldns_rbtree_rotate_left(rbtree, sibling);
4817b5038d7SDag-Erling Smørgrav 		/* new sibling after rotation */
4827b5038d7SDag-Erling Smørgrav 		if(child_parent->right == child) sibling = child_parent->left;
4837b5038d7SDag-Erling Smørgrav 		else sibling = child_parent->right;
4847b5038d7SDag-Erling Smørgrav 	}
4857b5038d7SDag-Erling Smørgrav 	else if(child_parent->left == child
4867b5038d7SDag-Erling Smørgrav 		&& sibling->color == BLACK
4877b5038d7SDag-Erling Smørgrav 		&& sibling->left->color == RED
4887b5038d7SDag-Erling Smørgrav 		&& sibling->right->color == BLACK)
4897b5038d7SDag-Erling Smørgrav 	{
4907b5038d7SDag-Erling Smørgrav 		sibling->color = RED;
4917b5038d7SDag-Erling Smørgrav 		sibling->left->color = BLACK;
4927b5038d7SDag-Erling Smørgrav 		ldns_rbtree_rotate_right(rbtree, sibling);
4937b5038d7SDag-Erling Smørgrav 		/* new sibling after rotation */
4947b5038d7SDag-Erling Smørgrav 		if(child_parent->right == child) sibling = child_parent->left;
4957b5038d7SDag-Erling Smørgrav 		else sibling = child_parent->right;
4967b5038d7SDag-Erling Smørgrav 	}
4977b5038d7SDag-Erling Smørgrav 
4987b5038d7SDag-Erling Smørgrav 	/* now we have a black sibling with a red child. rotate and exchange colors. */
4997b5038d7SDag-Erling Smørgrav 	sibling->color = child_parent->color;
5007b5038d7SDag-Erling Smørgrav 	child_parent->color = BLACK;
5017b5038d7SDag-Erling Smørgrav 	if(child_parent->right == child)
5027b5038d7SDag-Erling Smørgrav 	{
5037b5038d7SDag-Erling Smørgrav 		sibling->left->color = BLACK;
5047b5038d7SDag-Erling Smørgrav 		ldns_rbtree_rotate_right(rbtree, child_parent);
5057b5038d7SDag-Erling Smørgrav 	}
5067b5038d7SDag-Erling Smørgrav 	else
5077b5038d7SDag-Erling Smørgrav 	{
5087b5038d7SDag-Erling Smørgrav 		sibling->right->color = BLACK;
5097b5038d7SDag-Erling Smørgrav 		ldns_rbtree_rotate_left(rbtree, child_parent);
5107b5038d7SDag-Erling Smørgrav 	}
5117b5038d7SDag-Erling Smørgrav }
5127b5038d7SDag-Erling Smørgrav 
5137b5038d7SDag-Erling Smørgrav int
ldns_rbtree_find_less_equal(ldns_rbtree_t * rbtree,const void * key,ldns_rbnode_t ** result)5147b5038d7SDag-Erling Smørgrav ldns_rbtree_find_less_equal(ldns_rbtree_t *rbtree, const void *key, ldns_rbnode_t **result)
5157b5038d7SDag-Erling Smørgrav {
5167b5038d7SDag-Erling Smørgrav 	int r;
5177b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *node;
5187b5038d7SDag-Erling Smørgrav 
5197b5038d7SDag-Erling Smørgrav 	/* We start at root... */
5207b5038d7SDag-Erling Smørgrav 	node = rbtree->root;
5217b5038d7SDag-Erling Smørgrav 
5227b5038d7SDag-Erling Smørgrav 	*result = NULL;
5237b5038d7SDag-Erling Smørgrav 
5247b5038d7SDag-Erling Smørgrav 	/* While there are children... */
5257b5038d7SDag-Erling Smørgrav 	while (node != LDNS_RBTREE_NULL) {
5267b5038d7SDag-Erling Smørgrav 		r = rbtree->cmp(key, node->key);
5277b5038d7SDag-Erling Smørgrav 		if (r == 0) {
5287b5038d7SDag-Erling Smørgrav 			/* Exact match */
5297b5038d7SDag-Erling Smørgrav 			*result = node;
5307b5038d7SDag-Erling Smørgrav 			return 1;
5317b5038d7SDag-Erling Smørgrav 		}
5327b5038d7SDag-Erling Smørgrav 		if (r < 0) {
5337b5038d7SDag-Erling Smørgrav 			node = node->left;
5347b5038d7SDag-Erling Smørgrav 		} else {
5357b5038d7SDag-Erling Smørgrav 			/* Temporary match */
5367b5038d7SDag-Erling Smørgrav 			*result = node;
5377b5038d7SDag-Erling Smørgrav 			node = node->right;
5387b5038d7SDag-Erling Smørgrav 		}
5397b5038d7SDag-Erling Smørgrav 	}
5407b5038d7SDag-Erling Smørgrav 	return 0;
5417b5038d7SDag-Erling Smørgrav }
5427b5038d7SDag-Erling Smørgrav 
5437b5038d7SDag-Erling Smørgrav /*
5447b5038d7SDag-Erling Smørgrav  * Finds the first element in the red black tree
5457b5038d7SDag-Erling Smørgrav  *
5467b5038d7SDag-Erling Smørgrav  */
5477b5038d7SDag-Erling Smørgrav ldns_rbnode_t *
ldns_rbtree_first(const ldns_rbtree_t * rbtree)548986ba33cSDag-Erling Smørgrav ldns_rbtree_first(const ldns_rbtree_t *rbtree)
5497b5038d7SDag-Erling Smørgrav {
5507b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *node = rbtree->root;
5517b5038d7SDag-Erling Smørgrav 
5527b5038d7SDag-Erling Smørgrav 	if (rbtree->root != LDNS_RBTREE_NULL) {
5537b5038d7SDag-Erling Smørgrav 		for (node = rbtree->root; node->left != LDNS_RBTREE_NULL; node = node->left);
5547b5038d7SDag-Erling Smørgrav 	}
5557b5038d7SDag-Erling Smørgrav 	return node;
5567b5038d7SDag-Erling Smørgrav }
5577b5038d7SDag-Erling Smørgrav 
5587b5038d7SDag-Erling Smørgrav ldns_rbnode_t *
ldns_rbtree_last(const ldns_rbtree_t * rbtree)559986ba33cSDag-Erling Smørgrav ldns_rbtree_last(const ldns_rbtree_t *rbtree)
5607b5038d7SDag-Erling Smørgrav {
5617b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *node = rbtree->root;
5627b5038d7SDag-Erling Smørgrav 
5637b5038d7SDag-Erling Smørgrav 	if (rbtree->root != LDNS_RBTREE_NULL) {
5647b5038d7SDag-Erling Smørgrav 		for (node = rbtree->root; node->right != LDNS_RBTREE_NULL; node = node->right);
5657b5038d7SDag-Erling Smørgrav 	}
5667b5038d7SDag-Erling Smørgrav 	return node;
5677b5038d7SDag-Erling Smørgrav }
5687b5038d7SDag-Erling Smørgrav 
5697b5038d7SDag-Erling Smørgrav /*
5707b5038d7SDag-Erling Smørgrav  * Returns the next node...
5717b5038d7SDag-Erling Smørgrav  *
5727b5038d7SDag-Erling Smørgrav  */
5737b5038d7SDag-Erling Smørgrav ldns_rbnode_t *
ldns_rbtree_next(ldns_rbnode_t * node)5747b5038d7SDag-Erling Smørgrav ldns_rbtree_next(ldns_rbnode_t *node)
5757b5038d7SDag-Erling Smørgrav {
5767b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *parent;
5777b5038d7SDag-Erling Smørgrav 
5787b5038d7SDag-Erling Smørgrav 	if (node->right != LDNS_RBTREE_NULL) {
5797b5038d7SDag-Erling Smørgrav 		/* One right, then keep on going left... */
5807b5038d7SDag-Erling Smørgrav 		for (node = node->right;
5817b5038d7SDag-Erling Smørgrav 			node->left != LDNS_RBTREE_NULL;
5827b5038d7SDag-Erling Smørgrav 			node = node->left);
5837b5038d7SDag-Erling Smørgrav 	} else {
5847b5038d7SDag-Erling Smørgrav 		parent = node->parent;
5857b5038d7SDag-Erling Smørgrav 		while (parent != LDNS_RBTREE_NULL && node == parent->right) {
5867b5038d7SDag-Erling Smørgrav 			node = parent;
5877b5038d7SDag-Erling Smørgrav 			parent = parent->parent;
5887b5038d7SDag-Erling Smørgrav 		}
5897b5038d7SDag-Erling Smørgrav 		node = parent;
5907b5038d7SDag-Erling Smørgrav 	}
5917b5038d7SDag-Erling Smørgrav 	return node;
5927b5038d7SDag-Erling Smørgrav }
5937b5038d7SDag-Erling Smørgrav 
5947b5038d7SDag-Erling Smørgrav ldns_rbnode_t *
ldns_rbtree_previous(ldns_rbnode_t * node)5957b5038d7SDag-Erling Smørgrav ldns_rbtree_previous(ldns_rbnode_t *node)
5967b5038d7SDag-Erling Smørgrav {
5977b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *parent;
5987b5038d7SDag-Erling Smørgrav 
5997b5038d7SDag-Erling Smørgrav 	if (node->left != LDNS_RBTREE_NULL) {
6007b5038d7SDag-Erling Smørgrav 		/* One left, then keep on going right... */
6017b5038d7SDag-Erling Smørgrav 		for (node = node->left;
6027b5038d7SDag-Erling Smørgrav 			node->right != LDNS_RBTREE_NULL;
6037b5038d7SDag-Erling Smørgrav 			node = node->right);
6047b5038d7SDag-Erling Smørgrav 	} else {
6057b5038d7SDag-Erling Smørgrav 		parent = node->parent;
6067b5038d7SDag-Erling Smørgrav 		while (parent != LDNS_RBTREE_NULL && node == parent->left) {
6077b5038d7SDag-Erling Smørgrav 			node = parent;
6087b5038d7SDag-Erling Smørgrav 			parent = parent->parent;
6097b5038d7SDag-Erling Smørgrav 		}
6107b5038d7SDag-Erling Smørgrav 		node = parent;
6117b5038d7SDag-Erling Smørgrav 	}
6127b5038d7SDag-Erling Smørgrav 	return node;
6137b5038d7SDag-Erling Smørgrav }
6147b5038d7SDag-Erling Smørgrav 
6157b5038d7SDag-Erling Smørgrav /**
6167b5038d7SDag-Erling Smørgrav  * split off elements number of elements from the start
6177b5038d7SDag-Erling Smørgrav  * of the name tree and return a new tree
6187b5038d7SDag-Erling Smørgrav  */
6197b5038d7SDag-Erling Smørgrav ldns_rbtree_t *
ldns_rbtree_split(ldns_rbtree_t * tree,size_t elements)6207b5038d7SDag-Erling Smørgrav ldns_rbtree_split(ldns_rbtree_t *tree,
6217b5038d7SDag-Erling Smørgrav 			   size_t elements)
6227b5038d7SDag-Erling Smørgrav {
6237b5038d7SDag-Erling Smørgrav 	ldns_rbtree_t *new_tree;
6247b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *cur_node;
6257b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *move_node;
6267b5038d7SDag-Erling Smørgrav 	size_t count = 0;
6277b5038d7SDag-Erling Smørgrav 
6287b5038d7SDag-Erling Smørgrav 	new_tree = ldns_rbtree_create(tree->cmp);
6297b5038d7SDag-Erling Smørgrav 
6307b5038d7SDag-Erling Smørgrav 	cur_node = ldns_rbtree_first(tree);
6317b5038d7SDag-Erling Smørgrav 	while (count < elements && cur_node != LDNS_RBTREE_NULL) {
6327b5038d7SDag-Erling Smørgrav 		move_node = ldns_rbtree_delete(tree, cur_node->key);
6337b5038d7SDag-Erling Smørgrav 		(void)ldns_rbtree_insert(new_tree, move_node);
6347b5038d7SDag-Erling Smørgrav 		cur_node = ldns_rbtree_first(tree);
6357b5038d7SDag-Erling Smørgrav 		count++;
6367b5038d7SDag-Erling Smørgrav 	}
6377b5038d7SDag-Erling Smørgrav 
6387b5038d7SDag-Erling Smørgrav 	return new_tree;
6397b5038d7SDag-Erling Smørgrav }
6407b5038d7SDag-Erling Smørgrav 
6417b5038d7SDag-Erling Smørgrav /*
6427b5038d7SDag-Erling Smørgrav  * add all node from the second tree to the first (removing them from the
6437b5038d7SDag-Erling Smørgrav  * second), and fix up nsec(3)s if present
6447b5038d7SDag-Erling Smørgrav  */
6457b5038d7SDag-Erling Smørgrav void
ldns_rbtree_join(ldns_rbtree_t * tree1,ldns_rbtree_t * tree2)6467b5038d7SDag-Erling Smørgrav ldns_rbtree_join(ldns_rbtree_t *tree1, ldns_rbtree_t *tree2)
6477b5038d7SDag-Erling Smørgrav {
6487b5038d7SDag-Erling Smørgrav 	ldns_traverse_postorder(tree2, ldns_rbtree_insert_vref, tree1);
6497b5038d7SDag-Erling Smørgrav }
6507b5038d7SDag-Erling Smørgrav 
6517b5038d7SDag-Erling Smørgrav /** recursive descent traverse */
6527b5038d7SDag-Erling Smørgrav static void
traverse_post(void (* func)(ldns_rbnode_t *,void *),void * arg,ldns_rbnode_t * node)6537b5038d7SDag-Erling Smørgrav traverse_post(void (*func)(ldns_rbnode_t*, void*), void* arg,
6547b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t* node)
6557b5038d7SDag-Erling Smørgrav {
6567b5038d7SDag-Erling Smørgrav 	if(!node || node == LDNS_RBTREE_NULL)
6577b5038d7SDag-Erling Smørgrav 		return;
6587b5038d7SDag-Erling Smørgrav 	/* recurse */
6597b5038d7SDag-Erling Smørgrav 	traverse_post(func, arg, node->left);
6607b5038d7SDag-Erling Smørgrav 	traverse_post(func, arg, node->right);
6617b5038d7SDag-Erling Smørgrav 	/* call user func */
6627b5038d7SDag-Erling Smørgrav 	(*func)(node, arg);
6637b5038d7SDag-Erling Smørgrav }
6647b5038d7SDag-Erling Smørgrav 
6657b5038d7SDag-Erling Smørgrav void
ldns_traverse_postorder(ldns_rbtree_t * tree,void (* func)(ldns_rbnode_t *,void *),void * arg)6667b5038d7SDag-Erling Smørgrav ldns_traverse_postorder(ldns_rbtree_t* tree,
6677b5038d7SDag-Erling Smørgrav 	void (*func)(ldns_rbnode_t*, void*), void* arg)
6687b5038d7SDag-Erling Smørgrav {
6697b5038d7SDag-Erling Smørgrav 	traverse_post(func, arg, tree->root);
6707b5038d7SDag-Erling Smørgrav }
671