Rewrite of red-black tree code.

This commit is contained in:
matt 2006-09-05 04:35:45 +00:00
parent f23a530674
commit 3aa5e506b7
2 changed files with 568 additions and 187 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rb.c,v 1.5 2006/09/02 20:46:50 matt Exp $ */
/* $NetBSD: rb.c,v 1.6 2006/09/05 04:35:45 matt Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -40,15 +40,21 @@
#include <sys/types.h>
#include <stddef.h>
#include <assert.h>
#include <stdbool.h>
#define KASSERT(s) assert(s)
#else
#include <lib/libkern/libkern.h>
#endif
#include "rb.h"
static void rb_tree_rotate(struct rb_tree *, struct rb_node *, int);
static void rb_tree_swap_nodes(struct rb_tree *, struct rb_node *, int);
static void rb_tree_insert_rebalance(struct rb_tree *, struct rb_node *);
static void rb_tree_removal_rebalance(struct rb_tree *, struct rb_node *);
static void rb_tree_removal_rebalance(struct rb_tree *, struct rb_node *,
unsigned int);
#ifndef NDEBUG
static bool rb_tree_check_node(const struct rb_tree *, const struct rb_node *,
const struct rb_node *, bool);
#endif
/*
* Rather than testing for the NULL everywhere, all terminal leaves are
@ -70,57 +76,78 @@ rb_tree_init(struct rb_tree *rbt, rb_compare_nodes_fn compare_nodes,
}
/*
* Rotate the tree between Y and X
* X c a Y
* a b b c
* Swap the location and colors of 'self' and its child @ which. The child
* can not be a sentinel node.
*/
void
rb_tree_rotate(struct rb_tree *rbt, struct rb_node *self, int which)
rb_tree_swap_nodes(struct rb_tree *rbt, struct rb_node *old_father, int which)
{
const int other = which ^ RB_OTHER;
struct rb_node * const parent = self->rb_parent;
struct rb_node * const child = self->rb_nodes[other];
const unsigned int other = which ^ RB_OTHER;
struct rb_node * const grandpa = old_father->rb_parent;
struct rb_node * const old_child = old_father->rb_nodes[which];
struct rb_node * const new_father = old_child;
struct rb_node * const new_child = old_father;
unsigned int properties;
KASSERT(!child->rb_sentinel);
KASSERT(child->rb_parent == self);
#if 0
(*rbt->rbt_print_node)(child, which ? "before-l " : "before-r ");
#endif
KASSERT(!RB_SENTINEL_P(old_child));
KASSERT(old_child->rb_parent == old_father);
if ((child->rb_parent = parent) == NULL) {
KASSERT(rbt->rbt_root == self);
rbt->rbt_root = child;
} else {
parent->rb_nodes[self->rb_position] = child;
KASSERT(rb_tree_check_node(rbt, old_father, NULL, false));
KASSERT(rb_tree_check_node(rbt, old_child, NULL, false));
KASSERT(RB_ROOT_P(old_father) || rb_tree_check_node(rbt, grandpa, NULL, false));
/*
* Exchange descendant linkages.
*/
grandpa->rb_nodes[old_father->rb_position] = new_father;
new_child->rb_nodes[which] = old_child->rb_nodes[other];
new_father->rb_nodes[other] = new_child;
/*
* Update ancestor linkages
*/
new_father->rb_parent = grandpa;
new_child->rb_parent = new_father;
/*
* Exchange properties between new_father and new_child. The only
* change is that new_child's position is now on the other side.
*/
properties = old_child->rb_properties;
new_father->rb_properties = old_father->rb_properties;
new_child->rb_properties = properties;
new_child->rb_position = other;
/*
* Make sure to reparent the new child to ourself.
*/
if (!RB_SENTINEL_P(new_child->rb_nodes[which])) {
new_child->rb_nodes[which]->rb_parent = new_child;
new_child->rb_nodes[which]->rb_position = which;
}
self->rb_nodes[other] = child->rb_nodes[which];
if (!self->rb_nodes[other]->rb_sentinel)
self->rb_nodes[other]->rb_parent = self;
child->rb_nodes[which] = self;
child->rb_position = self->rb_position;
self->rb_parent = child;
self->rb_position = which;
#if 0
(*rbt->rbt_print_node)(self, which ? "after-l " : "after-r ");
#endif
KASSERT(rb_tree_check_node(rbt, new_father, NULL, false));
KASSERT(rb_tree_check_node(rbt, new_child, NULL, false));
KASSERT(RB_ROOT_P(new_father) || rb_tree_check_node(rbt, grandpa, NULL, false));
}
void
rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
{
struct rb_node *prev, *next, *tmp, *parent;
u_int position = 2;
struct rb_node *prev, *next, *parent, *tmp;
unsigned int position;
self->rb_properties = 0;
prev = NULL;
next = NULL;
parent = NULL;
tmp = rbt->rbt_root;
parent = (struct rb_node *)&rbt->rbt_root;
position = RB_LEFT;
/*
* Find out where to place this new leaf.
*/
while (!tmp->rb_sentinel) {
while (!RB_SENTINEL_P(tmp)) {
const int diff = (*rbt->rbt_compare_nodes)(tmp, self);
parent = tmp;
KASSERT(diff != 0);
@ -139,115 +166,138 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
/*
* Verify our sequential position
*/
if (prev != NULL && next == NULL)
if (prev != NULL && !RB_SENTINEL_P(prev) && next == NULL)
next = TAILQ_NEXT(prev, rb_link);
if (prev == NULL && next != NULL)
if (prev == NULL && (next != NULL && !RB_SENTINEL_P(next)))
next = TAILQ_PREV(next, rb_node_qh, rb_link);
KASSERT(prev == NULL || (*rbt->rbt_compare_nodes)(prev, self) > 0);
KASSERT(next == NULL || (*rbt->rbt_compare_nodes)(self, next) < 0);
KASSERT(prev == NULL || RB_SENTINEL_P(prev) || (*rbt->rbt_compare_nodes)(prev, self) > 0);
KASSERT(next == NULL || RB_SENTINEL_P(next) || (*rbt->rbt_compare_nodes)(self, next) < 0);
/*
* Initialize the node and insert as a leaf into the tree.
*/
rbt->rbt_count++;
self->rb_parent = parent;
if (parent == NULL) {
KASSERT(rbt->rbt_root->rb_sentinel);
self->rb_position = RB_PARENT;
self->rb_left = rbt->rbt_root;
self->rb_right = rbt->rbt_root;
rbt->rbt_root = self;
self->rb_position = position;
if (__predict_false(parent == (struct rb_node *) &rbt->rbt_root)) {
RB_MARK_ROOT(self);
} else {
KASSERT(position == RB_LEFT || position == RB_RIGHT);
self->rb_position = position;
self->rb_left = parent->rb_nodes[position];
self->rb_right = parent->rb_nodes[position];
parent->rb_nodes[position] = self;
KASSERT(!RB_ROOT_P(self)); /* Already done */
}
KASSERT(RB_SENTINEL_P(parent->rb_nodes[position]));
self->rb_left = parent->rb_nodes[position];
self->rb_right = parent->rb_nodes[position];
parent->rb_nodes[position] = self;
KASSERT(self->rb_left == &sentinel_node &&
self->rb_right == &sentinel_node);
/*
* Insert the new node into a sorted list for easy sequential access
*/
if (next != NULL) {
rbt->rbt_count++;
if (next != NULL && !RB_SENTINEL_P(next)) {
TAILQ_INSERT_BEFORE(next, self, rb_link);
} else {
TAILQ_INSERT_TAIL(&rbt->rbt_nodes, self, rb_link);
}
#if 0
/*
* Rebalance tree after insertation
* Validate the tree before we rebalance
*/
rb_tree_check(rbt, false);
#endif
/*
* Rebalance tree after insertion
*/
rb_tree_insert_rebalance(rbt, self);
}
#if 0
/*
* Validate the tree after we rebalanced
*/
rb_tree_check(rbt, true);
#endif
}
void
rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self)
{
self->rb_red = 1;
RB_MARK_RED(self);
while (self != rbt->rbt_root && self->rb_parent->rb_red) {
const int which =
while (!RB_ROOT_P(self) && RB_RED_P(self->rb_parent)) {
const unsigned int which =
(self->rb_parent == self->rb_parent->rb_parent->rb_left
? RB_LEFT
: RB_RIGHT);
const int other = which ^ RB_OTHER;
struct rb_node *uncle;
const unsigned int other = which ^ RB_OTHER;
struct rb_node * father = self->rb_parent;
struct rb_node * grandpa = father->rb_parent;
struct rb_node * const uncle = grandpa->rb_nodes[other];
KASSERT(!self->rb_sentinel);
KASSERT(!RB_SENTINEL_P(self));
/*
* We are red, our are parent is red, and our
* grandparent is black.
* We are red and our parent is red, therefore we must have a
* grandfather and he must be black.
*/
uncle = self->rb_parent->rb_parent->rb_nodes[other];
if (uncle->rb_red) {
KASSERT(RB_RED_P(self)
&& RB_RED_P(father)
&& RB_BLACK_P(grandpa));
if (RB_RED_P(uncle)) {
/*
* Case 1: our uncle is red
* Simply invert the colors of our parent and
* uncle and make our grandparent red. And
* then solve the problem up at his level.
*/
uncle->rb_red = 0;
self->rb_parent->rb_red = 0;
self->rb_parent->rb_parent->rb_red = 1;
self = self->rb_parent->rb_parent;
} else {
/*
* Case 2&3: our uncle is black.
*/
if (self == self->rb_parent->rb_nodes[other]) {
/*
* Case 2: we are on the same side as our uncle
* Rotate parent away from uncle so this
* case becomes case 3
*/
self = self->rb_parent;
rb_tree_rotate(rbt, self, which);
}
/*
* Case 3: we are opposite a child of a black uncle.
* Change parent to black and grandparent to
* red. Rotate grandparent away from ourself.
*/
self->rb_parent->rb_red = 0;
self->rb_parent->rb_parent->rb_red = 1;
rb_tree_rotate(rbt, self->rb_parent->rb_parent, other);
RB_MARK_BLACK(uncle);
RB_MARK_BLACK(father);
RB_MARK_RED(grandpa);
self = grandpa;
continue;
}
/*
* Case 2&3: our uncle is black.
*/
if (self == father->rb_nodes[other]) {
/*
* Case 2: we are on the same side as our uncle
* Swap ourselves with our parent so this case
* becomes case 3. Basically our parent becomes our
* child.
*/
self = father;
rb_tree_swap_nodes(rbt, self, other);
father = self->rb_parent;
grandpa = father->rb_parent;
}
KASSERT(RB_RED_P(self) && RB_RED_P(father));
KASSERT(grandpa->rb_nodes[which] == father);
/*
* Case 3: we are opposite a child of a black uncle.
* Swap our parent and grandparent. Since our grandfather
* is black, our father will become black and our new sibling
* (former grandparent) will become red.
*/
rb_tree_swap_nodes(rbt, grandpa, which);
KASSERT(RB_RED_P(self) && RB_BLACK_P(father));
break;
}
/*
* Final step: Set the root to black.
*/
rbt->rbt_root->rb_red = 0;
RB_MARK_BLACK(rbt->rbt_root);
}
struct rb_node *
rb_tree_find(struct rb_tree *rbt, void *key)
{
struct rb_node *parent = rbt->rbt_root;
while (!parent->rb_sentinel) {
while (!RB_SENTINEL_P(parent)) {
const int diff = (*rbt->rbt_compare_key)(parent, key);
if (diff == 0)
return parent;
@ -257,116 +307,411 @@ rb_tree_find(struct rb_tree *rbt, void *key)
return NULL;
}
/*
*
*/
void
rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self)
{
struct rb_node *child;
/*
* Easy case, one or more children is NULL (leaf node or parent of
* leaf node).
* Easy case, there are no children. This means this node is
* at rank [N] (the bottom) of the red-black tree. We can simple just
* prune it. This leave the problem of identifying the node removed.
* Since the node "left" is a sentinel it doesn't carry any information.
* Instead we identify the removed node by parent and position.
*/
if (self->rb_left->rb_sentinel || self->rb_left->rb_sentinel) {
const int which = (!self->rb_left->rb_sentinel ? RB_LEFT : RB_RIGHT);
child = self->rb_nodes[which];
if (self->rb_parent == NULL) {
rbt->rbt_root = child;
} else {
self->rb_parent->rb_nodes[self->rb_position] = child;
}
if (child->rb_sentinel)
child = self->rb_parent;
else
child->rb_parent = self->rb_parent;
} else {
struct rb_node *new_self;
child = self->rb_right;
while (!child->rb_left->rb_sentinel)
child = child->rb_left;
new_self = child;
KASSERT(new_self == TAILQ_NEXT(self, rb_link));
/*
* Take new_self out of the tree (its only subnode can be on the
* right since we know the left subnode is NULL).
*/
child->rb_parent->rb_left = child->rb_right;
if (!child->rb_right->rb_sentinel) {
child->rb_right->rb_parent = child->rb_parent;
child->rb_right->rb_position = RB_LEFT;
}
/*
* Take self out of the tree and insert new_self into its place.
*/
new_self->rb_right = self->rb_right;
new_self->rb_left = self->rb_left;
if (!new_self->rb_right->rb_sentinel)
new_self->rb_right->rb_parent = new_self;
if (!new_self->rb_left->rb_sentinel)
new_self->rb_left->rb_parent = new_self;
new_self->rb_red = self->rb_red;
new_self->rb_parent = self->rb_parent;
/*
* Update parent
*/
if (new_self->rb_parent == NULL) {
rbt->rbt_root = new_self;
} else {
new_self->rb_parent->rb_nodes[self->rb_position] = new_self;
}
if (RB_CHILDLESS_P(self)) {
KASSERT(rb_tree_check_node(rbt, self, NULL, false));
self->rb_parent->rb_nodes[self->rb_position] = self->rb_left;
if (RB_BLACK_P(self) && !RB_ROOT_P(self))
rb_tree_removal_rebalance(rbt,
self->rb_parent, self->rb_position);
KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, self->rb_parent, NULL, true));
goto done;
}
/*
* If this node only has one valid child, that child must be itself
* childless. This is because a red-black tree only has leaves at
* two ranks, [N-1] and [N]. If this node only has one child at this
* rank, this must be rank [N-1] since all nodes at rank [N] are
* childless. Thus our child must be at rank [N] and therevore must
* be childless.
*
* Promoting this node's child to rank [N-1] and giving this node's
* color allows us to pretend we really removed a node of rank [N].
* Now if the child was red, even better since we can just return
* knowing that removing a red node from a red-black tree still
* leaves a valid red-black tree.
*
* D \ D \ D
* B F > B E > B E
* A C E _ / A C _ F / A C _ x
*
* We are removing F, but F has a child E. So we swap E and F (in
* theory but we really replace F by E thereby removing F from the
* tree).
*/
if (!RB_TWOCHILDREN_P(self)) {
const unsigned int which = RB_LEFT_SENTINEL_P(self) ? RB_RIGHT : RB_LEFT;
const unsigned int other = which ^ RB_OTHER;
struct rb_node * const new_self = self->rb_nodes[which];
const bool was_black = RB_BLACK_P(new_self);
KASSERT(RB_CHILDLESS_P(new_self));
KASSERT(rb_tree_check_node(rbt, new_self, NULL, false));
/*
* Copy self to new_self.
*/
self->rb_parent->rb_nodes[self->rb_position] = new_self;
new_self->rb_parent = self->rb_parent;
new_self->rb_properties = self->rb_properties;
new_self->rb_nodes[which] = new_self->rb_nodes[other];
KASSERT(rb_tree_check_node(rbt, new_self, NULL, false));
if (was_black) {
/*
* Now rebalance
*/
rb_tree_removal_rebalance(rbt, new_self, other);
} else {
/*
* If new_self was red, then self must have been black.
*/
KASSERT(RB_BLACK_P(self));
/* RB_MARK_BLACK(new_self); */
}
KASSERT(rb_tree_check_node(rbt, new_self, NULL, true));
goto done;
}
/*
* The node to be removed is in the interior of the red-black tree.
* This results in a difficulty in this red-black implementation
* since contrary to a traditional implemenation the interior nodes
* contain the keys while the leaves have no keys.
*
* D | C
* B F | B F
* A C E G | A x E G
* 1 2 3 4 5 6 7 | 1 2 3 5 6 7
*
* We need to remove D. Whom do we swap with, C or E? It doesn't
* matter since they are both at rank [N]. We put C as root and
* then pretend D was a child B. Even though D's key would never
* have been valid at C, since it's now deleted it's key is
* irrevalent. We simply claim to have deleted right(B).
*
* D | E
* B F | B F
* A E G | A x G
* 1 2 4 5 6 7 | 1 2 5 6 7
*
* We need to remove D. Whom do we swap with? E, of course. E is
* the closest node of rank [N]. Always choose the highest rank you
* can. We make E root and then pretend D was a child F. Again D's
* key is irrevalent. We simply claim to have deleted left(F).
*
* D | D
* B F | B G
* A G | A F
* 1 2 4 6 7 | 1 2 4 6 7
*
* We need to remove D. Whom do we swap with? B and F are equally
* bad since they both have one child. So we swap one and that
* reduces to the previous case.
*/
if (RB_TWOCHILDREN_P(self)) {
struct rb_node * const next = TAILQ_NEXT(self, rb_link);
struct rb_node * const prev = TAILQ_PREV(self, rb_node_qh, rb_link);
struct rb_node * new_self;
struct rb_node * parent;
unsigned int which;
bool was_black;
KASSERT(next != NULL && prev != NULL);
KASSERT(!RB_TWOCHILDREN_P(next));
KASSERT(!RB_TWOCHILDREN_P(prev));
/*
* First, pick the childless victim.
* Now we two possible victims
* Otherwise, if root, pick from the side with more nodes.
* Lastly, pick from the side closest to the root.
*/
if (RB_CHILDLESS_P(next) && !RB_CHILDLESS_P(prev)) {
new_self = next;
} else if (RB_CHILDLESS_P(prev) && !RB_CHILDLESS_P(next)) {
new_self = prev;
} else if (RB_ROOT_P(self)) {
new_self = prev;
} else {
new_self = next;
}
KASSERT(new_self != rbt->rbt_root);
KASSERT(!RB_TWOCHILDREN_P(new_self));
if (RB_CHILDLESS_P(new_self)) {
KASSERT(rb_tree_check_node(rbt, new_self, NULL, false));
which = new_self->rb_position;
parent = new_self->rb_parent;
was_black = RB_BLACK_P(new_self);
parent->rb_nodes[which] = new_self->rb_left;
KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
} else {
/*
* New self has one child. And we know it's on the
* opposite side than what we want. So we want to
* replace new_self with it and then self with new_self.
*/
which = new_self->rb_position;
parent = new_self->rb_nodes[which ^ RB_OTHER];
was_black = RB_BLACK_P(parent);
KASSERT(RB_SENTINEL_P(new_self->rb_nodes[which]));
KASSERT(!RB_SENTINEL_P(parent));
KASSERT(RB_CHILDLESS_P(parent));
/*
* Move parent to new_self's location in the tree.
*/
new_self->rb_parent->rb_nodes[new_self->rb_position] = parent;
parent->rb_parent = new_self->rb_parent;
parent->rb_properties = new_self->rb_properties;
KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
}
/*
* Move new_self to our location in the tree.
*/
self->rb_parent->rb_nodes[self->rb_position] = new_self;
new_self->rb_left = self->rb_left;
new_self->rb_right = self->rb_right;
new_self->rb_parent = self->rb_parent;
new_self->rb_properties = self->rb_properties;
new_self->rb_left->rb_parent = new_self;
new_self->rb_right->rb_parent = new_self;
KASSERT(rb_tree_check_node(rbt, new_self, NULL, false));
/*
* Rebalance if the node was
*/
if (was_black)
rb_tree_removal_rebalance(rbt, parent, which);
}
done:
/*
* Remove ourselves from the node list and decrement the count.
*/
TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
rbt->rbt_count--;
if (child != NULL) {
KASSERT(!child->rb_sentinel);
#if 0
(*rbt->rbt_print_node)(child, "before ");
#endif
rb_tree_removal_rebalance(rbt, child);
#if 0
(*rbt->rbt_print_node)(child, "after ");
#endif
}
}
void
rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *self)
rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
unsigned int which)
{
KASSERT(!RB_SENTINEL_P(parent));
KASSERT(RB_SENTINEL_P(parent->rb_nodes[which]));
while (RB_BLACK_P(parent->rb_nodes[which])) {
unsigned int other = which ^ RB_OTHER;
struct rb_node *brother = parent->rb_nodes[other];
KASSERT(!RB_SENTINEL_P(brother));
/*
* For cases 1, 2a, and 2b, our brother's children must
* be black.
*/
if (RB_BLACK_P(brother->rb_left)
&& RB_BLACK_P(brother->rb_right)) {
/*
* Case 1: Our brother is red, swap its position
* (and colors) with our parent. This is now case 2b.
*
* B -> D
* x d -> b E
* C E -> x C
*/
if (RB_RED_P(brother)) {
KASSERT(RB_BLACK_P(parent));
rb_tree_swap_nodes(rbt, parent, other);
brother = parent->rb_nodes[other];
KASSERT(RB_BLACK_P(parent->rb_nodes[which]));
KASSERT(!RB_SENTINEL_P(brother));
KASSERT(RB_RED_P(parent));
KASSERT(RB_BLACK_P(brother->rb_left)
&& RB_BLACK_P(brother->rb_right));
}
if (RB_BLACK_P(parent)) {
/*
* Both our parent and brother are black.
* Change our brother to red, advance up rank
* and go through the loop again.
*
* B -> B
* A D -> A d
* C E -> C E
*/
RB_MARK_RED(brother);
if (RB_ROOT_P(parent))
return;
KASSERT(rb_tree_check_node(rbt, brother, NULL, false));
KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
which = parent->rb_position;
parent = parent->rb_parent;
} else {
KASSERT(RB_BLACK_P(brother));
RB_MARK_BLACK(parent);
RB_MARK_RED(brother);
KASSERT(rb_tree_check_node(rbt, brother, NULL, true));
KASSERT(rb_tree_check_node(rbt, parent, NULL, true));
return;
}
} else {
KASSERT(RB_BLACK_P(brother));
KASSERT(!RB_CHILDLESS_P(brother));
/*
* Case 3: our brother is black, our left nephew is
* red, and our right nephew is black. Swap our
* brother with our left nephew. This result in a
* tree that matches case 4.
*
* B -> D
* A D -> B E
* c e -> A C
*/
if (RB_BLACK_P(brother->rb_nodes[other])) {
KASSERT(RB_RED_P(brother->rb_nodes[which]));
rb_tree_swap_nodes(rbt, brother, which);
brother = parent->rb_nodes[other];
KASSERT(RB_RED_P(brother->rb_nodes[other]));
}
/*
* Case 4: our brother is black and our right nephew
* is red. Swap our parent and brother locations and
* change our right nephew to black. (these can be
* done in either order so we change the color first).
* The result is a valid red-black tree and is a
* terminal case.
*
* B -> D
* A D -> B E
* c e -> A C
*/
RB_MARK_BLACK(brother->rb_nodes[other]);
rb_tree_swap_nodes(rbt, parent, other);
KASSERT(rb_tree_check_node(rbt, parent, NULL, true));
return;
}
}
KASSERT(rb_tree_check_node(rbt, parent, NULL, true));
}
#ifndef NDEBUG
bool
rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self,
const struct rb_node *prev, bool red_check)
{
KASSERT(!self->rb_sentinel);
while (self->rb_parent != NULL && !self->rb_red) {
struct rb_node *parent = self->rb_parent;
int which = (self == parent->rb_left) ? RB_LEFT : RB_RIGHT;
int other = which ^ RB_OTHER;
struct rb_node *sibling = parent->rb_nodes[other];
KASSERT(self->rb_left);
KASSERT(self->rb_right);
KASSERT(prev == NULL || (*rbt->rbt_compare_nodes)(prev, self) > 0);
if (sibling->rb_red) {
sibling->rb_red = 0;
parent->rb_red = 1;
rb_tree_rotate(rbt, parent, which);
parent = self->rb_parent;
sibling = parent->rb_nodes[other];
/*
* Verify our relationship to our parent.
*/
if (RB_ROOT_P(self)) {
KASSERT(self == rbt->rbt_root);
KASSERT(self->rb_position == RB_LEFT);
KASSERT(self->rb_parent->rb_nodes[RB_LEFT] == self);
KASSERT(self->rb_parent == (const struct rb_node *) &rbt->rbt_root);
} else {
KASSERT(self != rbt->rbt_root);
KASSERT(!RB_PARENT_SENTINEL_P(self));
if (self->rb_position == RB_LEFT) {
KASSERT((*rbt->rbt_compare_nodes)(self, self->rb_parent) > 0);
KASSERT(self->rb_parent->rb_nodes[RB_LEFT] == self);
} else {
KASSERT((*rbt->rbt_compare_nodes)(self, self->rb_parent) < 0);
KASSERT(self->rb_parent->rb_nodes[RB_RIGHT] == self);
}
}
if (sibling->rb_sentinel ||
(!sibling->rb_left->rb_red && !sibling->rb_right->rb_red)) {
sibling->rb_red = 1;
self = parent;
continue;
/*
* The root must be black.
* There can never be two adjacent red nodes.
*/
if (red_check) {
KASSERT(!RB_ROOT_P(self) || RB_BLACK_P(self));
if (RB_RED_P(self)) {
KASSERT(!RB_ROOT_P(self));
KASSERT(RB_BLACK_P(self->rb_parent));
KASSERT(RB_LEFT_SENTINEL_P(self)
|| RB_BLACK_P(self->rb_left));
KASSERT(RB_RIGHT_SENTINEL_P(self)
|| RB_BLACK_P(self->rb_right));
}
/*
* A grandparent's children must be real nodes and not
* sentinels. First check out grandparent.
*/
KASSERT(RB_ROOT_P(self)
|| RB_ROOT_P(self->rb_parent)
|| RB_TWOCHILDREN_P(self->rb_parent->rb_parent));
/*
* If we are have grandchildren on our left, then
* we must have a child on our right.
*/
KASSERT(RB_LEFT_SENTINEL_P(self)
|| RB_CHILDLESS_P(self->rb_left)
|| !RB_RIGHT_SENTINEL_P(self));
/*
* If we are have grandchildren on our right, then
* we must have a child on our left.
*/
KASSERT(RB_RIGHT_SENTINEL_P(self)
|| RB_CHILDLESS_P(self->rb_right)
|| !RB_LEFT_SENTINEL_P(self));
}
if (!sibling->rb_nodes[other]->rb_red) {
sibling->rb_nodes[which]->rb_red = 0;
sibling->rb_red = 1;
rb_tree_rotate(rbt, sibling, other);
parent = self->rb_parent;
sibling = parent->rb_nodes[other];
return true;
}
void
rb_tree_check(const struct rb_tree *rbt, bool red_check)
{
const struct rb_node *self;
const struct rb_node *prev;
int counts[2] = { 0, 0 };
unsigned int which = RB_LEFT;
KASSERT(rbt->rbt_root == NULL || rbt->rbt_root->rb_position == RB_LEFT);
prev = NULL;
TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) {
rb_tree_check_node(rbt, self, prev, false);
if (self == rbt->rbt_root) {
which = RB_RIGHT;
} else {
counts[which]++;
}
prev = self;
}
KASSERT(rbt->rbt_count == counts[RB_RIGHT] + counts[RB_LEFT] + (which == RB_RIGHT));
sibling->rb_red = parent->rb_red;
parent->rb_red = 0;
sibling->rb_nodes[other]->rb_red = 0;
rb_tree_rotate(rbt, parent, which);
break;
/*
* The root must be black.
* There can never be two adjacent red nodes.
*/
if (red_check) {
KASSERT(rbt->rbt_root == NULL || RB_BLACK_P(rbt->rbt_root));
TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) {
rb_tree_check_node(rbt, self, NULL, true);
}
}
}
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: rb.h,v 1.2 2002/10/08 11:58:54 simonb Exp $ */
/* $NetBSD: rb.h,v 1.3 2006/09/05 04:35:45 matt Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -40,6 +40,7 @@
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/endian.h>
struct rb_node {
struct rb_node *rb_nodes[3];
@ -51,10 +52,44 @@ struct rb_node {
#define rb_right rb_nodes[RB_RIGHT]
#define rb_parent rb_nodes[RB_PARENT]
TAILQ_ENTRY(rb_node) rb_link;
int rb_balance : 16;
unsigned int rb_red : 1;
unsigned int rb_sentinel : 1;
unsigned int rb_position : 2;
union {
struct {
#if BYTE_ORDER == LITTLE_ENDIAN
unsigned int : 27;
unsigned int s_root : 1;
unsigned int s_position : 2;
unsigned int s_color : 1;
unsigned int s_sentinel : 1;
#endif
#if BYTE_ORDER == BIG_ENDIAN
unsigned int s_sentinel : 1;
unsigned int s_color : 1;
unsigned int s_position : 2;
unsigned int s_root : 1;
unsigned int : 27;
#endif
} u_s;
unsigned int u_i;
} rb_u;
#define rb_root rb_u.u_s.s_root
#define rb_position rb_u.u_s.s_position
#define rb_color rb_u.u_s.s_color
#define rb_sentinel rb_u.u_s.s_sentinel
#define rb_properties rb_u.u_i
#define RB_SENTINEL_P(rb) ((rb)->rb_sentinel + 0)
#define RB_LEFT_SENTINEL_P(rb) ((rb)->rb_left->rb_sentinel + 0)
#define RB_RIGHT_SENTINEL_P(rb) ((rb)->rb_right->rb_sentinel + 0)
#define RB_PARENT_SENTINEL_P(rb) ((rb)->rb_parent->rb_sentinel + 0)
#define RB_CHILDLESS_P(rb) (RB_LEFT_SENTINEL_P(rb) \
&& RB_RIGHT_SENTINEL_P(rb))
#define RB_TWOCHILDREN_P(rb) (!RB_LEFT_SENTINEL_P(rb) \
&& !RB_RIGHT_SENTINEL_P(rb))
#define RB_ROOT_P(rb) ((rb)->rb_root != false)
#define RB_RED_P(rb) ((rb)->rb_color + 0)
#define RB_BLACK_P(rb) (!(rb)->rb_color)
#define RB_MARK_RED(rb) ((void)((rb)->rb_color = 1))
#define RB_MARK_BLACK(rb) ((void)((rb)->rb_color = 0))
#define RB_MARK_ROOT(rb) ((void)((rb)->rb_root = 1))
};
TAILQ_HEAD(rb_node_qh, rb_node);
@ -70,7 +105,7 @@ struct rb_tree {
rb_compare_nodes_fn rbt_compare_nodes;
rb_compare_key_fn rbt_compare_key;
rb_print_node_fn rbt_print_node;
u_int rbt_count;
unsigned int rbt_count;
};
void rb_tree_init(struct rb_tree *, rb_compare_nodes_fn, rb_compare_key_fn,
@ -78,5 +113,6 @@ void rb_tree_init(struct rb_tree *, rb_compare_nodes_fn, rb_compare_key_fn,
void rb_tree_insert_node(struct rb_tree *, struct rb_node *);
struct rb_node *rb_tree_find(struct rb_tree *, void *);
void rb_tree_remove_node(struct rb_tree *, struct rb_node *);
void rb_tree_check(const struct rb_tree *, bool);
#endif /* _LIBKERN_RB_H_*/