/* This software is licensed by the MIT License, see LICENSE file */ /* Copyright © 2022 Gregory Lirent */ #include "__internal/rbtree.h" #define RBI_BREAK ((rbiter_f)3) #define RBI_FIRST ((rbiter_f)8) 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] /*#####################################################################################################################*/ const rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1] = {{ .colored = 0, .value = 0, .parent = rbnode_empty, .left = rbnode_empty, .right = rbnode_empty }}; /*#####################################################################################################################*/ static inline void 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)) { rbnode_t* p = c->parent; if (rbdir_dir(p, d) == c) { rbdir_dir(p, d) = n; } else rbdir_inv(c, d) = n; } else *x = n; rbdir_inv(n, d) = c; c->parent = n; } static inline void replace(rbnode_t** x, rbnode_t* c, rbnode_t* n) { rbnode_t* p; p = c->parent; if (!rbnode_is_empty(p)) { if (p->left == c) { p->left = n; } else p->right = n; } else *x = n; n->parent = p; } /*#####################################################################################################################*/ static rbnode_t* inorder_next(rbnode_t* c, rbiter_f f) { rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT; rbnode_t* p; for (;;) { if (rbnode_is_empty(rbdir_inv(c, d))) { p = c->parent; if (rbnode_is_root(p) || rbdir_dir(p, d) == c) { return p; } c = p; p = c->parent; if (rbnode_is_root(p) || rbdir_dir(p, d) == c) { return p; } do { c = p; p = c->parent; } while(rbdir_inv(p, d) == c); c = p; } else { c = rbdir_inv(c, d); break; } if (rbnode_is_root(c)) return c; } while (!rbnode_is_empty(rbdir_dir(c, d))) c = rbdir_dir(c, d); return c; } static rbnode_t* postorder_next(rbnode_t* c, rbiter_f f) { rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT; rbnode_t* p; if (rbnode_is_empty(p = c->parent)) return c; if (rbdir_dir(p, d) == c && !rbnode_is_empty(rbdir_inv(p, d))) { c = rbdir_inv(p, d); while (!rbnode_is_empty(c)) { p = c; c = (!rbnode_is_empty(rbdir_inv(p, d))) ? rbdir_inv(p, d) : rbdir_dir(p, d); } } return p; } static rbnode_t* preorder_next(rbnode_t* c, rbiter_f f) { rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT; rbnode_t* p; if (!rbnode_is_empty(rbdir_dir(c, d))) return rbdir_dir(c, d); for (;;) { if (!rbnode_is_empty(rbdir_inv(c, d))) { return rbdir_inv(c, d); } p = c->parent; while (rbdir_inv(p, d) == c) { c = p; p = c->parent; } if (rbnode_is_empty(p)) return c; c = p; } } /*#####################################################################################################################*/ static void delete_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_rbtree_node_delete(rbnode_t** x, rbnode_t* c) { rbnode_t *n, *t; int s; void* v; 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) delete_fixup(x, n); return c; } void libcdsb_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_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; } /*#####################################################################################################################*/ _Bool libcdsb_rbtree_iter_init(rbiter_t* iter, rbnode_t *const *root, rbiter_f f) { rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT; rbnode_t* c = *root; if (!rbnode_is_empty(c)) { if (!(f&RBI_BREAK)) { while (rbdir_dir(c, d) != rbnode_empty) { c = rbdir_dir(c, d); } } else if ((f&RBI_BREAK) == RBI_POSTORDER) { rbnode_t* p; do { p = c; c = (!rbnode_is_empty(rbdir_dir(c, d))) ? rbdir_dir(c, d) : rbdir_inv(c, d); } while (!rbnode_is_empty(c)); c = p; } } else { iter->cursor = rbnode_empty; iter->flags = 0; return false; } iter->cursor = c; iter->flags = f|RBI_FIRST; return true; } void libcdsb_rbtree_iter_reset(rbiter_t* iter) { if (iter->flags&RBI_FIRST) return; while (!rbnode_is_empty(iter->cursor->parent)) { iter->cursor = iter->cursor->parent; } if ((iter->flags&RBI_BREAK) == RBI_BREAK) { libcdsb_rbtree_iter_init(iter, &iter->cursor, iter->flags&~RBI_BREAK); } else libcdsb_rbtree_iter_init(iter, &iter->cursor, iter->flags); } rbnode_t* hhttpc_rbtree_iter_next(rbiter_t* iter) { rbnode_t* c; c = iter->cursor; if (rbnode_is_empty(c)) return rbnode_empty; if (!(iter->flags&RBI_FIRST)) { if (rbnode_is_root(c)) { if ((iter->flags&RBI_BREAK) == RBI_INORDER) { iter->flags |= RBI_BREAK; } else { libcdsb_rbtree_iter_reset(iter); if (iter->flags&RBI_POSTORDER) { iter->flags |= RBI_BREAK; return c; } else return rbnode_empty; } } } else if ((iter->flags&RBI_BREAK) == RBI_BREAK) { iter->flags = (iter->flags&~(RBI_BREAK^RBI_POSTORDER)); return rbnode_empty; } else iter->flags &= ~RBI_FIRST; switch (iter->flags&RBI_BREAK) { case RBI_POSTORDER: iter->cursor = postorder_next(c, iter->flags); break; case RBI_PREORDER: iter->cursor = preorder_next(c, iter->flags); break; case RBI_INORDER: default: iter->cursor = inorder_next(c, iter->flags); break; } return c; }