Remove rbt_nil

Since this is an intrusive tree, rbt_nil is the whole size of the node
and can be quite large.  For example, miscelm is ~100 bytes.
This commit is contained in:
Dave Watson 2016-02-17 06:56:14 -08:00 committed by Jason Evans
parent 0da8ce1e96
commit 2b1fc90b7b
2 changed files with 86 additions and 109 deletions

View File

@ -42,7 +42,6 @@ struct { \
#define rb_tree(a_type) \ #define rb_tree(a_type) \
struct { \ struct { \
a_type *rbt_root; \ a_type *rbt_root; \
a_type rbt_nil; \
} }
/* Left accessors. */ /* Left accessors. */
@ -84,8 +83,8 @@ struct { \
#define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ #define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \
/* Bookkeeping bit cannot be used by node pointer. */ \ /* Bookkeeping bit cannot be used by node pointer. */ \
assert(((uintptr_t)(a_node) & 0x1) == 0); \ assert(((uintptr_t)(a_node) & 0x1) == 0); \
rbtn_left_set(a_type, a_field, (a_node), &(a_rbt)->rbt_nil); \ rbtn_left_set(a_type, a_field, (a_node), NULL); \
rbtn_right_set(a_type, a_field, (a_node), &(a_rbt)->rbt_nil); \ rbtn_right_set(a_type, a_field, (a_node), NULL); \
rbtn_red_set(a_type, a_field, (a_node)); \ rbtn_red_set(a_type, a_field, (a_node)); \
} while (0) } while (0)
#else #else
@ -111,25 +110,23 @@ struct { \
/* Node initializer. */ /* Node initializer. */
#define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ #define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \
rbtn_left_set(a_type, a_field, (a_node), &(a_rbt)->rbt_nil); \ rbtn_left_set(a_type, a_field, (a_node), NULL); \
rbtn_right_set(a_type, a_field, (a_node), &(a_rbt)->rbt_nil); \ rbtn_right_set(a_type, a_field, (a_node), NULL); \
rbtn_red_set(a_type, a_field, (a_node)); \ rbtn_red_set(a_type, a_field, (a_node)); \
} while (0) } while (0)
#endif #endif
/* Tree initializer. */ /* Tree initializer. */
#define rb_new(a_type, a_field, a_rbt) do { \ #define rb_new(a_type, a_field, a_rbt) do { \
(a_rbt)->rbt_root = &(a_rbt)->rbt_nil; \ (a_rbt)->rbt_root = NULL; \
rbt_node_new(a_type, a_field, a_rbt, &(a_rbt)->rbt_nil); \
rbtn_black_set(a_type, a_field, &(a_rbt)->rbt_nil); \
} while (0) } while (0)
/* Internal utility macros. */ /* Internal utility macros. */
#define rbtn_first(a_type, a_field, a_rbt, a_root, r_node) do { \ #define rbtn_first(a_type, a_field, a_rbt, a_root, r_node) do { \
(r_node) = (a_root); \ (r_node) = (a_root); \
if ((r_node) != &(a_rbt)->rbt_nil) { \ if ((r_node) != NULL) { \
for (; \ for (; \
rbtn_left_get(a_type, a_field, (r_node)) != &(a_rbt)->rbt_nil;\ rbtn_left_get(a_type, a_field, (r_node)) != NULL; \
(r_node) = rbtn_left_get(a_type, a_field, (r_node))) { \ (r_node) = rbtn_left_get(a_type, a_field, (r_node))) { \
} \ } \
} \ } \
@ -137,10 +134,9 @@ struct { \
#define rbtn_last(a_type, a_field, a_rbt, a_root, r_node) do { \ #define rbtn_last(a_type, a_field, a_rbt, a_root, r_node) do { \
(r_node) = (a_root); \ (r_node) = (a_root); \
if ((r_node) != &(a_rbt)->rbt_nil) { \ if ((r_node) != NULL) { \
for (; rbtn_right_get(a_type, a_field, (r_node)) != \ for (; rbtn_right_get(a_type, a_field, (r_node)) != NULL; \
&(a_rbt)->rbt_nil; (r_node) = rbtn_right_get(a_type, a_field, \ (r_node) = rbtn_right_get(a_type, a_field, (r_node))) { \
(r_node))) { \
} \ } \
} \ } \
} while (0) } while (0)
@ -335,8 +331,8 @@ a_prefix##destroy(a_rbt_type *rbtree, void (*cb)(a_type *, void *), \
* Args: * Args:
* tree: Pointer to an initialized red-black tree object. * tree: Pointer to an initialized red-black tree object.
* cb : Callback function, which, if non-null, is called for each node * cb : Callback function, which, if non-null, is called for each node
* during iteration. There is no way to stop iteration once it has * during iteration. There is no way to stop iteration once it
* begun. * has begun.
* arg : Opaque pointer passed to cb(). * arg : Opaque pointer passed to cb().
*/ */
#define rb_gen(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp) \ #define rb_gen(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp) \
@ -346,36 +342,30 @@ a_prefix##new(a_rbt_type *rbtree) { \
} \ } \
a_attr bool \ a_attr bool \
a_prefix##empty(a_rbt_type *rbtree) { \ a_prefix##empty(a_rbt_type *rbtree) { \
return (rbtree->rbt_root == &rbtree->rbt_nil); \ return (rbtree->rbt_root == NULL); \
} \ } \
a_attr a_type * \ a_attr a_type * \
a_prefix##first(a_rbt_type *rbtree) { \ a_prefix##first(a_rbt_type *rbtree) { \
a_type *ret; \ a_type *ret; \
rbtn_first(a_type, a_field, rbtree, rbtree->rbt_root, ret); \ rbtn_first(a_type, a_field, rbtree, rbtree->rbt_root, ret); \
if (ret == &rbtree->rbt_nil) { \
ret = NULL; \
} \
return (ret); \ return (ret); \
} \ } \
a_attr a_type * \ a_attr a_type * \
a_prefix##last(a_rbt_type *rbtree) { \ a_prefix##last(a_rbt_type *rbtree) { \
a_type *ret; \ a_type *ret; \
rbtn_last(a_type, a_field, rbtree, rbtree->rbt_root, ret); \ rbtn_last(a_type, a_field, rbtree, rbtree->rbt_root, ret); \
if (ret == &rbtree->rbt_nil) { \
ret = NULL; \
} \
return (ret); \ return (ret); \
} \ } \
a_attr a_type * \ a_attr a_type * \
a_prefix##next(a_rbt_type *rbtree, a_type *node) { \ a_prefix##next(a_rbt_type *rbtree, a_type *node) { \
a_type *ret; \ a_type *ret; \
if (rbtn_right_get(a_type, a_field, node) != &rbtree->rbt_nil) { \ if (rbtn_right_get(a_type, a_field, node) != NULL) { \
rbtn_first(a_type, a_field, rbtree, rbtn_right_get(a_type, \ rbtn_first(a_type, a_field, rbtree, rbtn_right_get(a_type, \
a_field, node), ret); \ a_field, node), ret); \
} else { \ } else { \
a_type *tnode = rbtree->rbt_root; \ a_type *tnode = rbtree->rbt_root; \
assert(tnode != &rbtree->rbt_nil); \ assert(tnode != NULL); \
ret = &rbtree->rbt_nil; \ ret = NULL; \
while (true) { \ while (true) { \
int cmp = (a_cmp)(node, tnode); \ int cmp = (a_cmp)(node, tnode); \
if (cmp < 0) { \ if (cmp < 0) { \
@ -386,24 +376,21 @@ a_prefix##next(a_rbt_type *rbtree, a_type *node) { \
} else { \ } else { \
break; \ break; \
} \ } \
assert(tnode != &rbtree->rbt_nil); \ assert(tnode != NULL); \
} \ } \
} \ } \
if (ret == &rbtree->rbt_nil) { \
ret = (NULL); \
} \
return (ret); \ return (ret); \
} \ } \
a_attr a_type * \ a_attr a_type * \
a_prefix##prev(a_rbt_type *rbtree, a_type *node) { \ a_prefix##prev(a_rbt_type *rbtree, a_type *node) { \
a_type *ret; \ a_type *ret; \
if (rbtn_left_get(a_type, a_field, node) != &rbtree->rbt_nil) { \ if (rbtn_left_get(a_type, a_field, node) != NULL) { \
rbtn_last(a_type, a_field, rbtree, rbtn_left_get(a_type, \ rbtn_last(a_type, a_field, rbtree, rbtn_left_get(a_type, \
a_field, node), ret); \ a_field, node), ret); \
} else { \ } else { \
a_type *tnode = rbtree->rbt_root; \ a_type *tnode = rbtree->rbt_root; \
assert(tnode != &rbtree->rbt_nil); \ assert(tnode != NULL); \
ret = &rbtree->rbt_nil; \ ret = NULL; \
while (true) { \ while (true) { \
int cmp = (a_cmp)(node, tnode); \ int cmp = (a_cmp)(node, tnode); \
if (cmp < 0) { \ if (cmp < 0) { \
@ -414,12 +401,9 @@ a_prefix##prev(a_rbt_type *rbtree, a_type *node) { \
} else { \ } else { \
break; \ break; \
} \ } \
assert(tnode != &rbtree->rbt_nil); \ assert(tnode != NULL); \
} \ } \
} \ } \
if (ret == &rbtree->rbt_nil) { \
ret = (NULL); \
} \
return (ret); \ return (ret); \
} \ } \
a_attr a_type * \ a_attr a_type * \
@ -427,7 +411,7 @@ a_prefix##search(a_rbt_type *rbtree, const a_type *key) { \
a_type *ret; \ a_type *ret; \
int cmp; \ int cmp; \
ret = rbtree->rbt_root; \ ret = rbtree->rbt_root; \
while (ret != &rbtree->rbt_nil \ while (ret != NULL \
&& (cmp = (a_cmp)(key, ret)) != 0) { \ && (cmp = (a_cmp)(key, ret)) != 0) { \
if (cmp < 0) { \ if (cmp < 0) { \
ret = rbtn_left_get(a_type, a_field, ret); \ ret = rbtn_left_get(a_type, a_field, ret); \
@ -435,17 +419,14 @@ a_prefix##search(a_rbt_type *rbtree, const a_type *key) { \
ret = rbtn_right_get(a_type, a_field, ret); \ ret = rbtn_right_get(a_type, a_field, ret); \
} \ } \
} \ } \
if (ret == &rbtree->rbt_nil) { \
ret = (NULL); \
} \
return (ret); \ return (ret); \
} \ } \
a_attr a_type * \ a_attr a_type * \
a_prefix##nsearch(a_rbt_type *rbtree, const a_type *key) { \ a_prefix##nsearch(a_rbt_type *rbtree, const a_type *key) { \
a_type *ret; \ a_type *ret; \
a_type *tnode = rbtree->rbt_root; \ a_type *tnode = rbtree->rbt_root; \
ret = &rbtree->rbt_nil; \ ret = NULL; \
while (tnode != &rbtree->rbt_nil) { \ while (tnode != NULL) { \
int cmp = (a_cmp)(key, tnode); \ int cmp = (a_cmp)(key, tnode); \
if (cmp < 0) { \ if (cmp < 0) { \
ret = tnode; \ ret = tnode; \
@ -457,17 +438,14 @@ a_prefix##nsearch(a_rbt_type *rbtree, const a_type *key) { \
break; \ break; \
} \ } \
} \ } \
if (ret == &rbtree->rbt_nil) { \
ret = (NULL); \
} \
return (ret); \ return (ret); \
} \ } \
a_attr a_type * \ a_attr a_type * \
a_prefix##psearch(a_rbt_type *rbtree, const a_type *key) { \ a_prefix##psearch(a_rbt_type *rbtree, const a_type *key) { \
a_type *ret; \ a_type *ret; \
a_type *tnode = rbtree->rbt_root; \ a_type *tnode = rbtree->rbt_root; \
ret = &rbtree->rbt_nil; \ ret = NULL; \
while (tnode != &rbtree->rbt_nil) { \ while (tnode != NULL) { \
int cmp = (a_cmp)(key, tnode); \ int cmp = (a_cmp)(key, tnode); \
if (cmp < 0) { \ if (cmp < 0) { \
tnode = rbtn_left_get(a_type, a_field, tnode); \ tnode = rbtn_left_get(a_type, a_field, tnode); \
@ -479,9 +457,6 @@ a_prefix##psearch(a_rbt_type *rbtree, const a_type *key) { \
break; \ break; \
} \ } \
} \ } \
if (ret == &rbtree->rbt_nil) { \
ret = (NULL); \
} \
return (ret); \ return (ret); \
} \ } \
a_attr void \ a_attr void \
@ -493,7 +468,7 @@ a_prefix##insert(a_rbt_type *rbtree, a_type *node) { \
rbt_node_new(a_type, a_field, rbtree, node); \ rbt_node_new(a_type, a_field, rbtree, node); \
/* Wind. */ \ /* Wind. */ \
path->node = rbtree->rbt_root; \ path->node = rbtree->rbt_root; \
for (pathp = path; pathp->node != &rbtree->rbt_nil; pathp++) { \ for (pathp = path; pathp->node != NULL; pathp++) { \
int cmp = pathp->cmp = a_cmp(node, pathp->node); \ int cmp = pathp->cmp = a_cmp(node, pathp->node); \
assert(cmp != 0); \ assert(cmp != 0); \
if (cmp < 0) { \ if (cmp < 0) { \
@ -513,7 +488,8 @@ a_prefix##insert(a_rbt_type *rbtree, a_type *node) { \
rbtn_left_set(a_type, a_field, cnode, left); \ rbtn_left_set(a_type, a_field, cnode, left); \
if (rbtn_red_get(a_type, a_field, left)) { \ if (rbtn_red_get(a_type, a_field, left)) { \
a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ a_type *leftleft = rbtn_left_get(a_type, a_field, left);\
if (rbtn_red_get(a_type, a_field, leftleft)) { \ if (leftleft != NULL && rbtn_red_get(a_type, a_field, \
leftleft)) { \
/* Fix up 4-node. */ \ /* Fix up 4-node. */ \
a_type *tnode; \ a_type *tnode; \
rbtn_black_set(a_type, a_field, leftleft); \ rbtn_black_set(a_type, a_field, leftleft); \
@ -528,7 +504,8 @@ a_prefix##insert(a_rbt_type *rbtree, a_type *node) { \
rbtn_right_set(a_type, a_field, cnode, right); \ rbtn_right_set(a_type, a_field, cnode, right); \
if (rbtn_red_get(a_type, a_field, right)) { \ if (rbtn_red_get(a_type, a_field, right)) { \
a_type *left = rbtn_left_get(a_type, a_field, cnode); \ a_type *left = rbtn_left_get(a_type, a_field, cnode); \
if (rbtn_red_get(a_type, a_field, left)) { \ if (left != NULL && rbtn_red_get(a_type, a_field, \
left)) { \
/* Split 4-node. */ \ /* Split 4-node. */ \
rbtn_black_set(a_type, a_field, left); \ rbtn_black_set(a_type, a_field, left); \
rbtn_black_set(a_type, a_field, right); \ rbtn_black_set(a_type, a_field, right); \
@ -561,7 +538,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
/* Wind. */ \ /* Wind. */ \
nodep = NULL; /* Silence compiler warning. */ \ nodep = NULL; /* Silence compiler warning. */ \
path->node = rbtree->rbt_root; \ path->node = rbtree->rbt_root; \
for (pathp = path; pathp->node != &rbtree->rbt_nil; pathp++) { \ for (pathp = path; pathp->node != NULL; pathp++) { \
int cmp = pathp->cmp = a_cmp(node, pathp->node); \ int cmp = pathp->cmp = a_cmp(node, pathp->node); \
if (cmp < 0) { \ if (cmp < 0) { \
pathp[1].node = rbtn_left_get(a_type, a_field, \ pathp[1].node = rbtn_left_get(a_type, a_field, \
@ -573,7 +550,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
/* Find node's successor, in preparation for swap. */ \ /* Find node's successor, in preparation for swap. */ \
pathp->cmp = 1; \ pathp->cmp = 1; \
nodep = pathp; \ nodep = pathp; \
for (pathp++; pathp->node != &rbtree->rbt_nil; \ for (pathp++; pathp->node != NULL; \
pathp++) { \ pathp++) { \
pathp->cmp = -1; \ pathp->cmp = -1; \
pathp[1].node = rbtn_left_get(a_type, a_field, \ pathp[1].node = rbtn_left_get(a_type, a_field, \
@ -616,7 +593,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
} \ } \
} else { \ } else { \
a_type *left = rbtn_left_get(a_type, a_field, node); \ a_type *left = rbtn_left_get(a_type, a_field, node); \
if (left != &rbtree->rbt_nil) { \ if (left != NULL) { \
/* node has no successor, but it has a left child. */\ /* node has no successor, but it has a left child. */\
/* Splice node out, without losing the left child. */\ /* Splice node out, without losing the left child. */\
assert(!rbtn_red_get(a_type, a_field, node)); \ assert(!rbtn_red_get(a_type, a_field, node)); \
@ -636,33 +613,32 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
return; \ return; \
} else if (pathp == path) { \ } else if (pathp == path) { \
/* The tree only contained one node. */ \ /* The tree only contained one node. */ \
rbtree->rbt_root = &rbtree->rbt_nil; \ rbtree->rbt_root = NULL; \
return; \ return; \
} \ } \
} \ } \
if (rbtn_red_get(a_type, a_field, pathp->node)) { \ if (rbtn_red_get(a_type, a_field, pathp->node)) { \
/* Prune red node, which requires no fixup. */ \ /* Prune red node, which requires no fixup. */ \
assert(pathp[-1].cmp < 0); \ assert(pathp[-1].cmp < 0); \
rbtn_left_set(a_type, a_field, pathp[-1].node, \ rbtn_left_set(a_type, a_field, pathp[-1].node, NULL); \
&rbtree->rbt_nil); \
return; \ return; \
} \ } \
/* The node to be pruned is black, so unwind until balance is */\ /* The node to be pruned is black, so unwind until balance is */\
/* restored. */\ /* restored. */\
pathp->node = &rbtree->rbt_nil; \ pathp->node = NULL; \
for (pathp--; (uintptr_t)pathp >= (uintptr_t)path; pathp--) { \ for (pathp--; (uintptr_t)pathp >= (uintptr_t)path; pathp--) { \
assert(pathp->cmp != 0); \ assert(pathp->cmp != 0); \
if (pathp->cmp < 0) { \ if (pathp->cmp < 0) { \
rbtn_left_set(a_type, a_field, pathp->node, \ rbtn_left_set(a_type, a_field, pathp->node, \
pathp[1].node); \ pathp[1].node); \
assert(!rbtn_red_get(a_type, a_field, pathp[1].node)); \
if (rbtn_red_get(a_type, a_field, pathp->node)) { \ if (rbtn_red_get(a_type, a_field, pathp->node)) { \
a_type *right = rbtn_right_get(a_type, a_field, \ a_type *right = rbtn_right_get(a_type, a_field, \
pathp->node); \ pathp->node); \
a_type *rightleft = rbtn_left_get(a_type, a_field, \ a_type *rightleft = rbtn_left_get(a_type, a_field, \
right); \ right); \
a_type *tnode; \ a_type *tnode; \
if (rbtn_red_get(a_type, a_field, rightleft)) { \ if (rightleft != NULL && rbtn_red_get(a_type, a_field, \
rightleft)) { \
/* In the following diagrams, ||, //, and \\ */\ /* In the following diagrams, ||, //, and \\ */\
/* indicate the path to the removed node. */\ /* indicate the path to the removed node. */\
/* */\ /* */\
@ -705,7 +681,8 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
pathp->node); \ pathp->node); \
a_type *rightleft = rbtn_left_get(a_type, a_field, \ a_type *rightleft = rbtn_left_get(a_type, a_field, \
right); \ right); \
if (rbtn_red_get(a_type, a_field, rightleft)) { \ if (rightleft != NULL && rbtn_red_get(a_type, a_field, \
rightleft)) { \
/* || */\ /* || */\
/* pathp(b) */\ /* pathp(b) */\
/* // \ */\ /* // \ */\
@ -759,7 +736,8 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
left); \ left); \
a_type *leftrightleft = rbtn_left_get(a_type, a_field, \ a_type *leftrightleft = rbtn_left_get(a_type, a_field, \
leftright); \ leftright); \
if (rbtn_red_get(a_type, a_field, leftrightleft)) { \ if (leftrightleft != NULL && rbtn_red_get(a_type, \
a_field, leftrightleft)) { \
/* || */\ /* || */\
/* pathp(b) */\ /* pathp(b) */\
/* / \\ */\ /* / \\ */\
@ -785,7 +763,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
/* (b) */\ /* (b) */\
/* / */\ /* / */\
/* (b) */\ /* (b) */\
assert(leftright != &rbtree->rbt_nil); \ assert(leftright != NULL); \
rbtn_red_set(a_type, a_field, leftright); \ rbtn_red_set(a_type, a_field, leftright); \
rbtn_rotate_right(a_type, a_field, pathp->node, \ rbtn_rotate_right(a_type, a_field, pathp->node, \
tnode); \ tnode); \
@ -808,7 +786,8 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
return; \ return; \
} else if (rbtn_red_get(a_type, a_field, pathp->node)) { \ } else if (rbtn_red_get(a_type, a_field, pathp->node)) { \
a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ a_type *leftleft = rbtn_left_get(a_type, a_field, left);\
if (rbtn_red_get(a_type, a_field, leftleft)) { \ if (leftleft != NULL && rbtn_red_get(a_type, a_field, \
leftleft)) { \
/* || */\ /* || */\
/* pathp(r) */\ /* pathp(r) */\
/* / \\ */\ /* / \\ */\
@ -846,7 +825,8 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
} \ } \
} else { \ } else { \
a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ a_type *leftleft = rbtn_left_get(a_type, a_field, left);\
if (rbtn_red_get(a_type, a_field, leftleft)) { \ if (leftleft != NULL && rbtn_red_get(a_type, a_field, \
leftleft)) { \
/* || */\ /* || */\
/* pathp(b) */\ /* pathp(b) */\
/* / \\ */\ /* / \\ */\
@ -892,13 +872,13 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
a_attr a_type * \ a_attr a_type * \
a_prefix##iter_recurse(a_rbt_type *rbtree, a_type *node, \ a_prefix##iter_recurse(a_rbt_type *rbtree, a_type *node, \
a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \
if (node == &rbtree->rbt_nil) { \ if (node == NULL) { \
return (&rbtree->rbt_nil); \ return (NULL); \
} else { \ } else { \
a_type *ret; \ a_type *ret; \
if ((ret = a_prefix##iter_recurse(rbtree, rbtn_left_get(a_type, \ if ((ret = a_prefix##iter_recurse(rbtree, rbtn_left_get(a_type, \
a_field, node), cb, arg)) != &rbtree->rbt_nil \ a_field, node), cb, arg)) != NULL || (ret = cb(rbtree, node, \
|| (ret = cb(rbtree, node, arg)) != NULL) { \ arg)) != NULL) { \
return (ret); \ return (ret); \
} \ } \
return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \
@ -912,8 +892,8 @@ a_prefix##iter_start(a_rbt_type *rbtree, a_type *start, a_type *node, \
if (cmp < 0) { \ if (cmp < 0) { \
a_type *ret; \ a_type *ret; \
if ((ret = a_prefix##iter_start(rbtree, start, \ if ((ret = a_prefix##iter_start(rbtree, start, \
rbtn_left_get(a_type, a_field, node), cb, arg)) != \ rbtn_left_get(a_type, a_field, node), cb, arg)) != NULL || \
&rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \ (ret = cb(rbtree, node, arg)) != NULL) { \
return (ret); \ return (ret); \
} \ } \
return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \
@ -940,21 +920,18 @@ a_prefix##iter(a_rbt_type *rbtree, a_type *start, a_type *(*cb)( \
} else { \ } else { \
ret = a_prefix##iter_recurse(rbtree, rbtree->rbt_root, cb, arg);\ ret = a_prefix##iter_recurse(rbtree, rbtree->rbt_root, cb, arg);\
} \ } \
if (ret == &rbtree->rbt_nil) { \
ret = NULL; \
} \
return (ret); \ return (ret); \
} \ } \
a_attr a_type * \ a_attr a_type * \
a_prefix##reverse_iter_recurse(a_rbt_type *rbtree, a_type *node, \ a_prefix##reverse_iter_recurse(a_rbt_type *rbtree, a_type *node, \
a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \
if (node == &rbtree->rbt_nil) { \ if (node == NULL) { \
return (&rbtree->rbt_nil); \ return (NULL); \
} else { \ } else { \
a_type *ret; \ a_type *ret; \
if ((ret = a_prefix##reverse_iter_recurse(rbtree, \ if ((ret = a_prefix##reverse_iter_recurse(rbtree, \
rbtn_right_get(a_type, a_field, node), cb, arg)) != \ rbtn_right_get(a_type, a_field, node), cb, arg)) != NULL || \
&rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \ (ret = cb(rbtree, node, arg)) != NULL) { \
return (ret); \ return (ret); \
} \ } \
return (a_prefix##reverse_iter_recurse(rbtree, \ return (a_prefix##reverse_iter_recurse(rbtree, \
@ -969,8 +946,8 @@ a_prefix##reverse_iter_start(a_rbt_type *rbtree, a_type *start, \
if (cmp > 0) { \ if (cmp > 0) { \
a_type *ret; \ a_type *ret; \
if ((ret = a_prefix##reverse_iter_start(rbtree, start, \ if ((ret = a_prefix##reverse_iter_start(rbtree, start, \
rbtn_right_get(a_type, a_field, node), cb, arg)) != \ rbtn_right_get(a_type, a_field, node), cb, arg)) != NULL || \
&rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \ (ret = cb(rbtree, node, arg)) != NULL) { \
return (ret); \ return (ret); \
} \ } \
return (a_prefix##reverse_iter_recurse(rbtree, \ return (a_prefix##reverse_iter_recurse(rbtree, \
@ -998,23 +975,20 @@ a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \
ret = a_prefix##reverse_iter_recurse(rbtree, rbtree->rbt_root, \ ret = a_prefix##reverse_iter_recurse(rbtree, rbtree->rbt_root, \
cb, arg); \ cb, arg); \
} \ } \
if (ret == &rbtree->rbt_nil) { \
ret = NULL; \
} \
return (ret); \ return (ret); \
} \ } \
a_attr void \ a_attr void \
a_prefix##destroy_recurse(a_rbt_type *rbtree, a_type *node, void (*cb)( \ a_prefix##destroy_recurse(a_rbt_type *rbtree, a_type *node, void (*cb)( \
a_type *, void *), void *arg) { \ a_type *, void *), void *arg) { \
if (node == &rbtree->rbt_nil) { \ if (node == NULL) { \
return; \ return; \
} \ } \
a_prefix##destroy_recurse(rbtree, rbtn_left_get(a_type, a_field, \ a_prefix##destroy_recurse(rbtree, rbtn_left_get(a_type, a_field, \
node), cb, arg); \ node), cb, arg); \
rbtn_left_set(a_type, a_field, (node), &rbtree->rbt_nil); \ rbtn_left_set(a_type, a_field, (node), NULL); \
a_prefix##destroy_recurse(rbtree, rbtn_right_get(a_type, a_field, \ a_prefix##destroy_recurse(rbtree, rbtn_right_get(a_type, a_field, \
node), cb, arg); \ node), cb, arg); \
rbtn_right_set(a_type, a_field, (node), &rbtree->rbt_nil); \ rbtn_right_set(a_type, a_field, (node), NULL); \
if (cb) { \ if (cb) { \
cb(node, arg); \ cb(node, arg); \
} \ } \
@ -1023,7 +997,7 @@ a_attr void \
a_prefix##destroy(a_rbt_type *rbtree, void (*cb)(a_type *, void *), \ a_prefix##destroy(a_rbt_type *rbtree, void (*cb)(a_type *, void *), \
void *arg) { \ void *arg) { \
a_prefix##destroy_recurse(rbtree, rbtree->rbt_root, cb, arg); \ a_prefix##destroy_recurse(rbtree, rbtree->rbt_root, cb, arg); \
rbtree->rbt_root = &rbtree->rbt_nil; \ rbtree->rbt_root = NULL; \
} }
#endif /* RB_H_ */ #endif /* RB_H_ */

