libcdsb/src/rbtree.c

197 lines
4.6 KiB
C
Raw Normal View History

2022-06-05 18:40:37 +00:00
/* 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]
/*#####################################################################################################################*/
2022-06-07 18:34:30 +00:00
rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1] = {{
2022-06-05 18:40:37 +00:00
.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;
2022-06-06 20:45:11 +00:00
if (!rbnode_is_empty(rbdir_dir(n, d)))
2022-06-05 18:40:37 +00:00
rbdir_dir(n, d)->parent = c;
if (!rbnode_is_root(c)) {
2022-06-06 20:45:11 +00:00
if (c->parent->left == c) c->parent->left = n;
else c->parent->right = n;
2022-06-05 18:40:37 +00:00
} else *x = n;
2022-06-06 20:45:11 +00:00
rbdir_dir(n, d) = c;
2022-06-05 18:40:37 +00:00
c->parent = n;
}
static inline void replace(rbnode_t** x, rbnode_t* c, rbnode_t* n) {
2022-06-07 18:34:30 +00:00
if (!rbnode_is_root(c)) {
if (c->parent->left == c) {
c->parent->left = n;
} else c->parent->right = n;
2022-06-05 18:40:37 +00:00
} else *x = n;
2022-06-07 18:34:30 +00:00
n->parent = c->parent;
2022-06-05 18:40:37 +00:00
}
/*#####################################################################################################################*/
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;
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;
}
2022-06-06 20:45:11 +00:00
p->colored = 0;
2022-06-05 18:40:37 +00:00
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;
}