diff --git a/common/lib/libprop/Makefile.inc b/common/lib/libprop/Makefile.inc index 65685934e463..2e14639eb70e 100644 --- a/common/lib/libprop/Makefile.inc +++ b/common/lib/libprop/Makefile.inc @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.inc,v 1.8 2008/06/30 20:14:09 matt Exp $ +# $NetBSD: Makefile.inc,v 1.9 2012/07/27 09:10:59 pooka Exp $ .PATH: ${.PARSEDIR} @@ -6,4 +6,6 @@ SRCS+= prop_array.c prop_array_util.c prop_bool.c prop_data.c \ prop_dictionary.c prop_dictionary_util.c prop_ingest.c \ prop_kern.c prop_number.c prop_object.c prop_stack.c prop_string.c -#SRCS+= prop_rb.c +.ifdef (PROPLIB_WANT_RB) +SRCS+= prop_rb.c +.endif diff --git a/common/lib/libprop/prop_array.c b/common/lib/libprop/prop_array.c index ecb6a8689fce..c73996fb25d4 100644 --- a/common/lib/libprop/prop_array.c +++ b/common/lib/libprop/prop_array.c @@ -1,4 +1,4 @@ -/* $NetBSD: prop_array.c,v 1.20 2008/08/11 05:54:21 christos Exp $ */ +/* $NetBSD: prop_array.c,v 1.21 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. @@ -29,8 +29,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include "prop_object_impl.h" +#include #if !defined(_KERNEL) && !defined(_STANDALONE) #include @@ -340,7 +340,7 @@ static prop_object_t _prop_array_iterator_next_object(void *v) { struct _prop_array_iterator *pai = v; - prop_array_t pa __unused = pai->pai_base.pi_obj; + prop_array_t pa _PROP_ARG_UNUSED = pai->pai_base.pi_obj; prop_object_t po; _PROP_ASSERT(prop_object_is_array(pa)); @@ -367,7 +367,7 @@ static void _prop_array_iterator_reset(void *v) { struct _prop_array_iterator *pai = v; - prop_array_t pa __unused = pai->pai_base.pi_obj; + prop_array_t pa _PROP_ARG_UNUSED = pai->pai_base.pi_obj; _PROP_ASSERT(prop_object_is_array(pa)); diff --git a/common/lib/libprop/prop_array_util.c b/common/lib/libprop/prop_array_util.c index 8515bd5d3e2a..52e905b68df5 100644 --- a/common/lib/libprop/prop_array_util.c +++ b/common/lib/libprop/prop_array_util.c @@ -1,4 +1,4 @@ -/* $NetBSD: prop_array_util.c,v 1.3 2011/03/24 17:05:39 bouyer Exp $ */ +/* $NetBSD: prop_array_util.c,v 1.4 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -38,8 +38,8 @@ * exactly what we're doing here. */ -#include #include "prop_object_impl.h" /* hide kernel vs. not-kernel vs. standalone */ +#include bool prop_array_get_bool(prop_array_t array, diff --git a/common/lib/libprop/prop_dictionary.c b/common/lib/libprop/prop_dictionary.c index 8c2dcea9f082..39eb4383766c 100644 --- a/common/lib/libprop/prop_dictionary.c +++ b/common/lib/libprop/prop_dictionary.c @@ -1,4 +1,4 @@ -/* $NetBSD: prop_dictionary.c,v 1.37 2011/04/20 19:40:00 martin Exp $ */ +/* $NetBSD: prop_dictionary.c,v 1.38 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. @@ -29,10 +29,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "prop_object_impl.h" #include #include #include -#include "prop_object_impl.h" #include "prop_rb_impl.h" #if !defined(_KERNEL) && !defined(_STANDALONE) @@ -173,7 +173,7 @@ struct _prop_dictionary_iterator { static int /*ARGSUSED*/ -_prop_dict_keysym_rb_compare_nodes(void *ctx __unused, +_prop_dict_keysym_rb_compare_nodes(void *ctx _PROP_ARG_UNUSED, const void *n1, const void *n2) { const struct _prop_dictionary_keysym *pdk1 = n1; @@ -184,7 +184,7 @@ _prop_dict_keysym_rb_compare_nodes(void *ctx __unused, static int /*ARGSUSED*/ -_prop_dict_keysym_rb_compare_key(void *ctx __unused, +_prop_dict_keysym_rb_compare_key(void *ctx _PROP_ARG_UNUSED, const void *n, const void *v) { const struct _prop_dictionary_keysym *pdk = n; @@ -628,7 +628,7 @@ static prop_object_t _prop_dictionary_iterator_next_object(void *v) { struct _prop_dictionary_iterator *pdi = v; - prop_dictionary_t pd __unused = pdi->pdi_base.pi_obj; + prop_dictionary_t pd _PROP_ARG_UNUSED = pdi->pdi_base.pi_obj; prop_dictionary_keysym_t pdk; _PROP_ASSERT(prop_object_is_dictionary(pd)); @@ -655,7 +655,7 @@ static void _prop_dictionary_iterator_reset(void *v) { struct _prop_dictionary_iterator *pdi = v; - prop_dictionary_t pd __unused = pdi->pdi_base.pi_obj; + prop_dictionary_t pd _PROP_ARG_UNUSED = pdi->pdi_base.pi_obj; _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); _prop_dictionary_iterator_reset_locked(pdi); diff --git a/common/lib/libprop/prop_dictionary_util.c b/common/lib/libprop/prop_dictionary_util.c index 65baf73cc6c9..0b4867268efa 100644 --- a/common/lib/libprop/prop_dictionary_util.c +++ b/common/lib/libprop/prop_dictionary_util.c @@ -1,4 +1,4 @@ -/* $NetBSD: prop_dictionary_util.c,v 1.4 2011/03/24 17:05:39 bouyer Exp $ */ +/* $NetBSD: prop_dictionary_util.c,v 1.5 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -38,8 +38,8 @@ * exactly what we're doing here. */ -#include #include "prop_object_impl.h" /* only to hide kernel vs. not-kernel */ +#include bool prop_dictionary_get_dict(prop_dictionary_t dict, const char *key, prop_dictionary_t *dp) diff --git a/common/lib/libprop/prop_ingest.c b/common/lib/libprop/prop_ingest.c index 823d2c6c736e..9d161b579bce 100644 --- a/common/lib/libprop/prop_ingest.c +++ b/common/lib/libprop/prop_ingest.c @@ -1,4 +1,4 @@ -/* $NetBSD: prop_ingest.c,v 1.3 2008/04/28 20:22:53 martin Exp $ */ +/* $NetBSD: prop_ingest.c,v 1.4 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -29,8 +29,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include "prop_object_impl.h" +#include struct _prop_ingest_context { prop_ingest_error_t pic_error; diff --git a/common/lib/libprop/prop_number.c b/common/lib/libprop/prop_number.c index ba61b580fdac..c6b47c5d7e1f 100644 --- a/common/lib/libprop/prop_number.c +++ b/common/lib/libprop/prop_number.c @@ -1,4 +1,4 @@ -/* $NetBSD: prop_number.c,v 1.23 2010/09/24 22:51:52 rmind Exp $ */ +/* $NetBSD: prop_number.c,v 1.24 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -119,7 +119,7 @@ _prop_number_compare_values(const struct _prop_number_value *pnv1, static int /*ARGSUSED*/ -_prop_number_rb_compare_nodes(void *ctx __unused, +_prop_number_rb_compare_nodes(void *ctx _PROP_ARG_UNUSED, const void *n1, const void *n2) { const struct _prop_number *pn1 = n1; @@ -130,7 +130,8 @@ _prop_number_rb_compare_nodes(void *ctx __unused, static int /*ARGSUSED*/ -_prop_number_rb_compare_key(void *ctx __unused, const void *n, const void *v) +_prop_number_rb_compare_key(void *ctx _PROP_ARG_UNUSED, + const void *n, const void *v) { const struct _prop_number *pn = n; const struct _prop_number_value *pnv = v; diff --git a/common/lib/libprop/prop_object.c b/common/lib/libprop/prop_object.c index 6df343957474..7be6c307d381 100644 --- a/common/lib/libprop/prop_object.c +++ b/common/lib/libprop/prop_object.c @@ -1,4 +1,4 @@ -/* $NetBSD: prop_object.c,v 1.27 2011/04/20 20:00:07 martin Exp $ */ +/* $NetBSD: prop_object.c,v 1.28 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. @@ -29,8 +29,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include "prop_object_impl.h" +#include + +#ifdef _PROP_NEED_REFCNT_MTX +static pthread_mutex_t _prop_refcnt_mtx = PTHREAD_MUTEX_INITIALIZER; +#endif /* _PROP_NEED_REFCNT_MTX */ #if !defined(_KERNEL) && !defined(_STANDALONE) #include @@ -40,7 +44,6 @@ #include #include #endif -#include #ifdef _STANDALONE void * @@ -853,10 +856,14 @@ _prop_object_externalize_write_file(const char *fname, const char *xml, * and create the temporary file. */ _prop_object_externalize_file_dirname(fname, tname); - if (strlcat(tname, "/.plistXXXXXX", sizeof(tname)) >= sizeof(tname)) { +#define PLISTTMP "/.plistXXXXXX" + if (strlen(tname) + strlen(PLISTTMP) >= sizeof(tname)) { errno = ENAMETOOLONG; return (false); } + strcat(tname, PLISTTMP); +#undef PLISTTMP + if ((fd = mkstemp(tname)) == -1) return (false); @@ -982,7 +989,7 @@ prop_object_retain(prop_object_t obj) struct _prop_object *po = obj; uint32_t ncnt; - ncnt = atomic_inc_32_nv(&po->po_refcnt); + _PROP_ATOMIC_INC32_NV(&po->po_refcnt, ncnt); _PROP_ASSERT(ncnt != 0); } @@ -1014,7 +1021,7 @@ prop_object_release_emergency(prop_object_t obj) unlock = po->po_type->pot_unlock; /* Dance a bit to make sure we always get the non-racy ocnt */ - ocnt = atomic_dec_32_nv(&po->po_refcnt); + _PROP_ATOMIC_DEC32_NV(&po->po_refcnt, ocnt); ocnt++; _PROP_ASSERT(ocnt != 0); @@ -1036,7 +1043,7 @@ prop_object_release_emergency(prop_object_t obj) unlock(); parent = po; - atomic_inc_32(&po->po_refcnt); + _PROP_ATOMIC_INC32(&po->po_refcnt); } _PROP_ASSERT(parent); /* One object was just freed. */ @@ -1073,7 +1080,7 @@ prop_object_release(prop_object_t obj) /* Save pointer to object unlock function */ unlock = po->po_type->pot_unlock; - ocnt = atomic_dec_32_nv(&po->po_refcnt); + _PROP_ATOMIC_DEC32_NV(&po->po_refcnt, ocnt); ocnt++; _PROP_ASSERT(ocnt != 0); @@ -1092,7 +1099,7 @@ prop_object_release(prop_object_t obj) if (ret == _PROP_OBJECT_FREE_DONE) break; - atomic_inc_32(&po->po_refcnt); + _PROP_ATOMIC_INC32(&po->po_refcnt); } while (ret == _PROP_OBJECT_FREE_RECURSE); if (ret == _PROP_OBJECT_FREE_FAILED) prop_object_release_emergency(obj); diff --git a/common/lib/libprop/prop_object_impl.h b/common/lib/libprop/prop_object_impl.h index 0768c9f1f7c6..0548e7d51997 100644 --- a/common/lib/libprop/prop_object_impl.h +++ b/common/lib/libprop/prop_object_impl.h @@ -1,4 +1,4 @@ -/* $NetBSD: prop_object_impl.h,v 1.30 2009/09/13 18:45:10 pooka Exp $ */ +/* $NetBSD: prop_object_impl.h,v 1.31 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -293,6 +293,13 @@ __link_set_add_rodata(prop_linkpools, _link_ ## pp); #define _PROP_ONCE_DECL(x) static ONCE_DECL(x); #define _PROP_ONCE_RUN(x,f) RUN_ONCE(&(x), f) +#include + +#define _PROP_ATOMIC_INC32(x) atomic_inc_32(x) +#define _PROP_ATOMIC_DEC32(x) atomic_dec_32(x) +#define _PROP_ATOMIC_INC32_NV(x, v) v = atomic_inc_32_nv(x) +#define _PROP_ATOMIC_DEC32_NV(x, v) v = atomic_dec_32_nv(x) + #elif defined(_STANDALONE) /* @@ -333,6 +340,11 @@ void * _prop_standalone_realloc(void *, size_t); #define _PROP_ONCE_DECL(x) _PROP_NOTHREAD_ONCE_DECL(x) #define _PROP_ONCE_RUN(x,f) _PROP_NOTHREAD_ONCE_RUN(x,f) +#define _PROP_ATOMIC_INC32(x) ++*(x) +#define _PROP_ATOMIC_DEC32(x) --*(x) +#define _PROP_ATOMIC_INC32_NV(x, v) v = ++*(x) +#define _PROP_ATOMIC_DEC32_NV(x, v) v = --*(x) + #else /* @@ -364,6 +376,7 @@ void * _prop_standalone_realloc(void *, size_t); * Use the same mechanism as libc; we get pthread mutexes for threaded * programs and do-nothing stubs for non-threaded programs. */ +#include #include "reentrant.h" #define _PROP_MUTEX_DECL_STATIC(x) static mutex_t x; #define _PROP_MUTEX_INIT(x) mutex_init(&(x), NULL) @@ -381,6 +394,11 @@ void * _prop_standalone_realloc(void *, size_t); static pthread_once_t x = PTHREAD_ONCE_INIT; #define _PROP_ONCE_RUN(x,f) thr_once(&(x), (void(*)(void))f); +#define _PROP_ATOMIC_INC32(x) atomic_inc_32(x) +#define _PROP_ATOMIC_DEC32(x) atomic_dec_32(x) +#define _PROP_ATOMIC_INC32_NV(x, v) v = atomic_inc_32_nv(x) +#define _PROP_ATOMIC_DEC32_NV(x, v) v = atomic_dec_32_nv(x) + #elif defined(HAVE_NBTOOL_CONFIG_H) /* * None of NetBSD's build tools are multi-threaded. @@ -399,6 +417,12 @@ void * _prop_standalone_realloc(void *, size_t); #define _PROP_ONCE_DECL(x) _PROP_NOTHREAD_ONCE_DECL(x) #define _PROP_ONCE_RUN(x,f) _PROP_NOTHREAD_ONCE_RUN(x,f) + +#define _PROP_ATOMIC_INC32(x) ++*(x) +#define _PROP_ATOMIC_DEC32(x) --*(x) +#define _PROP_ATOMIC_INC32_NV(x, v) v = ++*(x) +#define _PROP_ATOMIC_DEC32_NV(x, v) v = --*(x) + #else /* * Use pthread mutexes everywhere else. @@ -419,8 +443,38 @@ void * _prop_standalone_realloc(void *, size_t); #define _PROP_ONCE_DECL(x) \ static pthread_once_t x = PTHREAD_ONCE_INIT; #define _PROP_ONCE_RUN(x,f) pthread_once(&(x),(void(*)(void))f) -#endif +#define _PROP_NEED_REFCNT_MTX + +#define _PROP_ATOMIC_INC32(x) \ +do { \ + pthread_mutex_lock(&_prop_refcnt_mtx); \ + (*(x))++; \ + pthread_mutex_unlock(&_prop_refcnt_mtx); \ +} while (/*CONSTCOND*/0) + +#define _PROP_ATOMIC_DEC32(x) \ +do { \ + pthread_mutex_lock(&_prop_refcnt_mtx); \ + (*(x))--; \ + pthread_mutex_unlock(&_prop_refcnt_mtx); \ +} while (/*CONSTCOND*/0) + +#define _PROP_ATOMIC_INC32_NV(x, v) \ +do { \ + pthread_mutex_lock(&_prop_refcnt_mtx); \ + v = ++(*(x)); \ + pthread_mutex_unlock(&_prop_refcnt_mtx); \ +} while (/*CONSTCOND*/0) + +#define _PROP_ATOMIC_DEC32_NV(x, v) \ +do { \ + pthread_mutex_lock(&_prop_refcnt_mtx); \ + v = --(*(x)); \ + pthread_mutex_unlock(&_prop_refcnt_mtx); \ +} while (/*CONSTCOND*/0) + +#endif #endif /* _KERNEL */ /* diff --git a/common/lib/libprop/prop_rb.c b/common/lib/libprop/prop_rb.c index 83657bc288f4..f0c9ed99bf2b 100644 --- a/common/lib/libprop/prop_rb.c +++ b/common/lib/libprop/prop_rb.c @@ -1,4 +1,4 @@ -/* $NetBSD: prop_rb.c,v 1.9 2008/06/17 21:29:47 thorpej Exp $ */ +/* $NetBSD: prop_rb.c,v 1.10 2012/07/27 09:10:59 pooka Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -27,168 +27,122 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. + * + * NetBSD: rb.c,v 1.11 2011/06/20 09:11:16 mrg Exp */ +#include "prop_object_impl.h" #include -#include "prop_object_impl.h" #include "prop_rb_impl.h" -#undef KASSERT #ifdef RBDEBUG -#define KASSERT(x) _PROP_ASSERT(x) +#define KASSERT(s) _PROP_ASSERT(s) #else -#define KASSERT(x) /* nothing */ +#define KASSERT(s) do { } while (/*CONSTCOND*/ 0) #endif #ifndef __predict_false -#define __predict_false(x) (x) +#define __predict_false(x) (x) #endif -static void rb_tree_reparent_nodes(struct rb_tree *, struct rb_node *, - unsigned 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); #ifdef RBDEBUG static const struct rb_node *rb_tree_iterate_const(const struct rb_tree *, - const struct rb_node *, unsigned int); + const struct rb_node *, const unsigned int); static bool rb_tree_check_node(const struct rb_tree *, const struct rb_node *, const struct rb_node *, bool); -#endif - -#ifdef RBDEBUG -#define RBT_COUNT_INCR(rbt) (rbt)->rbt_count++ -#define RBT_COUNT_DECR(rbt) (rbt)->rbt_count-- #else -#define RBT_COUNT_INCR(rbt) /* nothing */ -#define RBT_COUNT_DECR(rbt) /* nothing */ +#define rb_tree_check_node(a, b, c, d) true #endif -#define RBUNCONST(a) ((void *)(unsigned long)(const void *)(a)) +#define RB_NODETOITEM(rbto, rbn) \ + ((void *)((uintptr_t)(rbn) - (rbto)->rbto_node_offset)) +#define RB_ITEMTONODE(rbto, rbn) \ + ((rb_node_t *)((uintptr_t)(rbn) + (rbto)->rbto_node_offset)) -/* - * Rather than testing for the NULL everywhere, all terminal leaves are - * pointed to this node (and that includes itself). Note that by setting - * it to be const, that on some architectures trying to write to it will - * cause a fault. - */ -static const struct rb_node sentinel_node = { - .rb_nodes = { RBUNCONST(&sentinel_node), - RBUNCONST(&sentinel_node), - NULL }, - .rb_u = { .u_s = { .s_sentinel = 1 } }, -}; +#define RB_SENTINEL_NODE NULL void -_prop_rb_tree_init(struct rb_tree *rbt, const struct rb_tree_ops *ops) +_prop_rb_tree_init(struct rb_tree *rbt, const rb_tree_ops_t *ops) { - RB_TAILQ_INIT(&rbt->rbt_nodes); -#ifdef RBDEBUG - rbt->rbt_count = 0; -#endif + rbt->rbt_ops = ops; - *((const struct rb_node **)&rbt->rbt_root) = &sentinel_node; + rbt->rbt_root = RB_SENTINEL_NODE; + RB_TAILQ_INIT(&rbt->rbt_nodes); +#ifndef RBSMALL + rbt->rbt_minmax[RB_DIR_LEFT] = rbt->rbt_root; /* minimum node */ + rbt->rbt_minmax[RB_DIR_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; + 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. - */ -/*ARGSUSED*/ -static void -rb_tree_reparent_nodes(struct rb_tree *rbt _PROP_ARG_UNUSED, - struct rb_node *old_father, unsigned int which) +void * +_prop_rb_tree_find(struct rb_tree *rbt, const void *key) { - const unsigned int other = which ^ RB_NODE_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; + const rb_tree_ops_t *rbto = rbt->rbt_ops; + rbto_compare_key_fn compare_key = rbto->rbto_compare_key; + struct rb_node *parent = rbt->rbt_root; - KASSERT(which == RB_NODE_LEFT || which == RB_NODE_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)) { + void *pobj = RB_NODETOITEM(rbto, parent); + const signed int diff = (*compare_key)(rbto->rbto_context, + pobj, key); + if (diff == 0) + return pobj; + 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; } -bool -_prop_rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self) +void * +_prop_rb_tree_insert_node(struct rb_tree *rbt, void *object) { - struct rb_node *parent, *tmp; - rb_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes; + const rb_tree_ops_t *rbto = rbt->rbt_ops; + rbto_compare_nodes_fn compare_nodes = rbto->rbto_compare_nodes; + struct rb_node *parent, *tmp, *self = RB_ITEMTONODE(rbto, object); unsigned int position; + bool rebalance; + + RBSTAT_INC(rbt->rbt_insertions); - self->rb_properties = 0; tmp = rbt->rbt_root; /* * This is a hack. Because rbt->rbt_root is just a struct rb_node *, - * just like rb_node->rb_nodes[RB_NODE_LEFT], we can use this fact to + * just like rb_node->rb_nodes[RB_DIR_LEFT], we can use this fact to * avoid a lot of tests for root and know that even at root, - * updating rb_node->rb_parent->rb_nodes[rb_node->rb_position] will - * rbt->rbt_root. + * updating RB_FATHER(rb_node)->rb_nodes[RB_POSITION(rb_node)] will + * update rbt->rbt_root. */ - /* LINTED: see above */ - parent = (struct rb_node *)&rbt->rbt_root; - position = RB_NODE_LEFT; + parent = (struct rb_node *)(void *)&rbt->rbt_root; + position = RB_DIR_LEFT; /* * Find out where to place this new leaf. */ while (!RB_SENTINEL_P(tmp)) { - const int diff = (*compare_nodes)(tmp, self); + void *tobj = RB_NODETOITEM(rbto, tmp); + const signed int diff = (*compare_nodes)(rbto->rbto_context, + tobj, object); if (__predict_false(diff == 0)) { /* - * Node already exists; don't insert. + * Node already exists; return it. */ - return false; + return tobj; } parent = tmp; - KASSERT(diff != 0); - if (diff < 0) { - position = RB_NODE_LEFT; - } else { - position = RB_NODE_RIGHT; - } + position = (diff < 0); tmp = parent->rb_nodes[position]; } @@ -196,7 +150,7 @@ _prop_rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self) { struct rb_node *prev = NULL, *next = NULL; - if (position == RB_NODE_RIGHT) + if (position == RB_DIR_RIGHT) prev = parent; else if (tmp != rbt->rbt_root) next = parent; @@ -212,212 +166,337 @@ _prop_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 - || (*compare_nodes)(prev, self) > 0); - KASSERT(next == NULL - || (*compare_nodes)(self, next) > 0); + KASSERT(prev == NULL || (*compare_nodes)(rbto->rbto_context, + RB_NODETOITEM(rbto, prev), RB_NODETOITEM(rbto, self)) < 0); + KASSERT(next == NULL || (*compare_nodes)(rbto->rbto_context, + RB_NODETOITEM(rbto, self), RB_NODETOITEM(rbto, next)) < 0); } #endif /* * Initialize the node and insert as a leaf into the tree. */ - self->rb_parent = parent; - self->rb_position = position; - /* LINTED: rbt_root hack */ - if (__predict_false(parent == (struct rb_node *) &rbt->rbt_root)) { - RB_MARK_ROOT(self); + RB_SET_FATHER(self, parent); + RB_SET_POSITION(self, position); + if (__predict_false(parent == (struct rb_node *)(void *)&rbt->rbt_root)) { + RB_MARK_BLACK(self); /* root is always black */ +#ifndef RBSMALL + rbt->rbt_minmax[RB_DIR_LEFT] = self; + rbt->rbt_minmax[RB_DIR_RIGHT] = self; +#endif + rebalance = false; } else { - KASSERT(position == RB_NODE_LEFT || position == RB_NODE_RIGHT); - KASSERT(!RB_ROOT_P(self)); /* Already done */ + KASSERT(position == RB_DIR_LEFT || position == RB_DIR_RIGHT); +#ifndef RBSMALL + /* + * 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; +#endif /* !RBSMALL */ + /* + * All new nodes are colored red. We only need to rebalance + * if our parent is also red. + */ + RB_MARK_RED(self); + rebalance = RB_RED_P(parent); } 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); + KASSERT(RB_CHILDLESS_P(self)); /* * Insert the new node into a sorted list for easy sequential access */ - RBT_COUNT_INCR(rbt); + RBSTAT_INC(rbt->rbt_count); #ifdef RBDEBUG - if (RB_ROOT_P(self)) { + if (RB_ROOT_P(rbt, self)) { RB_TAILQ_INSERT_HEAD(&rbt->rbt_nodes, self, rb_link); - } else if (position == RB_NODE_LEFT) { - KASSERT((*compare_nodes)(self, self->rb_parent) > 0); - RB_TAILQ_INSERT_BEFORE(self->rb_parent, self, rb_link); + } else if (position == RB_DIR_LEFT) { + KASSERT((*compare_nodes)(rbto->rbto_context, + RB_NODETOITEM(rbto, self), + RB_NODETOITEM(rbto, RB_FATHER(self))) < 0); + RB_TAILQ_INSERT_BEFORE(RB_FATHER(self), self, rb_link); } else { - KASSERT((*compare_nodes)(self->rb_parent, self) > 0); - RB_TAILQ_INSERT_AFTER(&rbt->rbt_nodes, self->rb_parent, + KASSERT((*compare_nodes)(rbto->rbto_context, + RB_NODETOITEM(rbto, RB_FATHER(self)), + RB_NODETOITEM(rbto, self)) < 0); + RB_TAILQ_INSERT_AFTER(&rbt->rbt_nodes, RB_FATHER(self), self, rb_link); } #endif - -#if 0 - /* - * Validate the tree before we rebalance - */ - _prop_rb_tree_check(rbt, false); -#endif + KASSERT(rb_tree_check_node(rbt, self, NULL, !rebalance)); /* * Rebalance tree after insertion */ - rb_tree_insert_rebalance(rbt, self); + if (rebalance) { + rb_tree_insert_rebalance(rbt, self); + KASSERT(rb_tree_check_node(rbt, self, NULL, true)); + } -#if 0 - /* - * Validate the tree after we rebalanced - */ - _prop_rb_tree_check(rbt, true); -#endif - - return true; + /* Succesfully inserted, return our node pointer. */ + return object; } - + +/* + * 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. + */ +/*ARGSUSED*/ +static void +rb_tree_reparent_nodes(struct rb_tree *rbt, struct rb_node *old_father, + const unsigned int which) +{ + const unsigned int other = which ^ RB_DIR_OTHER; + struct rb_node * const grandpa = RB_FATHER(old_father); + 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; + + KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT); + + KASSERT(!RB_SENTINEL_P(old_child)); + KASSERT(RB_FATHER(old_child) == 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(rbt, old_father) || + rb_tree_check_node(rbt, grandpa, NULL, false)); + + /* + * Exchange descendant linkages. + */ + grandpa->rb_nodes[RB_POSITION(old_father)] = new_father; + new_child->rb_nodes[which] = old_child->rb_nodes[other]; + new_father->rb_nodes[other] = new_child; + + /* + * Update ancestor linkages + */ + RB_SET_FATHER(new_father, grandpa); + RB_SET_FATHER(new_child, 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. + */ +#if 0 + { + struct rb_node tmp; + tmp.rb_info = 0; + RB_COPY_PROPERTIES(&tmp, old_child); + RB_COPY_PROPERTIES(new_father, old_father); + RB_COPY_PROPERTIES(new_child, &tmp); + } +#else + RB_SWAP_PROPERTIES(new_father, new_child); +#endif + RB_SET_POSITION(new_child, other); + + /* + * Make sure to reparent the new child to ourself. + */ + if (!RB_SENTINEL_P(new_child->rb_nodes[which])) { + RB_SET_FATHER(new_child->rb_nodes[which], new_child); + RB_SET_POSITION(new_child->rb_nodes[which], 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(rbt, 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); + struct rb_node * father = RB_FATHER(self); + struct rb_node * grandpa = RB_FATHER(father); + struct rb_node * uncle; + unsigned int which; + unsigned int other; - 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_NODE_LEFT - : RB_NODE_RIGHT); - const unsigned int other = which ^ RB_NODE_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(!RB_ROOT_P(rbt, self)); + KASSERT(RB_RED_P(self)); + KASSERT(RB_RED_P(father)); + RBSTAT_INC(rbt->rbt_insertion_rebalance_calls); + for (;;) { KASSERT(!RB_SENTINEL_P(self)); + + KASSERT(RB_RED_P(self)); + KASSERT(RB_RED_P(father)); /* * We are red and our parent is red, therefore we must have a * grandfather and he must be black. */ - KASSERT(RB_RED_P(self) - && RB_RED_P(father) - && RB_BLACK_P(grandpa)); + grandpa = RB_FATHER(father); + KASSERT(RB_BLACK_P(grandpa)); + KASSERT(RB_DIR_RIGHT == 1 && RB_DIR_LEFT == 0); + which = (father == grandpa->rb_right); + other = which ^ RB_DIR_OTHER; + uncle = grandpa->rb_nodes[other]; - 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. - */ - RB_MARK_BLACK(uncle); - RB_MARK_BLACK(father); - RB_MARK_RED(grandpa); - self = grandpa; - continue; - } + if (RB_BLACK_P(uncle)) + break; + + RBSTAT_INC(rbt->rbt_insertion_rebalance_passes); /* - * Case 2&3: our uncle is black. + * 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. */ - if (self == father->rb_nodes[other]) { + RB_MARK_BLACK(uncle); + RB_MARK_BLACK(father); + if (__predict_false(RB_ROOT_P(rbt, grandpa))) { /* - * 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. + * If our grandpa is root, don't bother + * setting him to red, just return. */ - rb_tree_reparent_nodes(rbt, father, other); - KASSERT(father->rb_parent == self); - KASSERT(self->rb_nodes[which] == father); - KASSERT(self->rb_parent == grandpa); - self = father; - father = self->rb_parent; + KASSERT(RB_BLACK_P(grandpa)); + return; } - 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_reparent_nodes(rbt, grandpa, which); - KASSERT(self->rb_parent == father); - KASSERT(self->rb_parent->rb_nodes[self->rb_position ^ RB_NODE_OTHER] == grandpa); + RB_MARK_RED(grandpa); + self = grandpa; + father = RB_FATHER(self); KASSERT(RB_RED_P(self)); - KASSERT(RB_BLACK_P(father)); - KASSERT(RB_RED_P(grandpa)); - break; + if (RB_BLACK_P(father)) { + /* + * If our greatgrandpa is black, we're done. + */ + KASSERT(RB_BLACK_P(rbt->rbt_root)); + return; + } } + KASSERT(!RB_ROOT_P(rbt, self)); + KASSERT(RB_RED_P(self)); + KASSERT(RB_RED_P(father)); + KASSERT(RB_BLACK_P(uncle)); + KASSERT(RB_BLACK_P(grandpa)); + /* + * 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. + */ + rb_tree_reparent_nodes(rbt, father, other); + KASSERT(RB_FATHER(father) == self); + KASSERT(self->rb_nodes[which] == father); + KASSERT(RB_FATHER(self) == grandpa); + self = father; + father = RB_FATHER(self); + } + 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_reparent_nodes(rbt, grandpa, which); + KASSERT(RB_FATHER(self) == father); + KASSERT(RB_FATHER(self)->rb_nodes[RB_POSITION(self) ^ RB_DIR_OTHER] == grandpa); + KASSERT(RB_RED_P(self)); + KASSERT(RB_BLACK_P(father)); + KASSERT(RB_RED_P(grandpa)); + /* * Final step: Set the root to black. */ RB_MARK_BLACK(rbt->rbt_root); } - -struct rb_node * -_prop_rb_tree_find(struct rb_tree *rbt, const void *key) -{ - struct rb_node *parent = rbt->rbt_root; - rb_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; - while (!RB_SENTINEL_P(parent)) { - const int diff = (*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) +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; + const unsigned int which = RB_POSITION(self); + struct rb_node *father = RB_FATHER(self); +#ifndef RBSMALL + const bool was_root = RB_ROOT_P(rbt, self); +#endif - KASSERT(rebalance || (RB_ROOT_P(self) || RB_RED_P(self))); + KASSERT(rebalance || (RB_ROOT_P(rbt, self) || RB_RED_P(self))); KASSERT(!rebalance || RB_BLACK_P(self)); 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_COUNT_DECR(rbt); + RBSTAT_DEC(rbt->rbt_count); +#ifndef RBSMALL + if (__predict_false(rbt->rbt_minmax[RB_POSITION(self)] == self)) { + rbt->rbt_minmax[RB_POSITION(self)] = father; + /* + * When removing the root, rbt->rbt_minmax[RB_DIR_LEFT] is + * updated automatically, but we also need to update + * rbt->rbt_minmax[RB_DIR_RIGHT]; + */ + if (__predict_false(was_root)) { + rbt->rbt_minmax[RB_DIR_RIGHT] = father; + } + } + RB_SET_FATHER(self, NULL); +#endif + /* + * 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)); + KASSERT(was_root || 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) { - unsigned int standin_which = standin->rb_position; - unsigned int standin_other = standin_which ^ RB_NODE_OTHER; - struct rb_node *standin_child; - struct rb_node *standin_father; + const unsigned int standin_which = RB_POSITION(standin); + unsigned int standin_other = standin_which ^ RB_DIR_OTHER; + struct rb_node *standin_son; + struct rb_node *standin_father = RB_FATHER(standin); bool rebalance = RB_BLACK_P(standin); - if (standin->rb_parent == self) { + if (standin_father == 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]; + standin_son = 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]; + standin_son = standin->rb_nodes[standin_other]; } /* @@ -427,7 +506,7 @@ rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self, /* * If standin has a child, it must be red. */ - KASSERT(RB_SENTINEL_P(standin_child) || RB_RED_P(standin_child)); + KASSERT(RB_SENTINEL_P(standin_son) || RB_RED_P(standin_son)); /* * Verify things are sane. @@ -435,83 +514,103 @@ rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self, KASSERT(rb_tree_check_node(rbt, self, NULL, false)); KASSERT(rb_tree_check_node(rbt, standin, NULL, false)); - if (!RB_SENTINEL_P(standin_child)) { + if (__predict_false(RB_RED_P(standin_son))) { /* - * We know we have a red child so if we swap them we can - * void flipping standin's child to black afterwards. - */ - KASSERT(rb_tree_check_node(rbt, standin_child, NULL, true)); - rb_tree_reparent_nodes(rbt, standin, - standin_child->rb_position); - KASSERT(rb_tree_check_node(rbt, standin, NULL, true)); - KASSERT(rb_tree_check_node(rbt, standin_child, NULL, true)); - /* - * Since we are removing a red leaf, no need to rebalance. + * We know we have a red child so if we flip it to black + * we don't have to rebalance. */ + KASSERT(rb_tree_check_node(rbt, standin_son, NULL, true)); + RB_MARK_BLACK(standin_son); rebalance = false; - /* - * We know that standin can not be a child of self, so - * update before of that. - */ - KASSERT(standin->rb_parent != self); - standin_which = standin->rb_position; - standin_other = standin_which ^ RB_NODE_OTHER; - } - KASSERT(RB_CHILDLESS_P(standin)); - /* - * If we are about to delete the standin's father, then when we call - * rebalance, we need to use ourselves as our father. Otherwise - * remember our original father. Also, if we are our standin's father - * we only need to reparent the standin's brother. - */ - if (standin->rb_parent == self) { + if (standin_father == self) { + KASSERT(RB_POSITION(standin_son) == standin_which); + } else { + KASSERT(RB_POSITION(standin_son) == standin_other); + /* + * Change the son's parentage to point to his grandpa. + */ + RB_SET_FATHER(standin_son, standin_father); + RB_SET_POSITION(standin_son, standin_which); + } + } + + if (standin_father == self) { /* - * | R --> S | - * | Q S --> Q * | - * | --> | + * If we are about to delete the standin's father, then when + * we call rebalance, we need to use ourselves as our father. + * Otherwise remember our original father. Also, sincef we are + * our standin's father we only need to reparent the standin's + * brother. + * + * | R --> S | + * | Q S --> Q T | + * | t --> | */ - standin_father = standin; KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other])); KASSERT(!RB_SENTINEL_P(self->rb_nodes[standin_other])); KASSERT(self->rb_nodes[standin_which] == standin); /* - * Make our brother our son. + * Have our son/standin adopt his brother as his new son. */ - standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; - standin->rb_nodes[standin_other]->rb_parent = standin; - KASSERT(standin->rb_nodes[standin_other]->rb_position == standin_other); + standin_father = standin; } else { /* - * | P --> P | - * | S --> Q | - * | Q --> | + * | R --> S . | + * | / \ | T --> / \ | / | + * | ..... | S --> ..... | T | + * + * Sever standin's connection to his father. */ - standin_father = standin->rb_parent; - standin_father->rb_nodes[standin_which] = - standin->rb_nodes[standin_which]; - standin->rb_left = self->rb_left; - standin->rb_right = self->rb_right; - standin->rb_left->rb_parent = standin; - standin->rb_right->rb_parent = standin; + standin_father->rb_nodes[standin_which] = standin_son; + /* + * Adopt the far son. + */ + standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; + RB_SET_FATHER(standin->rb_nodes[standin_other], standin); + KASSERT(RB_POSITION(self->rb_nodes[standin_other]) == standin_other); + /* + * Use standin_other because we need to preserve standin_which + * for the removal_rebalance. + */ + standin_other = standin_which; } + /* + * Move the only remaining son to our standin. If our standin is our + * son, this will be the only son needed to be moved. + */ + KASSERT(standin->rb_nodes[standin_other] != self->rb_nodes[standin_other]); + standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; + RB_SET_FATHER(standin->rb_nodes[standin_other], standin); + /* * Now copy the result of self to standin and then replace * self with standin in the tree. */ - standin->rb_parent = self->rb_parent; - standin->rb_properties = self->rb_properties; - standin->rb_parent->rb_nodes[standin->rb_position] = standin; + RB_COPY_PROPERTIES(standin, self); + RB_SET_FATHER(standin, RB_FATHER(self)); + RB_FATHER(standin)->rb_nodes[RB_POSITION(standin)] = 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_COUNT_DECR(rbt); + RBSTAT_DEC(rbt->rbt_count); +#ifndef RBSMALL + if (__predict_false(rbt->rbt_minmax[RB_POSITION(self)] == self)) + rbt->rbt_minmax[RB_POSITION(self)] = RB_FATHER(self); + RB_SET_FATHER(self, NULL); +#endif KASSERT(rb_tree_check_node(rbt, standin, NULL, false)); - KASSERT(rb_tree_check_node(rbt, standin_father, NULL, false)); + KASSERT(RB_FATHER_SENTINEL_P(standin) + || rb_tree_check_node(rbt, standin_father, NULL, false)); + KASSERT(RB_LEFT_SENTINEL_P(standin) + || rb_tree_check_node(rbt, standin->rb_left, NULL, false)); + KASSERT(RB_RIGHT_SENTINEL_P(standin) + || rb_tree_check_node(rbt, standin->rb_right, NULL, false)); if (!rebalance) return; @@ -527,46 +626,61 @@ rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self, * * But it's more efficient to just evalate and recolor the child. */ -/*ARGSUSED*/ static void -rb_tree_prune_blackred_branch(struct rb_tree *rbt _PROP_ARG_UNUSED, - struct rb_node *self, unsigned int which) +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 = RB_FATHER(self); + struct rb_node *son = self->rb_nodes[which]; +#ifndef RBSMALL + const bool was_root = RB_ROOT_P(rbt, self); +#endif - KASSERT(which == RB_NODE_LEFT || which == RB_NODE_RIGHT); - KASSERT(RB_BLACK_P(self) && RB_RED_P(child)); - KASSERT(!RB_TWOCHILDREN_P(child)); - KASSERT(RB_CHILDLESS_P(child)); + KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT); + 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; + RB_COPY_PROPERTIES(son, self); + father->rb_nodes[RB_POSITION(son)] = son; + RB_SET_FATHER(son, father); /* - * 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_COUNT_DECR(rbt); + RBSTAT_DEC(rbt->rbt_count); +#ifndef RBSMALL + if (__predict_false(was_root)) { + KASSERT(rbt->rbt_minmax[which] == son); + rbt->rbt_minmax[which ^ RB_DIR_OTHER] = son; + } else if (rbt->rbt_minmax[RB_POSITION(self)] == self) { + rbt->rbt_minmax[RB_POSITION(self)] = son; + } + RB_SET_FATHER(self, NULL); +#endif - KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, parent, NULL, true)); - KASSERT(rb_tree_check_node(rbt, child, NULL, true)); + KASSERT(was_root || rb_tree_check_node(rbt, father, NULL, true)); + KASSERT(rb_tree_check_node(rbt, son, NULL, true)); } -/* - * - */ + void -_prop_rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self) +_prop_rb_tree_remove_node(struct rb_tree *rbt, void *object) { - struct rb_node *standin; + const rb_tree_ops_t *rbto = rbt->rbt_ops; + struct rb_node *standin, *self = RB_ITEMTONODE(rbto, object); 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. @@ -585,11 +699,8 @@ _prop_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); + const bool rebalance = RB_BLACK_P(self) && !RB_ROOT_P(rbt, self); + rb_tree_prune_node(rbt, self, rebalance); return; } KASSERT(!RB_CHILDLESS_P(self)); @@ -602,7 +713,7 @@ _prop_rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self) * | S --> R --> R | * | r --> s --> * | */ - which = RB_LEFT_SENTINEL_P(self) ? RB_NODE_RIGHT : RB_NODE_LEFT; + which = RB_LEFT_SENTINEL_P(self) ? RB_DIR_RIGHT : RB_DIR_LEFT; KASSERT(RB_BLACK_P(self)); KASSERT(RB_RED_P(self->rb_nodes[which])); KASSERT(RB_CHILDLESS_P(self->rb_nodes[which])); @@ -615,13 +726,13 @@ _prop_rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self) * We invert these because we prefer to remove from the inside of * the tree. */ - which = self->rb_position ^ RB_NODE_OTHER; + which = RB_POSITION(self) ^ RB_DIR_OTHER; /* * Let's find the node closes to us opposite of our parent * Now swap it with ourself, "prune" it, and rebalance, if needed. */ - standin = _prop_rb_tree_iterate(rbt, self, which); + standin = RB_ITEMTONODE(rbto,_prop_rb_tree_iterate(rbt, object, which)); rb_tree_swap_prune_and_rebalance(rbt, self, standin); } @@ -631,12 +742,15 @@ 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_NODE_LEFT || which == RB_NODE_RIGHT); + KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT); + RBSTAT_INC(rbt->rbt_removal_rebalance_calls); while (RB_BLACK_P(parent->rb_nodes[which])) { - unsigned int other = which ^ RB_NODE_OTHER; + unsigned int other = which ^ RB_DIR_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 @@ -645,21 +759,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 { @@ -668,63 +785,100 @@ 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); KASSERT(RB_BLACK_P(brother->rb_left)); KASSERT(RB_BLACK_P(brother->rb_right)); - if (RB_ROOT_P(parent)) - return; + if (RB_ROOT_P(rbt, parent)) + return; /* root == parent == black */ 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; + which = RB_POSITION(parent); + parent = RB_FATHER(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)); break; /* We're done! */ } 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 + * Our brother must be black and have at least one + * red child (it may have two). */ + KASSERT(RB_BLACK_P(brother)); + KASSERT(RB_RED_P(brother->rb_nodes[which]) || + RB_RED_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])); rb_tree_reparent_nodes(rbt, brother, which); - KASSERT(brother->rb_parent == parent->rb_nodes[other]); + KASSERT(RB_FATHER(brother) == parent->rb_nodes[other]); 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 + * 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 --> | + * + * If we had two red nephews, then after the swap, + * our former father would have a red grandson. */ + KASSERT(RB_BLACK_P(brother)); + KASSERT(RB_RED_P(brother->rb_nodes[other])); RB_MARK_BLACK(brother->rb_nodes[other]); rb_tree_reparent_nodes(rbt, parent, other); break; /* We're done! */ @@ -733,20 +887,77 @@ rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent, KASSERT(rb_tree_check_node(rbt, parent, NULL, true)); } -struct rb_node * -_prop_rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self, - unsigned int direction) +void * +_prop_rb_tree_iterate(struct rb_tree *rbt, void *object, + const unsigned int direction) { - const unsigned int other = direction ^ RB_NODE_OTHER; - KASSERT(direction == RB_NODE_LEFT || direction == RB_NODE_RIGHT); + const rb_tree_ops_t *rbto = rbt->rbt_ops; + const unsigned int other = direction ^ RB_DIR_OTHER; + struct rb_node *self; - if (self == NULL) { + KASSERT(direction == RB_DIR_LEFT || direction == RB_DIR_RIGHT); + + if (object == NULL) { +#ifndef RBSMALL + if (RB_SENTINEL_P(rbt->rbt_root)) + return NULL; + return RB_NODETOITEM(rbto, 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]; + while (!RB_SENTINEL_P(self->rb_nodes[direction])) + self = self->rb_nodes[direction]; + return RB_NODETOITEM(rbto, self); +#endif /* !RBSMALL */ + } + self = RB_ITEMTONODE(rbto, object); + KASSERT(!RB_SENTINEL_P(self)); + /* + * We can't go any further in this direction. We proceed up in the + * opposite direction until our parent is in direction we want to go. + */ + if (RB_SENTINEL_P(self->rb_nodes[direction])) { + while (!RB_ROOT_P(rbt, self)) { + if (other == RB_POSITION(self)) + return RB_NODETOITEM(rbto, RB_FATHER(self)); + self = RB_FATHER(self); + } + return NULL; + } + + /* + * Advance down one in current direction and go down as far as possible + * in the opposite direction. + */ + self = self->rb_nodes[direction]; + KASSERT(!RB_SENTINEL_P(self)); + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return RB_NODETOITEM(rbto, self); +} + +#ifdef RBDEBUG +static const struct rb_node * +rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self, + const unsigned int direction) +{ + const unsigned int other = direction ^ RB_DIR_OTHER; + KASSERT(direction == RB_DIR_LEFT || direction == RB_DIR_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[direction])) + self = self->rb_nodes[direction]; return self; +#endif /* !RBSMALL */ } KASSERT(!RB_SENTINEL_P(self)); /* @@ -754,10 +965,10 @@ _prop_rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self, * opposite direction until our parent is in direction we want to go. */ if (RB_SENTINEL_P(self->rb_nodes[direction])) { - while (!RB_ROOT_P(self)) { - if (other == self->rb_position) - return self->rb_parent; - self = self->rb_parent; + while (!RB_ROOT_P(rbt, self)) { + if (other == RB_POSITION(self)) + return RB_FATHER(self); + self = RB_FATHER(self); } return NULL; } @@ -773,74 +984,54 @@ _prop_rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self, return self; } -#ifdef RBDEBUG -static const struct rb_node * -rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self, - unsigned int direction) +static unsigned int +rb_tree_count_black(const struct rb_node *self) { - const unsigned int other = direction ^ RB_NODE_OTHER; - KASSERT(direction == RB_NODE_LEFT || direction == RB_NODE_RIGHT); + unsigned int left, right; - if (self == NULL) { - 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; - } - KASSERT(!RB_SENTINEL_P(self)); - /* - * We can't go any further in this direction. We proceed up in the - * opposite direction until our parent is in direction we want to go. - */ - if (RB_SENTINEL_P(self->rb_nodes[direction])) { - while (!RB_ROOT_P(self)) { - if (other == self->rb_position) - return self->rb_parent; - self = self->rb_parent; - } - return NULL; - } + if (RB_SENTINEL_P(self)) + return 0; - /* - * Advance down one in current direction and go down as far as possible - * in the opposite direction. - */ - self = self->rb_nodes[direction]; - KASSERT(!RB_SENTINEL_P(self)); - while (!RB_SENTINEL_P(self->rb_nodes[other])) - self = self->rb_nodes[other]; - return self; + left = rb_tree_count_black(self->rb_left); + right = rb_tree_count_black(self->rb_right); + + KASSERT(left == right); + + return left + RB_BLACK_P(self); } static 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); - KASSERT(self->rb_left); - KASSERT(self->rb_right); - KASSERT(prev == NULL || - (*rbt->rbt_ops->rbto_compare_nodes)(prev, self) > 0); + const rb_tree_ops_t *rbto = rbt->rbt_ops; + rbto_compare_nodes_fn compare_nodes = rbto->rbto_compare_nodes; + + KASSERT(!RB_SENTINEL_P(self)); + KASSERT(prev == NULL || (*compare_nodes)(rbto->rbto_context, + RB_NODETOITEM(rbto, prev), RB_NODETOITEM(rbto, self)) < 0); /* * Verify our relationship to our parent. */ - if (RB_ROOT_P(self)) { + if (RB_ROOT_P(rbt, self)) { KASSERT(self == rbt->rbt_root); - KASSERT(self->rb_position == RB_NODE_LEFT); - KASSERT(self->rb_parent->rb_nodes[RB_NODE_LEFT] == self); - KASSERT(self->rb_parent == (const struct rb_node *) &rbt->rbt_root); + KASSERT(RB_POSITION(self) == RB_DIR_LEFT); + KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_LEFT] == self); + KASSERT(RB_FATHER(self) == (const struct rb_node *) &rbt->rbt_root); } else { + int diff = (*compare_nodes)(rbto->rbto_context, + RB_NODETOITEM(rbto, self), + RB_NODETOITEM(rbto, RB_FATHER(self))); + KASSERT(self != rbt->rbt_root); - KASSERT(!RB_PARENT_SENTINEL_P(self)); - if (self->rb_position == RB_NODE_LEFT) { - KASSERT((*rbt->rbt_ops->rbto_compare_nodes)(self, self->rb_parent) > 0); - KASSERT(self->rb_parent->rb_nodes[RB_NODE_LEFT] == self); + KASSERT(!RB_FATHER_SENTINEL_P(self)); + if (RB_POSITION(self) == RB_DIR_LEFT) { + KASSERT(diff < 0); + KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_LEFT] == self); } else { - KASSERT((*rbt->rbt_ops->rbto_compare_nodes)(self, self->rb_parent) < 0); - KASSERT(self->rb_parent->rb_nodes[RB_NODE_RIGHT] == self); + KASSERT(diff > 0); + KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_RIGHT] == self); } } @@ -848,12 +1039,14 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, * Verify our position in the linked list against the tree itself. */ { - const struct rb_node *prev0 = rb_tree_iterate_const(rbt, self, RB_NODE_LEFT); - const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_NODE_RIGHT); + const struct rb_node *prev0 = rb_tree_iterate_const(rbt, self, RB_DIR_LEFT); + const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_DIR_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_NODE_RIGHT); KASSERT(next0 == TAILQ_NEXT(self, rb_link)); +#ifndef RBSMALL + KASSERT(prev0 != NULL || self == rbt->rbt_minmax[RB_DIR_LEFT]); + KASSERT(next0 != NULL || self == rbt->rbt_minmax[RB_DIR_RIGHT]); +#endif } /* @@ -861,12 +1054,13 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, * There can never be two adjacent red nodes. */ if (red_check) { - KASSERT(!RB_ROOT_P(self) || RB_BLACK_P(self)); + KASSERT(!RB_ROOT_P(rbt, self) || RB_BLACK_P(self)); + (void) rb_tree_count_black(self); if (RB_RED_P(self)) { const struct rb_node *brother; - KASSERT(!RB_ROOT_P(self)); - brother = self->rb_parent->rb_nodes[self->rb_position ^ RB_NODE_OTHER]; - KASSERT(RB_BLACK_P(self->rb_parent)); + KASSERT(!RB_ROOT_P(rbt, self)); + brother = RB_FATHER(self)->rb_nodes[RB_POSITION(self) ^ RB_DIR_OTHER]; + KASSERT(RB_BLACK_P(RB_FATHER(self))); /* * I'm red and have no children, then I must either * have no brother or my brother also be red and @@ -915,11 +1109,11 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, * black, my 2nd closet relative away from my parent * is either red or has a red parent or red children. */ - if (!RB_ROOT_P(self) + if (!RB_ROOT_P(rbt, self) && RB_CHILDLESS_P(self) - && RB_BLACK_P(self->rb_parent)) { - const unsigned int which = self->rb_position; - const unsigned int other = which ^ RB_NODE_OTHER; + && RB_BLACK_P(RB_FATHER(self))) { + const unsigned int which = RB_POSITION(self); + const unsigned int other = which ^ RB_DIR_OTHER; const struct rb_node *relative0, *relative; relative0 = rb_tree_iterate_const(rbt, @@ -933,7 +1127,7 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, KASSERT(RB_RED_P(relative) || RB_RED_P(relative->rb_left) || RB_RED_P(relative->rb_right) - || RB_RED_P(relative->rb_parent)); + || RB_RED_P(RB_FATHER(relative))); #endif } } @@ -941,9 +1135,9 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, * 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)); + KASSERT(RB_ROOT_P(rbt, self) + || RB_ROOT_P(rbt, RB_FATHER(self)) + || RB_TWOCHILDREN_P(RB_FATHER(RB_FATHER(self)))); /* * If we are have grandchildren on our left, then * we must have a child on our right. @@ -995,11 +1189,11 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, const struct rb_node *prev0; const struct rb_node *next0; - prev0 = rb_tree_iterate_const(rbt, self, RB_NODE_LEFT); + prev0 = rb_tree_iterate_const(rbt, self, RB_DIR_LEFT); KASSERT(prev0 != NULL); KASSERT(RB_RIGHT_SENTINEL_P(prev0)); - next0 = rb_tree_iterate_const(rbt, self, RB_NODE_RIGHT); + next0 = rb_tree_iterate_const(rbt, self, RB_DIR_RIGHT); KASSERT(next0 != NULL); KASSERT(RB_LEFT_SENTINEL_P(next0)); } @@ -1008,50 +1202,74 @@ rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, return true; } -static unsigned int -rb_tree_count_black(const struct rb_node *self) -{ - unsigned int left, right; - - if (RB_SENTINEL_P(self)) - return 0; - - left = rb_tree_count_black(self->rb_left); - right = rb_tree_count_black(self->rb_right); - - KASSERT(left == right); - - return left + RB_BLACK_P(self); -} - void _prop_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 || rbt->rbt_root->rb_position == RB_NODE_LEFT); + KASSERT(rbt->rbt_root != NULL); + KASSERT(RB_LEFT_P(rbt->rbt_root)); + +#if defined(RBSTATS) && !defined(RBSMALL) + KASSERT(rbt->rbt_count > 1 + || rbt->rbt_minmax[RB_DIR_LEFT] == rbt->rbt_minmax[RB_DIR_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 /* RBDEBUG */ + +#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/common/lib/libprop/prop_rb_impl.h b/common/lib/libprop/prop_rb_impl.h index f04723acf026..8ebb926c78cc 100644 --- a/common/lib/libprop/prop_rb_impl.h +++ b/common/lib/libprop/prop_rb_impl.h @@ -1,4 +1,4 @@ -/* $NetBSD: prop_rb_impl.h,v 1.8 2010/09/25 01:42:38 matt Exp $ */ +/* $NetBSD: prop_rb_impl.h,v 1.9 2012/07/27 09:11:00 pooka Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -47,107 +47,149 @@ #else /* __NetBSD__ */ #include +#ifdef RBDEBUG #include -#include +#endif -struct rb_node { - struct rb_node *rb_nodes[3]; -#define RB_NODE_LEFT 0 -#define RB_NODE_RIGHT 1 -#define RB_NODE_OTHER 1 -#define RB_NODE_PARENT 2 -#define rb_left rb_nodes[RB_NODE_LEFT] -#define rb_right rb_nodes[RB_NODE_RIGHT] -#define rb_parent rb_nodes[RB_NODE_PARENT] - union { - struct { -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned int : 28; - unsigned int s_root : 1; - unsigned int s_position : 1; - 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 : 1; - unsigned int s_root : 1; - unsigned int : 28; -#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)) +typedef struct rb_node { + struct rb_node *rb_nodes[2]; +#define RB_DIR_LEFT 0 +#define RB_DIR_RIGHT 1 +#define RB_DIR_OTHER 1 +#define rb_left rb_nodes[RB_DIR_LEFT] +#define rb_right rb_nodes[RB_DIR_RIGHT] + + /* + * rb_info contains the two flags and the parent back pointer. + * We put the two flags in the low two bits since we know that + * rb_node will have an alignment of 4 or 8 bytes. + */ + uintptr_t rb_info; +#define RB_FLAG_POSITION 0x2 +#define RB_FLAG_RED 0x1 +#define RB_FLAG_MASK (RB_FLAG_POSITION|RB_FLAG_RED) +#define RB_FATHER(rb) \ + ((struct rb_node *)((rb)->rb_info & ~RB_FLAG_MASK)) +#define RB_SET_FATHER(rb, father) \ + ((void)((rb)->rb_info = (uintptr_t)(father)|((rb)->rb_info & RB_FLAG_MASK))) + +#define RB_SENTINEL_P(rb) ((rb) == NULL) +#define RB_LEFT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_left) +#define RB_RIGHT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_right) +#define RB_FATHER_SENTINEL_P(rb) RB_SENTINEL_P(RB_FATHER((rb))) +#define RB_CHILDLESS_P(rb) \ + (RB_SENTINEL_P(rb) || (RB_LEFT_SENTINEL_P(rb) && RB_RIGHT_SENTINEL_P(rb))) +#define RB_TWOCHILDREN_P(rb) \ + (!RB_SENTINEL_P(rb) && !RB_LEFT_SENTINEL_P(rb) && !RB_RIGHT_SENTINEL_P(rb)) + +#define RB_POSITION(rb) \ + (((rb)->rb_info & RB_FLAG_POSITION) ? RB_DIR_RIGHT : RB_DIR_LEFT) +#define RB_RIGHT_P(rb) (RB_POSITION(rb) == RB_DIR_RIGHT) +#define RB_LEFT_P(rb) (RB_POSITION(rb) == RB_DIR_LEFT) +#define RB_RED_P(rb) (!RB_SENTINEL_P(rb) && ((rb)->rb_info & RB_FLAG_RED) != 0) +#define RB_BLACK_P(rb) (RB_SENTINEL_P(rb) || ((rb)->rb_info & RB_FLAG_RED) == 0) +#define RB_MARK_RED(rb) ((void)((rb)->rb_info |= RB_FLAG_RED)) +#define RB_MARK_BLACK(rb) ((void)((rb)->rb_info &= ~RB_FLAG_RED)) +#define RB_INVERT_COLOR(rb) ((void)((rb)->rb_info ^= RB_FLAG_RED)) +#define RB_ROOT_P(rbt, rb) ((rbt)->rbt_root == (rb)) +#define RB_SET_POSITION(rb, position) \ + ((void)((position) ? ((rb)->rb_info |= RB_FLAG_POSITION) : \ + ((rb)->rb_info &= ~RB_FLAG_POSITION))) +#define RB_ZERO_PROPERTIES(rb) ((void)((rb)->rb_info &= ~RB_FLAG_MASK)) +#define RB_COPY_PROPERTIES(dst, src) \ + ((void)((dst)->rb_info ^= ((dst)->rb_info ^ (src)->rb_info) & RB_FLAG_MASK)) +#define RB_SWAP_PROPERTIES(a, b) do { \ + uintptr_t xorinfo = ((a)->rb_info ^ (b)->rb_info) & RB_FLAG_MASK; \ + (a)->rb_info ^= xorinfo; \ + (b)->rb_info ^= xorinfo; \ + } while (/*CONSTCOND*/ 0) #ifdef RBDEBUG TAILQ_ENTRY(rb_node) rb_link; #endif -}; +} rb_node_t; + +#define RB_TREE_MIN(T) rb_tree_iterate((T), NULL, RB_DIR_LEFT) +#define RB_TREE_MAX(T) rb_tree_iterate((T), NULL, RB_DIR_RIGHT) +#define RB_TREE_FOREACH(N, T) \ + for ((N) = RB_TREE_MIN(T); (N); \ + (N) = rb_tree_iterate((T), (N), RB_DIR_RIGHT)) +#define RB_TREE_FOREACH_REVERSE(N, T) \ + for ((N) = RB_TREE_MAX(T); (N); \ + (N) = rb_tree_iterate((T), (N), RB_DIR_LEFT)) #ifdef RBDEBUG 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 (/*CONSTCOND*/0) #define RB_TAILQ_INIT(a) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_HEAD(a, b, c) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_BEFORE(a, b, c) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_AFTER(a, b, c, d) do { } while (/*CONSTCOND*/0) -#endif +#endif /* RBDEBUG */ -typedef int (*rb_compare_nodes_fn)(const struct rb_node *, - const struct rb_node *); -typedef int (*rb_compare_key_fn)(const struct rb_node *, const void *); +/* + * rbto_compare_nodes_fn: + * return a positive value if the first node > the second node. + * return a negative value if the first node < the second node. + * return 0 if they are considered same. + * + * rbto_compare_key_fn: + * return a positive value if the node > the key. + * return a negative value if the node < the key. + * return 0 if they are considered same. + */ -struct rb_tree_ops { - rb_compare_nodes_fn rbto_compare_nodes; - rb_compare_key_fn rbto_compare_key; -}; +typedef signed int (*rbto_compare_nodes_fn)(void *, const void *, const void *); +typedef signed int (*rbto_compare_key_fn)(void *, const void *, const void *); -struct rb_tree { +typedef struct { + rbto_compare_nodes_fn rbto_compare_nodes; + rbto_compare_key_fn rbto_compare_key; + size_t rbto_node_offset; + void *rbto_context; +} rb_tree_ops_t; + +typedef struct rb_tree { struct rb_node *rbt_root; + const rb_tree_ops_t *rbt_ops; + struct rb_node *rbt_minmax[2]; #ifdef RBDEBUG struct rb_node_qh rbt_nodes; #endif - const struct rb_tree_ops *rbt_ops; -#ifdef RBDEBUG +#ifdef RBSTATS unsigned int rbt_count; + 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 -}; +} rb_tree_t; -void _prop_rb_tree_init(struct rb_tree *, const struct rb_tree_ops *); -bool _prop_rb_tree_insert_node(struct rb_tree *, struct rb_node *); -struct rb_node * - _prop_rb_tree_find(struct rb_tree *, const void *); -void _prop_rb_tree_remove_node(struct rb_tree *, struct rb_node *); +#ifdef RBSTATS +#define RBSTAT_INC(v) ((void)((v)++)) +#define RBSTAT_DEC(v) ((void)((v)--)) +#else +#define RBSTAT_INC(v) do { } while (/*CONSTCOND*/0) +#define RBSTAT_DEC(v) do { } while (/*CONSTCOND*/0) +#endif + +void _prop_rb_tree_init(rb_tree_t *, const rb_tree_ops_t *); +void * _prop_rb_tree_insert_node(rb_tree_t *, void *); +void * _prop_rb_tree_find(rb_tree_t *, const void *); +void * _prop_rb_tree_find_node(rb_tree_t *, const void *); +void _prop_rb_tree_remove_node(rb_tree_t *, void *); +void * _prop_rb_tree_iterate(rb_tree_t *, void *, const unsigned int); #ifdef RBDEBUG void _prop_rb_tree_check(const struct rb_tree *, bool); #endif -struct rb_node * - _prop_rb_tree_iterate(struct rb_tree *, struct rb_node *, unsigned int); #endif /* __NetBSD__ */