HelenOS sources
This source file includes following definitions.
- odict_print_tree
- odict_validate_tree
- odict_validate
- odict_initialize
- odict_finalize
- odlink_initialize
- odict_insert
- odict_remove
- odict_key_update
- odlink_used
- odict_empty
- odict_count
- odict_first
- odict_last
- odict_prev
- odict_next
- odict_find_eq
- odict_find_eq_last
- odict_find_geq
- odict_find_gt
- odict_find_leq
- odict_find_lt
- odict_pgu
- odict_sibling
- odict_rotate_left
- odict_rotate_right
- odict_swap_node
- odict_replace_subtree
- odict_unlink
- odict_link_child_a
- odict_link_child_b
- odict_search_start_node
#include <adt/list.h>
#include <adt/odict.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
static void odict_pgu(odlink_t *, odlink_t **, odict_child_sel_t *,
odlink_t **, odict_child_sel_t *, odlink_t **);
static void odict_rotate_left(odlink_t *);
static void odict_rotate_right(odlink_t *);
static void odict_swap_node(odlink_t *, odlink_t *);
static void odict_replace_subtree(odlink_t *, odlink_t *);
static void odict_unlink(odlink_t *);
static void odict_link_child_a(odlink_t *, odlink_t *);
static void odict_link_child_b(odlink_t *, odlink_t *);
static void odict_sibling(odlink_t *, odlink_t *, odict_child_sel_t *,
odlink_t **);
static odlink_t *odict_search_start_node(odict_t *, void *, odlink_t *);
static void odict_print_tree(odlink_t *cur)
{
if (cur == NULL) {
printf("0");
return;
}
printf("[%p/%c", cur, cur->color == odc_red ? 'r' : 'b');
if (cur->a != NULL || cur->b != NULL) {
printf(" ");
odict_print_tree(cur->a);
printf(" ");
odict_print_tree(cur->b);
}
printf("]");
}
static errno_t odict_validate_tree(odlink_t *cur, int *rbd)
{
errno_t rc;
int bd_a, bd_b;
int cur_d;
if (cur->up == NULL) {
if (cur->odict->root != cur) {
printf("cur->up == NULL and yet cur != root\n");
return EINVAL;
}
if (cur->color != odc_black) {
printf("Root is not black\n");
return EINVAL;
}
}
if (cur->a != NULL) {
if (cur->a->up != cur) {
printf("cur->a->up != cur\n");
return EINVAL;
}
if (cur->a->color == odc_red && cur->color == odc_red) {
printf("cur->a is red, cur is red\n");
return EINVAL;
}
rc = odict_validate_tree(cur->a, &bd_a);
if (rc != EOK)
return rc;
} else {
bd_a = -1;
}
if (cur->b != NULL) {
if (cur->b->up != cur) {
printf("cur->b->up != cur\n");
return EINVAL;
}
if (cur->b->color == odc_red && cur->color == odc_red) {
printf("cur->b is red, cur is red\n");
return EINVAL;
}
rc = odict_validate_tree(cur->b, &bd_b);
if (rc != EOK)
return rc;
} else {
bd_b = -1;
}
if (bd_a >= 0 && bd_b >= 0) {
if (bd_a != bd_b) {
printf("Black depth %d != %d\n", bd_a, bd_b);
return EINVAL;
}
}
cur_d = cur->color == odc_black ? 1 : 0;
if (bd_a >= 0)
*rbd = bd_a + cur_d;
else if (bd_b >= 0)
*rbd = bd_b + cur_d;
else
*rbd = cur_d;
return EOK;
}
errno_t odict_validate(odict_t *odict)
{
int bd;
errno_t rc;
if (odict->root == NULL)
return EOK;
rc = odict_validate_tree(odict->root, &bd);
if (rc != EOK)
odict_print_tree(odict->root);
return rc;
}
void odict_initialize(odict_t *odict, odgetkey_t getkey, odcmp_t cmp)
{
odict->root = NULL;
list_initialize(&odict->entries);
odict->getkey = getkey;
odict->cmp = cmp;
}
void odict_finalize(odict_t *odict)
{
assert(odict->root == NULL);
}
void odlink_initialize(odlink_t *odlink)
{
odlink->odict = NULL;
odlink->up = NULL;
odlink->a = NULL;
odlink->b = NULL;
link_initialize(&odlink->lentries);
}
void odict_insert(odlink_t *odlink, odict_t *odict, odlink_t *hint)
{
int d;
odlink_t *cur;
odlink_t *p;
odlink_t *g;
odlink_t *u;
odict_child_sel_t pcs, gcs;
assert(!odlink_used(odlink));
if (odict->root == NULL) {
odict->root = odlink;
odlink->odict = odict;
odlink->color = odc_black;
list_append(&odlink->lentries, &odict->entries);
return;
}
cur = odict_search_start_node(odict, odict->getkey(odlink), hint);
while (true) {
d = odict->cmp(odict->getkey(odlink), odict->getkey(cur));
if (d < 0) {
if (cur->a == NULL) {
odict_link_child_a(odlink, cur);
break;
}
cur = cur->a;
} else {
if (cur->b == NULL) {
odict_link_child_b(odlink, cur);
break;
}
cur = cur->b;
}
}
odlink->color = odc_red;
while (true) {
if (odlink->up == NULL) {
odlink->color = odc_black;
break;
}
if (odlink->up->color == odc_black)
break;
odict_pgu(odlink, &p, &pcs, &g, &gcs, &u);
if (g == NULL) {
p->color = odc_black;
break;
}
if (p->color == odc_red && u != NULL && u->color == odc_red) {
p->color = odc_black;
u->color = odc_black;
g->color = odc_red;
odlink = g;
continue;
}
if (pcs != gcs) {
if (gcs == odcs_a) {
odict_rotate_left(p);
} else {
odict_rotate_right(p);
}
odlink = p;
odict_pgu(odlink, &p, &pcs, &g, &gcs, &u);
}
assert(pcs == gcs);
if (pcs == odcs_a) {
odict_rotate_right(g);
} else {
odict_rotate_left(g);
}
p->color = odc_black;
g->color = odc_red;
break;
}
}
void odict_remove(odlink_t *odlink)
{
odlink_t *n;
odlink_t *c;
odlink_t *p;
odlink_t *s;
odlink_t *sc, *st;
odict_child_sel_t pcs;
if (odlink->a != NULL && odlink->b != NULL) {
n = odict_next(odlink, odlink->odict);
assert(n != NULL);
odict_swap_node(odlink, n);
}
if (odlink->a != NULL) {
assert(odlink->b == NULL);
c = odlink->a;
} else {
c = odlink->b;
}
if (odlink->color == odc_red) {
assert(c == NULL);
odict_unlink(odlink);
return;
}
if (c != NULL && c->color == odc_red) {
c->color = odc_black;
odict_replace_subtree(c, odlink);
odlink->up = odlink->a = odlink->b = NULL;
odlink->odict = NULL;
list_remove(&odlink->lentries);
return;
}
assert(c == NULL);
n = NULL;
p = odlink->up;
odict_unlink(odlink);
again:
if (p == NULL)
return;
odict_sibling(n, p, &pcs, &s);
if (s->color == odc_red) {
assert(p->color == odc_black);
p->color = odc_red;
s->color = odc_black;
if (n == p->a)
odict_rotate_left(p);
else
odict_rotate_right(p);
odict_sibling(n, p, &pcs, &s);
assert(s->color == odc_black);
}
if (p->color == odc_black &&
s->color == odc_black &&
(s->a == NULL || s->a->color == odc_black) &&
(s->b == NULL || s->b->color == odc_black)) {
s->color = odc_red;
n = p;
p = n->up;
goto again;
}
if (p->color == odc_red &&
s->color == odc_black &&
(s->a == NULL || s->a->color == odc_black) &&
(s->b == NULL || s->b->color == odc_black)) {
s->color = odc_red;
p->color = odc_black;
return;
}
if (pcs == odcs_a) {
st = s->a;
sc = s->b;
} else {
st = s->b;
sc = s->a;
}
if (s->color == odc_black &&
(st != NULL && st->color == odc_red) &&
(sc == NULL || sc->color == odc_black)) {
if (pcs == odcs_a)
odict_rotate_right(s);
else
odict_rotate_left(s);
s->color = odc_red;
s->up->color = odc_black;
odict_sibling(n, p, &pcs, &s);
if (pcs == odcs_a) {
st = s->a;
sc = s->b;
} else {
st = s->b;
sc = s->a;
}
}
assert(s->color == odc_black);
assert(sc != NULL);
assert(sc->color == odc_red);
if (pcs == odcs_a)
odict_rotate_left(p);
else
odict_rotate_right(p);
s->color = p->color;
p->color = odc_black;
sc->color = odc_black;
}
void odict_key_update(odlink_t *odlink, odict_t *odict)
{
odlink_t *n;
n = odict_next(odlink, odict);
odict_remove(odlink);
odict_insert(odlink, odict, n);
}
bool odlink_used(odlink_t *odlink)
{
return odlink->odict != NULL;
}
bool odict_empty(odict_t *odict)
{
return odict->root == NULL;
}
unsigned long odict_count(odict_t *odict)
{
unsigned long cnt;
odlink_t *cur;
cnt = 0;
cur = odict_first(odict);
while (cur != NULL) {
++cnt;
cur = odict_next(cur, odict);
}
return cnt;
}
odlink_t *odict_first(odict_t *odict)
{
link_t *link;
link = list_first(&odict->entries);
if (link == NULL)
return NULL;
return list_get_instance(link, odlink_t, lentries);
}
odlink_t *odict_last(odict_t *odict)
{
link_t *link;
link = list_last(&odict->entries);
if (link == NULL)
return NULL;
return list_get_instance(link, odlink_t, lentries);
}
odlink_t *odict_prev(odlink_t *odlink, odict_t *odict)
{
link_t *link;
link = list_prev(&odlink->lentries, &odlink->odict->entries);
if (link == NULL)
return NULL;
return list_get_instance(link, odlink_t, lentries);
}
odlink_t *odict_next(odlink_t *odlink, odict_t *odict)
{
link_t *link;
link = list_next(&odlink->lentries, &odlink->odict->entries);
if (link == NULL)
return NULL;
return list_get_instance(link, odlink_t, lentries);
}
odlink_t *odict_find_eq(odict_t *odict, void *key, odlink_t *hint)
{
odlink_t *geq;
geq = odict_find_geq(odict, key, hint);
if (geq == NULL)
return NULL;
if (odict->cmp(odict->getkey(geq), key) == 0)
return geq;
else
return NULL;
}
odlink_t *odict_find_eq_last(odict_t *odict, void *key, odlink_t *hint)
{
odlink_t *leq;
leq = odict_find_leq(odict, key, hint);
if (leq == NULL)
return NULL;
if (odict->cmp(odict->getkey(leq), key) == 0)
return leq;
else
return NULL;
}
odlink_t *odict_find_geq(odict_t *odict, void *key, odlink_t *hint)
{
odlink_t *cur;
odlink_t *next;
int d;
cur = odict_search_start_node(odict, key, hint);
if (cur == NULL)
return NULL;
while (true) {
d = odict->cmp(odict->getkey(cur), key);
if (d >= 0)
next = cur->a;
else
next = cur->b;
if (next == NULL)
break;
cur = next;
}
if (d >= 0) {
return cur;
} else {
return odict_next(cur, odict);
}
}
odlink_t *odict_find_gt(odict_t *odict, void *key, odlink_t *hint)
{
odlink_t *leq;
leq = odict_find_leq(odict, key, hint);
if (leq != NULL)
return odict_next(leq, odict);
else
return odict_first(odict);
}
odlink_t *odict_find_leq(odict_t *odict, void *key, odlink_t *hint)
{
odlink_t *cur;
odlink_t *next;
int d;
cur = odict_search_start_node(odict, key, hint);
if (cur == NULL)
return NULL;
while (true) {
d = odict->cmp(key, odict->getkey(cur));
if (d >= 0)
next = cur->b;
else
next = cur->a;
if (next == NULL)
break;
cur = next;
}
if (d >= 0) {
return cur;
} else {
return odict_prev(cur, odict);
}
}
odlink_t *odict_find_lt(odict_t *odict, void *key, odlink_t *hint)
{
odlink_t *geq;
geq = odict_find_geq(odict, key, hint);
if (geq != NULL)
return odict_prev(geq, odict);
else
return odict_last(odict);
}
static void odict_pgu(odlink_t *n, odlink_t **p, odict_child_sel_t *pcs,
odlink_t **g, odict_child_sel_t *gcs, odlink_t **u)
{
*p = n->up;
if (*p == NULL) {
*g = NULL;
*u = NULL;
return;
}
if ((*p)->a == n) {
*pcs = odcs_a;
} else {
assert((*p)->b == n);
*pcs = odcs_b;
}
*g = (*p)->up;
if (*g == NULL) {
*u = NULL;
return;
}
if ((*g)->a == *p) {
*gcs = odcs_a;
*u = (*g)->b;
} else {
assert((*g)->b == *p);
*gcs = odcs_b;
*u = (*g)->a;
}
}
static void odict_sibling(odlink_t *n, odlink_t *p, odict_child_sel_t *pcs,
odlink_t **rs)
{
if (p->a == n) {
*pcs = odcs_a;
*rs = p->b;
} else {
*pcs = odcs_b;
*rs = p->a;
}
}
static void odict_rotate_left(odlink_t *p)
{
odlink_t *q;
q = p->b;
assert(q != NULL);
odict_replace_subtree(q, p);
p->up = q;
p->b = q->a;
if (p->b != NULL)
p->b->up = p;
q->a = p;
if (p->odict->root == p)
p->odict->root = q;
}
static void odict_rotate_right(odlink_t *q)
{
odlink_t *p;
p = q->a;
assert(p != NULL);
odict_replace_subtree(p, q);
q->up = p;
q->a = p->b;
if (q->a != NULL)
q->a->up = q;
p->b = q;
if (q->odict->root == q)
q->odict->root = p;
}
static void odict_swap_node(odlink_t *a, odlink_t *b)
{
odlink_t *n;
odict_color_t c;
if (a->up != NULL && a->up != b) {
if (a->up->a == a) {
a->up->a = b;
} else {
assert(a->up->b == a);
a->up->b = b;
}
}
if (a->a != NULL && a->a != b)
a->a->up = b;
if (a->b != NULL && a->b != b)
a->b->up = b;
if (b->up != NULL && b->up != a) {
if (b->up->a == b) {
b->up->a = a;
} else {
assert(b->up->b == b);
b->up->b = a;
}
}
if (b->a != NULL && b->a != a)
b->a->up = a;
if (b->b != NULL && b->b != a)
b->b->up = a;
n = a->up;
a->up = b->up;
b->up = n;
n = a->a;
a->a = b->a;
b->a = n;
n = a->b;
a->b = b->b;
b->b = n;
c = a->color;
a->color = b->color;
b->color = c;
if (a->up == a)
a->up = b;
if (a->a == a)
a->a = b;
if (a->b == a)
a->b = b;
if (b->up == b)
b->up = a;
if (b->a == b)
b->a = a;
if (b->b == b)
b->b = a;
if (a == a->odict->root)
a->odict->root = b;
else if (b == a->odict->root)
a->odict->root = a;
}
static void odict_replace_subtree(odlink_t *n, odlink_t *old)
{
if (old->up != NULL) {
if (old->up->a == old) {
old->up->a = n;
} else {
assert(old->up->b == old);
old->up->b = n;
}
} else {
assert(old->odict->root == old);
old->odict->root = n;
}
n->up = old->up;
}
static void odict_unlink(odlink_t *n)
{
if (n->up != NULL) {
if (n->up->a == n) {
n->up->a = NULL;
} else {
assert(n->up->b == n);
n->up->b = NULL;
}
n->up = NULL;
} else {
assert(n->odict->root == n);
n->odict->root = NULL;
}
if (n->a != NULL) {
n->a->up = NULL;
n->a = NULL;
}
if (n->b != NULL) {
n->b->up = NULL;
n->b = NULL;
}
n->odict = NULL;
list_remove(&n->lentries);
}
static void odict_link_child_a(odlink_t *n, odlink_t *old)
{
old->a = n;
n->up = old;
n->odict = old->odict;
list_insert_before(&n->lentries, &old->lentries);
}
static void odict_link_child_b(odlink_t *n, odlink_t *old)
{
old->b = n;
n->up = old;
n->odict = old->odict;
list_insert_after(&n->lentries, &old->lentries);
}
static odlink_t *odict_search_start_node(odict_t *odict, void *key,
odlink_t *hint)
{
odlink_t *a;
odlink_t *b;
odlink_t *cur;
int d, da, db;
assert(hint == NULL || hint->odict == odict);
b = odict_last(odict);
if (b != NULL) {
d = odict->cmp(odict->getkey(b), key);
if (d < 0)
return b;
}
a = odict_first(odict);
if (a != NULL) {
d = odict->cmp(key, odict->getkey(a));
if (d < 0)
return a;
}
if (hint == NULL)
return odict->root;
a = b = cur = hint;
while (cur->up != NULL) {
cur = cur->up;
d = odict->cmp(odict->getkey(cur), odict->getkey(a));
if (d < 0)
a = cur;
d = odict->cmp(odict->getkey(b), odict->getkey(cur));
if (d < 0)
b = cur;
da = odict->cmp(odict->getkey(a), key);
db = odict->cmp(key, odict->getkey(b));
if (da < 0 && db < 0) {
return cur;
}
}
return odict->root;
}
HelenOS homepage, sources at GitHub