Add rb_tree_find_node_{geq,leq}. Add stats. Make TAILQ DEBUG only.

Keep track of tree's min/max nodes for easier iteration.  Improve comments.
Move functions around to improve locality.
This commit is contained in:
matt 2006-09-09 05:55:51 +00:00
parent cec3b712bd
commit 75de26ab17
2 changed files with 325 additions and 142 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rb.c,v 1.8 2006/09/08 04:07:15 matt Exp $ */ /* $NetBSD: rb.c,v 1.9 2006/09/09 05:55:51 matt Exp $ */
/*- /*-
* Copyright (c) 2001 The NetBSD Foundation, Inc. * Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -68,7 +68,7 @@ static const struct rb_node sentinel_node = {
.rb_nodes[0] = __UNCONST(&sentinel_node), .rb_nodes[0] = __UNCONST(&sentinel_node),
.rb_nodes[1] = __UNCONST(&sentinel_node), .rb_nodes[1] = __UNCONST(&sentinel_node),
.rb_sentinel = 1 .rb_sentinel = 1
}; };
void void
rb_tree_init(struct rb_tree *rbt, rb_compare_nodes_fn compare_nodes, rb_tree_init(struct rb_tree *rbt, rb_compare_nodes_fn compare_nodes,
@ -79,72 +79,77 @@ rb_tree_init(struct rb_tree *rbt, rb_compare_nodes_fn compare_nodes,
rbt->rbt_compare_nodes = compare_nodes; rbt->rbt_compare_nodes = compare_nodes;
rbt->rbt_compare_key = compare_key; rbt->rbt_compare_key = compare_key;
*((const struct rb_node **)&rbt->rbt_root) = &sentinel_node; *((const struct rb_node **)&rbt->rbt_root) = &sentinel_node;
rbt->rbt_minmax[RB_LEFT] = rbt->rbt_root; /* minimum node */
rbt->rbt_minmax[RB_RIGHT] = rbt->rbt_root; /* maximum node */
#ifdef RBSTATS
rbt->rbt_insertions = 0;
rbt->rbt_removals = 0;
rbt->rbt_insertion_rebalance_calls = 0;
rbt->rbt_insertion_rebalance_passes = 0;
rbt->rbt_removal_rebalance_calls = 0;
rbt->rbt_removal_rebalance_passes = 0;
#endif
} }
/* struct rb_node *
* Swap the location and colors of 'self' and its child @ which. The child rb_tree_find_node(struct rb_tree *rbt, const void *key)
* can not be a sentinel node.
*/
static void
rb_tree_reparent_nodes(struct rb_tree *rbt, struct rb_node *old_father, int which)
{ {
const unsigned int other = which ^ RB_OTHER; struct rb_node *parent = rbt->rbt_root;
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(which == RB_LEFT || which == RB_RIGHT); while (!RB_SENTINEL_P(parent)) {
const int diff = (*rbt->rbt_compare_key)(parent, key);
KASSERT(!RB_SENTINEL_P(old_child)); if (diff == 0)
KASSERT(old_child->rb_parent == old_father); return parent;
parent = parent->rb_nodes[diff > 0];
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;
} }
KASSERT(rb_tree_check_node(rbt, new_father, NULL, false)); return NULL;
KASSERT(rb_tree_check_node(rbt, new_child, NULL, false));
KASSERT(RB_ROOT_P(new_father) || rb_tree_check_node(rbt, grandpa, NULL, false));
} }
struct rb_node *
rb_tree_find_node_geq(struct rb_tree *rbt, const void *key)
{
struct rb_node *parent = rbt->rbt_root;
struct rb_node *last = NULL;
while (!RB_SENTINEL_P(parent)) {
const int diff = (*rbt->rbt_compare_key)(parent, key);
if (diff == 0)
return parent;
if (diff < 0)
last = parent;
parent = parent->rb_nodes[diff > 0];
}
return last;
}
struct rb_node *
rb_tree_find_node_leq(struct rb_tree *rbt, const void *key)
{
struct rb_node *parent = rbt->rbt_root;
struct rb_node *last = NULL;
while (!RB_SENTINEL_P(parent)) {
const int diff = (*rbt->rbt_compare_key)(parent, key);
if (diff == 0)
return parent;
if (diff > 0)
last = parent;
parent = parent->rb_nodes[diff > 0];
}
return last;
}
void void
rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self) rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
{ {
struct rb_node *parent, *tmp; struct rb_node *parent, *tmp;
unsigned int position; unsigned int position;
RBSTAT_INC(rbt->rbt_insertions);
self->rb_properties = 0; self->rb_properties = 0;
tmp = rbt->rbt_root; tmp = rbt->rbt_root;
/* /*
@ -206,9 +211,18 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
self->rb_position = position; self->rb_position = position;
if (__predict_false(parent == (struct rb_node *) &rbt->rbt_root)) { if (__predict_false(parent == (struct rb_node *) &rbt->rbt_root)) {
RB_MARK_ROOT(self); RB_MARK_ROOT(self);
rbt->rbt_minmax[RB_LEFT] = self;
rbt->rbt_minmax[RB_RIGHT] = self;
} else { } else {
KASSERT(position == RB_LEFT || position == RB_RIGHT); KASSERT(position == RB_LEFT || position == RB_RIGHT);
KASSERT(!RB_ROOT_P(self)); /* Already done */ KASSERT(!RB_ROOT_P(self)); /* Already done */
/*
* Keep track of the minimum and maximum nodes. If our
* parent is a minmax node and we on their min/max side,
* we must be the new min/max node.
*/
if (parent == rbt->rbt_minmax[position])
rbt->rbt_minmax[position] = self;
} }
KASSERT(RB_SENTINEL_P(parent->rb_nodes[position])); KASSERT(RB_SENTINEL_P(parent->rb_nodes[position]));
self->rb_left = parent->rb_nodes[position]; self->rb_left = parent->rb_nodes[position];
@ -254,10 +268,72 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
#endif #endif
} }
/*
* Swap the location and colors of 'self' and its child @ which. The child
* can not be a sentinel node. This is our rotation function. However,
* since it preserves coloring, it great simplifies both insertion and
* removal since rotation almost always involves the exchanging of colors
* as a separate step.
*/
static void
rb_tree_reparent_nodes(struct rb_tree *rbt, struct rb_node *old_father, int which)
{
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(which == RB_LEFT || which == RB_RIGHT);
KASSERT(!RB_SENTINEL_P(old_child));
KASSERT(old_child->rb_parent == old_father);
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;
}
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));
}
static void static void
rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self) rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self)
{ {
RB_MARK_RED(self); RB_MARK_RED(self);
RBSTAT_INC(rbt->rbt_insertion_rebalance_calls);
while (!RB_ROOT_P(self) && RB_RED_P(self->rb_parent)) { while (!RB_ROOT_P(self) && RB_RED_P(self->rb_parent)) {
const unsigned int which = const unsigned int which =
@ -269,6 +345,7 @@ rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self)
struct rb_node * grandpa = father->rb_parent; struct rb_node * grandpa = father->rb_parent;
struct rb_node * const uncle = grandpa->rb_nodes[other]; struct rb_node * const uncle = grandpa->rb_nodes[other];
RBSTAT_INC(rbt->rbt_insertion_rebalance_passes);
KASSERT(!RB_SENTINEL_P(self)); KASSERT(!RB_SENTINEL_P(self));
/* /*
* We are red and our parent is red, therefore we must have a * We are red and our parent is red, therefore we must have a
@ -331,21 +408,6 @@ rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self)
RB_MARK_BLACK(rbt->rbt_root); 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 (!RB_SENTINEL_P(parent)) {
const int diff = (*rbt->rbt_compare_key)(parent, key);
if (diff == 0)
return parent;
parent = parent->rb_nodes[diff > 0];
}
return NULL;
}
static void static void
rb_tree_prune_node(struct rb_tree *rbt, struct rb_node *self, int rebalance) rb_tree_prune_node(struct rb_tree *rbt, struct rb_node *self, int rebalance)
{ {
@ -357,19 +419,42 @@ rb_tree_prune_node(struct rb_tree *rbt, struct rb_node *self, int rebalance)
KASSERT(RB_CHILDLESS_P(self)); KASSERT(RB_CHILDLESS_P(self));
KASSERT(rb_tree_check_node(rbt, self, NULL, false)); KASSERT(rb_tree_check_node(rbt, self, NULL, false));
/*
* Since we are childless, we know that self->rb_left is pointing
* to the sentinel node.
*/
father->rb_nodes[which] = self->rb_left; father->rb_nodes[which] = self->rb_left;
/* /*
* Remove ourselves from the node list and decrement the count. * Remove ourselves from the node list, decrement the count,
* and update min/max.
*/ */
RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link); RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
rbt->rbt_count--; rbt->rbt_count--;
if (__predict_false(rbt->rbt_minmax[self->rb_position] == self)) {
rbt->rbt_minmax[self->rb_position] = father;
/*
* When removing the root, rbt->rbt_minmax[RB_LEFT] is
* updated automatically, but we also need to update
* rbt->rbt_minmax[RB_RIGHT];
*/
if (__predict_false(RB_ROOT_P(self))) {
rbt->rbt_minmax[RB_RIGHT] = father;
}
}
self->rb_sentinel = 1; /* so remove_node will fail */
/*
* Rebalance if requested.
*/
if (rebalance) if (rebalance)
rb_tree_removal_rebalance(rbt, father, which); rb_tree_removal_rebalance(rbt, father, which);
KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, father, NULL, true)); KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, father, NULL, true));
} }
/*
* When deleting an interior node
*/
static void static void
rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self, rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self,
struct rb_node *standin) struct rb_node *standin)
@ -383,14 +468,14 @@ rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self,
if (standin->rb_parent == self) { if (standin->rb_parent == self) {
/* /*
* As a child of self, any childen would be opposite of * As a child of self, any childen would be opposite of
* our parent (self). * our parent.
*/ */
KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other])); KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other]));
standin_child = standin->rb_nodes[standin_which]; standin_child = standin->rb_nodes[standin_which];
} else { } else {
/* /*
* Since we aren't a child of self, any childen would be * Since we aren't a child of self, any childen would be
* on the same side as our parent (self). * on the same side as our parent.
*/ */
KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_which])); KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_which]));
standin_child = standin->rb_nodes[standin_other]; standin_child = standin->rb_nodes[standin_other];
@ -481,10 +566,15 @@ rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self,
standin->rb_parent->rb_nodes[standin->rb_position] = standin; standin->rb_parent->rb_nodes[standin->rb_position] = standin;
/* /*
* Remove ourselves from the node list and decrement the count. * Remove ourselves from the node list, decrement the count,
* and update min/max.
*/ */
RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link); RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
rbt->rbt_count--; rbt->rbt_count--;
if (__predict_false(rbt->rbt_minmax[self->rb_position] == self))
rbt->rbt_minmax[self->rb_position] = self->rb_parent;
self->rb_sentinel = 1;
KASSERT(rb_tree_check_node(rbt, standin, NULL, false)); KASSERT(rb_tree_check_node(rbt, standin, NULL, false));
KASSERT(rb_tree_check_node(rbt, standin_father, NULL, false)); KASSERT(rb_tree_check_node(rbt, standin_father, NULL, false));
@ -507,32 +597,40 @@ static void
rb_tree_prune_blackred_branch(struct rb_tree *rbt, struct rb_node *self, rb_tree_prune_blackred_branch(struct rb_tree *rbt, struct rb_node *self,
unsigned int which) unsigned int which)
{ {
struct rb_node *parent = self->rb_parent; struct rb_node *father = self->rb_parent;
struct rb_node *child = self->rb_nodes[which]; struct rb_node *son = self->rb_nodes[which];
KASSERT(which == RB_LEFT || which == RB_RIGHT); KASSERT(which == RB_LEFT || which == RB_RIGHT);
KASSERT(RB_BLACK_P(self) && RB_RED_P(child)); KASSERT(RB_BLACK_P(self) && RB_RED_P(son));
KASSERT(!RB_TWOCHILDREN_P(child)); KASSERT(!RB_TWOCHILDREN_P(son));
KASSERT(RB_CHILDLESS_P(child)); KASSERT(RB_CHILDLESS_P(son));
KASSERT(rb_tree_check_node(rbt, self, NULL, false)); KASSERT(rb_tree_check_node(rbt, self, NULL, false));
KASSERT(rb_tree_check_node(rbt, child, NULL, false)); KASSERT(rb_tree_check_node(rbt, son, NULL, false));
/* /*
* Remove ourselves from the tree and give our former child our * Remove ourselves from the tree and give our former child our
* properties (position, color, root). * properties (position, color, root).
*/ */
parent->rb_nodes[self->rb_position] = child; father->rb_nodes[self->rb_position] = son;
child->rb_parent = parent; son->rb_parent = father;
child->rb_properties = self->rb_properties; son->rb_properties = self->rb_properties;
/* /*
* Remove ourselves from the node list and decrement the count. * Remove ourselves from the node list, decrement the count,
* and update minmax.
*/ */
RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link); RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
rbt->rbt_count--; rbt->rbt_count--;
if (__predict_false(RB_ROOT_P(self))) {
KASSERT(rbt->rbt_minmax[which] == son);
rbt->rbt_minmax[which ^ RB_OTHER] = son;
} else if (rbt->rbt_minmax[self->rb_position] == self) {
rbt->rbt_minmax[self->rb_position] = son;
}
self->rb_sentinel = 1;
KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, parent, NULL, true)); KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, father, NULL, true));
KASSERT(rb_tree_check_node(rbt, child, NULL, true)); KASSERT(rb_tree_check_node(rbt, son, NULL, true));
} }
/* /*
* *
@ -542,6 +640,10 @@ rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self)
{ {
struct rb_node *standin; struct rb_node *standin;
unsigned int which; unsigned int which;
KASSERT(!RB_SENTINEL_P(self));
RBSTAT_INC(rbt->rbt_removals);
/* /*
* In the following diagrams, we (the node to be removed) are S. Red * In the following diagrams, we (the node to be removed) are S. Red
* nodes are lowercase. T could be either red or black. * nodes are lowercase. T could be either red or black.
@ -560,11 +662,8 @@ rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self)
* | s --> * | * | s --> * |
*/ */
if (RB_CHILDLESS_P(self)) { if (RB_CHILDLESS_P(self)) {
if (RB_RED_P(self) || RB_ROOT_P(self)) { bool rebalance = RB_BLACK_P(self) && !RB_ROOT_P(self);
rb_tree_prune_node(rbt, self, false); rb_tree_prune_node(rbt, self, rebalance);
return;
}
rb_tree_prune_node(rbt, self, true);
return; return;
} }
KASSERT(!RB_CHILDLESS_P(self)); KASSERT(!RB_CHILDLESS_P(self));
@ -607,11 +706,14 @@ rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
KASSERT(!RB_SENTINEL_P(parent)); KASSERT(!RB_SENTINEL_P(parent));
KASSERT(RB_SENTINEL_P(parent->rb_nodes[which])); KASSERT(RB_SENTINEL_P(parent->rb_nodes[which]));
KASSERT(which == RB_LEFT || which == RB_RIGHT); KASSERT(which == RB_LEFT || which == RB_RIGHT);
RBSTAT_INC(rbt->rbt_removal_rebalance_calls);
while (RB_BLACK_P(parent->rb_nodes[which])) { while (RB_BLACK_P(parent->rb_nodes[which])) {
unsigned int other = which ^ RB_OTHER; unsigned int other = which ^ RB_OTHER;
struct rb_node *brother = parent->rb_nodes[other]; struct rb_node *brother = parent->rb_nodes[other];
RBSTAT_INC(rbt->rbt_removal_rebalance_passes);
KASSERT(!RB_SENTINEL_P(brother)); KASSERT(!RB_SENTINEL_P(brother));
/* /*
* For cases 1, 2a, and 2b, our brother's children must * For cases 1, 2a, and 2b, our brother's children must
@ -620,21 +722,24 @@ rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
if (RB_BLACK_P(parent) if (RB_BLACK_P(parent)
&& RB_BLACK_P(brother->rb_left) && RB_BLACK_P(brother->rb_left)
&& RB_BLACK_P(brother->rb_right)) { && 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)) { if (RB_RED_P(brother)) {
/*
* Case 1: Our brother is red, swap its
* position (and colors) with our parent.
* This should now be case 2b (unless C or E
* has a red child which is case 3; thus no
* explicit branch to case 2b).
*
* B -> D
* A d -> b E
* C E -> A C
*/
KASSERT(RB_BLACK_P(parent)); KASSERT(RB_BLACK_P(parent));
rb_tree_reparent_nodes(rbt, parent, other); rb_tree_reparent_nodes(rbt, parent, other);
brother = parent->rb_nodes[other]; brother = parent->rb_nodes[other];
KASSERT(!RB_SENTINEL_P(brother)); KASSERT(!RB_SENTINEL_P(brother));
KASSERT(RB_BLACK_P(brother));
KASSERT(RB_RED_P(parent)); KASSERT(RB_RED_P(parent));
KASSERT(RB_BLACK_P(brother));
KASSERT(rb_tree_check_node(rbt, brother, NULL, false)); KASSERT(rb_tree_check_node(rbt, brother, NULL, false));
KASSERT(rb_tree_check_node(rbt, parent, NULL, false)); KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
} else { } else {
@ -643,8 +748,8 @@ rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
* Change our brother to red, advance up rank * Change our brother to red, advance up rank
* and go through the loop again. * and go through the loop again.
* *
* B -> B * B -> *B
* A D -> A d * *A D -> A d
* C E -> C E * C E -> C E
*/ */
RB_MARK_RED(brother); RB_MARK_RED(brother);
@ -656,14 +761,31 @@ rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
KASSERT(rb_tree_check_node(rbt, parent, NULL, false)); KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
which = parent->rb_position; which = parent->rb_position;
parent = parent->rb_parent; parent = parent->rb_parent;
continue;
} }
} else if (RB_RED_P(parent) }
/*
* Avoid an else here so that case 2a above can hit either
* case 2b, 3, or 4.
*/
if (RB_RED_P(parent)
&& RB_BLACK_P(brother) && RB_BLACK_P(brother)
&& RB_BLACK_P(brother->rb_left) && RB_BLACK_P(brother->rb_left)
&& RB_BLACK_P(brother->rb_right)) { && RB_BLACK_P(brother->rb_right)) {
KASSERT(RB_RED_P(parent));
KASSERT(RB_BLACK_P(brother)); KASSERT(RB_BLACK_P(brother));
KASSERT(RB_BLACK_P(brother->rb_left)); KASSERT(RB_BLACK_P(brother->rb_left));
KASSERT(RB_BLACK_P(brother->rb_right)); KASSERT(RB_BLACK_P(brother->rb_right));
/*
* We are black, our father is red, our brother and
* both nephews are black. Simply invert/exchange the
* colors of our father and brother (to black and red
* respectively).
*
* | f --> F |
* | * B --> * b |
* | N N --> N N |
*/
RB_MARK_BLACK(parent); RB_MARK_BLACK(parent);
RB_MARK_RED(brother); RB_MARK_RED(brother);
KASSERT(rb_tree_check_node(rbt, brother, NULL, true)); KASSERT(rb_tree_check_node(rbt, brother, NULL, true));
@ -671,17 +793,18 @@ rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
} else { } else {
KASSERT(RB_BLACK_P(brother)); KASSERT(RB_BLACK_P(brother));
KASSERT(!RB_CHILDLESS_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])) { if (RB_BLACK_P(brother->rb_nodes[other])) {
/*
* Case 3: our brother is black, our near
* nephew is red, and our far nephew is black.
* Swap our brother with our near nephew.
* This result in a tree that matches case 4.
* (Our father could be red or black).
*
* | F --> F |
* | x B --> x B |
* | n --> n |
*/
KASSERT(RB_RED_P(brother->rb_nodes[which])); KASSERT(RB_RED_P(brother->rb_nodes[which]));
rb_tree_reparent_nodes(rbt, brother, which); rb_tree_reparent_nodes(rbt, brother, which);
KASSERT(brother->rb_parent == parent->rb_nodes[other]); KASSERT(brother->rb_parent == parent->rb_nodes[other]);
@ -689,16 +812,25 @@ rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
KASSERT(RB_RED_P(brother->rb_nodes[other])); KASSERT(RB_RED_P(brother->rb_nodes[other]));
} }
/* /*
* Case 4: our brother is black and our right nephew * Case 4: our brother is black and our far nephew
* is red. Swap our parent and brother locations and * is red. Swap our father and brother locations and
* change our right nephew to black. (these can be * change our far nephew to black. (these can be
* done in either order so we change the color first). * done in either order so we change the color first).
* The result is a valid red-black tree and is a * The result is a valid red-black tree and is a
* terminal case. * terminal case. (again we don't care about the
* father's color)
* *
* B -> D * If the father is red, we will get a red-black-black
* A D -> B E * tree:
* c e -> A C * | f -> f --> b |
* | B -> B --> F N |
* | n -> N --> |
*
* If the father is black, we will get an all black
* tree:
* | F -> F --> B |
* | B -> B --> F N |
* | n -> N --> |
*/ */
RB_MARK_BLACK(brother->rb_nodes[other]); RB_MARK_BLACK(brother->rb_nodes[other]);
rb_tree_reparent_nodes(rbt, parent, other); rb_tree_reparent_nodes(rbt, parent, other);
@ -716,12 +848,9 @@ rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self,
KASSERT(direction == RB_LEFT || direction == RB_RIGHT); KASSERT(direction == RB_LEFT || direction == RB_RIGHT);
if (self == NULL) { if (self == NULL) {
self = rbt->rbt_root; if (RB_SENTINEL_P(rbt->rbt_root))
if (RB_SENTINEL_P(self))
return NULL; return NULL;
while (!RB_SENTINEL_P(self->rb_nodes[other])) return rbt->rbt_minmax[direction];
self = self->rb_nodes[other];
return self;
} }
KASSERT(!RB_SENTINEL_P(self)); KASSERT(!RB_SENTINEL_P(self));
/* /*
@ -757,12 +886,9 @@ rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self,
KASSERT(direction == RB_LEFT || direction == RB_RIGHT); KASSERT(direction == RB_LEFT || direction == RB_RIGHT);
if (self == NULL) { if (self == NULL) {
self = rbt->rbt_root; if (RB_SENTINEL_P(rbt->rbt_root))
if (RB_SENTINEL_P(self))
return NULL; return NULL;
while (!RB_SENTINEL_P(self->rb_nodes[other])) return rbt->rbt_minmax[direction];
self = self->rb_nodes[other];
return self;
} }
KASSERT(!RB_SENTINEL_P(self)); KASSERT(!RB_SENTINEL_P(self));
/* /*
@ -825,9 +951,9 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self,
const struct rb_node *prev0 = rb_tree_iterate_const(rbt, self, RB_LEFT); const struct rb_node *prev0 = rb_tree_iterate_const(rbt, self, RB_LEFT);
const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_RIGHT); const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_RIGHT);
KASSERT(prev0 == TAILQ_PREV(self, rb_node_qh, rb_link)); KASSERT(prev0 == TAILQ_PREV(self, rb_node_qh, rb_link));
if (next0 != TAILQ_NEXT(self, rb_link))
next0 = rb_tree_iterate_const(rbt, self, RB_RIGHT);
KASSERT(next0 == TAILQ_NEXT(self, rb_link)); KASSERT(next0 == TAILQ_NEXT(self, rb_link));
KASSERT(prev0 != NULL || self == rbt->rbt_minmax[RB_LEFT]);
KASSERT(next0 != NULL || self == rbt->rbt_minmax[RB_RIGHT]);
} }
/* /*
@ -1005,7 +1131,11 @@ rb_tree_check(const struct rb_tree *rbt, bool red_check)
const struct rb_node *prev; const struct rb_node *prev;
unsigned int count; unsigned int count;
KASSERT(rbt->rbt_root == NULL || rbt->rbt_root->rb_position == RB_LEFT); KASSERT(rbt->rbt_root != NULL);
KASSERT(rbt->rbt_root->rb_position == RB_LEFT);
KASSERT(rbt->rbt_count > 1
|| rbt->rbt_minmax[RB_LEFT] == rbt->rbt_minmax[RB_RIGHT]);
prev = NULL; prev = NULL;
count = 0; count = 0;
@ -1028,4 +1158,33 @@ rb_tree_check(const struct rb_tree *rbt, bool red_check)
} }
} }
} }
#endif #endif /* !NDEBUG || DIAGNOSTIC */
#ifdef RBSTATS
static void
rb_tree_mark_depth(const struct rb_tree *rbt, const struct rb_node *self,
size_t *depths, size_t depth)
{
if (RB_SENTINEL_P(self))
return;
if (RB_TWOCHILDREN_P(self)) {
rb_tree_mark_depth(rbt, self->rb_left, depths, depth + 1);
rb_tree_mark_depth(rbt, self->rb_right, depths, depth + 1);
return;
}
depths[depth]++;
if (!RB_LEFT_SENTINEL_P(self)) {
rb_tree_mark_depth(rbt, self->rb_left, depths, depth + 1);
}
if (!RB_RIGHT_SENTINEL_P(self)) {
rb_tree_mark_depth(rbt, self->rb_right, depths, depth + 1);
}
}
void
rb_tree_depths(const struct rb_tree *rbt, size_t *depths)
{
rb_tree_mark_depth(rbt, rbt->rbt_root, depths, 1);
}
#endif /* RBSTATS */

