|
|
|
@ -32,46 +32,31 @@
|
|
|
|
|
should be okay for most variations. 4 is isomorphic to left-leaning red-black
|
|
|
|
|
tree, <Sedgewick, 2008, LLRB>. The above illustration is 5.
|
|
|
|
|
|
|
|
|
|
@param[TREE_EXPECT_TRAIT]
|
|
|
|
|
Do not un-define certain variables for subsequent inclusion in a parameterized
|
|
|
|
|
trait.
|
|
|
|
|
|
|
|
|
|
@param[TREE_DEFAULT_NAME, TREE_DEFAULT]
|
|
|
|
|
@param[TREE_DEFAULT]
|
|
|
|
|
Default trait; a name that satisfies `C` naming conventions when mangled and a
|
|
|
|
|
<typedef:<PB>value> used in <fn:<B>tree<D>get>. There can be multiple
|
|
|
|
|
defaults, but only one can omit `TREE_DEFAULT_NAME`.
|
|
|
|
|
<typedef:<PB>value> used in <fn:<B>tree<D>get>.
|
|
|
|
|
|
|
|
|
|
@param[TREE_TO_STRING]
|
|
|
|
|
To string trait `<STR>` contained in <src/to_string.h>. Require
|
|
|
|
|
`<name>[<trait>]to_string` be declared as <typedef:<PSTR>to_string_fn>.
|
|
|
|
|
|
|
|
|
|
@param[TREE_TO_STRING_NAME, TREE_TO_STRING]
|
|
|
|
|
To string trait contained in <src/to_string.h>; an optional unique `<SZ>`
|
|
|
|
|
that satisfies `C` naming conventions when mangled and function implementing
|
|
|
|
|
<typedef:<PSTR>to_string_fn>.
|
|
|
|
|
@param[TREE_EXPECT_TRAIT, TREE_TRAIT]
|
|
|
|
|
Named traits are obtained by including `tree.h` multiple times with
|
|
|
|
|
`TREE_EXPECT_TRAIT` and then subsequently including the name in `TREE_TRAIT`.
|
|
|
|
|
|
|
|
|
|
@fixme merge, difference
|
|
|
|
|
|
|
|
|
|
@std C89 */
|
|
|
|
|
|
|
|
|
|
#if !defined(TREE_NAME)
|
|
|
|
|
#error Name TREE_NAME undefined.
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(TREE_DEFAULT_NAME) || defined(TREE_DEFAULT)
|
|
|
|
|
#define TREE_DEFAULT_TRAIT 1
|
|
|
|
|
#else
|
|
|
|
|
#define TREE_DEFAULT_TRAIT 0
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(TREE_TO_STRING_NAME) || defined(TREE_TO_STRING)
|
|
|
|
|
#define TREE_TO_STRING_TRAIT 1
|
|
|
|
|
#else
|
|
|
|
|
#define TREE_TO_STRING_TRAIT 0
|
|
|
|
|
#error Name undefined.
|
|
|
|
|
#endif
|
|
|
|
|
#define TREE_TRAITS TREE_DEFAULT_TRAIT + TREE_TO_STRING_TRAIT
|
|
|
|
|
#if TREE_TRAITS > 1
|
|
|
|
|
#error Only one trait per include is allowed; use TREE_EXPECT_TRAIT.
|
|
|
|
|
#if defined(TREE_TRAIT) ^ defined(BOX_TYPE)
|
|
|
|
|
#error TREE_TRAIT name must come after TREE_EXPECT_TRAIT.
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(TREE_DEFAULT_NAME) && !defined(TREE_DEFAULT)
|
|
|
|
|
#error TREE_DEFAULT_NAME requires TREE_DEFAULT.
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(TREE_TO_STRING_NAME) && !defined(TREE_TO_STRING)
|
|
|
|
|
#error TREE_TO_STRING_NAME requires TREE_TO_STRING.
|
|
|
|
|
#if defined(TREE_TEST) && (!defined(TREE_TRAIT) && !defined(TREE_TO_STRING) \
|
|
|
|
|
|| defined(TREE_TRAIT) && !defined(TREE_HAS_TO_STRING))
|
|
|
|
|
#error Test requires to string.
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef TREE_H /* <!-- idempotent */
|
|
|
|
@ -117,8 +102,7 @@ struct tree_node_count { size_t branches, leaves; };
|
|
|
|
|
#endif /* idempotent --> */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if TREE_TRAITS == 0 /* <!-- base code */
|
|
|
|
|
|
|
|
|
|
#ifndef TREE_TRAIT /* <!-- base code */
|
|
|
|
|
|
|
|
|
|
#ifndef TREE_ORDER
|
|
|
|
|
#define TREE_ORDER 65 /* Maximum branching factor. This sets the granularity. */
|
|
|
|
@ -143,10 +127,9 @@ typedef const TREE_VALUE PB_(value_c);
|
|
|
|
|
|
|
|
|
|
/** Returns a positive result if `a` is out-of-order with respect to `b`,
|
|
|
|
|
inducing a strict weak order. This is compatible, but less strict then the
|
|
|
|
|
comparators from `bsearch` and `qsort`; it only needs to divide entries
|
|
|
|
|
into two instead of three categories. */
|
|
|
|
|
comparators from `bsearch` and `qsort`; it only needs to divide entries into
|
|
|
|
|
two instead of three categories. */
|
|
|
|
|
typedef int (*PB_(compare_fn))(PB_(key_c) a, PB_(key_c) b);
|
|
|
|
|
|
|
|
|
|
#ifndef TREE_COMPARE /* <!-- !cmp */
|
|
|
|
|
/** The default `TREE_COMPARE` on `a` and `b` is integer comparison that
|
|
|
|
|
results in ascending order, `a > b`. @implements <typedef:<PB>compare_fn> */
|
|
|
|
@ -154,7 +137,6 @@ static int PB_(default_compare)(PB_(key_c) a, PB_(key_c) b)
|
|
|
|
|
{ return a > b; }
|
|
|
|
|
#define TREE_COMPARE &PB_(default_compare)
|
|
|
|
|
#endif /* !cmp --> */
|
|
|
|
|
|
|
|
|
|
/* Check that `TREE_COMPARE` is a function implementing
|
|
|
|
|
<typedef:<PB>compare_fn>, if defined. */
|
|
|
|
|
static const PB_(compare_fn) PB_(compare) = (TREE_COMPARE);
|
|
|
|
@ -198,7 +180,6 @@ static const struct PB_(branch) *PB_(as_branch_c)(const struct PB_(node) *
|
|
|
|
|
/* Address of a specific key by node. There is a need for node plus index
|
|
|
|
|
without height, but we'll just let height be unused. */
|
|
|
|
|
struct PB_(ref) { struct PB_(node) *node; unsigned height, idx; };
|
|
|
|
|
struct PB_(ref_c) { const struct PB_(node) *node; unsigned height, idx; };
|
|
|
|
|
/* Node plus height is a sub-tree. A <tag:<B>tree> is a sub-tree of the tree. */
|
|
|
|
|
struct PB_(tree) { struct PB_(node) *node; unsigned height; };
|
|
|
|
|
/** To initialize it to an idle state, see <fn:<B>tree>, `{0}` (`C99`), or
|
|
|
|
@ -214,26 +195,15 @@ struct B_(tree) { struct PB_(tree) root; };
|
|
|
|
|
pointer-to-<typedef:<PB>value>. The reason these are pointers is because it
|
|
|
|
|
is not contiguous in memory. */
|
|
|
|
|
struct B_(tree_entry) { PB_(key) *key; PB_(value) *value; };
|
|
|
|
|
/* FIXME: are you sure that this doesn't allow you to movify keys? we do not
|
|
|
|
|
want modification of keys (right?? otoh, it is the *placement* not the actual
|
|
|
|
|
value that is fixed.) */
|
|
|
|
|
struct B_(tree_entry_c) { PB_(key_c) *key; const PB_(value) *value; };
|
|
|
|
|
/** On `TREE_VALUE`, otherwise it's just an alias for
|
|
|
|
|
pointer-to-<typedef:<PB>key>. */
|
|
|
|
|
typedef struct B_(tree_entry) PB_(entry);
|
|
|
|
|
typedef struct B_(tree_entry_c) PB_(entry_c);
|
|
|
|
|
static PB_(entry) PB_(null_entry)(void)
|
|
|
|
|
{ const PB_(entry) e = { 0, 0 }; return e; }
|
|
|
|
|
static PB_(entry_c) PB_(null_entry_c)(void)
|
|
|
|
|
{ const PB_(entry_c) e = { 0, 0 }; return e; }
|
|
|
|
|
/** Constructs entry from `node` and `i`. */
|
|
|
|
|
static PB_(entry) PB_(cons_entry)(struct PB_(node) *const node,
|
|
|
|
|
const unsigned i) { PB_(entry) e;
|
|
|
|
|
e.key = node->key + i, e.value = node->value + i; return e; }
|
|
|
|
|
/** Constructs entry from `node` and `i`. */
|
|
|
|
|
static PB_(entry_c) PB_(cons_entry_c)(const struct PB_(node) *const node,
|
|
|
|
|
const unsigned i) { PB_(entry_c) e;
|
|
|
|
|
e.key = node->key + i, e.value = node->value + i; return e; }
|
|
|
|
|
/** Gets the value of `ref`. */
|
|
|
|
|
static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
|
|
|
|
|
{ return ref.node ? ref.node->value + ref.idx : 0; }
|
|
|
|
@ -242,15 +212,10 @@ static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
|
|
|
|
|
|
|
|
|
|
typedef PB_(key) PB_(value);
|
|
|
|
|
typedef PB_(key) *PB_(entry);
|
|
|
|
|
typedef PB_(key_c) *PB_(entry_c);
|
|
|
|
|
static PB_(entry_c) PB_(null_entry_c)(void) { return 0; }
|
|
|
|
|
static PB_(entry) PB_(null_entry)(void) { return 0; }
|
|
|
|
|
/** Constructs entry from `node` and `i`. */
|
|
|
|
|
static PB_(entry) PB_(cons_entry)(struct PB_(node) *const node,
|
|
|
|
|
const unsigned i) { return node->key + i; }
|
|
|
|
|
/** Constructs entry from `node` and `i`. */
|
|
|
|
|
static PB_(entry_c) PB_(cons_entry_c)(const struct PB_(node) *const node,
|
|
|
|
|
const unsigned i) { return node->key + i; }
|
|
|
|
|
/** Gets the value of `ref`. */
|
|
|
|
|
static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
|
|
|
|
|
{ return ref.node ? ref.node->key + ref.idx : 0; }
|
|
|
|
@ -296,69 +261,39 @@ static int PB_(to_predecessor)(struct PB_(tree) tree,
|
|
|
|
|
*ref = prev;
|
|
|
|
|
} return 1; /* Jumped nodes. */
|
|
|
|
|
}
|
|
|
|
|
/* @return If `ref_c` in `tree` has a successor, then it increments. */
|
|
|
|
|
#define TREE_TO_SUCCESSOR(to_successor_c, ref_c) \
|
|
|
|
|
static int PB_(to_successor_c)(struct PB_(tree) tree, \
|
|
|
|
|
struct PB_(ref_c) *const ref) { \
|
|
|
|
|
assert(ref); \
|
|
|
|
|
if(!tree.node || tree.height == UINT_MAX) return 0; /* Empty. */ \
|
|
|
|
|
if(!ref->node) \
|
|
|
|
|
ref->node = tree.node, ref->height = tree.height, ref->idx = 0; \
|
|
|
|
|
else \
|
|
|
|
|
ref->idx++; \
|
|
|
|
|
while(ref->height) ref->height--, \
|
|
|
|
|
ref->node = PB_(as_branch_c)(ref->node)->child[ref->idx], ref->idx = 0; \
|
|
|
|
|
if(ref->idx < ref->node->size) return 1; /* Likely. */ \
|
|
|
|
|
if(!ref->node->size) return 0; /* When bulk-loading. */ \
|
|
|
|
|
{ /* Re-descend; pick the minimum height node that has a next key. */ \
|
|
|
|
|
struct PB_(ref_c) next; \
|
|
|
|
|
unsigned a0; \
|
|
|
|
|
PB_(key) x; \
|
|
|
|
|
for(next.node = 0, x = ref->node->key[ref->node->size - 1]; tree.height; \
|
|
|
|
|
tree.node = PB_(as_branch_c)(tree.node)->child[a0], tree.height--) { \
|
|
|
|
|
unsigned a1 = tree.node->size; \
|
|
|
|
|
a0 = 0; \
|
|
|
|
|
while(a0 < a1) { \
|
|
|
|
|
const unsigned m = (a0 + a1) / 2; \
|
|
|
|
|
if(PB_(compare)(x, tree.node->key[m]) > 0) a0 = m + 1; else a1 = m;\
|
|
|
|
|
} \
|
|
|
|
|
if(a0 < tree.node->size) \
|
|
|
|
|
next.node = tree.node, next.height = tree.height, next.idx = a0; \
|
|
|
|
|
} \
|
|
|
|
|
if(!next.node) return 0; /* Off right. */ \
|
|
|
|
|
*ref = next; \
|
|
|
|
|
} return 1; /* Jumped nodes. */ \
|
|
|
|
|
}
|
|
|
|
|
TREE_TO_SUCCESSOR(to_successor, ref) /* For cursor. */
|
|
|
|
|
TREE_TO_SUCCESSOR(to_successor_c, ref_c) /* For forward iteration. */
|
|
|
|
|
#undef TREE_TO_SUCCESSOR
|
|
|
|
|
|
|
|
|
|
#define BOX_CONTENT PB_(entry_c)
|
|
|
|
|
/** Is `e` not null? @implements `is_element_c` */
|
|
|
|
|
static int PB_(is_element_c)(PB_(entry_c) e) {
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
|
return !!e.key;
|
|
|
|
|
#else
|
|
|
|
|
return !!e;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* @implements `forward` */
|
|
|
|
|
struct PB_(forward) { const struct PB_(tree) *root; struct PB_(ref_c) next; };
|
|
|
|
|
|
|
|
|
|
/** @return Before `tree`, (can be null.) @implements `forward` */
|
|
|
|
|
static struct PB_(forward) PB_(forward)(const struct B_(tree) *const tree) {
|
|
|
|
|
struct PB_(forward) it;
|
|
|
|
|
it.root = tree ? &tree->root : 0, it.next.node = 0;
|
|
|
|
|
return it;
|
|
|
|
|
}
|
|
|
|
|
/** Move to next `it`. @return Element or null. @implements `next_c` */
|
|
|
|
|
static PB_(entry_c) PB_(next_c)(struct PB_(forward) *const it) {
|
|
|
|
|
return assert(it), PB_(to_successor_c)(*it->root, &it->next) ?
|
|
|
|
|
PB_(cons_entry_c)(it->next.node, it->next.idx) : PB_(null_entry_c)();
|
|
|
|
|
/** @return If `ref` in `tree` has a successor, then it increments. */
|
|
|
|
|
static int PB_(to_successor)(struct PB_(tree) tree,
|
|
|
|
|
struct PB_(ref) *const ref) {
|
|
|
|
|
assert(ref);
|
|
|
|
|
if(!tree.node || tree.height == UINT_MAX) return 0; /* Empty. */
|
|
|
|
|
if(!ref->node)
|
|
|
|
|
ref->node = tree.node, ref->height = tree.height, ref->idx = 0;
|
|
|
|
|
else
|
|
|
|
|
ref->idx++;
|
|
|
|
|
while(ref->height) ref->height--,
|
|
|
|
|
ref->node = PB_(as_branch_c)(ref->node)->child[ref->idx], ref->idx = 0;
|
|
|
|
|
if(ref->idx < ref->node->size) return 1; /* Likely. */
|
|
|
|
|
if(!ref->node->size) return 0; /* When bulk-loading. */
|
|
|
|
|
{ /* Re-descend; pick the minimum height node that has a next key. */
|
|
|
|
|
struct PB_(ref) next;
|
|
|
|
|
unsigned a0;
|
|
|
|
|
PB_(key) x;
|
|
|
|
|
for(next.node = 0, x = ref->node->key[ref->node->size - 1]; tree.height;
|
|
|
|
|
tree.node = PB_(as_branch_c)(tree.node)->child[a0], tree.height--) {
|
|
|
|
|
unsigned a1 = tree.node->size;
|
|
|
|
|
a0 = 0;
|
|
|
|
|
while(a0 < a1) {
|
|
|
|
|
const unsigned m = (a0 + a1) / 2;
|
|
|
|
|
if(PB_(compare)(x, tree.node->key[m]) > 0) a0 = m + 1; else a1 = m;
|
|
|
|
|
}
|
|
|
|
|
if(a0 < tree.node->size)
|
|
|
|
|
next.node = tree.node, next.height = tree.height, next.idx = a0;
|
|
|
|
|
}
|
|
|
|
|
if(!next.node) return 0; /* Off right. */
|
|
|
|
|
*ref = next;
|
|
|
|
|
} return 1; /* Jumped nodes. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define BOX_ITERATOR PB_(entry)
|
|
|
|
|
/** Is `e` not null? @implements `is_element` */
|
|
|
|
|
static int PB_(is_element)(const PB_(entry) e) {
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
@ -367,14 +302,11 @@ static int PB_(is_element)(const PB_(entry) e) {
|
|
|
|
|
return !!e;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* @implements `cursor` */
|
|
|
|
|
struct PB_(cursor) { struct PB_(tree) *root; struct PB_(ref) ref; int seen; };
|
|
|
|
|
|
|
|
|
|
/** Eliminates code-re-use from <fn:<PB>begin> and <fn:<PB>end>.
|
|
|
|
|
struct PB_(iterator) { struct PB_(tree) *root; struct PB_(ref) ref; int seen; };
|
|
|
|
|
/** Eliminates code-re-use from <fn:<PB>iterator> and <fn:<PB>end>.
|
|
|
|
|
@return Fills `it` and returns if `tree` has contents, in which case, `idx`
|
|
|
|
|
is uninitialized. */
|
|
|
|
|
static int PB_(cursor_fill_part)(struct PB_(cursor) *const it,
|
|
|
|
|
static int PB_(iterator_fill_part)(struct PB_(iterator) *const it,
|
|
|
|
|
struct B_(tree) *const tree) {
|
|
|
|
|
assert(it);
|
|
|
|
|
it->seen = 0;
|
|
|
|
@ -389,20 +321,21 @@ static int PB_(cursor_fill_part)(struct PB_(cursor) *const it,
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/** @return Before the start of `tree`, (can be null.) @implements `begin` */
|
|
|
|
|
static struct PB_(cursor) PB_(begin)(struct B_(tree) *const tree) {
|
|
|
|
|
struct PB_(cursor) it;
|
|
|
|
|
if(PB_(cursor_fill_part)(&it, tree)) {
|
|
|
|
|
static struct PB_(iterator) PB_(iterator)(struct B_(tree) *const tree) {
|
|
|
|
|
struct PB_(iterator) it;
|
|
|
|
|
if(PB_(iterator_fill_part)(&it, tree)) {
|
|
|
|
|
for(it.ref.node = tree->root.node; it.ref.height;
|
|
|
|
|
it.ref.node = PB_(as_branch)(it.ref.node)->child[0], it.ref.height--);
|
|
|
|
|
it.ref.node = PB_(as_branch)(it.ref.node)->child[0],
|
|
|
|
|
it.ref.height--);
|
|
|
|
|
it.ref.idx = 0;
|
|
|
|
|
}
|
|
|
|
|
return it;
|
|
|
|
|
}
|
|
|
|
|
/** @return Iterator after the end of `tree`, (can be null.)
|
|
|
|
|
@implements `end` */
|
|
|
|
|
static struct PB_(cursor) PB_(end)(struct B_(tree) *const tree) {
|
|
|
|
|
struct PB_(cursor) it;
|
|
|
|
|
if(PB_(cursor_fill_part)(&it, tree)) {
|
|
|
|
|
static struct PB_(iterator) PB_(end)(struct B_(tree) *const tree) {
|
|
|
|
|
struct PB_(iterator) it;
|
|
|
|
|
if(PB_(iterator_fill_part)(&it, tree)) {
|
|
|
|
|
for(it.ref.node = tree->root.node; it.ref.height;
|
|
|
|
|
it.ref.node = PB_(as_branch)(it.ref.node)->child[it.ref.node->size],
|
|
|
|
|
it.ref.height--);
|
|
|
|
@ -410,9 +343,8 @@ static struct PB_(cursor) PB_(end)(struct B_(tree) *const tree) {
|
|
|
|
|
}
|
|
|
|
|
return it;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Advances `it`. @return Element or null. @implements `next` */
|
|
|
|
|
static PB_(entry) PB_(next)(struct PB_(cursor) *const it) {
|
|
|
|
|
static PB_(entry) PB_(next)(struct PB_(iterator) *const it) {
|
|
|
|
|
assert(it);
|
|
|
|
|
if(!it->root || (it->seen || !it->ref.node)
|
|
|
|
|
&& !PB_(to_successor)(*it->root, &it->ref))
|
|
|
|
@ -423,7 +355,7 @@ static PB_(entry) PB_(next)(struct PB_(cursor) *const it) {
|
|
|
|
|
: (it->seen = 0, PB_(null_entry)());
|
|
|
|
|
}
|
|
|
|
|
/** Move to previous `it`. @return Element or null. @implements `previous` */
|
|
|
|
|
static PB_(entry) PB_(previous)(struct PB_(cursor) *const it) {
|
|
|
|
|
static PB_(entry) PB_(previous)(struct PB_(iterator) *const it) {
|
|
|
|
|
assert(it);
|
|
|
|
|
if(!it->root || !PB_(to_predecessor)(*it->root, &it->ref))
|
|
|
|
|
return it->ref.node = 0, it->seen = 0, PB_(null_entry)();
|
|
|
|
@ -534,7 +466,6 @@ static struct PB_(ref) PB_(lookup_remove)(struct PB_(tree) *const tree,
|
|
|
|
|
#undef TREE_FORNODE
|
|
|
|
|
#undef TREE_FLIPPED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Zeroed data (not all-bits-zero) is initialized. @return An idle tree.
|
|
|
|
|
@order \Theta(1) @allow */
|
|
|
|
|
static struct B_(tree) B_(tree)(void) {
|
|
|
|
@ -853,7 +784,7 @@ static enum tree_result PB_(update)(struct PB_(tree) *const root,
|
|
|
|
|
PB_(key) key, PB_(key) *const eject) {
|
|
|
|
|
#endif /* set --> */
|
|
|
|
|
struct PB_(node) *new_head = 0;
|
|
|
|
|
struct PB_(ref) add, hole, cursor;
|
|
|
|
|
struct PB_(ref) add, hole, iterator;
|
|
|
|
|
assert(root);
|
|
|
|
|
if(!(add.node = root->node)) goto idle;
|
|
|
|
|
else if(root->height == UINT_MAX) goto empty;
|
|
|
|
@ -937,93 +868,93 @@ grow: /* Leaf is full. */ {
|
|
|
|
|
new_root->child[0] = root->node, root->node = hole.node;
|
|
|
|
|
hole.node->size = 1;
|
|
|
|
|
}
|
|
|
|
|
cursor = hole; /* Go down; (as opposed to doing it on paper.) */
|
|
|
|
|
iterator = hole; /* Go down; (as opposed to doing it on paper.) */
|
|
|
|
|
goto split;
|
|
|
|
|
} split: { /* Split between the new and existing nodes. */
|
|
|
|
|
struct PB_(node) *sibling;
|
|
|
|
|
assert(cursor.node && cursor.node->size && cursor.height);
|
|
|
|
|
assert(iterator.node && iterator.node->size && iterator.height);
|
|
|
|
|
sibling = new_head;
|
|
|
|
|
/*PB_(graph_usual)(tree, "graph/work.gv");*/
|
|
|
|
|
/* Descend now while split hasn't happened -- easier. */
|
|
|
|
|
new_head = --cursor.height ? PB_(as_branch)(new_head)->child[0] : 0;
|
|
|
|
|
cursor.node = PB_(as_branch)(cursor.node)->child[cursor.idx];
|
|
|
|
|
PB_(find_idx)(&cursor, key);
|
|
|
|
|
assert(!sibling->size && cursor.node->size == TREE_MAX); /* Atomic. */
|
|
|
|
|
/* Expand `cursor`, which is full, to multiple nodes. */
|
|
|
|
|
if(cursor.idx < TREE_SPLIT) { /* Descend hole to `cursor`. */
|
|
|
|
|
memcpy(sibling->key, cursor.node->key + TREE_SPLIT,
|
|
|
|
|
new_head = --iterator.height ? PB_(as_branch)(new_head)->child[0] : 0;
|
|
|
|
|
iterator.node = PB_(as_branch)(iterator.node)->child[iterator.idx];
|
|
|
|
|
PB_(find_idx)(&iterator, key);
|
|
|
|
|
assert(!sibling->size && iterator.node->size == TREE_MAX); /* Atomic. */
|
|
|
|
|
/* Expand `iterator`, which is full, to multiple nodes. */
|
|
|
|
|
if(iterator.idx < TREE_SPLIT) { /* Descend hole to `iterator`. */
|
|
|
|
|
memcpy(sibling->key, iterator.node->key + TREE_SPLIT,
|
|
|
|
|
sizeof *sibling->key * (TREE_MAX - TREE_SPLIT));
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
|
memcpy(sibling->value, cursor.node->value + TREE_SPLIT,
|
|
|
|
|
memcpy(sibling->value, iterator.node->value + TREE_SPLIT,
|
|
|
|
|
sizeof *sibling->value * (TREE_MAX - TREE_SPLIT));
|
|
|
|
|
#endif
|
|
|
|
|
hole.node->key[hole.idx] = cursor.node->key[TREE_SPLIT - 1];
|
|
|
|
|
hole.node->key[hole.idx] = iterator.node->key[TREE_SPLIT - 1];
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
|
hole.node->value[hole.idx] = cursor.node->value[TREE_SPLIT - 1];
|
|
|
|
|
hole.node->value[hole.idx] = iterator.node->value[TREE_SPLIT - 1];
|
|
|
|
|
#endif
|
|
|
|
|
memmove(cursor.node->key + cursor.idx + 1,
|
|
|
|
|
cursor.node->key + cursor.idx,
|
|
|
|
|
sizeof *cursor.node->key * (TREE_SPLIT - 1 - cursor.idx));
|
|
|
|
|
memmove(iterator.node->key + iterator.idx + 1,
|
|
|
|
|
iterator.node->key + iterator.idx,
|
|
|
|
|
sizeof *iterator.node->key * (TREE_SPLIT - 1 - iterator.idx));
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
|
memmove(cursor.node->value + cursor.idx + 1,
|
|
|
|
|
cursor.node->value + cursor.idx,
|
|
|
|
|
sizeof *cursor.node->value * (TREE_SPLIT - 1 - cursor.idx));
|
|
|
|
|
memmove(iterator.node->value + iterator.idx + 1,
|
|
|
|
|
iterator.node->value + iterator.idx,
|
|
|
|
|
sizeof *iterator.node->value * (TREE_SPLIT - 1 - iterator.idx));
|
|
|
|
|
#endif
|
|
|
|
|
if(cursor.height) {
|
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(cursor.node),
|
|
|
|
|
if(iterator.height) {
|
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
|
|
|
|
|
*const sb = PB_(as_branch)(sibling);
|
|
|
|
|
struct PB_(node) *temp = sb->child[0];
|
|
|
|
|
memcpy(sb->child, cb->child + TREE_SPLIT,
|
|
|
|
|
sizeof *cb->child * (TREE_MAX - TREE_SPLIT + 1));
|
|
|
|
|
memmove(cb->child + cursor.idx + 2, cb->child + cursor.idx + 1,
|
|
|
|
|
sizeof *cb->child * (TREE_SPLIT - 1 - cursor.idx));
|
|
|
|
|
cb->child[cursor.idx + 1] = temp;
|
|
|
|
|
memmove(cb->child + iterator.idx + 2, cb->child + iterator.idx + 1,
|
|
|
|
|
sizeof *cb->child * (TREE_SPLIT - 1 - iterator.idx));
|
|
|
|
|
cb->child[iterator.idx + 1] = temp;
|
|
|
|
|
}
|
|
|
|
|
hole = cursor;
|
|
|
|
|
} else if(cursor.idx > TREE_SPLIT) { /* Descend hole to `sibling`. */
|
|
|
|
|
hole.node->key[hole.idx] = cursor.node->key[TREE_SPLIT];
|
|
|
|
|
hole = iterator;
|
|
|
|
|
} else if(iterator.idx > TREE_SPLIT) { /* Descend hole to `sibling`. */
|
|
|
|
|
hole.node->key[hole.idx] = iterator.node->key[TREE_SPLIT];
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
|
hole.node->value[hole.idx] = cursor.node->value[TREE_SPLIT];
|
|
|
|
|
hole.node->value[hole.idx] = iterator.node->value[TREE_SPLIT];
|
|
|
|
|
#endif
|
|
|
|
|
hole.node = sibling, hole.height = cursor.height,
|
|
|
|
|
hole.idx = cursor.idx - TREE_SPLIT - 1;
|
|
|
|
|
memcpy(sibling->key, cursor.node->key + TREE_SPLIT + 1,
|
|
|
|
|
hole.node = sibling, hole.height = iterator.height,
|
|
|
|
|
hole.idx = iterator.idx - TREE_SPLIT - 1;
|
|
|
|
|
memcpy(sibling->key, iterator.node->key + TREE_SPLIT + 1,
|
|
|
|
|
sizeof *sibling->key * hole.idx);
|
|
|
|
|
memcpy(sibling->key + hole.idx + 1, cursor.node->key + cursor.idx,
|
|
|
|
|
sizeof *sibling->key * (TREE_MAX - cursor.idx));
|
|
|
|
|
memcpy(sibling->key + hole.idx + 1, iterator.node->key + iterator.idx,
|
|
|
|
|
sizeof *sibling->key * (TREE_MAX - iterator.idx));
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
|
memcpy(sibling->value, cursor.node->value + TREE_SPLIT + 1,
|
|
|
|
|
memcpy(sibling->value, iterator.node->value + TREE_SPLIT + 1,
|
|
|
|
|
sizeof *sibling->value * hole.idx);
|
|
|
|
|
memcpy(sibling->value + hole.idx + 1, cursor.node->value + cursor.idx,
|
|
|
|
|
sizeof *sibling->value * (TREE_MAX - cursor.idx));
|
|
|
|
|
memcpy(sibling->value + hole.idx + 1, iterator.node->value + iterator.idx,
|
|
|
|
|
sizeof *sibling->value * (TREE_MAX - iterator.idx));
|
|
|
|
|
#endif
|
|
|
|
|
if(cursor.height) {
|
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(cursor.node),
|
|
|
|
|
if(iterator.height) {
|
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
|
|
|
|
|
*const sb = PB_(as_branch)(sibling);
|
|
|
|
|
struct PB_(node) *temp = sb->child[0];
|
|
|
|
|
memcpy(sb->child, cb->child + TREE_SPLIT + 1,
|
|
|
|
|
sizeof *cb->child * (hole.idx + 1));
|
|
|
|
|
memcpy(sb->child + hole.idx + 2, cb->child + cursor.idx + 1,
|
|
|
|
|
sizeof *cb->child * (TREE_MAX - cursor.idx));
|
|
|
|
|
memcpy(sb->child + hole.idx + 2, cb->child + iterator.idx + 1,
|
|
|
|
|
sizeof *cb->child * (TREE_MAX - iterator.idx));
|
|
|
|
|
sb->child[hole.idx + 1] = temp;
|
|
|
|
|
}
|
|
|
|
|
} else { /* Equal split: leave the hole where it is. */
|
|
|
|
|
memcpy(sibling->key, cursor.node->key + TREE_SPLIT,
|
|
|
|
|
memcpy(sibling->key, iterator.node->key + TREE_SPLIT,
|
|
|
|
|
sizeof *sibling->key * (TREE_MAX - TREE_SPLIT));
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
|
memcpy(sibling->value, cursor.node->value + TREE_SPLIT,
|
|
|
|
|
memcpy(sibling->value, iterator.node->value + TREE_SPLIT,
|
|
|
|
|
sizeof *sibling->value * (TREE_MAX - TREE_SPLIT));
|
|
|
|
|
#endif
|
|
|
|
|
if(cursor.height) {
|
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(cursor.node),
|
|
|
|
|
if(iterator.height) {
|
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
|
|
|
|
|
*const sb = PB_(as_branch)(sibling);
|
|
|
|
|
memcpy(sb->child + 1, cb->child + TREE_SPLIT + 1,
|
|
|
|
|
sizeof *cb->child * (TREE_MAX - TREE_SPLIT));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Divide `TREE_MAX + 1` into two trees. */
|
|
|
|
|
cursor.node->size = TREE_SPLIT, sibling->size = TREE_MAX - TREE_SPLIT;
|
|
|
|
|
if(cursor.height) goto split; /* Loop max `\log_{TREE_MIN} size`. */
|
|
|
|
|
iterator.node->size = TREE_SPLIT, sibling->size = TREE_MAX - TREE_SPLIT;
|
|
|
|
|
if(iterator.height) goto split; /* Loop max `\log_{TREE_MIN} size`. */
|
|
|
|
|
hole.node->key[hole.idx] = key;
|
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
|
if(value) *value = PB_(ref_to_valuep)(hole);
|
|
|
|
@ -1391,7 +1322,7 @@ struct PB_(scaffold) {
|
|
|
|
|
struct tree_node_count victim, source;
|
|
|
|
|
size_t no;
|
|
|
|
|
struct PB_(node) **data;
|
|
|
|
|
struct { struct PB_(node) **head, **fresh, **cursor; } branch, leaf;
|
|
|
|
|
struct { struct PB_(node) **head, **fresh, **iterator; } branch, leaf;
|
|
|
|
|
};
|
|
|
|
|
/** Counts the nodes `no` in `tree` for <fn:<PB>nodes>. */
|
|
|
|
|
static int PB_(nodes_r)(struct PB_(tree) tree,
|
|
|
|
@ -1431,15 +1362,15 @@ static int PB_(nodes)(const struct B_(tree) *const tree,
|
|
|
|
|
static void PB_(cannibalize_r)(struct PB_(ref) ref,
|
|
|
|
|
struct PB_(scaffold) *const sc) {
|
|
|
|
|
struct PB_(branch) *branch = PB_(as_branch)(ref.node);
|
|
|
|
|
const int keep_branch = sc->branch.cursor < sc->branch.fresh;
|
|
|
|
|
const int keep_branch = sc->branch.iterator < sc->branch.fresh;
|
|
|
|
|
assert(ref.node && ref.height && sc);
|
|
|
|
|
if(keep_branch) *sc->branch.cursor = ref.node, sc->branch.cursor++;
|
|
|
|
|
if(keep_branch) *sc->branch.iterator = ref.node, sc->branch.iterator++;
|
|
|
|
|
if(ref.height == 1) { /* Children are leaves. */
|
|
|
|
|
unsigned n;
|
|
|
|
|
for(n = 0; n <= ref.node->size; n++) {
|
|
|
|
|
const int keep_leaf = sc->leaf.cursor < sc->leaf.fresh;
|
|
|
|
|
const int keep_leaf = sc->leaf.iterator < sc->leaf.fresh;
|
|
|
|
|
struct PB_(node) *child = branch->child[n];
|
|
|
|
|
if(keep_leaf) *sc->leaf.cursor = child, sc->leaf.cursor++;
|
|
|
|
|
if(keep_leaf) *sc->leaf.iterator = child, sc->leaf.iterator++;
|
|
|
|
|
else free(child);
|
|
|
|
|
}
|
|
|
|
|
} else while(ref.idx <= ref.node->size) {
|
|
|
|
@ -1461,12 +1392,12 @@ static void PB_(cannibalize)(const struct B_(tree) *const tree,
|
|
|
|
|
if(!sc->victim.branches && !sc->victim.leaves) return;
|
|
|
|
|
assert(tree->root.node);
|
|
|
|
|
ref.node = tree->root.node, ref.height = tree->root.height, ref.idx = 0;
|
|
|
|
|
sc->branch.cursor = sc->branch.head;
|
|
|
|
|
sc->leaf.cursor = sc->leaf.head;
|
|
|
|
|
sc->branch.iterator = sc->branch.head;
|
|
|
|
|
sc->leaf.iterator = sc->leaf.head;
|
|
|
|
|
if(ref.height) {
|
|
|
|
|
PB_(cannibalize_r)(ref, sc);
|
|
|
|
|
} else { /* Just one leaf. */
|
|
|
|
|
*sc->leaf.cursor = ref.node;
|
|
|
|
|
*sc->leaf.iterator = ref.node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/** Do the work of `src` cloned with `sc`. Called from <fn:<PB>clone>. */
|
|
|
|
@ -1475,7 +1406,7 @@ static struct PB_(node) *PB_(clone_r)(struct PB_(tree) src,
|
|
|
|
|
struct PB_(node) *node;
|
|
|
|
|
if(src.height) {
|
|
|
|
|
struct PB_(branch) *const srcb = PB_(as_branch)(src.node),
|
|
|
|
|
*const branch = PB_(as_branch)(node = *sc->branch.cursor++);
|
|
|
|
|
*const branch = PB_(as_branch)(node = *sc->branch.iterator++);
|
|
|
|
|
unsigned i;
|
|
|
|
|
struct PB_(tree) child;
|
|
|
|
|
*node = *src.node; /* Copy node. */
|
|
|
|
@ -1485,7 +1416,7 @@ static struct PB_(node) *PB_(clone_r)(struct PB_(tree) src,
|
|
|
|
|
branch->child[i] = PB_(clone_r)(child, sc);
|
|
|
|
|
}
|
|
|
|
|
} else { /* Leaves. */
|
|
|
|
|
node = *sc->leaf.cursor++;
|
|
|
|
|
node = *sc->leaf.iterator++;
|
|
|
|
|
*node = *src.node;
|
|
|
|
|
}
|
|
|
|
|
return node;
|
|
|
|
@ -1496,13 +1427,13 @@ static struct PB_(tree) PB_(clone)(const struct PB_(tree) *const src,
|
|
|
|
|
struct PB_(tree) sub;
|
|
|
|
|
assert(src && src->node && sc);
|
|
|
|
|
/* Go back to the beginning of the scaffold and pick off one by one. */
|
|
|
|
|
sc->branch.cursor = sc->branch.head;
|
|
|
|
|
sc->leaf.cursor = sc->leaf.head;
|
|
|
|
|
sc->branch.iterator = sc->branch.head;
|
|
|
|
|
sc->leaf.iterator = sc->leaf.head;
|
|
|
|
|
sub.node = PB_(clone_r)(*src, sc);
|
|
|
|
|
sub.height = src->height;
|
|
|
|
|
/* Used up all of them. No concurrent modifications, please. */
|
|
|
|
|
assert(sc->branch.cursor == sc->leaf.head
|
|
|
|
|
&& sc->leaf.cursor == sc->data + sc->no);
|
|
|
|
|
assert(sc->branch.iterator == sc->leaf.head
|
|
|
|
|
&& sc->leaf.iterator == sc->data + sc->no);
|
|
|
|
|
return sub;
|
|
|
|
|
}
|
|
|
|
|
/** `source` is copied to, and overwrites, `tree`.
|
|
|
|
@ -1536,26 +1467,26 @@ static int B_(tree_clone)(struct B_(tree) *const tree,
|
|
|
|
|
need.branches = sc.source.branches > sc.victim.branches
|
|
|
|
|
? sc.source.branches - sc.victim.branches : 0;
|
|
|
|
|
sc.branch.head = sc.data;
|
|
|
|
|
sc.branch.fresh = sc.branch.cursor
|
|
|
|
|
sc.branch.fresh = sc.branch.iterator
|
|
|
|
|
= sc.branch.head + sc.source.branches - need.branches;
|
|
|
|
|
sc.leaf.head = sc.branch.fresh |