Skip to content

Commit

Permalink
Eliminate the color field from the RB element struct. Identify the
Browse files Browse the repository at this point in the history
color of a node (or, really, the color of the link from the parent to
the node) by using one of the last two bits of the parent pointer in
that parent node. Adjust rebalancing methods to account for where
colors are stored, and the fact that null children have a color too.

Adjust RB_PARENT and RB_SET_PARENT to account for this change.

Reviewed by:	markj
Tested by:	pho, hselasky
Differential Revision:	https://reviews.freebsd.org/D25418
  • Loading branch information
dougm authored and dougm committed Jun 25, 2020
1 parent 73bd4de commit dac7202
Showing 1 changed file with 151 additions and 102 deletions.
253 changes: 151 additions & 102 deletions sys/sys/tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,38 +307,60 @@ struct name { \
(root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0)

#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}

#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ISRED(elm, field) ((elm) != NULL && RB_COLOR(elm, field) == RB_RED)

/*
* With the expectation that any object of struct type has an
* address that is a multiple of 4, and that therefore the
* 2 least significant bits of a pointer to struct type are
* always zero, this implementation sets those bits to indicate
* that the left or right child of the tree node is "red".
*/
#define RB_UP(elm, field) (elm)->field.rbe_parent
#define RB_BITS(elm, field) *(__uintptr_t *)&RB_UP(elm, field)
#define RB_RED_L (__uintptr_t)1
#define RB_RED_R (__uintptr_t)2
#define RB_RED_MASK (__uintptr_t)3
#define RB_FLIP_LEFT(elm, field) (RB_BITS(elm, field) ^= RB_RED_L)
#define RB_FLIP_RIGHT(elm, field) (RB_BITS(elm, field) ^= RB_RED_R)
#define RB_RED_LEFT(elm, field) ((RB_BITS(elm, field) & RB_RED_L) != 0)
#define RB_RED_RIGHT(elm, field) ((RB_BITS(elm, field) & RB_RED_R) != 0)
#define RB_PARENT(elm, field) ((__typeof(RB_UP(elm, field))) \
(RB_BITS(elm, field) & ~RB_RED_MASK))

/*
* This header may appear in user code where 'bool' is not defined,
* so it defines its own boolean type to avoid breaking that code.
*/
#define RB_BOOL int
#define RB_TRUE 1
#define RB_FALSE 0

#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)

#define RB_SET_PARENT(dst, src, field) do { \
RB_PARENT(dst, field) = src; \
RB_BITS(dst, field) &= RB_RED_MASK; \
RB_BITS(dst, field) |= (__uintptr_t)src; \
} while (/*CONSTCOND*/ 0)

#define RB_SET(elm, parent, field) do { \
RB_SET_PARENT(elm, parent, field); \
RB_UP(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)

#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
#define RB_COLOR(elm, field) (RB_PARENT(elm, field) == NULL ? RB_FALSE : \
RB_LEFT(RB_PARENT(elm, field), field) == elm ? \
RB_RED_LEFT(RB_PARENT(elm, field), field) : \
RB_RED_RIGHT(RB_PARENT(elm, field), field))

