]> Dogcows Code - chaz/rasterize/blobdiff - rbtree.c
add support for 3d scenes, depth testing, lighting
[chaz/rasterize] / rbtree.c
diff --git a/rbtree.c b/rbtree.c
new file mode 100644 (file)
index 0000000..ad24a17
--- /dev/null
+++ b/rbtree.c
@@ -0,0 +1,375 @@
+
+/*
+ * 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);
+}
+
This page took 0.022294 seconds and 4 git commands to generate.