123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600 |
- #define CHECK(n)
- #include <kernel.h>
- #include <sys/rb.h>
- #include <stdbool.h>
- enum rb_color { RED = 0U, BLACK = 1U };
- static struct rbnode *get_child(struct rbnode *n, uint8_t side)
- {
- CHECK(n);
- if (side != 0U) {
- return n->children[1];
- }
- uintptr_t l = (uintptr_t) n->children[0];
- l &= ~1UL;
- return (struct rbnode *) l;
- }
- static void set_child(struct rbnode *n, uint8_t side, void *val)
- {
- CHECK(n);
- if (side != 0U) {
- n->children[1] = val;
- } else {
- uintptr_t old = (uintptr_t) n->children[0];
- uintptr_t new = (uintptr_t) val;
- n->children[0] = (void *) (new | (old & 1UL));
- }
- }
- static enum rb_color get_color(struct rbnode *n)
- {
- CHECK(n);
- return ((uintptr_t)n->children[0]) & 1UL;
- }
- static bool is_black(struct rbnode *n)
- {
- return get_color(n) == BLACK;
- }
- static bool is_red(struct rbnode *n)
- {
- return get_color(n) == RED;
- }
- static void set_color(struct rbnode *n, enum rb_color color)
- {
- CHECK(n);
- uintptr_t *p = (void *) &n->children[0];
- *p = (*p & ~1UL) | (uint8_t)color;
- }
- static int find_and_stack(struct rbtree *tree, struct rbnode *node,
- struct rbnode **stack)
- {
- int sz = 0;
- stack[sz++] = tree->root;
- while (stack[sz - 1] != node) {
- uint8_t side = tree->lessthan_fn(node, stack[sz - 1]) ? 0U : 1U;
- struct rbnode *ch = get_child(stack[sz - 1], side);
- if (ch != NULL) {
- stack[sz++] = ch;
- } else {
- break;
- }
- }
- return sz;
- }
- struct rbnode *z_rb_get_minmax(struct rbtree *tree, uint8_t side)
- {
- struct rbnode *n;
- for (n = tree->root; (n != NULL) && (get_child(n, side) != NULL);
- n = get_child(n, side)) {
- ;
- }
- return n;
- }
- static uint8_t get_side(struct rbnode *parent, struct rbnode *child)
- {
- CHECK(get_child(parent, 0U) == child || get_child(parent, 1U) == child);
- return (get_child(parent, 1U) == child) ? 1U : 0U;
- }
- static void rotate(struct rbnode **stack, int stacksz)
- {
- CHECK(stacksz >= 2);
- struct rbnode *parent = stack[stacksz - 2];
- struct rbnode *child = stack[stacksz - 1];
- uint8_t side = get_side(parent, child);
- struct rbnode *a = get_child(child, side);
- struct rbnode *b = get_child(child, (side == 0U) ? 1U : 0U);
- if (stacksz >= 3) {
- struct rbnode *grandparent = stack[stacksz - 3];
- set_child(grandparent, get_side(grandparent, parent), child);
- }
- set_child(child, side, a);
- set_child(child, (side == 0U) ? 1U : 0U, parent);
- set_child(parent, side, b);
- stack[stacksz - 2] = child;
- stack[stacksz - 1] = parent;
- }
- static void fix_extra_red(struct rbnode **stack, int stacksz)
- {
- while (stacksz > 1) {
- struct rbnode *node = stack[stacksz - 1];
- struct rbnode *parent = stack[stacksz - 2];
-
- CHECK((get_child(node, 0U) == NULL) ||
- is_black(get_child(node, 0U)));
- CHECK((get_child(node, 1U) == NULL) ||
- is_black(get_child(node, 1U)));
- if (is_black(parent)) {
- return;
- }
-
- CHECK(stacksz >= 2);
- struct rbnode *grandparent = stack[stacksz - 3];
- uint8_t side = get_side(grandparent, parent);
- struct rbnode *aunt = get_child(grandparent,
- (side == 0U) ? 1U : 0U);
- if ((aunt != NULL) && is_red(aunt)) {
- set_color(grandparent, RED);
- set_color(parent, BLACK);
- set_color(aunt, BLACK);
-
- stacksz -= 2;
- continue;
- }
-
- uint8_t parent_side = get_side(parent, node);
- if (parent_side != side) {
- rotate(stack, stacksz);
- node = stack[stacksz - 1];
- }
-
- rotate(stack, stacksz - 1);
- set_color(stack[stacksz - 3], BLACK);
- set_color(stack[stacksz - 2], RED);
- return;
- }
-
- set_color(stack[0], BLACK);
- }
- void rb_insert(struct rbtree *tree, struct rbnode *node)
- {
- set_child(node, 0U, NULL);
- set_child(node, 1U, NULL);
- if (tree->root == NULL) {
- tree->root = node;
- tree->max_depth = 1;
- set_color(node, BLACK);
- return;
- }
- #ifdef CONFIG_MISRA_SANE
- struct rbnode **stack = &tree->iter_stack[0];
- #else
- struct rbnode *stack[tree->max_depth + 1];
- #endif
- int stacksz = find_and_stack(tree, node, stack);
- struct rbnode *parent = stack[stacksz - 1];
- uint8_t side = tree->lessthan_fn(node, parent) ? 0U : 1U;
- set_child(parent, side, node);
- set_color(node, RED);
- stack[stacksz++] = node;
- fix_extra_red(stack, stacksz);
- if (stacksz > tree->max_depth) {
- tree->max_depth = stacksz;
- }
-
- tree->root = stack[0];
- CHECK(is_black(tree->root));
- }
- static void fix_missing_black(struct rbnode **stack, int stacksz,
- struct rbnode *null_node)
- {
-
- while (stacksz > 1) {
- struct rbnode *c0, *c1, *inner, *outer;
- struct rbnode *n = stack[stacksz - 1];
- struct rbnode *parent = stack[stacksz - 2];
- uint8_t n_side = get_side(parent, n);
- struct rbnode *sib = get_child(parent,
- (n_side == 0U) ? 1U : 0U);
- CHECK(is_black(n));
-
- if (!is_black(sib)) {
- stack[stacksz - 1] = sib;
- rotate(stack, stacksz);
- set_color(parent, RED);
- set_color(sib, BLACK);
- stack[stacksz++] = n;
- parent = stack[stacksz - 2];
- sib = get_child(parent, (n_side == 0U) ? 1U : 0U);
- }
- CHECK(sib);
-
- c0 = get_child(sib, 0U);
- c1 = get_child(sib, 1U);
- if (((c0 == NULL) || is_black(c0)) && ((c1 == NULL) ||
- is_black(c1))) {
- if (n == null_node) {
- set_child(parent, n_side, NULL);
- }
- set_color(sib, RED);
- if (is_black(parent)) {
-
- stacksz--;
- continue;
- } else {
-
- set_color(parent, BLACK);
- return;
- }
- }
- CHECK((c0 && is_red(c0)) || (c1 && is_red(c1)));
-
- outer = get_child(sib, (n_side == 0U) ? 1U : 0U);
- if (!((outer != NULL) && is_red(outer))) {
- inner = get_child(sib, n_side);
- stack[stacksz - 1] = sib;
- stack[stacksz++] = inner;
- rotate(stack, stacksz);
- set_color(sib, RED);
- set_color(inner, BLACK);
-
- sib = stack[stacksz - 2];
- outer = get_child(sib, (n_side == 0U) ? 1U : 0U);
- stack[stacksz - 2] = n;
- stacksz--;
- }
-
- CHECK(is_red(outer));
- set_color(sib, get_color(parent));
- set_color(parent, BLACK);
- set_color(outer, BLACK);
- stack[stacksz - 1] = sib;
- rotate(stack, stacksz);
- if (n == null_node) {
- set_child(parent, n_side, NULL);
- }
- return;
- }
- }
- void rb_remove(struct rbtree *tree, struct rbnode *node)
- {
- struct rbnode *tmp;
- #ifdef CONFIG_MISRA_SANE
- struct rbnode **stack = &tree->iter_stack[0];
- #else
- struct rbnode *stack[tree->max_depth + 1];
- #endif
- int stacksz = find_and_stack(tree, node, stack);
- if (node != stack[stacksz - 1]) {
- return;
- }
-
- if ((get_child(node, 0U) != NULL) && (get_child(node, 1U) != NULL)) {
- int stacksz0 = stacksz;
- struct rbnode *hiparent, *loparent;
- struct rbnode *node2 = get_child(node, 0U);
- hiparent = (stacksz > 1) ? stack[stacksz - 2] : NULL;
- stack[stacksz++] = node2;
- while (get_child(node2, 1U) != NULL) {
- node2 = get_child(node2, 1U);
- stack[stacksz++] = node2;
- }
- loparent = stack[stacksz - 2];
-
- if (hiparent != NULL) {
- set_child(hiparent, get_side(hiparent, node), node2);
- } else {
- tree->root = node2;
- }
- if (loparent == node) {
- set_child(node, 0U, get_child(node2, 0U));
- set_child(node2, 0U, node);
- } else {
- set_child(loparent, get_side(loparent, node2), node);
- tmp = get_child(node, 0U);
- set_child(node, 0U, get_child(node2, 0U));
- set_child(node2, 0U, tmp);
- }
- set_child(node2, 1U, get_child(node, 1U));
- set_child(node, 1U, NULL);
- tmp = stack[stacksz0 - 1];
- stack[stacksz0 - 1] = stack[stacksz - 1];
- stack[stacksz - 1] = tmp;
- enum rb_color ctmp = get_color(node);
- set_color(node, get_color(node2));
- set_color(node2, ctmp);
- }
- CHECK((get_child(node, 0U) == NULL) ||
- (get_child(node, 1U) == NULL));
- struct rbnode *child = get_child(node, 0U);
- if (child == NULL) {
- child = get_child(node, 1U);
- }
-
- if (stacksz < 2) {
- tree->root = child;
- if (child != NULL) {
- set_color(child, BLACK);
- } else {
- tree->max_depth = 0;
- }
- return;
- }
- struct rbnode *parent = stack[stacksz - 2];
-
- if (child == NULL) {
- if (is_black(node)) {
- fix_missing_black(stack, stacksz, node);
- } else {
-
- set_child(parent, get_side(parent, node), NULL);
- }
- } else {
- set_child(parent, get_side(parent, node), child);
-
- __ASSERT(is_black(node) || is_black(child), "both nodes red?!");
- if (is_red(node) || is_red(child)) {
- set_color(child, BLACK);
- }
- }
-
- tree->root = stack[0];
- }
- #ifndef CONFIG_MISRA_SANE
- void z_rb_walk(struct rbnode *node, rb_visit_t visit_fn, void *cookie)
- {
- if (node != NULL) {
- z_rb_walk(get_child(node, 0U), visit_fn, cookie);
- visit_fn(node, cookie);
- z_rb_walk(get_child(node, 1U), visit_fn, cookie);
- }
- }
- #endif
- struct rbnode *z_rb_child(struct rbnode *node, uint8_t side)
- {
- return get_child(node, side);
- }
- int z_rb_is_black(struct rbnode *node)
- {
- return is_black(node);
- }
- bool rb_contains(struct rbtree *tree, struct rbnode *node)
- {
- struct rbnode *n = tree->root;
- while ((n != NULL) && (n != node)) {
- n = get_child(n, tree->lessthan_fn(n, node));
- }
- return n == node;
- }
- static inline struct rbnode *stack_left_limb(struct rbnode *n,
- struct _rb_foreach *f)
- {
- f->top++;
- f->stack[f->top] = n;
- f->is_left[f->top] = 0U;
- while ((n = get_child(n, 0U)) != NULL) {
- f->top++;
- f->stack[f->top] = n;
- f->is_left[f->top] = 1;
- }
- return f->stack[f->top];
- }
- struct rbnode *z_rb_foreach_next(struct rbtree *tree, struct _rb_foreach *f)
- {
- struct rbnode *n;
- if (tree->root == NULL) {
- return NULL;
- }
-
- if (f->top == -1) {
- return stack_left_limb(tree->root, f);
- }
-
- n = get_child(f->stack[f->top], 1U);
- if (n != NULL) {
- return stack_left_limb(n, f);
- }
-
- if (f->is_left[f->top] != 0U) {
- return f->stack[--f->top];
- }
-
- while ((f->top > 0) && (f->is_left[f->top] == 0U)) {
- f->top--;
- }
- f->top--;
- return (f->top >= 0) ? f->stack[f->top] : NULL;
- }
|