diff options
Diffstat (limited to 'src/rbtree.c')
-rw-r--r-- | src/rbtree.c | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/src/rbtree.c b/src/rbtree.c new file mode 100644 index 0000000..360c879 --- /dev/null +++ b/src/rbtree.c @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2010-2017 Richard Braun. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Upstream site with license notes : + * http://git.sceen.net/rbraun/librbraun.git/ + */ + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> + +#include "macros.h" +#include "rbtree.h" +#include "rbtree_i.h" + +/* + * Return the index of a node in the children array of its parent. + * + * The parent parameter must not be NULL, and must be the parent of the + * given node. + */ +static inline int +rbtree_node_index(const struct rbtree_node *node, + const struct rbtree_node *parent) +{ + assert(parent != NULL); + assert((node == NULL) || (rbtree_node_parent(node) == parent)); + + if (parent->children[RBTREE_LEFT] == node) { + return RBTREE_LEFT; + } + + assert(parent->children[RBTREE_RIGHT] == node); + + return RBTREE_RIGHT; +} + +/* + * Return the color of a node. + */ +static inline int +rbtree_node_color(const struct rbtree_node *node) +{ + return node->parent & RBTREE_COLOR_MASK; +} + +/* + * Return true if the node is red. + */ +static inline int +rbtree_node_is_red(const struct rbtree_node *node) +{ + return rbtree_node_color(node) == RBTREE_COLOR_RED; +} + +/* + * Return true if the node is black. + */ +static inline int +rbtree_node_is_black(const struct rbtree_node *node) +{ + return rbtree_node_color(node) == RBTREE_COLOR_BLACK; +} + +/* + * Set the parent of a node, retaining its current color. + */ +static inline void +rbtree_node_set_parent(struct rbtree_node *node, struct rbtree_node *parent) +{ + assert(rbtree_node_check_alignment(node)); + assert(rbtree_node_check_alignment(parent)); + + node->parent = (uintptr_t)parent | (node->parent & RBTREE_COLOR_MASK); +} + +/* + * Set the color of a node, retaining its current parent. + */ +static inline void +rbtree_node_set_color(struct rbtree_node *node, int color) +{ + assert((color & ~RBTREE_COLOR_MASK) == 0); + node->parent = (node->parent & RBTREE_PARENT_MASK) | color; +} + +/* + * Set the color of a node to red, retaining its current parent. + */ +static inline void +rbtree_node_set_red(struct rbtree_node *node) +{ + rbtree_node_set_color(node, RBTREE_COLOR_RED); +} + +/* + * Set the color of a node to black, retaining its current parent. + */ +static inline void +rbtree_node_set_black(struct rbtree_node *node) +{ + rbtree_node_set_color(node, RBTREE_COLOR_BLACK); +} + +/* + * Return the left-most deepest child node of the given node. + */ +static struct rbtree_node * +rbtree_node_find_deepest(struct rbtree_node *node) +{ + struct rbtree_node *parent; + + assert(node != NULL); + + for (;;) { + parent = node; + node = node->children[RBTREE_LEFT]; + + if (node == NULL) { + node = parent->children[RBTREE_RIGHT]; + + if (node == NULL) { + return parent; + } + } + } +} + +/* + * Perform a tree rotation, rooted at the given node. + * + * The direction parameter defines the rotation direction and is either + * RBTREE_LEFT or RBTREE_RIGHT. + */ +static void +rbtree_rotate(struct rbtree *tree, struct rbtree_node *node, int direction) +{ + struct rbtree_node *parent, *rnode; + int left, right; + + left = direction; + right = 1 - left; + parent = rbtree_node_parent(node); + rnode = node->children[right]; + + node->children[right] = rnode->children[left]; + + if (rnode->children[left] != NULL) { + rbtree_node_set_parent(rnode->children[left], node); + } + + rnode->children[left] = node; + rbtree_node_set_parent(rnode, parent); + + if (unlikely(parent == NULL)) { + tree->root = rnode; + } else { + parent->children[rbtree_node_index(node, parent)] = rnode; + } + + rbtree_node_set_parent(node, rnode); +} + +void +rbtree_insert_rebalance(struct rbtree *tree, struct rbtree_node *parent, + int index, struct rbtree_node *node) +{ + struct rbtree_node *grand_parent, *uncle; + int left, right; + + assert(rbtree_node_check_alignment(parent)); + assert(rbtree_node_check_alignment(node)); + + node->parent = (uintptr_t)parent | RBTREE_COLOR_RED; + node->children[RBTREE_LEFT] = NULL; + node->children[RBTREE_RIGHT] = NULL; + + if (unlikely(parent == NULL)) { + tree->root = node; + } else { + parent->children[index] = node; + } + + for (;;) { + if (parent == NULL) { + rbtree_node_set_black(node); + break; + } + + if (rbtree_node_is_black(parent)) { + break; + } + + grand_parent = rbtree_node_parent(parent); + assert(grand_parent != NULL); + + left = rbtree_node_index(parent, grand_parent); + right = 1 - left; + + uncle = grand_parent->children[right]; + + /* + * Uncle is red. Flip colors and repeat at grand parent. + */ + if ((uncle != NULL) && rbtree_node_is_red(uncle)) { + rbtree_node_set_black(uncle); + rbtree_node_set_black(parent); + rbtree_node_set_red(grand_parent); + node = grand_parent; + parent = rbtree_node_parent(node); + continue; + } + + /* + * Node is the right child of its parent. Rotate left at parent. + */ + if (parent->children[right] == node) { + rbtree_rotate(tree, parent, left); + parent = node; + } + + /* + * Node is the left child of its parent. Handle colors, rotate right + * at grand parent, and leave. + */ + rbtree_node_set_black(parent); + rbtree_node_set_red(grand_parent); + rbtree_rotate(tree, grand_parent, right); + break; + } + + assert(rbtree_node_is_black(tree->root)); +} + +void * +rbtree_replace_slot(struct rbtree *tree, rbtree_slot_t slot, + struct rbtree_node *node) +{ + struct rbtree_node *parent, *prev; + int index; + + parent = rbtree_slot_parent(slot); + + if (!parent) { + prev = tree->root; + tree->root = node; + } else { + index = rbtree_slot_index(slot); + assert(rbtree_check_index(index)); + prev = parent->children[index]; + parent->children[index] = node; + } + + assert(prev); + *node = *prev; + + for (size_t i = 0; i < ARRAY_SIZE(node->children); i++) { + if (!node->children[i]) { + continue; + } + + + rbtree_node_set_parent(node->children[i], node); + } + + return prev; +} + +void +rbtree_remove(struct rbtree *tree, struct rbtree_node *node) +{ + struct rbtree_node *child, *parent, *brother; + int color, left, right; + + if (node->children[RBTREE_LEFT] == NULL) { + child = node->children[RBTREE_RIGHT]; + } else if (node->children[RBTREE_RIGHT] == NULL) { + child = node->children[RBTREE_LEFT]; + } else { + struct rbtree_node *successor; + + /* + * Two-children case: replace the node with its successor. + */ + + successor = node->children[RBTREE_RIGHT]; + + while (successor->children[RBTREE_LEFT] != NULL) { + successor = successor->children[RBTREE_LEFT]; + } + + color = rbtree_node_color(successor); + child = successor->children[RBTREE_RIGHT]; + parent = rbtree_node_parent(node); + + if (unlikely(parent == NULL)) { + tree->root = successor; + } else { + parent->children[rbtree_node_index(node, parent)] = successor; + } + + parent = rbtree_node_parent(successor); + + /* + * Set parent directly to keep the original color. + */ + successor->parent = node->parent; + successor->children[RBTREE_LEFT] = node->children[RBTREE_LEFT]; + rbtree_node_set_parent(successor->children[RBTREE_LEFT], successor); + + if (node == parent) { + parent = successor; + } else { + successor->children[RBTREE_RIGHT] = node->children[RBTREE_RIGHT]; + rbtree_node_set_parent(successor->children[RBTREE_RIGHT], + successor); + parent->children[RBTREE_LEFT] = child; + + if (child != NULL) { + rbtree_node_set_parent(child, parent); + } + } + + goto update_color; + } + + /* + * Node has at most one child. + */ + + color = rbtree_node_color(node); + parent = rbtree_node_parent(node); + + if (child != NULL) { + rbtree_node_set_parent(child, parent); + } + + if (unlikely(parent == NULL)) { + tree->root = child; + } else { + parent->children[rbtree_node_index(node, parent)] = child; + } + + /* + * The node has been removed, update the colors. The child pointer can + * be NULL, in which case it is considered a black leaf. + */ +update_color: + if (color == RBTREE_COLOR_RED) { + return; + } + + for (;;) { + if ((child != NULL) && rbtree_node_is_red(child)) { + rbtree_node_set_black(child); + break; + } + + if (parent == NULL) { + break; + } + + left = rbtree_node_index(child, parent); + right = 1 - left; + + brother = parent->children[right]; + + /* + * Brother is red. Recolor and rotate left at parent so that brother + * becomes black. + */ + if (rbtree_node_is_red(brother)) { + rbtree_node_set_black(brother); + rbtree_node_set_red(parent); + rbtree_rotate(tree, parent, left); + brother = parent->children[right]; + } + + assert(brother != NULL); + + /* + * Brother has no red child. Recolor and repeat at parent. + */ + if (((brother->children[RBTREE_LEFT] == NULL) + || rbtree_node_is_black(brother->children[RBTREE_LEFT])) + && ((brother->children[RBTREE_RIGHT] == NULL) + || rbtree_node_is_black(brother->children[RBTREE_RIGHT]))) { + rbtree_node_set_red(brother); + child = parent; + parent = rbtree_node_parent(child); + continue; + } + + /* + * Brother's right child is black. Recolor and rotate right at brother. + */ + if ((brother->children[right] == NULL) + || rbtree_node_is_black(brother->children[right])) { + rbtree_node_set_black(brother->children[left]); + rbtree_node_set_red(brother); + rbtree_rotate(tree, brother, right); + brother = parent->children[right]; + } + + /* + * Brother's left child is black. Exchange parent and brother colors + * (we already know brother is black), set brother's right child black, + * rotate left at parent and leave. + */ + assert(brother->children[right] != NULL); + rbtree_node_set_color(brother, rbtree_node_color(parent)); + rbtree_node_set_black(parent); + rbtree_node_set_black(brother->children[right]); + rbtree_rotate(tree, parent, left); + break; + } + + assert((tree->root == NULL) || rbtree_node_is_black(tree->root)); +} + +struct rbtree_node * +rbtree_nearest(struct rbtree_node *parent, int index, int direction) +{ + assert(rbtree_check_index(direction)); + + if (parent == NULL) { + return NULL; + } + + assert(rbtree_check_index(index)); + + if (index != direction) { + return parent; + } + + return rbtree_walk(parent, direction); +} + +struct rbtree_node * +rbtree_firstlast(const struct rbtree *tree, int direction) +{ + struct rbtree_node *prev, *cur; + + assert(rbtree_check_index(direction)); + + prev = NULL; + + for (cur = tree->root; cur != NULL; cur = cur->children[direction]) { + prev = cur; + } + + return prev; +} + +struct rbtree_node * +rbtree_walk(struct rbtree_node *node, int direction) +{ + int left, right; + + assert(rbtree_check_index(direction)); + + left = direction; + right = 1 - left; + + if (node == NULL) { + return NULL; + } + + if (node->children[left] != NULL) { + node = node->children[left]; + + while (node->children[right] != NULL) { + node = node->children[right]; + } + } else { + struct rbtree_node *parent; + int index; + + for (;;) { + parent = rbtree_node_parent(node); + + if (parent == NULL) { + return NULL; + } + + index = rbtree_node_index(node, parent); + node = parent; + + if (index == right) { + break; + } + } + } + + return node; +} + +struct rbtree_node * +rbtree_postwalk_deepest(const struct rbtree *tree) +{ + struct rbtree_node *node; + + node = tree->root; + + if (node == NULL) { + return NULL; + } + + return rbtree_node_find_deepest(node); +} + +struct rbtree_node * +rbtree_postwalk_unlink(struct rbtree_node *node) +{ + struct rbtree_node *parent; + int index; + + if (node == NULL) { + return NULL; + } + + assert(node->children[RBTREE_LEFT] == NULL); + assert(node->children[RBTREE_RIGHT] == NULL); + + parent = rbtree_node_parent(node); + + if (parent == NULL) { + return NULL; + } + + index = rbtree_node_index(node, parent); + parent->children[index] = NULL; + node = parent->children[RBTREE_RIGHT]; + + if (node == NULL) { + return parent; + } + + return rbtree_node_find_deepest(node); +} |