Shrink rb_tree to 4 pointers (2 if RBSMALL is defined). Move compare

functions to a separate rb_tree_ops structure.  Make every int explicit
in being signed or unsigned.  Use RBDEBUG to enable debug code.  Move
rbt_count to RBSTATS.  Use RBSMALL to not keep track of min/max.
This commit is contained in:
matt 2006-09-09 06:52:18 +00:00
parent 21d899a826
commit d9bb545dc5
2 changed files with 108 additions and 55 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rb.c,v 1.9 2006/09/09 05:55:51 matt Exp $ */
/* $NetBSD: rb.c,v 1.10 2006/09/09 06:52:18 matt Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -41,17 +41,20 @@
#include <stddef.h>
#include <assert.h>
#include <stdbool.h>
#ifdef RBDEBUG
#define KASSERT(s) assert(s)
#else
#define KASSERT(s) (void) 0
#endif
#else
#include <lib/libkern/libkern.h>
#endif
#include "rb.h"
static void rb_tree_reparent_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 *,
unsigned int);
#ifndef NDEBUG
#ifdef RBDEBUG
static const struct rb_node *rb_tree_iterate_const(const struct rb_tree *,
const struct rb_node *, unsigned int);
static bool rb_tree_check_node(const struct rb_tree *, const struct rb_node *,
@ -71,17 +74,17 @@ static const struct rb_node sentinel_node = {
};
void
rb_tree_init(struct rb_tree *rbt, rb_compare_nodes_fn compare_nodes,
rb_compare_key_fn compare_key)
rb_tree_init(struct rb_tree *rbt, const struct rb_tree_ops *ops)
{
RB_TAILQ_INIT(&rbt->rbt_nodes);
rbt->rbt_count = 0;
rbt->rbt_compare_nodes = compare_nodes;
rbt->rbt_compare_key = compare_key;
rbt->rbt_ops = ops;
*((const struct rb_node **)&rbt->rbt_root) = &sentinel_node;
RB_TAILQ_INIT(&rbt->rbt_nodes);
#ifndef RBSMALL
rbt->rbt_minmax[RB_LEFT] = rbt->rbt_root; /* minimum node */
rbt->rbt_minmax[RB_RIGHT] = rbt->rbt_root; /* maximum node */
#endif
#ifdef RBSTATS
rbt->rbt_count = 0;
rbt->rbt_insertions = 0;
rbt->rbt_removals = 0;
rbt->rbt_insertion_rebalance_calls = 0;
@ -94,10 +97,11 @@ rb_tree_init(struct rb_tree *rbt, rb_compare_nodes_fn compare_nodes,
struct rb_node *
rb_tree_find_node(struct rb_tree *rbt, const void *key)
{
rb_compare_key_fn compare_key = rbt->rbt_ops->rb_compare_key;
struct rb_node *parent = rbt->rbt_root;
while (!RB_SENTINEL_P(parent)) {
const int diff = (*rbt->rbt_compare_key)(parent, key);
const signed int diff = (*compare_key)(parent, key);
if (diff == 0)
return parent;
parent = parent->rb_nodes[diff > 0];
@ -109,11 +113,12 @@ rb_tree_find_node(struct rb_tree *rbt, const void *key)
struct rb_node *
rb_tree_find_node_geq(struct rb_tree *rbt, const void *key)
{
rb_compare_key_fn compare_key = rbt->rbt_ops->rb_compare_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);
const signed int diff = (*compare_key)(parent, key);
if (diff == 0)
return parent;
if (diff < 0)
@ -127,11 +132,12 @@ rb_tree_find_node_geq(struct rb_tree *rbt, const void *key)
struct rb_node *
rb_tree_find_node_leq(struct rb_tree *rbt, const void *key)
{
rb_compare_key_fn compare_key = rbt->rbt_ops->rb_compare_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);
const signed int diff = (*compare_key)(parent, key);
if (diff == 0)
return parent;
if (diff > 0)
@ -145,6 +151,7 @@ rb_tree_find_node_leq(struct rb_tree *rbt, const void *key)
void
rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
{
rb_compare_nodes_fn compare_nodes = rbt->rbt_ops->rb_compare_nodes;
struct rb_node *parent, *tmp;
unsigned int position;
@ -166,7 +173,7 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
* Find out where to place this new leaf.
*/
while (!RB_SENTINEL_P(tmp)) {
const int diff = (*rbt->rbt_compare_nodes)(tmp, self);
const signed int diff = (*compare_nodes)(tmp, self);
parent = tmp;
KASSERT(diff != 0);
if (diff < 0) {
@ -177,7 +184,7 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
tmp = parent->rb_nodes[position];
}
#if !defined(NDEBUG) || defined(DIAGNOSTIC)
#ifdef RBDEBUG
{
struct rb_node *prev = NULL, *next = NULL;
@ -197,10 +204,8 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
prev = TAILQ_PREV(next, rb_node_qh, rb_link);
KASSERT(prev == NULL || !RB_SENTINEL_P(prev));
KASSERT(next == NULL || !RB_SENTINEL_P(next));
KASSERT(prev == NULL
|| (*rbt->rbt_compare_nodes)(prev, self) > 0);
KASSERT(next == NULL
|| (*rbt->rbt_compare_nodes)(self, next) > 0);
KASSERT(prev == NULL || (*compare_nodes)(prev, self) > 0);
KASSERT(next == NULL || (*compare_nodes)(self, next) > 0);
}
#endif
@ -211,11 +216,14 @@ 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);
#ifndef RBSMALL
rbt->rbt_minmax[RB_LEFT] = self;
rbt->rbt_minmax[RB_RIGHT] = self;
#endif
} else {
KASSERT(position == RB_LEFT || position == RB_RIGHT);
KASSERT(!RB_ROOT_P(self)); /* Already done */
#ifndef RBSMALL
/*
* Keep track of the minimum and maximum nodes. If our
* parent is a minmax node and we on their min/max side,
@ -223,6 +231,7 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
*/
if (parent == rbt->rbt_minmax[position])
rbt->rbt_minmax[position] = self;
#endif
}
KASSERT(RB_SENTINEL_P(parent->rb_nodes[position]));
self->rb_left = parent->rb_nodes[position];
@ -234,15 +243,15 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
/*
* Insert the new node into a sorted list for easy sequential access
*/
rbt->rbt_count++;
#if !defined(NDEBUG) || defined(DIAGNOSTIC)
RBSTAT_INC(rbt->rbt_count);
#ifdef RBDEBUG
if (RB_ROOT_P(self)) {
RB_TAILQ_INSERT_HEAD(&rbt->rbt_nodes, self, rb_link);
} else if (position == RB_LEFT) {
KASSERT((*rbt->rbt_compare_nodes)(self, self->rb_parent) > 0);
KASSERT((*compare_nodes)(self, self->rb_parent) > 0);
RB_TAILQ_INSERT_BEFORE(self->rb_parent, self, rb_link);
} else {
KASSERT((*rbt->rbt_compare_nodes)(self->rb_parent, self) > 0);
KASSERT((*compare_nodes)(self->rb_parent, self) > 0);
RB_TAILQ_INSERT_AFTER(&rbt->rbt_nodes, self->rb_parent,
self, rb_link);
}
@ -276,7 +285,8 @@ rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
* as a separate step.
*/
static void
rb_tree_reparent_nodes(struct rb_tree *rbt, struct rb_node *old_father, int which)
rb_tree_reparent_nodes(struct rb_tree *rbt, struct rb_node *old_father,
const unsigned int which)
{
const unsigned int other = which ^ RB_OTHER;
struct rb_node * const grandpa = old_father->rb_parent;
@ -409,7 +419,7 @@ rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self)
}
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, bool rebalance)
{
const unsigned int which = self->rb_position;
struct rb_node *father = self->rb_parent;
@ -430,7 +440,8 @@ rb_tree_prune_node(struct rb_tree *rbt, struct rb_node *self, int rebalance)
* and update min/max.
*/
RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
rbt->rbt_count--;
RBSTAT_DEC(rbt->rbt_count);
#ifndef RBSMALL
if (__predict_false(rbt->rbt_minmax[self->rb_position] == self)) {
rbt->rbt_minmax[self->rb_position] = father;
/*
@ -442,6 +453,7 @@ rb_tree_prune_node(struct rb_tree *rbt, struct rb_node *self, int rebalance)
rbt->rbt_minmax[RB_RIGHT] = father;
}
}
#endif
self->rb_sentinel = 1; /* so remove_node will fail */
/*
@ -570,10 +582,12 @@ rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self,
* and update min/max.
*/
RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
rbt->rbt_count--;
RBSTAT_DEC(rbt->rbt_count);
#ifndef RBSMALL
if (__predict_false(rbt->rbt_minmax[self->rb_position] == self))
rbt->rbt_minmax[self->rb_position] = self->rb_parent;
self->rb_sentinel = 1;
#endif
KASSERT(rb_tree_check_node(rbt, standin, NULL, false));
@ -620,7 +634,8 @@ rb_tree_prune_blackred_branch(struct rb_tree *rbt, struct rb_node *self,
* and update minmax.
*/
RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
rbt->rbt_count--;
RBSTAT_DEC(rbt->rbt_count);
#ifndef RBSMALL
if (__predict_false(RB_ROOT_P(self))) {
KASSERT(rbt->rbt_minmax[which] == son);
rbt->rbt_minmax[which ^ RB_OTHER] = son;
@ -628,6 +643,7 @@ rb_tree_prune_blackred_branch(struct rb_tree *rbt, struct rb_node *self,
rbt->rbt_minmax[self->rb_position] = son;
}
self->rb_sentinel = 1;
#endif
KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, father, NULL, true));
KASSERT(rb_tree_check_node(rbt, son, NULL, true));
@ -848,9 +864,18 @@ rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self,
KASSERT(direction == RB_LEFT || direction == RB_RIGHT);
if (self == NULL) {
#ifndef RBSMALL
if (RB_SENTINEL_P(rbt->rbt_root))
return NULL;
return rbt->rbt_minmax[direction];
#else
self = rbt->rbt_root;
if (RB_SENTINEL_P(self))
return NULL;
while (!RB_SENTINEL_P(self->rb_nodes[other]))
self = self->rb_nodes[other];
return self;
#endif /* !RBSMALL */
}
KASSERT(!RB_SENTINEL_P(self));
/*
@ -877,7 +902,7 @@ rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self,
return self;
}
#ifndef NDEBUG
#ifdef RBDEBUG
static const struct rb_node *
rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self,
unsigned int direction)
@ -886,9 +911,18 @@ rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self,
KASSERT(direction == RB_LEFT || direction == RB_RIGHT);
if (self == NULL) {
#ifndef RBSMALL
if (RB_SENTINEL_P(rbt->rbt_root))
return NULL;
return rbt->rbt_minmax[direction];
#else
self = rbt->rbt_root;
if (RB_SENTINEL_P(self))
return NULL;
while (!RB_SENTINEL_P(self->rb_nodes[other]))
self = self->rb_nodes[other];
return self;
#endif /* !RBSMALL */
}
KASSERT(!RB_SENTINEL_P(self));
/*
@ -919,10 +953,11 @@ static bool
rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self,
const struct rb_node *prev, bool red_check)
{
rb_compare_nodes_fn compare_nodes = rbt->rbt_ops->rb_compare_nodes;
KASSERT(!self->rb_sentinel);
KASSERT(self->rb_left);
KASSERT(self->rb_right);
KASSERT(prev == NULL || (*rbt->rbt_compare_nodes)(prev, self) > 0);
KASSERT(prev == NULL || (*compare_nodes)(prev, self) > 0);
/*
* Verify our relationship to our parent.
@ -936,10 +971,10 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self,
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((*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((*compare_nodes)(self, self->rb_parent) < 0);
KASSERT(self->rb_parent->rb_nodes[RB_RIGHT] == self);
}
}
@ -952,8 +987,10 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self,
const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_RIGHT);
KASSERT(prev0 == TAILQ_PREV(self, rb_node_qh, rb_link));
KASSERT(next0 == TAILQ_NEXT(self, rb_link));
#ifndef RBSMALL
KASSERT(prev0 != NULL || self == rbt->rbt_minmax[RB_LEFT]);
KASSERT(next0 != NULL || self == rbt->rbt_minmax[RB_RIGHT]);
#endif
}
/*
@ -1129,36 +1166,43 @@ rb_tree_check(const struct rb_tree *rbt, bool red_check)
{
const struct rb_node *self;
const struct rb_node *prev;
unsigned int count;
#ifdef RBSTATS
unsigned int count = 0;
#endif
KASSERT(rbt->rbt_root != NULL);
KASSERT(rbt->rbt_root->rb_position == RB_LEFT);
#if defined(RBSTATS) && !defined(RBSMALL)
KASSERT(rbt->rbt_count > 1
|| rbt->rbt_minmax[RB_LEFT] == rbt->rbt_minmax[RB_RIGHT]);
#endif
prev = NULL;
count = 0;
TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) {
rb_tree_check_node(rbt, self, prev, false);
#ifdef RBSTATS
count++;
#endif
}
#ifdef RBSTATS
KASSERT(rbt->rbt_count == count);
KASSERT(RB_SENTINEL_P(rbt->rbt_root)
|| rb_tree_count_black(rbt->rbt_root));
/*
* The root must be black.
* There can never be two adjacent red nodes.
*/
#endif
if (red_check) {
KASSERT(rbt->rbt_root == NULL || RB_BLACK_P(rbt->rbt_root));
KASSERT(RB_BLACK_P(rbt->rbt_root));
KASSERT(RB_SENTINEL_P(rbt->rbt_root)
|| rb_tree_count_black(rbt->rbt_root));
/*
* The root must be black.
* There can never be two adjacent red nodes.
*/
TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) {
rb_tree_check_node(rbt, self, NULL, true);
}
}
}
#endif /* !NDEBUG || DIAGNOSTIC */
#endif /* RBDEBUG */
#ifdef RBSTATS
static void

