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