--- /dev/null
+
+/*
+ * CS5600 University of Utah
+ * Charles McGarvey
+ * mcgarvey@eng.utah.edu
+ */
+
+#include "rbtree.h"
+
+
+#define BLACK (RBTREE_BLACK)
+#define RED (RBTREE_RED)
+#define SENTINEL (rbtree_sentinel)
+
+
+rbtree_node_t _rbtree_sentinel = {
+ &_rbtree_sentinel, &_rbtree_sentinel, &_rbtree_sentinel,
+ BLACK
+};
+rbtree_node_t* rbtree_sentinel = &_rbtree_sentinel;
+
+
+/*
+ * Allocate and initialize a new node for the tree.
+ */
+INLINE_MAYBE
+rbtree_node_t* rbtree_node_alloc(rbtree_t* t)
+{
+ rbtree_node_t* n = mem_alloc(sizeof(rbtree_node_t) + t->size);
+ n->parent = NULL;
+ n->left = n->right = rbtree_sentinel;
+ n->color = RBTREE_BLACK;
+ return n;
+}
+
+
+INLINE_MAYBE
+void rbtree_init(rbtree_t* t, size_t size, rbtree_search_fn_t search)
+{
+ t->root = rbtree_sentinel;
+ t->size = size;
+ t->search = search;
+}
+
+rbtree_t* rbtree_alloc(size_t size, rbtree_search_fn_t search)
+{
+ rbtree_t* t = mem_alloc(sizeof(rbtree_t));
+ rbtree_init(t, size, search);
+ return t;
+}
+
+
+void rbtree_destroy(rbtree_t* t)
+{
+ rbtree_clear(t);
+ mem_free(t);
+}
+
+
+INLINE_MAYBE
+void _rotate_left(rbtree_node_t** r, rbtree_node_t* n)
+{
+ rbtree_node_t* t = n->right;
+ n->right = t->left;
+
+ if (t->left != SENTINEL) {
+ t->left->parent = n;
+ }
+ t->parent = n->parent;
+
+ if (n == *r) {
+ *r = t;
+ }
+ else if (n == n->parent->left) {
+ n->parent->left = t;
+ }
+ else {
+ n->parent->right = t;
+ }
+
+ t->left = n;
+ n->parent = t;
+}
+
+INLINE_MAYBE
+void _rotate_right(rbtree_node_t** r, rbtree_node_t* n)
+{
+ rbtree_node_t* t = n->left;
+ n->left = t->right;
+
+ if (t->right != SENTINEL) {
+ t->right->parent = n;
+ }
+ t->parent = n->parent;
+
+ if (n == *r) {
+ *r = t;
+ }
+ else if (n == n->parent->right) {
+ n->parent->right = t;
+ }
+ else {
+ n->parent->left = t;
+ }
+
+ t->right = n;
+ n->parent = t;
+}
+
+
+rbtree_node_t* rbtree_insert(rbtree_t* t, void* data)
+{
+ rbtree_node_t* r = t->root;
+ rbtree_node_t* n = r;
+
+ int c = t->search(&n, data);
+ if (c == 0) {
+ memcpy(RBTREE_NODE_DATA(n), data, t->size);
+ return n;
+ }
+ else if (n == SENTINEL) {
+ r = rbtree_node_alloc(t);
+ memcpy(RBTREE_NODE_DATA(r), data, t->size);
+ t->root = r;
+ return r;
+ }
+
+ rbtree_node_t* m = rbtree_node_alloc(t);
+ m->parent = n;
+ m->color = RED;
+ memcpy(RBTREE_NODE_DATA(m), data, t->size);
+ if (c < 0) {
+ n->left = m;
+ }
+ else {
+ n->right = m;
+ }
+
+ n = m;
+ while (n != r && n->parent->color == RED) {
+ if (n->parent == n->parent->parent->left) {
+ rbtree_node_t* t = n->parent->parent->right;
+ if (t->color == RED) {
+ n->parent->color = BLACK;
+ t->color = BLACK;
+ n->parent->parent->color = RED;
+ n = n->parent->parent;
+ }
+ else {
+ if (n == n->parent->right) {
+ n = n->parent;
+ _rotate_left(&r, n);
+ }
+ n->parent->color = BLACK;
+ n->parent->parent->color = RED;
+ _rotate_right(&r, n->parent->parent);
+ }
+ }
+ else {
+ rbtree_node_t* t = n->parent->parent->left;
+ if (t->color == RED) {
+ n->parent->color = BLACK;
+ t->color = BLACK;
+ n->parent->parent->color = RED;
+ n = n->parent->parent;
+ }
+ else {
+ if (n == n->parent->left) {
+ n = n->parent;
+ _rotate_right(&r, n);
+ }
+ n->parent->color = BLACK;
+ n->parent->parent->color = RED;
+ _rotate_left(&r, n->parent->parent);
+ }
+ }
+ }
+ t->root = r;
+ r->color = BLACK;
+
+ return m;
+}
+
+rbtree_node_t* rbtree_delete(rbtree_t* t, void* data)
+{
+ rbtree_node_t* n = t->root;
+ if (t->search(&n, data) == 0) {
+ return rbtree_delete_node(t, n);
+ }
+ return NULL;
+}
+
+rbtree_node_t* rbtree_search(rbtree_t* t, void* data)
+{
+ rbtree_node_t* n = t->root;
+ if (t->search(&n, data) == 0) {
+ return n;
+ }
+ return NULL;
+}
+
+
+rbtree_node_t* rbtree_delete_node(rbtree_t* t, rbtree_node_t* n)
+{
+ rbtree_node_t* r = t->root;
+ rbtree_node_t* u;
+ rbtree_node_t* v;
+
+ if (n->left == SENTINEL) {
+ u = n->right;
+ v = n;
+ }
+ else if (n->right == SENTINEL) {
+ u = n->left;
+ v = n;
+ }
+ else {
+ v = rbtree_node_min(n->right);
+ if (v->left != SENTINEL) {
+ u = v->left;
+ }
+ else {
+ u = v->right;
+ }
+ }
+
+ if (v == r) {
+ r = u;
+ u->color = BLACK;
+ goto done;
+ }
+
+ int isred = (v->color == RED);
+
+ if (v == v->parent->left) {
+ v->parent->left = u;
+ }
+ else {
+ v->parent->right = u;
+ }
+
+ if (v == n) {
+ u->parent = v->parent;
+ }
+ else {
+ if (v->parent == n) {
+ u->parent = v;
+ }
+ else {
+ u->parent = v->parent;
+ }
+
+ *v = *n;
+
+ if (n == r) {
+ r = v;
+ }
+ else if (n == n->parent->left) {
+ n->parent->left = v;
+ }
+ else {
+ n->parent->right = v;
+ }
+
+ if (v->left != SENTINEL) {
+ v->left->parent = v;
+ }
+ if (v->right != SENTINEL) {
+ v->right->parent = v;
+ }
+ }
+
+ if (isred) {
+ goto done;
+ }
+
+ while (u != r && u->color == BLACK) {
+ if (u == u->parent->left) {
+ rbtree_node_t* w = u->parent->right;
+ if (w->color == RED) {
+ w->color = BLACK;
+ w->parent->color = RED;
+ _rotate_left(&r, u->parent);
+ w = u->parent->right;
+ }
+ if (w->left->color == BLACK && w->right->color == BLACK) {
+ w->color = RED;
+ u = u->parent;
+ }
+ else {
+ if (w->right->color == BLACK) {
+ w->left->color = BLACK;
+ w->color = RED;
+ _rotate_right(&r, w);
+ w = u->parent->right;
+ }
+ w->color = u->parent->color;
+ u->parent->color = BLACK;
+ w->right->color = BLACK;
+ _rotate_left(&r, u->parent);
+ u = r;
+ }
+ }
+ else {
+ rbtree_node_t* w = u->parent->left;
+ if (w->color == RED) {
+ w->color = BLACK;
+ w->parent->color = RED;
+ _rotate_right(&r, u->parent);
+ w = u->parent->left;
+ }
+ if (w->left->color == BLACK && w->right->color == BLACK) {
+ w->color = RED;
+ u = u->parent;
+ }
+ else {
+ if (w->left->color == BLACK) {
+ w->right->color = BLACK;
+ w->color = RED;
+ _rotate_left(&r, w);
+ w = u->parent->left;
+ }
+ w->color = u->parent->color;
+ u->parent->color = BLACK;
+ w->left->color = BLACK;
+ _rotate_right(&r, u->parent);
+ u = r;
+ }
+ }
+ }
+
+done:
+ t->root = r;
+ n->parent = n->left = n->right = NULL;
+ return n;
+}
+
+
+void node_call(rbtree_node_t* n, rbtree_call_fn_t fn)
+{
+ if (n == SENTINEL) {
+ return;
+ }
+ node_call(n->left, fn);
+ fn(RBTREE_NODE_DATA(n));
+ node_call(n->right, fn);
+}
+
+void rbtree_call(const rbtree_t* t, rbtree_call_fn_t fn)
+{
+ node_call(t->root, fn);
+}
+
+
+/*
+ * Prune off a branch of the tree.
+ */
+static void _node_prune(rbtree_node_t* n)
+{
+ if (n == SENTINEL) {
+ return;
+ }
+ _node_prune(n->left);
+ _node_prune(n->right);
+ mem_free(n);
+}
+
+void rbtree_clear(rbtree_t* t)
+{
+ if (t == NULL) {
+ return;
+ }
+ _node_prune(t->root);
+}
+