From 75de26ab173fe0b5c6cc1b7bc2c5a2ba6a44bf5e Mon Sep 17 00:00:00 2001 From: matt Date: Sat, 9 Sep 2006 05:55:51 +0000 Subject: [PATCH] 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. --- sys/lib/libkern/rb.c | 427 +++++++++++++++++++++++++++++-------------- sys/lib/libkern/rb.h | 40 +++- 2 files changed, 325 insertions(+), 142 deletions(-) diff --git a/sys/lib/libkern/rb.c b/sys/lib/libkern/rb.c index 6e1cc1e97f1f..70df82578b50 100644 --- a/sys/lib/libkern/rb.c +++ b/sys/lib/libkern/rb.c @@ -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. @@ -68,7 +68,7 @@ static const struct rb_node sentinel_node = { .rb_nodes[0] = __UNCONST(&sentinel_node), .rb_nodes[1] = __UNCONST(&sentinel_node), .rb_sentinel = 1 - }; +}; void 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_key = compare_key; *((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 } -/* - * Swap the location and colors of 'self' and its child @ which. The child - * can not be a sentinel node. - */ -static void -rb_tree_reparent_nodes(struct rb_tree *rbt, struct rb_node *old_father, int which) +struct rb_node * +rb_tree_find_node(struct rb_tree *rbt, const void *key) { - 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; + struct rb_node *parent = rbt->rbt_root; - 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; + 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]; } - 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)); + return NULL; } + +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 rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self) { struct rb_node *parent, *tmp; unsigned int position; + RBSTAT_INC(rbt->rbt_insertions); + self->rb_properties = 0; tmp = rbt->rbt_root; /* @@ -206,9 +211,18 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self) self->rb_position = position; if (__predict_false(parent == (struct rb_node *) &rbt->rbt_root)) { RB_MARK_ROOT(self); + rbt->rbt_minmax[RB_LEFT] = self; + rbt->rbt_minmax[RB_RIGHT] = self; } else { KASSERT(position == RB_LEFT || position == RB_RIGHT); 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])); self->rb_left = parent->rb_nodes[position]; @@ -254,10 +268,72 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self) #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 rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self) { RB_MARK_RED(self); + RBSTAT_INC(rbt->rbt_insertion_rebalance_calls); while (!RB_ROOT_P(self) && RB_RED_P(self->rb_parent)) { 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 * const uncle = grandpa->rb_nodes[other]; + RBSTAT_INC(rbt->rbt_insertion_rebalance_passes); KASSERT(!RB_SENTINEL_P(self)); /* * 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); } -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 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_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; /* - * 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); 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) rb_tree_removal_rebalance(rbt, father, which); KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, father, NULL, true)); } - + +/* + * When deleting an interior node + */ static void rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self, 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) { /* * 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])); standin_child = standin->rb_nodes[standin_which]; } else { /* * 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])); 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; /* - * 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); 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_father, NULL, false)); @@ -507,32 +597,40 @@ static void rb_tree_prune_blackred_branch(struct rb_tree *rbt, struct rb_node *self, unsigned int which) { - struct rb_node *parent = self->rb_parent; - struct rb_node *child = self->rb_nodes[which]; + struct rb_node *father = self->rb_parent; + struct rb_node *son = self->rb_nodes[which]; KASSERT(which == RB_LEFT || which == RB_RIGHT); - KASSERT(RB_BLACK_P(self) && RB_RED_P(child)); - KASSERT(!RB_TWOCHILDREN_P(child)); - KASSERT(RB_CHILDLESS_P(child)); + KASSERT(RB_BLACK_P(self) && RB_RED_P(son)); + KASSERT(!RB_TWOCHILDREN_P(son)); + KASSERT(RB_CHILDLESS_P(son)); 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 * properties (position, color, root). */ - parent->rb_nodes[self->rb_position] = child; - child->rb_parent = parent; - child->rb_properties = self->rb_properties; + father->rb_nodes[self->rb_position] = son; + son->rb_parent = father; + 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); 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_tree_check_node(rbt, child, NULL, true)); + KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, father, 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; 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 * 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 --> * | */ if (RB_CHILDLESS_P(self)) { - if (RB_RED_P(self) || RB_ROOT_P(self)) { - rb_tree_prune_node(rbt, self, false); - return; - } - rb_tree_prune_node(rbt, self, true); + bool rebalance = RB_BLACK_P(self) && !RB_ROOT_P(self); + rb_tree_prune_node(rbt, self, rebalance); return; } 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->rb_nodes[which])); KASSERT(which == RB_LEFT || which == RB_RIGHT); + RBSTAT_INC(rbt->rbt_removal_rebalance_calls); while (RB_BLACK_P(parent->rb_nodes[which])) { unsigned int other = which ^ RB_OTHER; struct rb_node *brother = parent->rb_nodes[other]; + RBSTAT_INC(rbt->rbt_removal_rebalance_passes); + KASSERT(!RB_SENTINEL_P(brother)); /* * 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) && 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)) { + /* + * 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)); rb_tree_reparent_nodes(rbt, parent, other); brother = parent->rb_nodes[other]; KASSERT(!RB_SENTINEL_P(brother)); - KASSERT(RB_BLACK_P(brother)); 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, parent, NULL, false)); } 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 * and go through the loop again. * - * B -> B - * A D -> A d + * B -> *B + * *A D -> A d * C E -> C E */ 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)); which = parent->rb_position; 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_left) && RB_BLACK_P(brother->rb_right)) { + KASSERT(RB_RED_P(parent)); KASSERT(RB_BLACK_P(brother)); KASSERT(RB_BLACK_P(brother->rb_left)); 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_RED(brother); 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 { 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])) { + /* + * 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])); rb_tree_reparent_nodes(rbt, brother, which); 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])); } /* - * 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 + * Case 4: our brother is black and our far nephew + * is red. Swap our father and brother locations and + * change our far 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. + * terminal case. (again we don't care about the + * father's color) * - * B -> D - * A D -> B E - * c e -> A C + * If the father is red, we will get a red-black-black + * tree: + * | 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_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); if (self == NULL) { - self = rbt->rbt_root; - if (RB_SENTINEL_P(self)) + if (RB_SENTINEL_P(rbt->rbt_root)) return NULL; - while (!RB_SENTINEL_P(self->rb_nodes[other])) - self = self->rb_nodes[other]; - return self; + return rbt->rbt_minmax[direction]; } 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); if (self == NULL) { - self = rbt->rbt_root; - if (RB_SENTINEL_P(self)) + if (RB_SENTINEL_P(rbt->rbt_root)) return NULL; - while (!RB_SENTINEL_P(self->rb_nodes[other])) - self = self->rb_nodes[other]; - return self; + return rbt->rbt_minmax[direction]; } 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 *next0 = rb_tree_iterate_const(rbt, self, RB_RIGHT); 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(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; 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; 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 */ diff --git a/sys/lib/libkern/rb.h b/sys/lib/libkern/rb.h index 598802529678..88eb12bd89b2 100644 --- a/sys/lib/libkern/rb.h +++ b/sys/lib/libkern/rb.h @@ -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. @@ -97,11 +97,11 @@ struct rb_node { #if !defined(NDEBUG) || defined(DEBUG) TAILQ_HEAD(rb_node_qh, rb_node); -#define RB_TAILQ_REMOVE TAILQ_REMOVE -#define RB_TAILQ_INIT TAILQ_INIT -#define RB_TAILQ_INSERT_HEAD(a, b, c) TAILQ_INSERT_HEAD -#define RB_TAILQ_INSERT_BEFORE(a, b, c) TAILQ_INSERT_BEFORE -#define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER +#define RB_TAILQ_REMOVE(a, b, c) TAILQ_REMOVE(a, b, c) +#define RB_TAILQ_INIT(a) TAILQ_INIT(a) +#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(a, b, c) +#define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER(a, b, c, d) #else #define RB_TAILQ_REMOVE(a, b, c) do { } while (0) #define RB_TAILQ_INIT(a) do { } while (0) @@ -121,16 +121,40 @@ struct rb_tree { #endif rb_compare_nodes_fn rbt_compare_nodes; rb_compare_key_fn rbt_compare_key; + struct rb_node *rbt_minmax[2]; 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_insert_node(struct rb_tree *, 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_check(const struct rb_tree *, bool); struct rb_node * 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_*/