--- /dev/null
+/*
+ * Copyright © 2017 Jason Ekstrand
+ *
+ * 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.
+ */
+
+#include "rb_tree.h"
+
+/** \file rb_tree.c
+ *
+ * An implementation of a red-black tree
+ *
+ * This file implements the guts of a red-black tree. The implementation
+ * is mostly based on the one in "Introduction to Algorithms", third
+ * edition, by Cormen, Leiserson, Rivest, and Stein. The primary
+ * divergence in our algorithms from those presented in CLRS is that we use
+ * NULL for the leaves instead of a sentinel. This means we have to do a
+ * tiny bit more tracking in our implementation of delete but it makes the
+ * algorithms far more explicit than stashing stuff in the sentinel.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+static bool
+rb_node_is_black(struct rb_node *n)
+{
+ /* NULL nodes are leaves and therefore black */
+ return (n == NULL) || (n->parent & 1);
+}
+
+static bool
+rb_node_is_red(struct rb_node *n)
+{
+ return !rb_node_is_black(n);
+}
+
+static void
+rb_node_set_black(struct rb_node *n)
+{
+ n->parent |= 1;
+}
+
+static void
+rb_node_set_red(struct rb_node *n)
+{
+ n->parent &= ~1ull;
+}
+
+static void
+rb_node_copy_color(struct rb_node *dst, struct rb_node *src)
+{
+ dst->parent = (dst->parent & ~1ull) | (src->parent & 1);
+}
+
+static void
+rb_node_set_parent(struct rb_node *n, struct rb_node *p)
+{
+ n->parent = (n->parent & 1) | (uintptr_t)p;
+}
+
+static struct rb_node *
+rb_node_minimum(struct rb_node *node)
+{
+ while (node->left)
+ node = node->left;
+ return node;
+}
+
+static struct rb_node *
+rb_node_maximum(struct rb_node *node)
+{
+ while (node->right)
+ node = node->right;
+ return node;
+}
+
+void
+rb_tree_init(struct rb_tree *T)
+{
+ T->root = NULL;
+}
+
+/**
+ * Replace the subtree of T rooted at u with the subtree rooted at v
+ *
+ * This is called RB-transplant in CLRS.
+ *
+ * The node to be replaced is assumed to be a non-leaf.
+ */
+static void
+rb_tree_splice(struct rb_tree *T, struct rb_node *u, struct rb_node *v)
+{
+ assert(u);
+ struct rb_node *p = rb_node_parent(u);
+ if (p == NULL) {
+ assert(T->root == u);
+ T->root = v;
+ } else if (u == p->left) {
+ p->left = v;
+ } else {
+ assert(u == p->right);
+ p->right = v;
+ }
+ if (v)
+ rb_node_set_parent(v, p);
+}
+
+static void
+rb_tree_rotate_left(struct rb_tree *T, struct rb_node *x)
+{
+ assert(x && x->right);
+
+ struct rb_node *y = x->right;
+ x->right = y->left;
+ if (y->left)
+ rb_node_set_parent(y->left, x);
+ rb_tree_splice(T, x, y);
+ y->left = x;
+ rb_node_set_parent(x, y);
+}
+
+static void
+rb_tree_rotate_right(struct rb_tree *T, struct rb_node *y)
+{
+ assert(y && y->left);
+
+ struct rb_node *x = y->left;
+ y->left = x->right;
+ if (x->right)
+ rb_node_set_parent(x->right, y);
+ rb_tree_splice(T, y, x);
+ x->right = y;
+ rb_node_set_parent(y, x);
+}
+
+void
+rb_tree_insert_at(struct rb_tree *T, struct rb_node *parent,
+ struct rb_node *node, bool insert_left)
+{
+ /* This sets null children, parent, and a color of red */
+ memset(node, 0, sizeof(*node));
+
+ if (parent == NULL) {
+ assert(T->root == NULL);
+ T->root = node;
+ rb_node_set_black(node);
+ return;
+ }
+
+ if (insert_left) {
+ assert(parent->left == NULL);
+ parent->left = node;
+ } else {
+ assert(parent->right == NULL);
+ parent->right = node;
+ }
+ rb_node_set_parent(node, parent);
+
+ /* Now we do the insertion fixup */
+ struct rb_node *z = node;
+ while (rb_node_is_red(rb_node_parent(z))) {
+ struct rb_node *z_p = rb_node_parent(z);
+ assert(z == z_p->left || z == z_p->right);
+ struct rb_node *z_p_p = rb_node_parent(z_p);
+ assert(z_p_p != NULL);
+ if (z_p == z_p_p->left) {
+ struct rb_node *y = z_p_p->right;
+ if (rb_node_is_red(y)) {
+ rb_node_set_black(z_p);
+ rb_node_set_black(y);
+ rb_node_set_red(z_p_p);
+ z = z_p_p;
+ } else {
+ if (z == z_p->right) {
+ z = z_p;
+ rb_tree_rotate_left(T, z);
+ /* We changed z */
+ z_p = rb_node_parent(z);
+ assert(z == z_p->left || z == z_p->right);
+ z_p_p = rb_node_parent(z_p);
+ }
+ rb_node_set_black(z_p);
+ rb_node_set_red(z_p_p);
+ rb_tree_rotate_right(T, z_p_p);
+ }
+ } else {
+ struct rb_node *y = z_p_p->left;
+ if (rb_node_is_red(y)) {
+ rb_node_set_black(z_p);
+ rb_node_set_black(y);
+ rb_node_set_red(z_p_p);
+ z = z_p_p;
+ } else {
+ if (z == z_p->left) {
+ z = z_p;
+ rb_tree_rotate_right(T, z);
+ /* We changed z */
+ z_p = rb_node_parent(z);
+ assert(z == z_p->left || z == z_p->right);
+ z_p_p = rb_node_parent(z_p);
+ }
+ rb_node_set_black(z_p);
+ rb_node_set_red(z_p_p);
+ rb_tree_rotate_left(T, z_p_p);
+ }
+ }
+ }
+ rb_node_set_black(T->root);
+}
+
+void
+rb_tree_remove(struct rb_tree *T, struct rb_node *z)
+{
+ /* x_p is always the parent node of X. We have to track this
+ * separately because x may be NULL.
+ */
+ struct rb_node *x, *x_p;
+ struct rb_node *y = z;
+ bool y_was_black = rb_node_is_black(y);
+ if (z->left == NULL) {
+ x = z->right;
+ x_p = rb_node_parent(z);
+ rb_tree_splice(T, z, x);
+ } else if (z->right == NULL) {
+ x = z->left;
+ x_p = rb_node_parent(z);
+ rb_tree_splice(T, z, x);
+ } else {
+ /* Find the minimum sub-node of z->right */
+ y = rb_node_minimum(z->right);
+ y_was_black = rb_node_is_black(y);
+
+ x = y->right;
+ if (rb_node_parent(y) == z) {
+ x_p = y;
+ } else {
+ x_p = rb_node_parent(y);
+ rb_tree_splice(T, y, x);
+ y->right = z->right;
+ rb_node_set_parent(y->right, y);
+ }
+ assert(y->left == NULL);
+ rb_tree_splice(T, z, y);
+ y->left = z->left;
+ rb_node_set_parent(y->left, y);
+ rb_node_copy_color(y, z);
+ }
+
+ assert(x_p == NULL || x == x_p->left || x == x_p->right);
+
+ if (!y_was_black)
+ return;
+
+ /* Fixup RB tree after the delete */
+ while (x != T->root && rb_node_is_black(x)) {
+ if (x == x_p->left) {
+ struct rb_node *w = x_p->right;
+ if (rb_node_is_red(w)) {
+ rb_node_set_black(w);
+ rb_node_set_red(x_p);
+ rb_tree_rotate_left(T, x_p);
+ assert(x == x_p->left);
+ w = x_p->right;
+ }
+ if (rb_node_is_black(w->left) && rb_node_is_black(w->right)) {
+ rb_node_set_red(w);
+ x = x_p;
+ } else {
+ if (rb_node_is_black(w->right)) {
+ rb_node_set_black(w->left);
+ rb_node_set_red(w);
+ rb_tree_rotate_right(T, w);
+ w = x_p->right;
+ }
+ rb_node_copy_color(w, x_p);
+ rb_node_set_black(x_p);
+ rb_node_set_black(w->right);
+ rb_tree_rotate_left(T, x_p);
+ x = T->root;
+ }
+ } else {
+ struct rb_node *w = x_p->left;
+ if (rb_node_is_red(w)) {
+ rb_node_set_black(w);
+ rb_node_set_red(x_p);
+ rb_tree_rotate_right(T, x_p);
+ assert(x == x_p->right);
+ w = x_p->left;
+ }
+ if (rb_node_is_black(w->right) && rb_node_is_black(w->left)) {
+ rb_node_set_red(w);
+ x = x_p;
+ } else {
+ if (rb_node_is_black(w->left)) {
+ rb_node_set_black(w->right);
+ rb_node_set_red(w);
+ rb_tree_rotate_left(T, w);
+ w = x_p->left;
+ }
+ rb_node_copy_color(w, x_p);
+ rb_node_set_black(x_p);
+ rb_node_set_black(w->left);
+ rb_tree_rotate_right(T, x_p);
+ x = T->root;
+ }
+ }
+ x_p = rb_node_parent(x);
+ }
+ if (x)
+ rb_node_set_black(x);
+}
+
+struct rb_node *
+rb_tree_first(struct rb_tree *T)
+{
+ return T->root ? rb_node_minimum(T->root) : NULL;
+}
+
+struct rb_node *
+rb_tree_last(struct rb_tree *T)
+{
+ return T->root ? rb_node_maximum(T->root) : NULL;
+}
+
+struct rb_node *
+rb_node_next(struct rb_node *node)
+{
+ if (node->right) {
+ /* If we have a right child, then the next thing (compared to this
+ * node) is the left-most child of our right child.
+ */
+ return rb_node_minimum(node->right);
+ } else {
+ /* If node doesn't have a right child, crawl back up the to the
+ * left until we hit a parent to the right.
+ */
+ struct rb_node *p = rb_node_parent(node);
+ while (p && node == p->right) {
+ node = p;
+ p = rb_node_parent(node);
+ }
+ assert(p == NULL || node == p->left);
+ return p;
+ }
+}
+
+struct rb_node *
+rb_node_prev(struct rb_node *node)
+{
+ if (node->left) {
+ /* If we have a left child, then the previous thing (compared to
+ * this node) is the right-most child of our left child.
+ */
+ return rb_node_maximum(node->left);
+ } else {
+ /* If node doesn't have a left child, crawl back up the to the
+ * right until we hit a parent to the left.
+ */
+ struct rb_node *p = rb_node_parent(node);
+ while (p && node == p->left) {
+ node = p;
+ p = rb_node_parent(node);
+ }
+ assert(p == NULL || node == p->right);
+ return p;
+ }
+}
+
+static void
+validate_rb_node(struct rb_node *n, int black_depth)
+{
+ if (n == NULL) {
+ assert(black_depth == 0);
+ return;
+ }
+
+ if (rb_node_is_black(n)) {
+ black_depth--;
+ } else {
+ assert(rb_node_is_black(n->left));
+ assert(rb_node_is_black(n->right));
+ }
+
+ validate_rb_node(n->left, black_depth);
+ validate_rb_node(n->right, black_depth);
+}
+
+void
+rb_tree_validate(struct rb_tree *T)
+{
+ if (T->root == NULL)
+ return;
+
+ assert(rb_node_is_black(T->root));
+
+ unsigned black_depth = 0;
+ for (struct rb_node *n = T->root; n; n = n->left) {
+ if (rb_node_is_black(n))
+ black_depth++;
+ }
+
+ validate_rb_node(T->root, black_depth);
+}
--- /dev/null
+/*
+ * Copyright © 2017 Jason Ekstrand
+ *
+ * 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.
+ */
+
+#ifndef RB_TREE_H
+#define RB_TREE_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/** A red-black tree node
+ *
+ * This struct represents a node in the red-black tree. This struct should
+ * be embedded as a member in whatever structure you wish to put in the
+ * tree.
+ */
+struct rb_node {
+ /** Parent and color of this node
+ *
+ * The least significant bit represents the color and is est to 1 for
+ * black and 0 for red. The other bits are the pointer to the parent
+ * and that pointer can be retrieved by masking off the bottom bit and
+ * casting to a pointer.
+ */
+ uintptr_t parent;
+
+ /** Left child of this node, null for a leaf */
+ struct rb_node *left;
+
+ /** Right child of this node, null for a leaf */
+ struct rb_node *right;
+};
+
+/** Return the parent node of the given node or NULL if it is the root */
+static inline struct rb_node *
+rb_node_parent(struct rb_node *n)
+{
+ return (struct rb_node *)(n->parent & ~1ull);
+}
+
+/** A red-black tree
+ *
+ * This struct represents the red-black tree itself. It is just a pointer
+ * to the root node with no other metadata.
+ */
+struct rb_tree {
+ struct rb_node *root;
+};
+
+/** Initialize a red-black tree */
+void rb_tree_init(struct rb_tree *T);
+
+/** Returns true if the red-black tree is empty */
+static inline bool
+rb_tree_is_empty(const struct rb_tree *T)
+{
+ return T->root == NULL;
+}
+
+/** Retrieve the data structure containing a node
+ *
+ * \param type The type of the containing data structure
+ *
+ * \param node A pointer to a rb_node
+ *
+ * \param field The rb_node field in the containing data structure
+ */
+#define rb_node_data(type, node, field) \
+ ((type *)(((char *)(node)) - offsetof(type, field)))
+
+/** Insert a node into a tree at a particular location
+ *
+ * This function should probably not be used directly as it relies on the
+ * caller to ensure that the parent node is correct. Use rb_tree_insert
+ * instead.
+ *
+ * \param T The red-black tree into which to insert the new node
+ *
+ * \param parent The node in the tree that will be the parent of the
+ * newly inserted node
+ *
+ * \param node The node to insert
+ *
+ * \param insert_left If true, the new node will be the left child of
+ * \p parent, otherwise it will be the right child
+ */
+void rb_tree_insert_at(struct rb_tree *T, struct rb_node *parent,
+ struct rb_node *node, bool insert_left);
+
+/** Insert a node into a tree
+ *
+ * \param T The red-black tree into which to insert the new node
+ *
+ * \param node The node to insert
+ *
+ * \param cmp A comparison function to use to order the nodes.
+ */
+static inline void
+rb_tree_insert(struct rb_tree *T, struct rb_node *node,
+ int (*cmp)(const struct rb_node *, const struct rb_node *))
+{
+ /* This function is declared inline in the hopes that the compiler can
+ * optimize away the comparison function pointer call.
+ */
+ struct rb_node *y = NULL;
+ struct rb_node *x = T->root;
+ bool left = false;
+ while (x != NULL) {
+ y = x;
+ left = cmp(node, x) < 0;
+ if (left)
+ x = x->left;
+ else
+ x = x->right;
+ }
+
+ rb_tree_insert_at(T, y, node, left);
+}
+
+/** Remove a node from a tree
+ *
+ * \param T The red-black tree from which to remove the node
+ *
+ * \param node The node to remove
+ */
+void rb_tree_remove(struct rb_tree *T, struct rb_node *z);
+
+/** Search the tree for a node
+ *
+ * If a node with a matching key exists, the first matching node found will
+ * be returned. If no matching node exists, NULL is returned.
+ *
+ * \param T The red-black tree to search
+ *
+ * \param key The key to search for
+ *
+ * \param cmp A comparison function to use to order the nodes
+ */
+static inline struct rb_node *
+rb_tree_search(struct rb_tree *T, const void *key,
+ int (*cmp)(const struct rb_node *, const void *))
+{
+ /* This function is declared inline in the hopes that the compiler can
+ * optimize away the comparison function pointer call.
+ */
+ struct rb_node *x = T->root;
+ while (x != NULL) {
+ int c = cmp(x, key);
+ if (c < 0)
+ x = x->right;
+ else if (c > 0)
+ x = x->left;
+ else
+ return x;
+ }
+
+ return x;
+}
+
+/** Sloppily search the tree for a node
+ *
+ * This function searches the tree for a given node. If a node with a
+ * matching key exists, that first matching node found will be returned.
+ * If no node with an exactly matching key exists, the node returned will
+ * be either the right-most node comparing less than \p key or the
+ * right-most node comparing greater than \p key. If the tree is empty,
+ * NULL is returned.
+ *
+ * \param T The red-black tree to search
+ *
+ * \param key The key to search for
+ *
+ * \param cmp A comparison function to use to order the nodes
+ */
+static inline struct rb_node *
+rb_tree_search_sloppy(struct rb_tree *T, const void *key,
+ int (*cmp)(const struct rb_node *, const void *))
+{
+ /* This function is declared inline in the hopes that the compiler can
+ * optimize away the comparison function pointer call.
+ */
+ struct rb_node *y = NULL;
+ struct rb_node *x = T->root;
+ while (x != NULL) {
+ y = x;
+ int c = cmp(x, key);
+ if (c < 0)
+ x = x->right;
+ else if (c > 0)
+ x = x->left;
+ else
+ return x;
+ }
+
+ return y;
+}
+
+/** Get the first (left-most) node in the tree or NULL */
+struct rb_node *rb_tree_first(struct rb_tree *T);
+
+/** Get the last (right-most) node in the tree or NULL */
+struct rb_node *rb_tree_last(struct rb_tree *T);
+
+/** Get the next node (to the right) in the tree or NULL */
+struct rb_node *rb_node_next(struct rb_node *node);
+
+/** Get the next previous (to the left) in the tree or NULL */
+struct rb_node *rb_node_prev(struct rb_node *node);
+
+/** Iterate over the nodes in the tree
+ *
+ * \param type The type of the containing data structure
+ *
+ * \param node The variable name for current node in the iteration;
+ * this will be declared as a pointer to \p type
+ *
+ * \param T The red-black tree
+ *
+ * \param field The rb_node field in containing data structure
+ */
+#define rb_tree_foreach(type, node, T, field) \
+ for (type *node = rb_node_data(type, rb_tree_first(T), field); \
+ &node->field != NULL; \
+ node = rb_node_data(type, rb_node_next(&node->field), field))
+
+/** Iterate over the nodes in the tree in reverse
+ *
+ * \param type The type of the containing data structure
+ *
+ * \param node The variable name for current node in the iteration;
+ * this will be declared as a pointer to \p type
+ *
+ * \param T The red-black tree
+ *
+ * \param field The rb_node field in containing data structure
+ */
+#define rb_tree_foreach_rev(type, node, T, field) \
+ for (type *node = rb_node_data(type, rb_tree_last(T), field); \
+ &node->field != NULL; \
+ node = rb_node_data(type, rb_node_prev(&node->field), field))
+
+/** Validate a red-black tree
+ *
+ * This function walks the tree and validates that this is a valid red-
+ * black tree. If anything is wrong, it will assert-fail.
+ */
+void rb_tree_validate(struct rb_tree *T);
+
+#endif /* RB_TREE_H */