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 26825eb42bSJan Lentfer * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27825eb42bSJan Lentfer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28825eb42bSJan Lentfer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 29825eb42bSJan Lentfer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30825eb42bSJan Lentfer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31825eb42bSJan Lentfer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32825eb42bSJan Lentfer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33825eb42bSJan Lentfer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34825eb42bSJan Lentfer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35825eb42bSJan Lentfer * 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> 46*d1b2b5caSJohn 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 /* 74825eb42bSJan Lentfer * Creates a new red black tree, intializes and returns a pointer to it. 75825eb42bSJan Lentfer * 76825eb42bSJan Lentfer * Return NULL on failure. 77825eb42bSJan Lentfer * 78825eb42bSJan Lentfer */ 79825eb42bSJan Lentfer ldns_rbtree_t * 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 */ 85*d1b2b5caSJohn 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 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 106825eb42bSJan Lentfer ldns_rbtree_free(ldns_rbtree_t *rbtree) 107825eb42bSJan Lentfer { 108*d1b2b5caSJohn 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 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 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 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 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 * 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 * 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 */ 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 */ 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' */ 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' */ 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* 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 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 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 * 548825eb42bSJan Lentfer ldns_rbtree_first (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 * 559825eb42bSJan Lentfer ldns_rbtree_last (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 * 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 * 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 * 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 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 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 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