/*
* Something to be invoked in a loop at the root of every modified subtree,
Expand Down Expand Up @@ -442,126 +464,145 @@ struct { \
attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while (RB_ISRED((parent = RB_PARENT(elm, field)), field)) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (RB_ISRED(tmp, field)) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
struct type *gparent, *parent; \
while ((parent = RB_PARENT(elm, field)) != NULL) { \
if (RB_LEFT(parent, field) == elm) \
RB_FLIP_LEFT(parent, field); \
else \
RB_FLIP_RIGHT(parent, field); \
if ((gparent = RB_PARENT(parent, field)) == NULL) \
break; \
if (RB_RED_LEFT(gparent, field) && \
RB_RED_RIGHT(gparent, field)) { \
RB_FLIP_LEFT(gparent, field); \
RB_FLIP_RIGHT(gparent, field); \
elm = gparent; \
continue; \
} \
if (RB_RED_LEFT(gparent, field) && \
parent == RB_LEFT(gparent, field)) { \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = parent; \
RB_ROTATE_LEFT(head, parent, elm, field);\
RB_FLIP_RIGHT(parent, field); \
RB_FLIP_LEFT(elm, field); \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (RB_ISRED(tmp, field)) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
RB_ROTATE_RIGHT(head, gparent, parent, field); \
RB_FLIP_LEFT(gparent, field); \
RB_FLIP_RIGHT(parent, field); \
} else if (RB_RED_RIGHT(gparent, field) && \
parent == RB_RIGHT(gparent, field)) { \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = parent; \
RB_ROTATE_RIGHT(head, parent, elm, field);\
RB_FLIP_LEFT(parent, field); \
RB_FLIP_RIGHT(elm, field); \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
RB_ROTATE_LEFT(head, gparent, parent, field); \
RB_FLIP_RIGHT(gparent, field); \
RB_FLIP_LEFT(parent, field); \
} \
break; \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
}

#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \
attr void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent) \
name##_RB_REMOVE_COLOR(struct name *head, struct type *par) \
{ \
struct type *elm, *tmp; \
elm = NULL; \
struct type *gpr, *sib, *nec; \
RB_BOOL left_elm, left_par, red_gpr; \
left_par = (RB_LEFT(par, field) == NULL); \
do { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
left_elm = left_par; \
if (left_elm ? \
!RB_RED_RIGHT(par, field) : \
!RB_RED_LEFT(par, field)) { \
gpr = RB_PARENT(par, field); \
left_par = gpr != NULL && \
RB_LEFT(gpr, field) == par; \
red_gpr = gpr == NULL ? \
RB_TRUE: RB_COLOR(par, field); \
} \
if (left_elm) { \
if (RB_RED_RIGHT(par, field)) { \
red_gpr = RB_TRUE; \
RB_ROTATE_LEFT(head, par, gpr, field); \
RB_FLIP_RIGHT(par, field); \
RB_FLIP_LEFT(gpr, field); \
} \
if (RB_ISRED(RB_RIGHT(tmp, field), field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
else if (RB_ISRED(RB_LEFT(tmp, field), field)) { \
struct type *oleft; \
RB_ROTATE_RIGHT(head, tmp, oleft, field); \
RB_COLOR(oleft, field) = RB_BLACK; \
tmp = oleft; \
sib = RB_RIGHT(par, field); \
if (RB_RED_RIGHT(sib, field)) { \
if (RB_RED_LEFT(sib, field)) { \
RB_FLIP_LEFT(sib, field); \
RB_FLIP_RIGHT(par, field); \
} \
RB_FLIP_RIGHT(sib, field); \
} else if (RB_RED_LEFT(sib, field)) { \
RB_ROTATE_RIGHT(head, sib, nec, field); \
RB_FLIP_LEFT(sib, field); \
sib = nec; \
} else { \
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
RB_FLIP_RIGHT(par, field); \
par = gpr; \
continue; \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
RB_COLOR(parent, field) = RB_BLACK; \
RB_ROTATE_LEFT(head, parent, tmp, field); \
elm = RB_ROOT(head); \
break; \
RB_ROTATE_LEFT(head, par, sib, field); \
return; \
} else { \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
if (RB_RED_LEFT(par, field)) { \
red_gpr = RB_TRUE; \
RB_ROTATE_RIGHT(head, par, gpr, field); \
RB_FLIP_LEFT(par, field); \
RB_FLIP_RIGHT(gpr, field); \
} \
if (RB_ISRED(RB_LEFT(tmp, field), field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
else if (RB_ISRED(RB_RIGHT(tmp, field), field)) { \
struct type *oright; \
RB_ROTATE_LEFT(head, tmp, oright, field); \
RB_COLOR(oright, field) = RB_BLACK; \
tmp = oright; \
} else if (!RB_ISRED(RB_LEFT(tmp, field), field)) { \
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
sib = RB_LEFT(par, field); \
if (RB_RED_LEFT(sib, field)) { \
if (RB_RED_RIGHT(sib, field)) { \
RB_FLIP_RIGHT(sib, field); \
RB_FLIP_LEFT(par, field); \
} \
RB_FLIP_LEFT(sib, field); \
} else if (RB_RED_RIGHT(sib, field)) { \
RB_ROTATE_LEFT(head, sib, nec, field); \
RB_FLIP_RIGHT(sib, field); \
sib = nec; \
} else { \
RB_FLIP_LEFT(par, field); \
par = gpr; \
continue; \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
RB_COLOR(parent, field) = RB_BLACK; \
RB_ROTATE_RIGHT(head, parent, tmp, field); \
elm = RB_ROOT(head); \
break; \
RB_ROTATE_RIGHT(head, par, sib, field); \
return; \
} \
} while (!RB_ISRED(elm, field) && parent != NULL); \
RB_COLOR(elm, field) = RB_BLACK; \
} while (!red_gpr); \
if (gpr == NULL); \
else if (left_par) \
RB_FLIP_LEFT(gpr, field); \
else \
RB_FLIP_RIGHT(gpr, field); \
}

#define RB_GENERATE_REMOVE(name, type, field, attr) \
attr struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *old, *parent, *right; \
int color; \
RB_BOOL red; \
\
old = elm; \
parent = RB_PARENT(elm, field); \
right = RB_RIGHT(elm, field); \
color = RB_COLOR(elm, field); \
if (RB_LEFT(elm, field) == NULL) \
elm = child = right; \
else if (right == NULL) \
elm = child = RB_LEFT(elm, field); \
else { \
if ((child = RB_LEFT(right, field)) == NULL) { \
child = RB_RIGHT(right, field); \
red = RB_RED_RIGHT(old, field); \
if (red) \
RB_FLIP_RIGHT(old, field); \
RB_RIGHT(old, field) = child; \
parent = elm = right; \
} else { \
Expand All @@ -570,18 +611,27 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \
while ((child = RB_LEFT(elm, field)) != NULL); \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
red = RB_RED_LEFT(parent, field); \
if (red) \
RB_FLIP_LEFT(parent, field); \
RB_LEFT(parent, field) = child; \
RB_SET_PARENT(RB_RIGHT(old, field), elm, field); \
} \
RB_SET_PARENT(RB_LEFT(old, field), elm, field); \
color = RB_COLOR(elm, field); \
elm->field = old->field; \
} \
if (elm == child) { \
red = RB_COLOR(old, field); \
if (!red); \
else if (RB_LEFT(parent, field) == old) \
RB_FLIP_LEFT(parent, field); \
else \
RB_FLIP_RIGHT(parent, field); \
} \
RB_SWAP_CHILD(head, old, elm, field); \
if (child != NULL) { \
if (child != NULL) \
RB_SET_PARENT(child, parent, field); \
RB_COLOR(child, field) = RB_BLACK; \
} else if (color != RB_RED && parent != NULL) \
else if (!red && parent != NULL) \
name##_RB_REMOVE_COLOR(head, parent); \
while (parent != NULL) { \
RB_AUGMENT(parent); \
Expand Down Expand Up @@ -610,13 +660,12 @@ name##_RB_INSERT(struct name *head, struct type *elm) \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
} else \
if (parent == NULL) \
RB_ROOT(head) = elm; \
else if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
while (elm != NULL) { \
RB_AUGMENT(elm); \
Expand Down

0 comments on commit dac7202

Please sign in to comment.