View File

@ -1,4 +1,4 @@
/* $NetBSD: rb.h,v 1.4 2006/09/08 04:07:15 matt Exp $ */ /* $NetBSD: rb.h,v 1.5 2006/09/09 05:55:51 matt Exp $ */
/*- /*-
* Copyright (c) 2001 The NetBSD Foundation, Inc. * Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -97,11 +97,11 @@ struct rb_node {
#if !defined(NDEBUG) || defined(DEBUG) #if !defined(NDEBUG) || defined(DEBUG)
TAILQ_HEAD(rb_node_qh, rb_node); TAILQ_HEAD(rb_node_qh, rb_node);
#define RB_TAILQ_REMOVE TAILQ_REMOVE #define RB_TAILQ_REMOVE(a, b, c) TAILQ_REMOVE(a, b, c)
#define RB_TAILQ_INIT TAILQ_INIT #define RB_TAILQ_INIT(a) TAILQ_INIT(a)
#define RB_TAILQ_INSERT_HEAD(a, b, c) TAILQ_INSERT_HEAD #define RB_TAILQ_INSERT_HEAD(a, b, c) TAILQ_INSERT_HEAD(a, b, c)
#define RB_TAILQ_INSERT_BEFORE(a, b, c) TAILQ_INSERT_BEFORE #define RB_TAILQ_INSERT_BEFORE(a, b, c) TAILQ_INSERT_BEFORE(a, b, c)
#define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER #define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER(a, b, c, d)
#else #else
#define RB_TAILQ_REMOVE(a, b, c) do { } while (0) #define RB_TAILQ_REMOVE(a, b, c) do { } while (0)
#define RB_TAILQ_INIT(a) do { } while (0) #define RB_TAILQ_INIT(a) do { } while (0)
@ -121,16 +121,40 @@ struct rb_tree {
#endif #endif
rb_compare_nodes_fn rbt_compare_nodes; rb_compare_nodes_fn rbt_compare_nodes;
rb_compare_key_fn rbt_compare_key; rb_compare_key_fn rbt_compare_key;
struct rb_node *rbt_minmax[2];
unsigned int rbt_count; unsigned int rbt_count;
#ifdef RBSTATS
unsigned int rbt_insertions;
unsigned int rbt_removals;
unsigned int rbt_insertion_rebalance_calls;
unsigned int rbt_insertion_rebalance_passes;
unsigned int rbt_removal_rebalance_calls;
unsigned int rbt_removal_rebalance_passes;
#endif
}; };
#ifdef RBSTATS
#define RBSTAT_INC(v) ((void)((v)++))
#else
#define RBSTAT_INC(v) do { } while (0)
#endif
void rb_tree_init(struct rb_tree *, rb_compare_nodes_fn, rb_compare_key_fn); 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 *); void rb_tree_insert_node(struct rb_tree *, struct rb_node *);
struct rb_node * struct rb_node *
rb_tree_find(struct rb_tree *, void *); rb_tree_find_node(struct rb_tree *, const void *);
struct rb_node *
rb_tree_find_node_geq(struct rb_tree *, const void *);
struct rb_node *
rb_tree_find_node_leq(struct rb_tree *, const void *);
void rb_tree_remove_node(struct rb_tree *, struct rb_node *); void rb_tree_remove_node(struct rb_tree *, struct rb_node *);
void rb_tree_check(const struct rb_tree *, bool);
struct rb_node * struct rb_node *
rb_tree_iterate(struct rb_tree *, struct rb_node *, unsigned int); rb_tree_iterate(struct rb_tree *, struct rb_node *, unsigned int);
#if !defined(NDEBUG) || defined(DIAGNOSTIC)
void rb_tree_check(const struct rb_tree *, bool);
#endif
#ifdef RBSTATS
void rb_tree_depths(const struct rb_tree *, size_t *);
#endif
#endif /* _LIBKERN_RB_H_*/ #endif /* _LIBKERN_RB_H_*/