View File

@ -3,7 +3,7 @@
#define rbtn_black_height(a_type, a_field, a_rbt, r_height) do { \ #define rbtn_black_height(a_type, a_field, a_rbt, r_height) do { \
a_type *rbp_bh_t; \ a_type *rbp_bh_t; \
for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; \ for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; \
rbp_bh_t != &(a_rbt)->rbt_nil; \ rbp_bh_t != NULL; \
rbp_bh_t = rbtn_left_get(a_type, a_field, rbp_bh_t)) { \ rbp_bh_t = rbtn_left_get(a_type, a_field, rbp_bh_t)) { \
if (!rbtn_red_get(a_type, a_field, rbp_bh_t)) { \ if (!rbtn_red_get(a_type, a_field, rbp_bh_t)) { \
(r_height)++; \ (r_height)++; \
@ -68,38 +68,43 @@ TEST_BEGIN(test_rb_empty)
TEST_END TEST_END
static unsigned static unsigned
tree_recurse(node_t *node, unsigned black_height, unsigned black_depth, tree_recurse(node_t *node, unsigned black_height, unsigned black_depth)
node_t *nil)
{ {
unsigned ret = 0; unsigned ret = 0;
node_t *left_node = rbtn_left_get(node_t, link, node); node_t *left_node;
node_t *right_node = rbtn_right_get(node_t, link, node); node_t *right_node;
if (node == NULL)
return (ret);
left_node = rbtn_left_get(node_t, link, node);
right_node = rbtn_right_get(node_t, link, node);
if (!rbtn_red_get(node_t, link, node)) if (!rbtn_red_get(node_t, link, node))
black_depth++; black_depth++;
/* Red nodes must be interleaved with black nodes. */ /* Red nodes must be interleaved with black nodes. */
if (rbtn_red_get(node_t, link, node)) { if (rbtn_red_get(node_t, link, node)) {
assert_false(rbtn_red_get(node_t, link, left_node), if (left_node != NULL)
"Node should be black"); assert_false(rbtn_red_get(node_t, link, left_node),
assert_false(rbtn_red_get(node_t, link, right_node), "Node should be black");
"Node should be black"); if (right_node != NULL)
assert_false(rbtn_red_get(node_t, link, right_node),
"Node should be black");
} }
if (node == nil)
return (ret);
/* Self. */ /* Self. */
assert_u32_eq(node->magic, NODE_MAGIC, "Bad magic"); assert_u32_eq(node->magic, NODE_MAGIC, "Bad magic");
/* Left subtree. */ /* Left subtree. */
if (left_node != nil) if (left_node != NULL)
ret += tree_recurse(left_node, black_height, black_depth, nil); ret += tree_recurse(left_node, black_height, black_depth);
else else
ret += (black_depth != black_height); ret += (black_depth != black_height);
/* Right subtree. */ /* Right subtree. */
if (right_node != nil) if (right_node != NULL)
ret += tree_recurse(right_node, black_height, black_depth, nil); ret += tree_recurse(right_node, black_height, black_depth);
else else
ret += (black_depth != black_height); ret += (black_depth != black_height);
@ -181,8 +186,7 @@ node_remove(tree_t *tree, node_t *node, unsigned nnodes)
node->magic = 0; node->magic = 0;
rbtn_black_height(node_t, link, tree, black_height); rbtn_black_height(node_t, link, tree, black_height);
imbalances = tree_recurse(tree->rbt_root, black_height, 0, imbalances = tree_recurse(tree->rbt_root, black_height, 0);
&(tree->rbt_nil));
assert_u_eq(imbalances, 0, "Tree is unbalanced"); assert_u_eq(imbalances, 0, "Tree is unbalanced");
assert_u_eq(tree_iterate(tree), nnodes-1, assert_u_eq(tree_iterate(tree), nnodes-1,
"Unexpected node iteration count"); "Unexpected node iteration count");
@ -253,7 +257,6 @@ TEST_BEGIN(test_rb_random)
for (j = 1; j <= NNODES; j++) { for (j = 1; j <= NNODES; j++) {
/* Initialize tree and nodes. */ /* Initialize tree and nodes. */
tree_new(&tree); tree_new(&tree);
tree.rbt_nil.magic = 0;
for (k = 0; k < j; k++) { for (k = 0; k < j; k++) {
nodes[k].magic = NODE_MAGIC; nodes[k].magic = NODE_MAGIC;
nodes[k].key = bag[k]; nodes[k].key = bag[k];
@ -266,7 +269,7 @@ TEST_BEGIN(test_rb_random)
rbtn_black_height(node_t, link, &tree, rbtn_black_height(node_t, link, &tree,
black_height); black_height);
imbalances = tree_recurse(tree.rbt_root, imbalances = tree_recurse(tree.rbt_root,
black_height, 0, &(tree.rbt_nil)); black_height, 0);
assert_u_eq(imbalances, 0, assert_u_eq(imbalances, 0,
"Tree is unbalanced"); "Tree is unbalanced");