diff options
Diffstat (limited to 'external/unbound/util/rbtree.c')
-rw-r--r-- | external/unbound/util/rbtree.c | 626 |
1 files changed, 0 insertions, 626 deletions
diff --git a/external/unbound/util/rbtree.c b/external/unbound/util/rbtree.c deleted file mode 100644 index f031c9a13..000000000 --- a/external/unbound/util/rbtree.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - * rbtree.c -- generic red black tree - * - * Copyright (c) 2001-2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/** - * \file - * Implementation of a redblack tree. - */ - -#include "config.h" -#include "log.h" -#include "fptr_wlist.h" -#include "util/rbtree.h" - -/** Node colour black */ -#define BLACK 0 -/** Node colour red */ -#define RED 1 - -/** the NULL node, global alloc */ -rbnode_type rbtree_null_node = { - RBTREE_NULL, /* Parent. */ - RBTREE_NULL, /* Left. */ - RBTREE_NULL, /* Right. */ - NULL, /* Key. */ - BLACK /* Color. */ -}; - -/** rotate subtree left (to preserve redblack property) */ -static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node); -/** rotate subtree right (to preserve redblack property) */ -static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node); -/** Fixup node colours when insert happened */ -static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node); -/** Fixup node colours when delete happened */ -static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, - rbnode_type* child_parent); - -/* - * Creates a new red black tree, initializes and returns a pointer to it. - * - * Return NULL on failure. - * - */ -rbtree_type * -rbtree_create (int (*cmpf)(const void *, const void *)) -{ - rbtree_type *rbtree; - - /* Allocate memory for it */ - rbtree = (rbtree_type *) malloc(sizeof(rbtree_type)); - if (!rbtree) { - return NULL; - } - - /* Initialize it */ - rbtree_init(rbtree, cmpf); - - return rbtree; -} - -void -rbtree_init(rbtree_type *rbtree, int (*cmpf)(const void *, const void *)) -{ - /* Initialize it */ - rbtree->root = RBTREE_NULL; - rbtree->count = 0; - rbtree->cmp = cmpf; -} - -/* - * Rotates the node to the left. - * - */ -static void -rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node) -{ - rbnode_type *right = node->right; - node->right = right->left; - if (right->left != RBTREE_NULL) - right->left->parent = node; - - right->parent = node->parent; - - if (node->parent != RBTREE_NULL) { - if (node == node->parent->left) { - node->parent->left = right; - } else { - node->parent->right = right; - } - } else { - rbtree->root = right; - } - right->left = node; - node->parent = right; -} - -/* - * Rotates the node to the right. - * - */ -static void -rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node) -{ - rbnode_type *left = node->left; - node->left = left->right; - if (left->right != RBTREE_NULL) - left->right->parent = node; - - left->parent = node->parent; - - if (node->parent != RBTREE_NULL) { - if (node == node->parent->right) { - node->parent->right = left; - } else { - node->parent->left = left; - } - } else { - rbtree->root = left; - } - left->right = node; - node->parent = left; -} - -static void -rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node) -{ - rbnode_type *uncle; - - /* While not at the root and need fixing... */ - while (node != rbtree->root && node->parent->color == RED) { - /* If our parent is left child of our grandparent... */ - if (node->parent == node->parent->parent->left) { - uncle = node->parent->parent->right; - - /* If our uncle is red... */ - if (uncle->color == RED) { - /* Paint the parent and the uncle black... */ - node->parent->color = BLACK; - uncle->color = BLACK; - - /* And the grandparent red... */ - node->parent->parent->color = RED; - - /* And continue fixing the grandparent */ - node = node->parent->parent; - } else { /* Our uncle is black... */ - /* Are we the right child? */ - if (node == node->parent->right) { - node = node->parent; - rbtree_rotate_left(rbtree, node); - } - /* Now we're the left child, repaint and rotate... */ - node->parent->color = BLACK; - node->parent->parent->color = RED; - rbtree_rotate_right(rbtree, node->parent->parent); - } - } else { - uncle = node->parent->parent->left; - - /* If our uncle is red... */ - if (uncle->color == RED) { - /* Paint the parent and the uncle black... */ - node->parent->color = BLACK; - uncle->color = BLACK; - - /* And the grandparent red... */ - node->parent->parent->color = RED; - - /* And continue fixing the grandparent */ - node = node->parent->parent; - } else { /* Our uncle is black... */ - /* Are we the right child? */ - if (node == node->parent->left) { - node = node->parent; - rbtree_rotate_right(rbtree, node); - } - /* Now we're the right child, repaint and rotate... */ - node->parent->color = BLACK; - node->parent->parent->color = RED; - rbtree_rotate_left(rbtree, node->parent->parent); - } - } - } - rbtree->root->color = BLACK; -} - - -/* - * Inserts a node into a red black tree. - * - * Returns NULL on failure or the pointer to the newly added node - * otherwise. - */ -rbnode_type * -rbtree_insert (rbtree_type *rbtree, rbnode_type *data) -{ - /* XXX Not necessary, but keeps compiler quiet... */ - int r = 0; - - /* We start at the root of the tree */ - rbnode_type *node = rbtree->root; - rbnode_type *parent = RBTREE_NULL; - - fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp)); - /* Lets find the new parent... */ - while (node != RBTREE_NULL) { - /* Compare two keys, do we have a duplicate? */ - if ((r = rbtree->cmp(data->key, node->key)) == 0) { - return NULL; - } - parent = node; - - if (r < 0) { - node = node->left; - } else { - node = node->right; - } - } - - /* Initialize the new node */ - data->parent = parent; - data->left = data->right = RBTREE_NULL; - data->color = RED; - rbtree->count++; - - /* Insert it into the tree... */ - if (parent != RBTREE_NULL) { - if (r < 0) { - parent->left = data; - } else { - parent->right = data; - } - } else { - rbtree->root = data; - } - - /* Fix up the red-black properties... */ - rbtree_insert_fixup(rbtree, data); - - return data; -} - -/* - * Searches the red black tree, returns the data if key is found or NULL otherwise. - * - */ -rbnode_type * -rbtree_search (rbtree_type *rbtree, const void *key) -{ - rbnode_type *node; - - if (rbtree_find_less_equal(rbtree, key, &node)) { - return node; - } else { - return NULL; - } -} - -/** helpers for delete: swap node colours */ -static void swap_int8(uint8_t* x, uint8_t* y) -{ - uint8_t t = *x; *x = *y; *y = t; -} - -/** helpers for delete: swap node pointers */ -static void swap_np(rbnode_type** x, rbnode_type** y) -{ - rbnode_type* t = *x; *x = *y; *y = t; -} - -/** Update parent pointers of child trees of 'parent' */ -static void change_parent_ptr(rbtree_type* rbtree, rbnode_type* parent, - rbnode_type* old, rbnode_type* new) -{ - if(parent == RBTREE_NULL) - { - log_assert(rbtree->root == old); - if(rbtree->root == old) rbtree->root = new; - return; - } - log_assert(parent->left == old || parent->right == old - || parent->left == new || parent->right == new); - if(parent->left == old) parent->left = new; - if(parent->right == old) parent->right = new; -} -/** Update parent pointer of a node 'child' */ -static void change_child_ptr(rbnode_type* child, rbnode_type* old, - rbnode_type* new) -{ - if(child == RBTREE_NULL) return; - log_assert(child->parent == old || child->parent == new); - if(child->parent == old) child->parent = new; -} - -rbnode_type* -rbtree_delete(rbtree_type *rbtree, const void *key) -{ - rbnode_type *to_delete; - rbnode_type *child; - if((to_delete = rbtree_search(rbtree, key)) == 0) return 0; - rbtree->count--; - - /* make sure we have at most one non-leaf child */ - if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL) - { - /* swap with smallest from right subtree (or largest from left) */ - rbnode_type *smright = to_delete->right; - while(smright->left != RBTREE_NULL) - smright = smright->left; - /* swap the smright and to_delete elements in the tree, - * but the rbnode_type is first part of user data struct - * so cannot just swap the keys and data pointers. Instead - * readjust the pointers left,right,parent */ - - /* swap colors - colors are tied to the position in the tree */ - swap_int8(&to_delete->color, &smright->color); - - /* swap child pointers in parents of smright/to_delete */ - change_parent_ptr(rbtree, to_delete->parent, to_delete, smright); - if(to_delete->right != smright) - change_parent_ptr(rbtree, smright->parent, smright, to_delete); - - /* swap parent pointers in children of smright/to_delete */ - change_child_ptr(smright->left, smright, to_delete); - change_child_ptr(smright->left, smright, to_delete); - change_child_ptr(smright->right, smright, to_delete); - change_child_ptr(smright->right, smright, to_delete); - change_child_ptr(to_delete->left, to_delete, smright); - if(to_delete->right != smright) - change_child_ptr(to_delete->right, to_delete, smright); - if(to_delete->right == smright) - { - /* set up so after swap they work */ - to_delete->right = to_delete; - smright->parent = smright; - } - - /* swap pointers in to_delete/smright nodes */ - swap_np(&to_delete->parent, &smright->parent); - swap_np(&to_delete->left, &smright->left); - swap_np(&to_delete->right, &smright->right); - - /* now delete to_delete (which is at the location where the smright previously was) */ - } - log_assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL); - - if(to_delete->left != RBTREE_NULL) child = to_delete->left; - else child = to_delete->right; - - /* unlink to_delete from the tree, replace to_delete with child */ - change_parent_ptr(rbtree, to_delete->parent, to_delete, child); - change_child_ptr(child, to_delete, to_delete->parent); - - if(to_delete->color == RED) - { - /* if node is red then the child (black) can be swapped in */ - } - else if(child->color == RED) - { - /* change child to BLACK, removing a RED node is no problem */ - if(child!=RBTREE_NULL) child->color = BLACK; - } - else rbtree_delete_fixup(rbtree, child, to_delete->parent); - - /* unlink completely */ - to_delete->parent = RBTREE_NULL; - to_delete->left = RBTREE_NULL; - to_delete->right = RBTREE_NULL; - to_delete->color = BLACK; - return to_delete; -} - -static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, - rbnode_type* child_parent) -{ - rbnode_type* sibling; - int go_up = 1; - - /* determine sibling to the node that is one-black short */ - if(child_parent->right == child) sibling = child_parent->left; - else sibling = child_parent->right; - - while(go_up) - { - if(child_parent == RBTREE_NULL) - { - /* removed parent==black from root, every path, so ok */ - return; - } - - if(sibling->color == RED) - { /* rotate to get a black sibling */ - child_parent->color = RED; - sibling->color = BLACK; - if(child_parent->right == child) - rbtree_rotate_right(rbtree, child_parent); - else rbtree_rotate_left(rbtree, child_parent); - /* new sibling after rotation */ - if(child_parent->right == child) sibling = child_parent->left; - else sibling = child_parent->right; - } - - if(child_parent->color == BLACK - && sibling->color == BLACK - && sibling->left->color == BLACK - && sibling->right->color == BLACK) - { /* fixup local with recolor of sibling */ - if(sibling != RBTREE_NULL) - sibling->color = RED; - - child = child_parent; - child_parent = child_parent->parent; - /* prepare to go up, new sibling */ - if(child_parent->right == child) sibling = child_parent->left; - else sibling = child_parent->right; - } - else go_up = 0; - } - - if(child_parent->color == RED - && sibling->color == BLACK - && sibling->left->color == BLACK - && sibling->right->color == BLACK) - { - /* move red to sibling to rebalance */ - if(sibling != RBTREE_NULL) - sibling->color = RED; - child_parent->color = BLACK; - return; - } - log_assert(sibling != RBTREE_NULL); - - /* get a new sibling, by rotating at sibling. See which child - of sibling is red */ - if(child_parent->right == child - && sibling->color == BLACK - && sibling->right->color == RED - && sibling->left->color == BLACK) - { - sibling->color = RED; - sibling->right->color = BLACK; - rbtree_rotate_left(rbtree, sibling); - /* new sibling after rotation */ - if(child_parent->right == child) sibling = child_parent->left; - else sibling = child_parent->right; - } - else if(child_parent->left == child - && sibling->color == BLACK - && sibling->left->color == RED - && sibling->right->color == BLACK) - { - sibling->color = RED; - sibling->left->color = BLACK; - rbtree_rotate_right(rbtree, sibling); - /* new sibling after rotation */ - if(child_parent->right == child) sibling = child_parent->left; - else sibling = child_parent->right; - } - - /* now we have a black sibling with a red child. rotate and exchange colors. */ - sibling->color = child_parent->color; - child_parent->color = BLACK; - if(child_parent->right == child) - { - log_assert(sibling->left->color == RED); - sibling->left->color = BLACK; - rbtree_rotate_right(rbtree, child_parent); - } - else - { - log_assert(sibling->right->color == RED); - sibling->right->color = BLACK; - rbtree_rotate_left(rbtree, child_parent); - } -} - -int -rbtree_find_less_equal(rbtree_type *rbtree, const void *key, - rbnode_type **result) -{ - int r; - rbnode_type *node; - - log_assert(result); - - /* We start at root... */ - node = rbtree->root; - - *result = NULL; - fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp)); - - /* While there are children... */ - while (node != RBTREE_NULL) { - r = rbtree->cmp(key, node->key); - if (r == 0) { - /* Exact match */ - *result = node; - return 1; - } - if (r < 0) { - node = node->left; - } else { - /* Temporary match */ - *result = node; - node = node->right; - } - } - return 0; -} - -/* - * Finds the first element in the red black tree - * - */ -rbnode_type * -rbtree_first (rbtree_type *rbtree) -{ - rbnode_type *node; - - for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left); - return node; -} - -rbnode_type * -rbtree_last (rbtree_type *rbtree) -{ - rbnode_type *node; - - for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right); - return node; -} - -/* - * Returns the next node... - * - */ -rbnode_type * -rbtree_next (rbnode_type *node) -{ - rbnode_type *parent; - - if (node->right != RBTREE_NULL) { - /* One right, then keep on going left... */ - for (node = node->right; node->left != RBTREE_NULL; node = node->left); - } else { - parent = node->parent; - while (parent != RBTREE_NULL && node == parent->right) { - node = parent; - parent = parent->parent; - } - node = parent; - } - return node; -} - -rbnode_type * -rbtree_previous(rbnode_type *node) -{ - rbnode_type *parent; - - if (node->left != RBTREE_NULL) { - /* One left, then keep on going right... */ - for (node = node->left; node->right != RBTREE_NULL; node = node->right); - } else { - parent = node->parent; - while (parent != RBTREE_NULL && node == parent->left) { - node = parent; - parent = parent->parent; - } - node = parent; - } - return node; -} - -/** recursive descent traverse */ -static void -traverse_post(void (*func)(rbnode_type*, void*), void* arg, rbnode_type* node) -{ - if(!node || node == RBTREE_NULL) - return; - /* recurse */ - traverse_post(func, arg, node->left); - traverse_post(func, arg, node->right); - /* call user func */ - (*func)(node, arg); -} - -void -traverse_postorder(rbtree_type* tree, void (*func)(rbnode_type*, void*), - void* arg) -{ - traverse_post(func, arg, tree->root); -} |