View File

@ -1,4 +1,4 @@
/* $NetBSD: rb.h,v 1.5 2006/09/09 05:55:51 matt Exp $ */
/* $NetBSD: rb.h,v 1.6 2006/09/09 06:52:18 matt Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -89,12 +89,12 @@ struct rb_node {
#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))
#if !defined(NDEBUG) || defined(DEBUG)
#ifdef RBDEBUG
TAILQ_ENTRY(rb_node) rb_link;
#endif
};
#if !defined(NDEBUG) || defined(DEBUG)
#ifdef RBDEBUG
TAILQ_HEAD(rb_node_qh, rb_node);
#define RB_TAILQ_REMOVE(a, b, c) TAILQ_REMOVE(a, b, c)
@ -108,22 +108,29 @@ TAILQ_HEAD(rb_node_qh, rb_node);
#define RB_TAILQ_INSERT_HEAD(a, b, c) do { } while (0)
#define RB_TAILQ_INSERT_BEFORE(a, b, c) do { } while (0)
#define RB_TAILQ_INSERT_AFTER(a, b, c, d) do { } while (0)
#endif
#endif /* RBDEBUG */
typedef int (*rb_compare_nodes_fn)(const struct rb_node *,
typedef signed int (*const rb_compare_nodes_fn)(const struct rb_node *,
const struct rb_node *);
typedef int (*rb_compare_key_fn)(const struct rb_node *, const void *);
typedef signed int (*const rb_compare_key_fn)(const struct rb_node *,
const void *);
struct rb_tree_ops {
rb_compare_nodes_fn rb_compare_nodes;
rb_compare_key_fn rb_compare_key;
};
struct rb_tree {
struct rb_node *rbt_root;
#if !defined(NDEBUG) || defined(DEBUG)
const struct rb_tree_ops *rbt_ops;
#ifndef RBSMALL
struct rb_node *rbt_minmax[2];
#endif
#ifdef RBDEBUG
struct rb_node_qh rbt_nodes;
#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_count;
unsigned int rbt_insertions;
unsigned int rbt_removals;
unsigned int rbt_insertion_rebalance_calls;
@ -135,11 +142,13 @@ struct rb_tree {
#ifdef RBSTATS
#define RBSTAT_INC(v) ((void)((v)++))
#define RBSTAT_DEC(v) ((void)((v)--))
#else
#define RBSTAT_INC(v) do { } while (0)
#define RBSTAT_DEC(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 *, const struct rb_tree_ops *);
void rb_tree_insert_node(struct rb_tree *, struct rb_node *);
struct rb_node *
rb_tree_find_node(struct rb_tree *, const void *);
@ -150,7 +159,7 @@ struct rb_node *
void rb_tree_remove_node(struct rb_tree *, struct rb_node *);
struct rb_node *
rb_tree_iterate(struct rb_tree *, struct rb_node *, unsigned int);
#if !defined(NDEBUG) || defined(DIAGNOSTIC)
#ifdef RBDEBUG
void rb_tree_check(const struct rb_tree *, bool);
#endif
#ifdef RBSTATS