/* This software is licensed by the MIT License, see LICENSE file */ /* Copyright © 2022 Gregory Lirent */ #include "__internal/rbtree.h" typedef enum libcdsb_rbtree_node_direction { RBD_LEFT = 1, RBD_RIGHT = 2 } rbdir_t; #define rbdir_dir(cur, d) (&((cur)->left))[(d)>>1] #define rbdir_inv(cur, d) (&((cur)->left))[(d)&1] #define rotate libcdsb_builtin_rotate #define replace libcdsb_builtin_replace #define fixup libcdsb_builtin_fixup static void libcdsb_builtin_rotate(rbnode_t **x, rbnode_t *c, rbdir_t d) { rbnode_t* n = rbdir_inv(c, d); rbdir_inv(c, d) = rbdir_dir(n, d); n->parent = c->parent; if (!rbnode_is_empty(rbdir_dir(n, d))) rbdir_dir(n, d)->parent = c; if (!rbnode_is_root(c)) { if (c->parent->left == c) c->parent->left = n; else c->parent->right = n; } else *x = n; rbdir_dir(n, d) = c; c->parent = n; } static void libcdsb_builtin_replace(rbnode_t** x, rbnode_t* c, rbnode_t* n) { if (!rbnode_is_root(c)) { if (c->parent->left == c) { c->parent->left = n; } else c->parent->right = n; } else *x = n; n->parent = c->parent; } static void libcdsb_builtin_fixup(rbnode_t** x, rbnode_t* n) { rbdir_t d; rbnode_t *s, *p; while (!rbnode_is_root(n) && !n->colored) { p = n->parent; d = (p->left == n) ? RBD_LEFT : RBD_RIGHT; s = rbdir_inv(p, d); if (s->colored) { s->colored = 0; p->colored = 1; rotate(x, p, d); p = n->parent; s = rbdir_inv(p, d); } if (!rbdir_dir(s, d)->colored && !rbdir_inv(s, d)->colored) { s->colored = 1; n = p; } else { if (!rbdir_inv(s, d)->colored) { rbdir_dir(s, d)->colored = 0; s->colored = 1; rotate(x, s, (d == RBD_LEFT) ? RBD_RIGHT : RBD_LEFT); p = n->parent; s = rbdir_inv(p, d); } s->colored = p->colored; p->colored = 0; rbdir_inv(s, d)->colored = 0; rotate(x, p, d); n = *x; } } n->colored = 0; } /*#####################################################################################################################*/ rbnode_t LIBCDSB_BUILTIN_RBTREE_NODE_EMPTY[1] = {{ .colored = 0, .value = 0, .parent = rbnode_empty, .left = rbnode_empty, .right = rbnode_empty }}; rbnode_t* libcdsb_builtin_rbtree_node_delete(rbnode_t** x, rbnode_t* c) { rbnode_t *n, *t; int s; s = c->colored; if (rbnode_is_empty(c->left)) { n = c->right; replace(x, c, c->right); } else if (rbnode_is_empty(c->right)) { n = c->left; replace(x, c, c->left); } else { t = c->right; while (!rbnode_is_empty(t->left)) { t = t->left; } s = t->colored; n = t->right; if (t->parent == c) { n->parent = t; } else { replace(x, t, t->right); c->right->parent = t; t->right = c->right; } replace(x, c, t); c->left->parent = t; t->colored = c->colored; t->left = c->left; } if (!s) fixup(x, n); return c; } void libcdsb_builtin_rbtree_node_fixup(rbnode_t** x, rbnode_t* n) { rbdir_t d[2]; rbnode_t *u, *p, *gp; while (n->parent->colored) { p = n->parent; gp = p->parent; d[0] = (gp->right == p) ? RBD_LEFT : RBD_RIGHT; u = rbdir_dir(gp, d[0]); if (rbdir_dir(p, d[0]) == n) { d[1] = (d[0] == RBD_LEFT) ? RBD_RIGHT : RBD_LEFT; } else d[1] = 0; if (u->colored) { u->colored = 0; p->colored = 0; gp->colored = 1; n = gp; } else { if (d[1]) { rotate(x, n = p, d[1]); p = n->parent; gp = p->parent; } p->colored = 0; gp->colored = 1; rotate(x, gp, d[0]); } if (rbnode_is_root(n)) break; } (*x)->colored = 0; } void* libcdsb_builtin_rbtree_node_create(void* v, rbnode_t* p, int c, int n) { rbnode_t* x; x = malloc(n); x->left = rbnode_empty; x->right = rbnode_empty; x->value = v; x->colored = c; x->parent = p; return x; } stack_t libcdsb_builtin_rbtree_iter_inorder(rbnode_t** root, bool reverse) { stack_t z, *cur; rbnode_t *n; memset(&z, 0, sizeof(z)); if (rbnode_is_empty(n = *root)) return z; while (!rbnode_is_empty(n)) { stack_insert(&z, n); n = n->left; } cur = z.prev; z.value = z.prev->value; z.prev = z.prev->prev; free(cur); cur = &z; while ((cur = cur->prev)) { n = cur->value; if (!rbnode_is_empty(n->right)) { n = n->right; while (!rbnode_is_empty(n)) { stack_insert(cur, n); n = n->left; } } } if (reverse) stack_reverse(&z); return z; } stack_t libcdsb_builtin_rbtree_iter_preorder(rbnode_t** root, bool reverse) { stack_t z, *cur, *next; rbnode_t *n; memset(&z, 0, sizeof(z)); if (rbnode_is_empty(*root)) return z; z.value = *root; cur = &z; do { n = (next = cur)->value; if (!rbnode_is_empty(n->left)) next = stack_insert(cur, n->left); if (!rbnode_is_empty(n->right)) stack_insert(next, n->right); } while (!is_null(cur = cur->prev)); if (reverse) stack_reverse(&z); return z; } stack_t libcdsb_builtin_rbtree_iter_postorder(rbnode_t** root, bool reverse) { rbnode_t *p, *n; stack_t z, *bot; bot = &z; z.prev = 0; z.value = 0; if (rbnode_is_empty(p = *root)) return z; goto mid_; do { if (n->parent->right != n && !rbnode_is_empty(n->parent->right)) { p = n->parent->right; do { mid_: n = p; p = !rbnode_is_empty(p->left) ? p->left : p->right; } while (!rbnode_is_empty(p)); } else n = n->parent; bot = stack_insert(bot, n); } while (!rbnode_is_root(n)); bot = z.prev; z = *bot; free(bot); if (reverse) stack_reverse(&z); return z; } stack_t libcdsb_builtin_rbtree_iter_breadth_first(rbnode_t** root, bool reverse) { stack_t z, *top, *bot, *cur; rbnode_t* n; memset(&z, 0, sizeof(z)); if (rbnode_is_empty(z.value = *root)) return z; for (top = bot = &z;;) { for (cur = bot;;) { n = top->value; if (!rbnode_is_empty(n->left)) cur = stack_insert(cur, n->left); if (!rbnode_is_empty(n->right)) cur = stack_insert(cur, n->right); if (top == bot) { top = top->prev; break; } else top = top->prev; } if (!is_null(top)) { while (!is_null(bot->prev)) bot = bot->prev; } else break; } if (reverse) stack_reverse(&z); return z; }