|
|
|
|
|
|
|
#ifndef RBTREE_H |
#define RBTREE_H |
|
#include "array.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct rb_node_hdr { |
struct rb_node_hdr *prev, *next; |
unsigned INT16 flags; |
|
}; |
|
|
|
|
|
struct rb_node_ind { |
struct rb_node_ind *prev, *next; |
struct svalue ind; |
}; |
|
struct rb_node_indval { |
struct rb_node_indval *prev, *next; |
struct svalue ind, val; |
}; |
|
union rb_node { |
struct rb_node_hdr h; |
struct rb_node_ind i; |
struct rb_node_indval iv; |
}; |
|
#define RB_RED 0x2000 |
#define RB_THREAD_PREV 0x4000 |
#define RB_THREAD_NEXT 0x8000 |
#define RB_FLAG_MASK 0xe000 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define RB_FLAG_MARKER 0x1000 |
#define RB_IND_FLAG_MASK 0xf000 |
|
|
PMOD_EXPORT int rb_ind_default_cmp (struct svalue *key, union rb_node *node); |
typedef int low_rb_cmp_fn (void *key, struct rb_node_hdr *node); |
|
PMOD_EXPORT union rb_node *rb_find_eq_extcmp (union rb_node *tree, struct svalue *key, |
struct svalue *cmp_less); |
PMOD_EXPORT union rb_node *rb_find_lt_extcmp (union rb_node *tree, struct svalue *key, |
struct svalue *cmp_less); |
PMOD_EXPORT union rb_node *rb_find_gt_extcmp (union rb_node *tree, struct svalue *key, |
struct svalue *cmp_less); |
PMOD_EXPORT union rb_node *rb_find_le_extcmp (union rb_node *tree, struct svalue *key, |
struct svalue *cmp_less); |
PMOD_EXPORT union rb_node *rb_find_ge_extcmp (union rb_node *tree, struct svalue *key, |
struct svalue *cmp_less); |
PMOD_EXPORT struct rb_node_hdr *rb_first (struct rb_node_hdr *tree); |
PMOD_EXPORT struct rb_node_hdr *rb_last (struct rb_node_hdr *tree); |
PMOD_EXPORT struct rb_node_hdr *rb_prev (struct rb_node_hdr *node); |
PMOD_EXPORT struct rb_node_hdr *rb_next (struct rb_node_hdr *node); |
|
#ifdef PIKE_DEBUG |
|
static inline struct rb_node_hdr *rb_node_ind_check (struct rb_node_ind *node) |
{return (struct rb_node_hdr *) node;} |
static inline struct rb_node_hdr *rb_node_indval_check (struct rb_node_indval *node) |
{return (struct rb_node_hdr *) node;} |
#else |
#define rb_node_ind_check(node) ((struct rb_node_hdr *) (node)) |
#define rb_node_indval_check(node) ((struct rb_node_hdr *) (node)) |
#endif |
|
#define RB_DECL_FIND_FUNC(type, func, tree, key, cmp_less) \ |
((struct type *) debug_malloc_pass ( \ |
(cmp_less) ? (struct rb_node_hdr *) PIKE_CONCAT (func, _extcmp) ( \ |
(union rb_node *) debug_malloc_pass (PIKE_CONCAT (type, _check) (tree)), \ |
dmalloc_touch (struct svalue *, key), \ |
(cmp_less)) \ |
: PIKE_CONCAT (low_, func) ( \ |
(struct rb_node_hdr *) debug_malloc_pass (PIKE_CONCAT (type, _check) (tree)), \ |
(low_rb_cmp_fn *) rb_ind_default_cmp, \ |
dmalloc_touch (struct svalue *, key)))) |
#define RB_DECL_STEP_FUNC(type, func, node) \ |
((struct type *) debug_malloc_pass ( \ |
func ((struct rb_node_hdr *) debug_malloc_pass (PIKE_CONCAT (type, _check) (node))))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT struct rb_node_ind *rb_ind_insert (struct rb_node_ind **tree, |
struct svalue *ind, |
struct svalue *cmp_less); |
PMOD_EXPORT struct rb_node_ind *rb_ind_add (struct rb_node_ind **tree, |
struct svalue *ind, |
struct svalue *cmp_less); |
PMOD_EXPORT int rb_ind_delete (struct rb_node_ind **tree, |
struct svalue *ind, |
struct svalue *cmp_less); |
PMOD_EXPORT struct rb_node_ind *rb_ind_copy (struct rb_node_ind *tree); |
PMOD_EXPORT void rb_ind_free (struct rb_node_ind *tree); |
#define rb_ind_find_eq(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_ind, rb_find_eq, tree, key, cmp_less) |
#define rb_ind_find_lt(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_ind, rb_find_lt, tree, key, cmp_less) |
#define rb_ind_find_gt(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_ind, rb_find_gt, tree, key, cmp_less) |
#define rb_ind_find_le(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_ind, rb_find_le, tree, key, cmp_less) |
#define rb_ind_find_ge(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_ind, rb_find_ge, tree, key, cmp_less) |
#define rb_ind_first(tree) RB_DECL_STEP_FUNC (rb_node_ind, rb_first, tree) |
#define rb_ind_last(tree) RB_DECL_STEP_FUNC (rb_node_ind, rb_last, tree) |
#define rb_ind_prev(tree) RB_DECL_STEP_FUNC (rb_node_ind, rb_prev, tree) |
#define rb_ind_next(tree) RB_DECL_STEP_FUNC (rb_node_ind, rb_next, tree) |
|
|
PMOD_EXPORT struct rb_node_indval *rb_indval_insert (struct rb_node_indval **tree, |
struct svalue *ind, |
struct svalue *val, |
struct svalue *cmp_less); |
PMOD_EXPORT struct rb_node_indval *rb_indval_add (struct rb_node_indval **tree, |
struct svalue *ind, |
struct svalue *val, |
struct svalue *cmp_less); |
PMOD_EXPORT struct rb_node_indval *rb_indval_add_after (struct rb_node_indval **tree, |
struct rb_node_indval *node, |
struct svalue *ind, |
struct svalue *val, |
struct svalue *cmp_less); |
PMOD_EXPORT int rb_indval_delete (struct rb_node_indval **tree, |
struct svalue *ind, |
struct svalue *cmp_less); |
PMOD_EXPORT struct rb_node_indval *rb_indval_delete_node (struct rb_node_indval **tree, |
struct rb_node_indval *node, |
struct svalue *cmp_less); |
PMOD_EXPORT struct rb_node_indval *rb_indval_copy (struct rb_node_indval *tree); |
PMOD_EXPORT void rb_indval_free (struct rb_node_indval *tree); |
#define rb_indval_find_eq(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_indval, rb_find_eq, tree, key, cmp_less) |
#define rb_indval_find_lt(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_indval, rb_find_lt, tree, key, cmp_less) |
#define rb_indval_find_gt(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_indval, rb_find_gt, tree, key, cmp_less) |
#define rb_indval_find_le(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_indval, rb_find_le, tree, key, cmp_less) |
#define rb_indval_find_ge(tree, key, cmp_less) RB_DECL_FIND_FUNC (rb_node_indval, rb_find_ge, tree, key, cmp_less) |
#define rb_indval_first(tree) RB_DECL_STEP_FUNC (rb_node_indval, rb_first, tree) |
#define rb_indval_last(tree) RB_DECL_STEP_FUNC (rb_node_indval, rb_last, tree) |
#define rb_indval_prev(tree) RB_DECL_STEP_FUNC (rb_node_indval, rb_prev, tree) |
#define rb_indval_next(tree) RB_DECL_STEP_FUNC (rb_node_indval, rb_next, tree) |
|
|
#define assign_rb_node_ind_no_free(to, node) do { \ |
struct svalue *_rb_node_to = (to); \ |
*_rb_node_to = (node)->ind; \ |
_rb_node_to->type &= ~RB_IND_FLAG_MASK; \ |
add_ref_svalue (_rb_node_to); \ |
} while (0) |
|
#define assign_rb_node_ind(to, node) do { \ |
struct svalue *_rb_node_to2 = (to); \ |
free_svalue (_rb_node_to2); \ |
assign_rb_node_ind_no_free (_rb_node_to2, (node)); \ |
} while (0) |
|
#define push_rb_node_ind(node) do { \ |
assign_rb_node_ind_no_free (Pike_sp, (node)); \ |
Pike_sp++; \ |
} while (0) |
|
#define use_rb_node_ind(node, var) \ |
(var = (node)->ind, var.type &= ~RB_IND_FLAG_MASK, var) |
|
|
|
|
|
|
|
|
#define STACK_SLICE_SIZE 20 |
|
* 2^(20/2) = 1024 before allocating another slice, but in the typical |
* case it's enough for trees with up to about 2^(20-1) = 524288 |
* elements. */ |
|
struct rb_stack_slice |
{ |
struct rb_stack_slice *up; |
struct rb_node_hdr *stack[STACK_SLICE_SIZE]; |
}; |
|
#define RBSTACK_INIT(slice, ssp) \ |
struct rb_stack_slice PIKE_CONCAT3 (_top_, slice, _); \ |
struct rb_stack_slice *slice = \ |
(PIKE_CONCAT3 (_top_, slice, _).up = 0, \ |
&PIKE_CONCAT3 (_top_, slice, _)); \ |
size_t ssp = 0 /* Only zero when the stack is empty. */ |
|
#define RBSTACK_PUSH(slice, ssp, node) do { \ |
if (ssp < STACK_SLICE_SIZE) \ |
slice->stack[ssp++] = (node); \ |
else { \ |
struct rb_stack_slice *_new_ = ALLOC_STRUCT (rb_stack_slice); \ |
_new_->up = slice; \ |
slice = _new_; \ |
slice->stack[0] = (node); \ |
ssp = 1; \ |
} \ |
} while (0) |
|
#define RBSTACK_POP(slice, ssp, node) do { \ |
if (ssp) { \ |
(node) = slice->stack[--ssp]; \ |
if (!ssp && slice->up) { \ |
struct rb_stack_slice *_old_ = slice; \ |
slice = slice->up; \ |
ssp = STACK_SLICE_SIZE; \ |
xfree (_old_); \ |
} \ |
} \ |
else (node) = 0; \ |
} while (0) |
|
#define RBSTACK_POP_IGNORE(slice, ssp) do { \ |
if (ssp && !--ssp && slice->up) { \ |
struct rb_stack_slice *_old_ = slice; \ |
slice = slice->up; \ |
ssp = STACK_SLICE_SIZE; \ |
xfree (_old_); \ |
} \ |
} while (0) |
|
#define RBSTACK_UP(slice, ssp, node) do { \ |
if (ssp) { \ |
(node) = slice->stack[--ssp]; \ |
if (!ssp && slice->up) { \ |
slice = slice->up; \ |
ssp = STACK_SLICE_SIZE; \ |
} \ |
} \ |
else (node) = 0; \ |
} while (0) |
|
#define RBSTACK_PEEK(slice, ssp, node) do { \ |
if (ssp) (node) = slice->stack[ssp - 1]; \ |
else (node) = 0; \ |
} while (0) |
|
#define RBSTACK_FREE(slice) do { \ |
while (slice->up) { \ |
struct rb_stack_slice *_old_ = slice; \ |
slice = slice->up; \ |
xfree (_old_); \ |
} \ |
} while (0) |
|
#define RBSTACK_FREE_SET_ROOT(slice, ssp, node) do { \ |
if (ssp) { \ |
while (slice->up) { \ |
struct rb_stack_slice *_old_ = slice; \ |
slice = slice->up; \ |
xfree (_old_); \ |
} \ |
(node) = slice->stack[0]; \ |
} \ |
} while (0) |
|
|
|
|
|
|
|
|
|
|
|
#define LOW_RB_TRAVERSE(label, slice, ssp, node, push, p_leaf, p_sub, between, n_leaf, n_sub, pop) \ |
do { \ |
struct rb_node_hdr *low_rb_last_; \ |
if (node) { \ |
PIKE_CONCAT (enter_, label): \ |
{push;} \ |
if ((node)->flags & RB_THREAD_PREV) \ |
{p_leaf;} \ |
else { \ |
{p_sub;} \ |
RBSTACK_PUSH (slice, ssp, node); \ |
(node) = (node)->prev; \ |
goto PIKE_CONCAT (enter_, label); \ |
} \ |
PIKE_CONCAT (between_, label): \ |
{between;} \ |
if ((node)->flags & RB_THREAD_NEXT) \ |
{n_leaf;} \ |
else { \ |
{n_sub;} \ |
RBSTACK_PUSH (slice, ssp, node); \ |
(node) = (node)->next; \ |
goto PIKE_CONCAT (enter_, label); \ |
} \ |
PIKE_CONCAT (leave_, label): \ |
while (1) { \ |
{pop;} \ |
low_rb_last_ = (node); \ |
RBSTACK_POP (slice, ssp, node); \ |
if (!(node)) break; \ |
if (low_rb_last_ == (node)->prev) \ |
goto PIKE_CONCAT (between_, label); \ |
} \ |
} \ |
} while (0) |
|
#define LOW_RB_DEBUG_TRAVERSE(label, slice, ssp, node, push, p_leaf, p_sub, between, n_leaf, n_sub, pop) \ |
do { \ |
size_t PIKE_CONCAT (depth_, label) = 0; \ |
LOW_RB_TRAVERSE( \ |
label, slice, ssp, node, \ |
fprintf (stderr, "%*s%p enter\n", \ |
PIKE_CONCAT (depth_, label)++, "", node); {push;}, \ |
fprintf (stderr, "%*s%p prev leaf\n", \ |
PIKE_CONCAT (depth_, label), "", node); {p_leaf;}, \ |
fprintf (stderr, "%*s%p prev subtree\n", \ |
PIKE_CONCAT (depth_, label), "", node); {p_sub;}, \ |
fprintf (stderr, "%*s%p between\n", \ |
PIKE_CONCAT (depth_, label) - 1, "", node); {between;}, \ |
fprintf (stderr, "%*s%p next leaf\n", \ |
PIKE_CONCAT (depth_, label), "", node); {n_leaf;}, \ |
fprintf (stderr, "%*s%p next subtree\n", \ |
PIKE_CONCAT (depth_, label), "", node); {n_sub;}, \ |
fprintf (stderr, "%*s%p leave\n", \ |
--PIKE_CONCAT (depth_, label), "", node); {pop;}); \ |
} while (0) |
|
|
|
#define LOW_RB_FIND(node, cmp, got_lt, got_eq, got_gt) \ |
do { \ |
int cmp_res; \ |
while (1) { \ |
DO_IF_DEBUG (if (!node) fatal ("Recursing into null node.\n")); \ |
{cmp;} \ |
if (cmp_res > 0) { \ |
if ((node)->flags & RB_THREAD_NEXT) { \ |
{got_lt;} \ |
break; \ |
} \ |
(node) = (node)->next; \ |
} \ |
else if (cmp_res < 0) { \ |
if ((node)->flags & RB_THREAD_PREV) { \ |
{got_gt;} \ |
break; \ |
} \ |
(node) = (node)->prev; \ |
} \ |
else { \ |
{got_eq;} \ |
break; \ |
} \ |
} \ |
} while (0) |
|
|
|
#define LOW_RB_TRACK(slice, ssp, node, cmp, got_lt, got_eq, got_gt) \ |
LOW_RB_FIND (node, { \ |
RBSTACK_PUSH (slice, ssp, node); \ |
{cmp;} \ |
}, got_lt, got_eq, got_gt) |
|
|
#define LOW_RB_TRACK_NEXT(slice, ssp, node) \ |
do { \ |
DO_IF_DEBUG ({ \ |
struct rb_node_hdr *low_rb_stack_top_; \ |
RBSTACK_PEEK (slice, ssp, low_rb_stack_top_); \ |
if (node != low_rb_stack_top_) \ |
fatal ("Given node is not on top of stack.\n"); \ |
}); \ |
if (node->flags & RB_THREAD_NEXT) { \ |
struct rb_node_hdr *low_rb_next_ = node->next; \ |
while (1) { \ |
RBSTACK_PEEK (slice, ssp, node); \ |
if (node == low_rb_next_) break; \ |
RBSTACK_POP_IGNORE (slice, ssp); \ |
} \ |
} \ |
else { \ |
node = node->next; \ |
RBSTACK_PUSH (slice, ssp, node); \ |
while (!(node->flags & RB_THREAD_PREV)) { \ |
node = node->prev; \ |
RBSTACK_PUSH (slice, ssp, node); \ |
} \ |
} \ |
} while (0) |
|
|
|
|
|
|
#define LOW_RB_INSERT(tree, node, cmp, insert, replace) \ |
do { \ |
if (((node) = *(tree))) { \ |
RBSTACK_INIT (slice, ssp); \ |
LOW_RB_TRACK (slice, ssp, node, cmp, { \ |
DO_IF_DEBUG ((node) = 0); \ |
{insert;} \ |
low_rb_link_at_next ((tree), slice, ssp, (node)); \ |
}, { \ |
{replace;} \ |
RBSTACK_FREE (slice); \ |
}, { \ |
DO_IF_DEBUG ((node) = 0); \ |
{insert;} \ |
low_rb_link_at_prev ((tree), slice, ssp, (node)); \ |
}); \ |
} \ |
else { \ |
{insert;} \ |
low_rb_init_root (*(tree) = (node)); \ |
} \ |
} while (0) |
|
|
|
|
typedef void low_rb_move_data_fn (struct rb_node_hdr *to, |
struct rb_node_hdr *from); |
|
typedef struct rb_node_hdr *low_rb_alloc_copy_fn (struct rb_node_hdr *node); |
|
void low_rb_init_root (struct rb_node_hdr *new_root); |
void low_rb_link_at_prev (struct rb_node_hdr **tree, |
struct rb_stack_slice *slice, size_t ssp, |
struct rb_node_hdr *new); |
void low_rb_link_at_next (struct rb_node_hdr **tree, |
struct rb_stack_slice *slice, size_t ssp, |
struct rb_node_hdr *new); |
struct rb_node_hdr *low_rb_unlink (struct rb_node_hdr **tree, |
struct rb_stack_slice *slice, size_t ssp, |
low_rb_move_data_fn *move_data); |
|
struct rb_node_hdr *low_rb_insert (struct rb_node_hdr **tree, |
low_rb_cmp_fn *cmpfun, void *key, |
struct rb_node_hdr *new); |
void low_rb_add (struct rb_node_hdr **tree, |
low_rb_cmp_fn *cmpfun, void *key, |
struct rb_node_hdr *new); |
void low_rb_add_after (struct rb_node_hdr **tree, |
low_rb_cmp_fn *cmpfun, void *key, |
struct rb_node_hdr *new, |
struct rb_node_hdr *existing); |
struct rb_node_hdr *low_rb_delete (struct rb_node_hdr **tree, |
low_rb_cmp_fn *cmpfun, void *key, |
low_rb_move_data_fn *move_data); |
struct rb_node_hdr *low_rb_delete_node (struct rb_node_hdr **tree, |
low_rb_cmp_fn *cmpfun, void *key, |
low_rb_move_data_fn *move_data, |
struct rb_node_hdr *node); |
struct rb_node_hdr *low_rb_copy (struct rb_node_hdr *tree, |
low_rb_alloc_copy_fn *alloc_copy); |
|
struct rb_node_hdr *low_rb_find_eq (struct rb_node_hdr *tree, |
low_rb_cmp_fn *cmpfun, void *key); |
struct rb_node_hdr *low_rb_find_lt (struct rb_node_hdr *tree, |
low_rb_cmp_fn *cmpfun, void *key); |
struct rb_node_hdr *low_rb_find_gt (struct rb_node_hdr *tree, |
low_rb_cmp_fn *cmpfun, void *key); |
struct rb_node_hdr *low_rb_find_le (struct rb_node_hdr *tree, |
low_rb_cmp_fn *cmpfun, void *key); |
struct rb_node_hdr *low_rb_find_ge (struct rb_node_hdr *tree, |
low_rb_cmp_fn *cmpfun, void *key); |
|
#ifdef PIKE_DEBUG |
void debug_check_rb_tree (struct rb_node_hdr *tree); |
#endif |
|
void init_rbtree (void); |
void exit_rbtree (void); |
|
#endif /* RBTREE_H */ |
|
|