2022-05-28 02:09:38 -04:00
|
|
|
/** @license 2022 Neil Edelman, distributed under the terms of the
|
|
|
|
[MIT License](https://opensource.org/licenses/MIT).
|
|
|
|
|
2022-12-27 02:31:08 -05:00
|
|
|
@abstract Stand-alone header <../src/tree.h>; examples <../test/test_tree.c>;
|
|
|
|
article <../doc/tree/tree.pdf>.
|
2022-05-28 02:09:38 -04:00
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
@subtitle Ordered tree
|
|
|
|
|
2022-12-27 02:31:08 -05:00
|
|
|
![Example of an order-3 tree.](../doc/tree/tree.png)
|
2022-05-28 02:09:38 -04:00
|
|
|
|
2022-07-06 13:02:28 -04:00
|
|
|
A <tag:<B>tree> is an ordered set or map contained in a tree. For memory
|
|
|
|
locality, this is implemented B-tree, described in
|
|
|
|
<Bayer, McCreight, 1972, Large>.
|
2022-05-28 02:09:38 -04:00
|
|
|
|
|
|
|
@param[TREE_NAME, TREE_KEY]
|
|
|
|
`<B>` that satisfies `C` naming conventions when mangled, required, and
|
2022-09-08 01:13:56 -04:00
|
|
|
`TREE_KEY`, a type, <typedef:<PB>key>, whose default is `unsigned int`.
|
|
|
|
`<PB>` is private, whose names are prefixed in a manner to avoid collisions.
|
2022-05-28 02:09:38 -04:00
|
|
|
|
|
|
|
@param[TREE_VALUE]
|
2022-12-27 02:31:08 -05:00
|
|
|
Optional payload to go with the type, <typedef:<PB>value>, thus making it a
|
|
|
|
map instead of a set.
|
2022-05-28 02:09:38 -04:00
|
|
|
|
|
|
|
@param[TREE_COMPARE]
|
2022-12-27 02:31:08 -05:00
|
|
|
This will define <fn:<B>compare>, a <typedef:<PB>compare_fn> that compares
|
|
|
|
keys as integer-types that results in ascending order, `a > b`. If
|
|
|
|
`TREE_COMPARE` is specified, the user most specify their own <fn:<B>compare>.
|
2022-05-28 02:09:38 -04:00
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
@param[TREE_ORDER]
|
|
|
|
Sets the branching factor, or order as <Knuth, 1998 Art 3>, to the range
|
|
|
|
`[3, UINT_MAX+1]`. Default 65 is tuned to an integer to pointer map, and
|
|
|
|
should be okay for most variations. 4 is isomorphic to left-leaning red-black
|
|
|
|
tree, <Sedgewick, 2008, LLRB>. The above illustration is 5.
|
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
@param[TREE_DEFAULT]
|
2022-09-08 01:13:56 -04:00
|
|
|
Default trait; a name that satisfies `C` naming conventions when mangled and a
|
2022-11-02 00:06:43 -04:00
|
|
|
<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>.
|
2022-09-08 01:13:56 -04:00
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
@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`.
|
2022-05-28 02:09:38 -04:00
|
|
|
|
|
|
|
@fixme merge, difference
|
|
|
|
|
|
|
|
@std C89 */
|
|
|
|
|
|
|
|
#if !defined(TREE_NAME)
|
2022-11-02 00:06:43 -04:00
|
|
|
#error Name undefined.
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
#if defined(TREE_TRAIT) ^ defined(BOX_TYPE)
|
|
|
|
#error TREE_TRAIT name must come after TREE_EXPECT_TRAIT.
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
#if defined(TREE_TEST) && (!defined(TREE_TRAIT) && !defined(TREE_TO_STRING) \
|
|
|
|
|| defined(TREE_TRAIT) && !defined(TREE_HAS_TO_STRING))
|
|
|
|
#error Test requires to string.
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef TREE_H /* <!-- idempotent */
|
|
|
|
#define TREE_H
|
2022-09-08 01:13:56 -04:00
|
|
|
#include <stddef.h> /* That's weird. */
|
2022-05-28 02:09:38 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <limits.h>
|
|
|
|
/* <Kernighan and Ritchie, 1988, p. 231>. */
|
2022-09-08 01:13:56 -04:00
|
|
|
#if defined(TREE_CAT_) || defined(TREE_CAT) || defined(B_) || defined(PB_)
|
2022-05-28 02:09:38 -04:00
|
|
|
#error Unexpected defines.
|
|
|
|
#endif
|
|
|
|
#define TREE_CAT_(n, m) n ## _ ## m
|
|
|
|
#define TREE_CAT(n, m) TREE_CAT_(n, m)
|
|
|
|
#define B_(n) TREE_CAT(TREE_NAME, n)
|
|
|
|
#define PB_(n) TREE_CAT(tree, B_(n))
|
2022-07-06 13:02:28 -04:00
|
|
|
/* Leaf: `TREE_MAX type`; branch: `TREE_MAX type + TREE_ORDER pointer`. In
|
|
|
|
<Goodrich, Tamassia, Mount, 2011, Data>, these are (a,b)-trees as
|
|
|
|
(TREE_MIN+1,TREE_MAX+1)-trees. */
|
2022-09-08 01:13:56 -04:00
|
|
|
#define TREE_MAX (TREE_ORDER - 1)
|
2022-05-28 02:09:38 -04:00
|
|
|
/* This is the worst-case branching factor; the performance will be
|
|
|
|
\O(log_{`TREE_MIN`+1} `size`). Usually this is `⌈(TREE_MAX+1)/2⌉-1`. However,
|
2022-07-06 13:02:28 -04:00
|
|
|
smaller values are less-eager; in the extreme,
|
|
|
|
<Johnson, Shasha, 1993, Free-at-Empty>, show good results; this has been
|
|
|
|
chosen to provide hysteresis. (Except `TREE_MAX 2`, it's fixed.) */
|
2022-05-28 02:09:38 -04:00
|
|
|
#define TREE_MIN (TREE_MAX / 3 ? TREE_MAX / 3 : 1)
|
|
|
|
#define TREE_SPLIT (TREE_ORDER / 2) /* Split index: even order left-leaning. */
|
2022-12-27 02:31:08 -05:00
|
|
|
#define TREE_RESULT X(ERROR), X(ABSENT), X(PRESENT)
|
2022-05-28 02:09:38 -04:00
|
|
|
#define X(n) TREE_##n
|
|
|
|
/** A result of modifying the tree, of which `TREE_ERROR` is false.
|
2022-09-08 01:13:56 -04:00
|
|
|
|
2022-12-27 02:31:08 -05:00
|
|
|
![A diagram of the result states.](../doc/tree/result.png) */
|
2022-05-28 02:09:38 -04:00
|
|
|
enum tree_result { TREE_RESULT };
|
|
|
|
#undef X
|
|
|
|
#define X(n) #n
|
|
|
|
/** A static array of strings describing the <tag:tree_result>. */
|
|
|
|
static const char *const tree_result_str[] = { TREE_RESULT };
|
|
|
|
#undef X
|
|
|
|
#undef TREE_RESULT
|
2022-09-08 01:13:56 -04:00
|
|
|
struct tree_node_count { size_t branches, leaves; };
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif /* idempotent --> */
|
|
|
|
|
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
#ifndef TREE_TRAIT /* <!-- base code */
|
2022-05-28 02:09:38 -04:00
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
#ifndef TREE_ORDER
|
|
|
|
#define TREE_ORDER 65 /* Maximum branching factor. This sets the granularity. */
|
|
|
|
#endif
|
|
|
|
#if TREE_ORDER < 3 || TREE_ORDER > UINT_MAX + 1
|
|
|
|
#error TREE_ORDER parameter range `[3, UINT_MAX+1]`.
|
|
|
|
#endif
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifndef TREE_KEY
|
|
|
|
#define TREE_KEY unsigned
|
|
|
|
#endif
|
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Ordered type used by <typedef:<PB>compare_fn>; defaults to `unsigned`. */
|
2022-05-28 02:09:38 -04:00
|
|
|
typedef TREE_KEY PB_(key);
|
|
|
|
|
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
/** On `TREE_VALUE`, this creates a map, otherwise a set of
|
|
|
|
<typedef:<PB>key>. */
|
2022-05-28 02:09:38 -04:00
|
|
|
typedef TREE_VALUE PB_(value);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** 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
|
2022-11-02 00:06:43 -04:00
|
|
|
comparators from `bsearch` and `qsort`; it only needs to divide entries into
|
|
|
|
two instead of three categories. */
|
2022-12-27 02:31:08 -05:00
|
|
|
typedef int (*PB_(compare_fn))(const PB_(key) a, const PB_(key) b);
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifndef TREE_COMPARE /* <!-- !cmp */
|
|
|
|
/** The default `TREE_COMPARE` on `a` and `b` is integer comparison that
|
2022-12-27 02:31:08 -05:00
|
|
|
results in ascending order, `a > b`. Use `TREE_COMPARE` to supply one's own.
|
|
|
|
@implements <typedef:<PB>compare_fn> */
|
|
|
|
static int B_(compare)(const PB_(key) a, const PB_(key) b)
|
2022-05-28 02:09:38 -04:00
|
|
|
{ return a > b; }
|
|
|
|
#define TREE_COMPARE &PB_(default_compare)
|
|
|
|
#endif /* !cmp --> */
|
|
|
|
|
2022-07-06 13:02:28 -04:00
|
|
|
/* These rules are more lazy than the original so as to not exhibit worst-case
|
|
|
|
behaviour in small trees, as <Johnson, Shasha, 1993, Free-at-Empty>, (lookup
|
|
|
|
is potentially slower after deleting.) In the terminology of
|
|
|
|
<Knuth, 1998 Art 3>,
|
2022-05-28 02:09:38 -04:00
|
|
|
* Every branch has at most `TREE_ORDER == TREE_MAX + 1` children, which is at
|
|
|
|
minimum three.
|
|
|
|
* Every non-root and non-bulk-loaded node has at least `TREE_MIN` keys,
|
|
|
|
(`⎣TREE_MAX/3⎦`.)
|
|
|
|
* Every branch has at least one child, `k`, and contains `k - 1` keys, (this
|
|
|
|
is a consequence of the fact that they are implicitly storing a complete
|
|
|
|
binary sub-tree.)
|
|
|
|
* All leaves are at the maximum depth and height zero; they do'n't carry links
|
2022-07-06 13:02:28 -04:00
|
|
|
to other nodes, (hence, leaf.) In this code, a branch node is a
|
|
|
|
specialization of a (leaf) node with children. One can tell if it's a branch
|
|
|
|
by keeping track of the height.
|
2022-05-28 02:09:38 -04:00
|
|
|
* There are two empty B-trees to facilitate allocation hysteresis between
|
|
|
|
0 -- 1: idle `{ 0, 0 }`, and `{ garbage leaf, UINT_MAX }`, one could test,
|
|
|
|
`!root || height == UINT_MAX`.
|
2022-07-06 13:02:28 -04:00
|
|
|
* Bulk-loading always is on the right side. */
|
2022-05-28 02:09:38 -04:00
|
|
|
struct PB_(node) {
|
2022-09-08 01:13:56 -04:00
|
|
|
unsigned size;
|
2022-05-28 02:09:38 -04:00
|
|
|
PB_(key) key[TREE_MAX]; /* Cache-friendly lookup. */
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
PB_(value) value[TREE_MAX];
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
/* B-tree branch is a <tag:<PB>node> and links to `size + 1` nodes. */
|
|
|
|
struct PB_(branch) { struct PB_(node) base, *child[TREE_ORDER]; };
|
2022-09-08 01:13:56 -04:00
|
|
|
/** @return Downcasts `as_leaf` to a branch. */
|
|
|
|
static struct PB_(branch) *PB_(as_branch)(struct PB_(node) *const as_leaf)
|
2022-05-28 02:09:38 -04:00
|
|
|
{ return (struct PB_(branch) *)(void *)
|
|
|
|
((char *)as_leaf - offsetof(struct PB_(branch), base)); }
|
2022-07-06 13:02:28 -04:00
|
|
|
/** @return Downcasts `as_node` to a branch. */
|
2022-09-08 01:13:56 -04:00
|
|
|
static const struct PB_(branch) *PB_(as_branch_c)(const struct PB_(node) *
|
2022-05-28 02:09:38 -04:00
|
|
|
const as_node) { return (const struct PB_(branch) *)(const void *)
|
|
|
|
((const char *)as_node - offsetof(struct PB_(branch), base)); }
|
2022-09-08 01:13:56 -04:00
|
|
|
/* 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. */
|
2022-05-28 02:09:38 -04:00
|
|
|
struct PB_(ref) { struct PB_(node) *node; unsigned height, idx; };
|
2022-12-27 02:31:08 -05:00
|
|
|
/* Node plus height is a sub-tree. A <tag:<B>tree> is a sub-tree of the tree.
|
|
|
|
fixme: 0-based height is problematic. UINT_MAX? No. */
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(tree) { struct PB_(node) *node; unsigned height; };
|
2022-09-08 01:13:56 -04:00
|
|
|
/** To initialize it to an idle state, see <fn:<B>tree>, `{0}` (`C99`), or
|
|
|
|
being `static`.
|
2022-07-06 13:02:28 -04:00
|
|
|
|
2022-12-27 02:31:08 -05:00
|
|
|
![States.](../doc/tree/states.png) */
|
2022-07-06 13:02:28 -04:00
|
|
|
struct B_(tree);
|
|
|
|
struct B_(tree) { struct PB_(tree) root; };
|
2022-05-28 02:09:38 -04:00
|
|
|
|
|
|
|
#ifdef TREE_VALUE /* <!-- value */
|
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Gets the value of `ref`. */
|
|
|
|
static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
|
2022-05-28 02:09:38 -04:00
|
|
|
{ return ref.node ? ref.node->value + ref.idx : 0; }
|
|
|
|
|
|
|
|
#else /* value --><!-- !value */
|
|
|
|
|
|
|
|
typedef PB_(key) PB_(value);
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Gets the value of `ref`. */
|
|
|
|
static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
|
2022-05-28 02:09:38 -04:00
|
|
|
{ return ref.node ? ref.node->key + ref.idx : 0; }
|
|
|
|
|
|
|
|
#endif /* !value --> */
|
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
struct PB_(iterator) { struct PB_(tree) *root; struct PB_(ref) ref; int seen; };
|
2022-09-08 01:13:56 -04:00
|
|
|
/** @return Before the start of `tree`, (can be null.) @implements `begin` */
|
2022-12-27 02:31:08 -05:00
|
|
|
static struct PB_(iterator) PB_(begin)(struct B_(tree) *const tree) {
|
2022-11-02 00:06:43 -04:00
|
|
|
struct PB_(iterator) it;
|
2022-12-27 02:31:08 -05:00
|
|
|
it.root = tree ? &tree->root : 0;
|
|
|
|
it.ref.height = tree ? tree->root.height : 0;
|
|
|
|
if(tree && tree->root.height != UINT_MAX)
|
2022-09-08 01:13:56 -04:00
|
|
|
for(it.ref.node = tree->root.node; it.ref.height;
|
2022-12-27 02:31:08 -05:00
|
|
|
it.ref.node = PB_(as_branch)(it.ref.node)->child[0], it.ref.height--);
|
|
|
|
else it.ref.node = 0;
|
|
|
|
it.ref.idx = 0;
|
|
|
|
it.seen = 0;
|
2022-09-08 01:13:56 -04:00
|
|
|
return it;
|
|
|
|
}
|
2022-12-27 02:31:08 -05:00
|
|
|
/** @return After the end of `tree`, (can be null.) @implements `end` */
|
2022-11-02 00:06:43 -04:00
|
|
|
static struct PB_(iterator) PB_(end)(struct B_(tree) *const tree) {
|
|
|
|
struct PB_(iterator) it;
|
2022-12-27 02:31:08 -05:00
|
|
|
it.root = tree ? &tree->root : 0;
|
|
|
|
it.ref.height = tree ? tree->root.height : 0;
|
|
|
|
if(tree && tree->root.height != UINT_MAX)
|
2022-09-08 01:13:56 -04:00
|
|
|
for(it.ref.node = tree->root.node; it.ref.height;
|
2022-12-27 02:31:08 -05:00
|
|
|
it.ref.node = PB_(as_branch)(it.ref.node)->child[it.ref.node->size],
|
|
|
|
it.ref.height--);
|
|
|
|
else it.ref.node = 0;
|
|
|
|
it.ref.idx = it.ref.node ? it.ref.node->size : 0;
|
|
|
|
it.seen = 0;
|
2022-05-28 02:09:38 -04:00
|
|
|
return it;
|
|
|
|
}
|
2022-12-27 02:31:08 -05:00
|
|
|
/** @return Whether `it` advances, filling `ref`. @implements `next` */
|
|
|
|
static int PB_(next)(struct PB_(iterator) *const it,
|
|
|
|
struct PB_(ref) **const ref) {
|
|
|
|
struct PB_(ref) adv;
|
2022-07-06 13:02:28 -04:00
|
|
|
assert(it);
|
2022-12-27 02:31:08 -05:00
|
|
|
if(!it->root || !it->ref.node) return it->seen = 0, 0;
|
|
|
|
if(!it->root->node || it->root->height == UINT_MAX)
|
|
|
|
return it->ref.node = 0, 0; /* Concurrent modification? */
|
|
|
|
adv = it->ref; /* Shorten keystrokes and work with a copy. */
|
|
|
|
if(!it->seen && adv.idx < adv.node->size) goto successor;
|
|
|
|
adv.idx++;
|
|
|
|
if(adv.height && adv.idx > adv.node->size)
|
|
|
|
return it->ref.node = 0, 0; /* Concurrent modification? */
|
|
|
|
while(adv.height) adv.height--,
|
|
|
|
adv.node = PB_(as_branch)(adv.node)->child[adv.idx], adv.idx = 0;
|
|
|
|
if(adv.idx < adv.node->size) goto successor; /* Likely. */
|
|
|
|
/* Bulk-loading or concurrent modification? */
|
|
|
|
if(adv.idx > adv.node->size) return it->ref.node = 0, 0;
|
|
|
|
{ /* Re-descend; pick the minimum height node that has a next key. */
|
|
|
|
struct PB_(ref) next;
|
|
|
|
struct PB_(tree) tree = *it->root;
|
|
|
|
unsigned a0;
|
|
|
|
const PB_(key) x = adv.node->key[adv.node->size - 1]; /* Target. */
|
|
|
|
for(next.node = 0; tree.height;
|
|
|
|
tree.node = PB_(as_branch)(tree.node)->child[a0], tree.height--) {
|
|
|
|
unsigned a1 = tree.node->size;
|
|
|
|
a0 = 0;
|
|
|
|
while(a0 < a1) {
|
|
|
|
const unsigned m = (a0 + a1) / 2;
|
|
|
|
if(B_(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 it->seen = 0, 0; /* Off right. */
|
|
|
|
adv = next;
|
|
|
|
} /* Jumped nodes. */
|
|
|
|
successor:
|
|
|
|
it->seen = 1;
|
|
|
|
it->ref = adv;
|
|
|
|
if(ref) *ref = &it->ref;
|
|
|
|
return 1;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
2022-12-27 02:31:08 -05:00
|
|
|
/** @return Whether `it` recedes, filling `v`. @implements `next` */
|
|
|
|
static int PB_(previous)(struct PB_(iterator) *const it,
|
|
|
|
struct PB_(ref) **const v) {
|
|
|
|
struct PB_(ref) prd;
|
2022-09-08 01:13:56 -04:00
|
|
|
assert(it);
|
2022-12-27 02:31:08 -05:00
|
|
|
if(!it->root || !it->ref.node) return it->seen = 0, 0;
|
|
|
|
if(!it->root->node || it->root->height == UINT_MAX)
|
|
|
|
return it->ref.node = 0, 0; /* Concurrent modification? */
|
|
|
|
prd = it->ref; /* Shorten keystrokes and work with a copy. */
|
|
|
|
if(prd.idx > prd.node->size) prd.idx = prd.node->size; /* Clip. */
|
|
|
|
if(!it->seen && prd.idx) { prd.idx--; goto predecessor; }
|
|
|
|
while(prd.height) prd.height--,
|
|
|
|
prd.node = PB_(as_branch)(prd.node)->child[prd.idx],
|
|
|
|
prd.idx = prd.node->size;
|
|
|
|
if(prd.idx) { prd.idx--; goto predecessor; } /* Likely. */
|
|
|
|
{ /* Re-descend; pick the minimum height node that has a previous key. */
|
|
|
|
struct PB_(ref) prev;
|
|
|
|
struct PB_(tree) tree = *it->root;
|
|
|
|
unsigned a0;
|
|
|
|
const PB_(key) x = prd.node->key[0]; /* Target. */
|
|
|
|
for(prev.node = 0; tree.height;
|
|
|
|
tree.node = PB_(as_branch)(tree.node)->child[a0], tree.height--) {
|
|
|
|
unsigned a1 = tree.node->size;
|
|
|
|
a0 = 0;
|
|
|
|
while(a0 < a1) {
|
|
|
|
const unsigned m = (a0 + a1) / 2;
|
|
|
|
if(B_(compare)(x, tree.node->key[m]) > 0) a0 = m + 1;
|
|
|
|
else a1 = m;
|
|
|
|
}
|
|
|
|
if(a0) prev.node = tree.node, prev.height = tree.height,
|
|
|
|
prev.idx = a0 - 1;
|
|
|
|
}
|
|
|
|
if(!prev.node) return it->seen = 0, 0; /* Off left. */
|
|
|
|
prd = prev;
|
|
|
|
} /* Jumped nodes. */
|
|
|
|
predecessor:
|
|
|
|
it->seen = 1;
|
|
|
|
it->ref = prd;
|
|
|
|
if(v) *v = &it->ref;
|
|
|
|
return 1;
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
/* Want to find slightly different things; code re-use is bad. Confusing.
|
|
|
|
This is the lower-bound. */
|
2022-07-06 13:02:28 -04:00
|
|
|
#define TREE_FORTREE(i) i.node = tree->node, i.height = tree->height; ; \
|
2022-09-08 01:13:56 -04:00
|
|
|
i.node = PB_(as_branch_c)(i.node)->child[i.idx], i.height--
|
2022-07-06 13:02:28 -04:00
|
|
|
#define TREE_START(i) unsigned hi = i.node->size; i.idx = 0;
|
2022-09-08 01:13:56 -04:00
|
|
|
#define TREE_FORNODE(i) do { \
|
2022-07-06 13:02:28 -04:00
|
|
|
const unsigned m = (i.idx + hi) / 2; \
|
2022-12-27 02:31:08 -05:00
|
|
|
if(B_(compare)(key, i.node->key[m]) > 0) i.idx = m + 1; \
|
2022-07-06 13:02:28 -04:00
|
|
|
else hi = m; \
|
|
|
|
} while(i.idx < hi);
|
2022-12-27 02:31:08 -05:00
|
|
|
#define TREE_FLIPPED(i) B_(compare)(i.node->key[i.idx], key) <= 0
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Finds `key` in `lo` one node at a time. */
|
2022-05-28 02:09:38 -04:00
|
|
|
static void PB_(find_idx)(struct PB_(ref) *const lo, const PB_(key) key) {
|
2022-07-06 13:02:28 -04:00
|
|
|
TREE_START((*lo))
|
2022-09-08 01:13:56 -04:00
|
|
|
if(!lo) return;
|
|
|
|
TREE_FORNODE((*lo))
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Finds lower-bound of `key` in non-empty `tree`, or, if `key` is greater
|
|
|
|
than all `tree`, one off the end. */
|
2022-07-06 13:02:28 -04:00
|
|
|
static struct PB_(ref) PB_(lower_r)(struct PB_(tree) *const tree,
|
|
|
|
const PB_(key) key) {
|
|
|
|
struct PB_(ref) i, lo = { 0, 0, 0 };
|
|
|
|
for(TREE_FORTREE(i)) {
|
|
|
|
TREE_START(i)
|
2022-09-08 01:13:56 -04:00
|
|
|
if(!hi) continue;
|
|
|
|
TREE_FORNODE(i)
|
2022-07-06 13:02:28 -04:00
|
|
|
if(i.idx < i.node->size) {
|
|
|
|
lo = i;
|
2022-09-08 01:13:56 -04:00
|
|
|
if(TREE_FLIPPED(i)) break; /* Multi-keys go here. */
|
|
|
|
}
|
|
|
|
if(!i.height) {
|
|
|
|
if(!lo.node) lo = i; /* Want one-off-end if last. */
|
|
|
|
break;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return lo;
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** @return Lower bound of `x` in `tree`. @order \O(\log |`tree`|) */
|
|
|
|
static struct PB_(ref) PB_(lower)(struct PB_(tree) tree, const PB_(key) x) {
|
|
|
|
if(!tree.node || tree.height == UINT_MAX) {
|
|
|
|
struct PB_(ref) ref; ref.node = 0; return ref;
|
|
|
|
} else {
|
|
|
|
return PB_(lower_r)(&tree, x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** Finds an exact `key` in non-empty `tree`. */
|
|
|
|
static struct PB_(ref) PB_(find)(const struct PB_(tree) *const tree,
|
|
|
|
const PB_(key) key) {
|
|
|
|
struct PB_(ref) i;
|
|
|
|
for(TREE_FORTREE(i)) {
|
|
|
|
TREE_START(i)
|
|
|
|
if(!hi) continue;
|
|
|
|
TREE_FORNODE(i)
|
|
|
|
if(i.idx < i.node->size && TREE_FLIPPED(i)) break;
|
|
|
|
if(!i.height) { i.node = 0; return i; }
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
/** Finds lower-bound of `key` in non-empty `tree` while counting the
|
|
|
|
non-filled `hole` and `is_equal`. */
|
2022-07-06 13:02:28 -04:00
|
|
|
static struct PB_(ref) PB_(lookup_insert)(struct PB_(tree) *const tree,
|
|
|
|
const PB_(key) key, struct PB_(ref) *const hole, int *const is_equal) {
|
2022-05-28 02:09:38 -04:00
|
|
|
struct PB_(ref) lo;
|
2022-07-06 13:02:28 -04:00
|
|
|
hole->node = 0;
|
|
|
|
for(TREE_FORTREE(lo)) {
|
|
|
|
TREE_START(lo)
|
|
|
|
if(hi < TREE_MAX) *hole = lo;
|
2022-09-08 01:13:56 -04:00
|
|
|
if(!hi) continue;
|
|
|
|
TREE_FORNODE(lo)
|
2022-07-06 13:02:28 -04:00
|
|
|
if(lo.node->size < TREE_MAX) hole->idx = lo.idx;
|
|
|
|
if(lo.idx < lo.node->size && TREE_FLIPPED(lo)) { *is_equal = 1; break; }
|
|
|
|
if(!lo.height) break;
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
return lo;
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Finds exact `key` in non-empty `tree`. If `node` is found, temporarily, the
|
|
|
|
nodes that have `TREE_MIN` keys have
|
|
|
|
`as_branch(node).child[TREE_MAX] = parent` or, for leaves, `leaf_parent`,
|
|
|
|
which must be set. (Patently terrible for running concurrently; hack, would be
|
|
|
|
nice to go down tree maybe.) */
|
2022-07-06 13:02:28 -04:00
|
|
|
static struct PB_(ref) PB_(lookup_remove)(struct PB_(tree) *const tree,
|
2022-09-08 01:13:56 -04:00
|
|
|
const PB_(key) key, struct PB_(node) **leaf_parent) {
|
|
|
|
struct PB_(node) *parent = 0;
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(ref) lo;
|
|
|
|
for(TREE_FORTREE(lo)) {
|
|
|
|
TREE_START(lo)
|
2022-09-08 01:13:56 -04:00
|
|
|
/* Cannot delete bulk add. */
|
|
|
|
if(parent && hi < TREE_MIN || !parent && !hi) { lo.node = 0; break; }
|
|
|
|
if(hi <= TREE_MIN) { /* Remember the parent temporarily. */
|
|
|
|
if(lo.height) PB_(as_branch)(lo.node)->child[TREE_MAX] = parent;
|
|
|
|
else *leaf_parent = parent;
|
|
|
|
}
|
|
|
|
TREE_FORNODE(lo)
|
2022-07-06 13:02:28 -04:00
|
|
|
if(lo.idx < lo.node->size && TREE_FLIPPED(lo)) break;
|
|
|
|
if(!lo.height) { lo.node = 0; break; } /* Was not in. */
|
2022-09-08 01:13:56 -04:00
|
|
|
parent = lo.node;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
|
|
|
return lo;
|
|
|
|
}
|
|
|
|
#undef TREE_FORTREE
|
|
|
|
#undef TREE_START
|
|
|
|
#undef TREE_FORNODE
|
|
|
|
#undef TREE_FLIPPED
|
2022-05-28 02:09:38 -04:00
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Zeroed data (not all-bits-zero) is initialized. @return An idle tree.
|
|
|
|
@order \Theta(1) @allow */
|
|
|
|
static struct B_(tree) B_(tree)(void) {
|
|
|
|
struct B_(tree) tree;
|
|
|
|
tree.root.node = 0; tree.root.height = 0;
|
|
|
|
return tree;
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Private: frees non-empty `tree` and it's children recursively, but doesn't
|
|
|
|
put it to idle or clear pointers.
|
|
|
|
@param[keep] Keep one leaf if non-null. Set to null before. */
|
2022-07-06 13:02:28 -04:00
|
|
|
static void PB_(clear_r)(struct PB_(tree) tree, struct PB_(node) **const keep) {
|
|
|
|
assert(tree.node);
|
|
|
|
if(!tree.height) {
|
|
|
|
if(keep && !*keep) *keep = tree.node;
|
|
|
|
else free(tree.node);
|
2022-05-28 02:09:38 -04:00
|
|
|
} else {
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(tree) child;
|
2022-05-28 02:09:38 -04:00
|
|
|
unsigned i;
|
2022-07-06 13:02:28 -04:00
|
|
|
child.height = tree.height - 1;
|
|
|
|
for(i = 0; i <= tree.node->size; i++)
|
2022-09-08 01:13:56 -04:00
|
|
|
child.node = PB_(as_branch)(tree.node)->child[i],
|
2022-07-06 13:02:28 -04:00
|
|
|
PB_(clear_r)(child, keep);
|
2022-09-08 01:13:56 -04:00
|
|
|
free(PB_(as_branch)(tree.node));
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Private: `tree` can be null. */
|
2022-07-06 13:02:28 -04:00
|
|
|
static void PB_(clear)(struct B_(tree) *tree) {
|
|
|
|
struct PB_(node) *one = 0;
|
|
|
|
/* Already not there/idle/empty. */
|
|
|
|
if(!tree || !tree->root.node || tree->root.height == UINT_MAX) return;
|
|
|
|
PB_(clear_r)(tree->root, &one), assert(one);
|
|
|
|
/* This is a special state where the tree has one leaf, but it is empty.
|
2022-09-08 01:13:56 -04:00
|
|
|
This state exists because it gives hysteresis to 0 -- 1 transition because
|
|
|
|
we have no advanced memory management. */
|
2022-07-06 13:02:28 -04:00
|
|
|
tree->root.node = one;
|
|
|
|
tree->root.height = UINT_MAX;
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Returns an initialized `tree` to idle, `tree` can be null.
|
|
|
|
@order \O(|`tree`|) @allow */
|
2022-05-28 02:09:38 -04:00
|
|
|
static void B_(tree_)(struct B_(tree) *const tree) {
|
|
|
|
if(!tree) return; /* Null. */
|
|
|
|
if(!tree->root.node) { /* Idle. */
|
|
|
|
assert(!tree->root.height);
|
|
|
|
} else if(tree->root.height == UINT_MAX) { /* Empty. */
|
2022-07-06 13:02:28 -04:00
|
|
|
assert(tree->root.node), free(tree->root.node);
|
2022-05-28 02:09:38 -04:00
|
|
|
} else {
|
|
|
|
PB_(clear_r)(tree->root, 0);
|
|
|
|
}
|
|
|
|
*tree = B_(tree)();
|
|
|
|
}
|
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Clears `tree`, which can be null, idle, empty, or full. If it is empty or
|
|
|
|
full, it remains active. @order \O(|`tree`|) @allow */
|
|
|
|
static void B_(tree_clear)(struct B_(tree) *const tree) { PB_(clear)(tree); }
|
|
|
|
|
|
|
|
/** Private: counts a sub-tree, `tree`. */
|
|
|
|
static size_t PB_(count_r)(const struct PB_(tree) tree) {
|
|
|
|
size_t c = tree.node->size;
|
|
|
|
if(tree.height) {
|
|
|
|
const struct PB_(branch) *const branch = PB_(as_branch)(tree.node);
|
|
|
|
struct PB_(tree) sub;
|
|
|
|
size_t i;
|
|
|
|
sub.height = tree.height - 1;
|
|
|
|
for(i = 0; i <= tree.node->size; i++) {
|
|
|
|
sub.node = branch->child[i];
|
|
|
|
c += PB_(count_r)(sub);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
/** Counts all the keys on `tree`, which can be null.
|
|
|
|
@order \O(|`tree`|) @allow */
|
|
|
|
static size_t B_(tree_count)(const struct B_(tree) *const tree) {
|
|
|
|
return tree && tree->root.height != UINT_MAX
|
|
|
|
? PB_(count_r)(tree->root) : 0;
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
/** @return Is `x` in `tree`? @order \O(\log |`tree`|) @allow */
|
|
|
|
static int B_(tree_contains)(const struct B_(tree) *const tree,
|
|
|
|
const PB_(key) x) {
|
|
|
|
return tree && tree->root.node && tree->root.height != UINT_MAX
|
|
|
|
&& PB_(find)(&tree->root, x).node ? 1 : 0;
|
|
|
|
}
|
|
|
|
/* fixme: entry <B>tree_query -- there is no functionality that returns the
|
|
|
|
key. */
|
|
|
|
|
|
|
|
/** @return Get the value of `key` in `tree`, or if no key, `default_value`.
|
|
|
|
The map type is `TREE_VALUE` and the set type is `TREE_KEY`.
|
|
|
|
@order \O(\log |`tree`|) @allow */
|
|
|
|
static PB_(value) B_(tree_get_or)(const struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key, const PB_(value) default_value) {
|
|
|
|
struct PB_(ref) ref;
|
|
|
|
return tree && tree->root.node && tree->root.height != UINT_MAX
|
|
|
|
&& (ref = PB_(find)(&tree->root, key)).node
|
|
|
|
? *PB_(ref_to_valuep)(ref) : default_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** For example, `tree = { 10 }`, `x = 5 -> 10`, `x = 10 -> 10`,
|
|
|
|
`x = 11 -> null`. (There is no upper value.)
|
|
|
|
@return Lower-bound value match for `key` in `tree` or `default_value` if
|
|
|
|
`key` is greater than all in `tree`. The map type is `TREE_VALUE` and the set
|
|
|
|
type is `TREE_KEY`. @order \O(\log |`tree`|) @allow */
|
|
|
|
static PB_(value) B_(tree_at_or)(const struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key, const PB_(value) default_value) {
|
|
|
|
struct PB_(ref) ref;
|
|
|
|
return tree && (ref = PB_(lower)(tree->root, key)).node
|
|
|
|
&& ref.idx < ref.node->size ? *PB_(ref_to_valuep)(ref) : default_value;
|
|
|
|
}
|
2022-05-28 02:09:38 -04:00
|
|
|
|
|
|
|
#ifdef TREE_VALUE /* <!-- map */
|
|
|
|
/** Packs `key` on the right side of `tree` without doing the usual
|
2022-07-06 13:02:28 -04:00
|
|
|
restructuring. All other topology modification functions should be avoided
|
|
|
|
until followed by <fn:<B>tree_bulk_finish>.
|
2022-05-28 02:09:38 -04:00
|
|
|
@param[value] A pointer to the key's value which is set by the function on
|
|
|
|
returning true. A null pointer in this parameter causes the value to go
|
|
|
|
uninitialized. This parameter is not there if one didn't specify `TREE_VALUE`.
|
|
|
|
@return One of <tag:tree_result>: `TREE_ERROR` and `errno` will be set,
|
2022-09-08 01:13:56 -04:00
|
|
|
`TREE_PRESENT` if the key is already (the highest) in the tree, and
|
2022-12-27 02:31:08 -05:00
|
|
|
`TREE_ABSENT`, added, the `value` (if applicable) is uninitialized.
|
2022-09-08 01:13:56 -04:00
|
|
|
@throws[EDOM] `x` is smaller than the largest key in `tree`. @throws[malloc]
|
|
|
|
@order \O(\log |`tree`|) @allow */
|
2022-05-28 02:09:38 -04:00
|
|
|
static enum tree_result B_(tree_bulk_add)(struct B_(tree) *const tree,
|
2022-09-08 01:13:56 -04:00
|
|
|
PB_(key) key, PB_(value) **const value) {
|
2022-05-28 02:09:38 -04:00
|
|
|
#else /* map --><!-- set */
|
|
|
|
static enum tree_result B_(tree_bulk_add)(struct B_(tree) *const tree,
|
2022-09-08 01:13:56 -04:00
|
|
|
PB_(key) key) {
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
|
|
|
struct PB_(node) *node = 0, *head = 0; /* The original and new. */
|
|
|
|
assert(tree);
|
|
|
|
if(!tree->root.node) { /* Idle tree. */
|
|
|
|
assert(!tree->root.height);
|
|
|
|
if(!(node = malloc(sizeof *node))) goto catch;
|
|
|
|
node->size = 0;
|
|
|
|
tree->root.node = node;
|
|
|
|
} else if(tree->root.height == UINT_MAX) { /* Empty tree. */
|
2022-09-08 01:13:56 -04:00
|
|
|
node = tree->root.node;
|
2022-05-28 02:09:38 -04:00
|
|
|
tree->root.height = 0;
|
2022-09-08 01:13:56 -04:00
|
|
|
node->size = 0;
|
2022-05-28 02:09:38 -04:00
|
|
|
} else {
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(tree) unfull = { 0, 0 };
|
2022-05-28 02:09:38 -04:00
|
|
|
unsigned new_nodes, n; /* Count new nodes. */
|
|
|
|
struct PB_(node) *tail = 0, *last = 0;
|
|
|
|
struct PB_(branch) *pretail = 0;
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(tree) scout;
|
2022-09-08 01:13:56 -04:00
|
|
|
PB_(key) max;
|
|
|
|
/* Right side bottom: `last` node with any keys, `unfull` not full. */
|
|
|
|
for(scout = tree->root; ; scout.node = PB_(as_branch)(scout.node)
|
2022-05-28 02:09:38 -04:00
|
|
|
->child[scout.node->size], scout.height--) {
|
|
|
|
if(scout.node->size < TREE_MAX) unfull = scout;
|
|
|
|
if(scout.node->size) last = scout.node;
|
|
|
|
if(!scout.height) break;
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
assert(last), max = last->key[last->size - 1];
|
2022-12-27 02:31:08 -05:00
|
|
|
if(B_(compare)(max, key) > 0) return errno = EDOM, TREE_ERROR;
|
|
|
|
if(B_(compare)(key, max) <= 0) {
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
if(value) {
|
|
|
|
struct PB_(ref) max_ref;
|
|
|
|
max_ref.node = last, max_ref.idx = last->size - 1;
|
|
|
|
*value = PB_(ref_to_valuep)(max_ref);
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
#endif
|
2022-09-08 01:13:56 -04:00
|
|
|
return TREE_PRESENT;
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* One leaf, and the rest branches. */
|
|
|
|
new_nodes = n = unfull.node ? unfull.height : tree->root.height + 2;
|
|
|
|
if(!n) {
|
|
|
|
node = unfull.node;
|
|
|
|
} else {
|
|
|
|
if(!(node = tail = malloc(sizeof *tail))) goto catch;
|
|
|
|
tail->size = 0;
|
|
|
|
while(--n) {
|
|
|
|
struct PB_(branch) *b;
|
|
|
|
if(!(b = malloc(sizeof *b))) goto catch;
|
|
|
|
b->base.size = 0;
|
|
|
|
if(!head) b->child[0] = 0, pretail = b; /* First loop. */
|
|
|
|
else b->child[0] = head; /* Not first loop. */
|
|
|
|
head = &b->base;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Post-error; modify the original as needed. */
|
|
|
|
if(pretail) pretail->child[0] = tail;
|
|
|
|
else head = node;
|
|
|
|
if(!unfull.node) { /* Add tree to head. */
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *const branch = PB_(as_branch)(head);
|
2022-05-28 02:09:38 -04:00
|
|
|
assert(new_nodes > 1);
|
|
|
|
branch->child[1] = branch->child[0];
|
|
|
|
branch->child[0] = tree->root.node;
|
|
|
|
node = tree->root.node = head, tree->root.height++;
|
|
|
|
} else if(unfull.height) { /* Add head to tree. */
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *const branch
|
|
|
|
= PB_(as_branch)(node = unfull.node);
|
2022-05-28 02:09:38 -04:00
|
|
|
assert(new_nodes);
|
|
|
|
branch->child[branch->base.size + 1] = head;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(node && node->size < TREE_MAX);
|
|
|
|
node->key[node->size] = key;
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
if(value) {
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(ref) max_ref;
|
|
|
|
max_ref.node = node, max_ref.idx = node->size;
|
|
|
|
*value = PB_(ref_to_valuep)(max_ref);
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
node->size++;
|
2022-12-27 02:31:08 -05:00
|
|
|
return TREE_ABSENT;
|
2022-09-08 01:13:56 -04:00
|
|
|
catch: /* Didn't work. Reset. */
|
|
|
|
free(node);
|
2022-07-06 13:02:28 -04:00
|
|
|
while(head) {
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(node) *const next = PB_(as_branch)(head)->child[0];
|
2022-07-06 13:02:28 -04:00
|
|
|
free(head);
|
2022-05-28 02:09:38 -04:00
|
|
|
head = next;
|
|
|
|
}
|
|
|
|
if(!errno) errno = ERANGE;
|
|
|
|
return TREE_ERROR;
|
2022-09-08 01:13:56 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
#else
|
|
|
|
}
|
|
|
|
#endif
|
2022-05-28 02:09:38 -04:00
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Distributes `tree` (can be null) on the right side so that, after a series
|
|
|
|
of <fn:<B>tree_bulk_add>, it will be consistent with the minimum number of
|
|
|
|
keys in a node. @return The re-distribution was a success and all nodes are
|
|
|
|
within rules. (Only when intermixing bulk and regular operations, can the
|
|
|
|
function return false.) @order \O(\log |`tree`|) @allow */
|
2022-05-28 02:09:38 -04:00
|
|
|
static int B_(tree_bulk_finish)(struct B_(tree) *const tree) {
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(tree) s;
|
2022-05-28 02:09:38 -04:00
|
|
|
struct PB_(node) *right;
|
|
|
|
if(!tree || !tree->root.node || tree->root.height == UINT_MAX) return 1;
|
|
|
|
for(s = tree->root; s.height; s.node = right, s.height--) {
|
|
|
|
unsigned distribute, right_want, right_move, take_sibling;
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *parent = PB_(as_branch)(s.node);
|
2022-05-28 02:09:38 -04:00
|
|
|
struct PB_(node) *sibling = (assert(parent->base.size),
|
|
|
|
parent->child[parent->base.size - 1]);
|
|
|
|
right = parent->child[parent->base.size];
|
2022-09-08 01:13:56 -04:00
|
|
|
/* Should this be increased to max/2 instead of max/3 to make a more
|
|
|
|
balanced tree? Otoh, why? */
|
2022-05-28 02:09:38 -04:00
|
|
|
if(TREE_MIN <= right->size) continue; /* Has enough. */
|
|
|
|
distribute = sibling->size + right->size;
|
2022-07-06 13:02:28 -04:00
|
|
|
/* Should have at least `TREE_MAX` on left. */
|
2022-05-28 02:09:38 -04:00
|
|
|
if(distribute < 2 * TREE_MIN) return 0;
|
|
|
|
right_want = distribute / 2;
|
|
|
|
right_move = right_want - right->size;
|
|
|
|
take_sibling = right_move - 1;
|
|
|
|
/* Either the right has met the properties of a B-tree node, (covered
|
|
|
|
above,) or the left sibling is full from bulk-loading (relaxed.) */
|
|
|
|
assert(right->size < right_want && right_want >= TREE_MIN
|
|
|
|
&& sibling->size - take_sibling >= TREE_MIN + 1);
|
|
|
|
/* Move the right node to accept more keys. */
|
|
|
|
memmove(right->key + right_move, right->key,
|
|
|
|
sizeof *right->key * right->size);
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
memmove(right->value + right_move, right->value,
|
|
|
|
sizeof *right->value * right->size);
|
|
|
|
#endif
|
|
|
|
if(s.height > 1) { /* (Parent height.) */
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *rbranch = PB_(as_branch)(right),
|
|
|
|
*sbranch = PB_(as_branch)(sibling);
|
2022-05-28 02:09:38 -04:00
|
|
|
memmove(rbranch->child + right_move, rbranch->child,
|
|
|
|
sizeof *rbranch->child * (right->size + 1));
|
|
|
|
memcpy(rbranch->child, sbranch->child + sibling->size + 1
|
|
|
|
- right_move, sizeof *sbranch->child * right_move);
|
|
|
|
}
|
|
|
|
right->size += right_move;
|
|
|
|
/* Move one node from the parent. */
|
|
|
|
memcpy(right->key + take_sibling,
|
|
|
|
parent->base.key + parent->base.size - 1, sizeof *right->key);
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
memcpy(right->value + take_sibling,
|
|
|
|
parent->base.value + parent->base.size - 1, sizeof *right->value);
|
|
|
|
#endif
|
|
|
|
/* Move the others from the sibling. */
|
|
|
|
memcpy(right->key, sibling->key + sibling->size - take_sibling,
|
|
|
|
sizeof *right->key * take_sibling);
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
memcpy(right->value, sibling->value + sibling->size - take_sibling,
|
|
|
|
sizeof *right->value * take_sibling);
|
|
|
|
#endif
|
|
|
|
sibling->size -= take_sibling;
|
|
|
|
/* Sibling's key is now the parent's. */
|
|
|
|
memcpy(parent->base.key + parent->base.size - 1,
|
|
|
|
sibling->key + sibling->size - 1, sizeof *right->key);
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
memcpy(parent->base.value + parent->base.size - 1,
|
|
|
|
sibling->value + sibling->size - 1, sizeof *right->value);
|
|
|
|
#endif
|
|
|
|
sibling->size--;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TREE_VALUE /* <!-- map */
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Adds or updates `key` in `root`. If not-null, `eject` will be the replaced
|
|
|
|
key, otherwise don't replace. If `value` is not-null, sticks the associated
|
|
|
|
value. */
|
|
|
|
static enum tree_result PB_(update)(struct PB_(tree) *const root,
|
|
|
|
PB_(key) key, PB_(key) *const eject, PB_(value) **const value) {
|
2022-05-28 02:09:38 -04:00
|
|
|
#else /* map --><!-- set */
|
2022-09-08 01:13:56 -04:00
|
|
|
static enum tree_result PB_(update)(struct PB_(tree) *const root,
|
|
|
|
PB_(key) key, PB_(key) *const eject) {
|
2022-07-06 13:02:28 -04:00
|
|
|
#endif /* set --> */
|
|
|
|
struct PB_(node) *new_head = 0;
|
2022-11-02 00:06:43 -04:00
|
|
|
struct PB_(ref) add, hole, iterator;
|
2022-09-08 01:13:56 -04:00
|
|
|
assert(root);
|
|
|
|
if(!(add.node = root->node)) goto idle;
|
|
|
|
else if(root->height == UINT_MAX) goto empty;
|
2022-07-06 13:02:28 -04:00
|
|
|
goto descend;
|
2022-05-28 02:09:38 -04:00
|
|
|
idle: /* No reserved memory. */
|
2022-09-08 01:13:56 -04:00
|
|
|
assert(!add.node && !root->height);
|
2022-05-28 02:09:38 -04:00
|
|
|
if(!(add.node = malloc(sizeof *add.node))) goto catch;
|
2022-09-08 01:13:56 -04:00
|
|
|
root->node = add.node;
|
|
|
|
root->height = UINT_MAX;
|
2022-05-28 02:09:38 -04:00
|
|
|
goto empty;
|
|
|
|
empty: /* Reserved dynamic memory, but tree is empty. */
|
2022-09-08 01:13:56 -04:00
|
|
|
assert(add.node && root->height == UINT_MAX);
|
|
|
|
add.height = root->height = 0;
|
2022-05-28 02:09:38 -04:00
|
|
|
add.node->size = 0;
|
|
|
|
add.idx = 0;
|
|
|
|
goto insert;
|
2022-07-06 13:02:28 -04:00
|
|
|
descend: /* Record last node that has space. */
|
|
|
|
{
|
|
|
|
int is_equal = 0;
|
2022-09-08 01:13:56 -04:00
|
|
|
add = PB_(lookup_insert)(root, key, &hole, &is_equal);
|
2022-07-06 13:02:28 -04:00
|
|
|
if(is_equal) {
|
2022-09-08 01:13:56 -04:00
|
|
|
if(eject) {
|
|
|
|
*eject = add.node->key[add.idx];
|
|
|
|
add.node->key[add.idx] = key;
|
|
|
|
}
|
2022-07-06 13:02:28 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
if(value) *value = PB_(ref_to_valuep)(add);
|
2022-07-06 13:02:28 -04:00
|
|
|
#endif
|
2022-09-08 01:13:56 -04:00
|
|
|
return TREE_PRESENT;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(hole.node == add.node) goto insert; else goto grow;
|
|
|
|
insert: /* Leaf has space to spare; usually end up here. */
|
2022-09-08 01:13:56 -04:00
|
|
|
assert(add.node && add.idx <= add.node->size && add.node->size < TREE_MAX);
|
2022-07-06 13:02:28 -04:00
|
|
|
memmove(add.node->key + add.idx + 1, add.node->key + add.idx,
|
|
|
|
sizeof *add.node->key * (add.node->size - add.idx));
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
memmove(add.node->value + add.idx + 1, add.node->value + add.idx,
|
|
|
|
sizeof *add.node->value * (add.node->size - add.idx));
|
|
|
|
#endif
|
|
|
|
add.node->size++;
|
|
|
|
add.node->key[add.idx] = key;
|
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
if(value) *value = PB_(ref_to_valuep)(add);
|
2022-07-06 13:02:28 -04:00
|
|
|
#endif
|
2022-12-27 02:31:08 -05:00
|
|
|
return TREE_ABSENT;
|
2022-07-06 13:02:28 -04:00
|
|
|
grow: /* Leaf is full. */ {
|
2022-09-08 01:13:56 -04:00
|
|
|
unsigned new_no = hole.node ? hole.height : root->height + 2;
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(node) **new_next = &new_head, *new_leaf;
|
|
|
|
struct PB_(branch) *new_branch;
|
|
|
|
assert(new_no);
|
|
|
|
/* Allocate new nodes in succession. */
|
|
|
|
while(new_no != 1) { /* All branches except one. */
|
|
|
|
if(!(new_branch = malloc(sizeof *new_branch))) goto catch;
|
|
|
|
new_branch->base.size = 0;
|
|
|
|
new_branch->child[0] = 0;
|
|
|
|
*new_next = &new_branch->base, new_next = new_branch->child;
|
|
|
|
new_no--;
|
|
|
|
}
|
|
|
|
/* Last point of potential failure; (don't need to have entry in catch.) */
|
|
|
|
if(!(new_leaf = malloc(sizeof *new_leaf))) goto catch;
|
|
|
|
new_leaf->size = 0;
|
|
|
|
*new_next = new_leaf;
|
|
|
|
/* Attach new nodes to the tree. The hole is now an actual hole. */
|
|
|
|
if(hole.node) { /* New nodes are a sub-structure of the tree. */
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *holeb = PB_(as_branch)(hole.node);
|
2022-07-06 13:02:28 -04:00
|
|
|
memmove(hole.node->key + hole.idx + 1, hole.node->key + hole.idx,
|
|
|
|
sizeof *hole.node->key * (hole.node->size - hole.idx));
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
memmove(hole.node->value + hole.idx + 1, hole.node->value + hole.idx,
|
|
|
|
sizeof *hole.node->value * (hole.node->size - hole.idx));
|
|
|
|
#endif
|
|
|
|
memmove(holeb->child + hole.idx + 2, holeb->child + hole.idx + 1,
|
|
|
|
sizeof *holeb->child * (hole.node->size - hole.idx));
|
|
|
|
holeb->child[hole.idx + 1] = new_head;
|
|
|
|
hole.node->size++;
|
|
|
|
} else { /* New nodes raise tree height. */
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *const new_root = PB_(as_branch)(new_head);
|
|
|
|
hole.node = new_head, hole.height = ++root->height, hole.idx = 0;
|
2022-07-06 13:02:28 -04:00
|
|
|
new_head = new_root->child[1] = new_root->child[0];
|
2022-09-08 01:13:56 -04:00
|
|
|
new_root->child[0] = root->node, root->node = hole.node;
|
2022-07-06 13:02:28 -04:00
|
|
|
hole.node->size = 1;
|
|
|
|
}
|
2022-11-02 00:06:43 -04:00
|
|
|
iterator = hole; /* Go down; (as opposed to doing it on paper.) */
|
2022-05-28 02:09:38 -04:00
|
|
|
goto split;
|
2022-07-06 13:02:28 -04:00
|
|
|
} split: { /* Split between the new and existing nodes. */
|
|
|
|
struct PB_(node) *sibling;
|
2022-11-02 00:06:43 -04:00
|
|
|
assert(iterator.node && iterator.node->size && iterator.height);
|
2022-07-06 13:02:28 -04:00
|
|
|
sibling = new_head;
|
2022-09-08 01:13:56 -04:00
|
|
|
/*PB_(graph_usual)(tree, "graph/work.gv");*/
|
2022-07-06 13:02:28 -04:00
|
|
|
/* Descend now while split hasn't happened -- easier. */
|
2022-11-02 00:06:43 -04:00
|
|
|
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,
|
2022-07-06 13:02:28 -04:00
|
|
|
sizeof *sibling->key * (TREE_MAX - TREE_SPLIT));
|
|
|
|
#ifdef TREE_VALUE
|
2022-11-02 00:06:43 -04:00
|
|
|
memcpy(sibling->value, iterator.node->value + TREE_SPLIT,
|
2022-07-06 13:02:28 -04:00
|
|
|
sizeof *sibling->value * (TREE_MAX - TREE_SPLIT));
|
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
hole.node->key[hole.idx] = iterator.node->key[TREE_SPLIT - 1];
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-11-02 00:06:43 -04:00
|
|
|
hole.node->value[hole.idx] = iterator.node->value[TREE_SPLIT - 1];
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
memmove(iterator.node->key + iterator.idx + 1,
|
|
|
|
iterator.node->key + iterator.idx,
|
|
|
|
sizeof *iterator.node->key * (TREE_SPLIT - 1 - iterator.idx));
|
2022-07-06 13:02:28 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-11-02 00:06:43 -04:00
|
|
|
memmove(iterator.node->value + iterator.idx + 1,
|
|
|
|
iterator.node->value + iterator.idx,
|
|
|
|
sizeof *iterator.node->value * (TREE_SPLIT - 1 - iterator.idx));
|
2022-07-06 13:02:28 -04:00
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
if(iterator.height) {
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
|
2022-09-08 01:13:56 -04:00
|
|
|
*const sb = PB_(as_branch)(sibling);
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(node) *temp = sb->child[0];
|
|
|
|
memcpy(sb->child, cb->child + TREE_SPLIT,
|
|
|
|
sizeof *cb->child * (TREE_MAX - TREE_SPLIT + 1));
|
2022-11-02 00:06:43 -04:00
|
|
|
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;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
2022-11-02 00:06:43 -04:00
|
|
|
hole = iterator;
|
|
|
|
} else if(iterator.idx > TREE_SPLIT) { /* Descend hole to `sibling`. */
|
|
|
|
hole.node->key[hole.idx] = iterator.node->key[TREE_SPLIT];
|
2022-07-06 13:02:28 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-11-02 00:06:43 -04:00
|
|
|
hole.node->value[hole.idx] = iterator.node->value[TREE_SPLIT];
|
2022-07-06 13:02:28 -04:00
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
hole.node = sibling, hole.height = iterator.height,
|
|
|
|
hole.idx = iterator.idx - TREE_SPLIT - 1;
|
|
|
|
memcpy(sibling->key, iterator.node->key + TREE_SPLIT + 1,
|
2022-07-06 13:02:28 -04:00
|
|
|
sizeof *sibling->key * hole.idx);
|
2022-11-02 00:06:43 -04:00
|
|
|
memcpy(sibling->key + hole.idx + 1, iterator.node->key + iterator.idx,
|
|
|
|
sizeof *sibling->key * (TREE_MAX - iterator.idx));
|
2022-07-06 13:02:28 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-11-02 00:06:43 -04:00
|
|
|
memcpy(sibling->value, iterator.node->value + TREE_SPLIT + 1,
|
2022-07-06 13:02:28 -04:00
|
|
|
sizeof *sibling->value * hole.idx);
|
2022-12-27 02:31:08 -05:00
|
|
|
memcpy(sibling->value + hole.idx + 1, iterator.node->value
|
|
|
|
+ iterator.idx, sizeof *sibling->value * (TREE_MAX - iterator.idx));
|
2022-07-06 13:02:28 -04:00
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
if(iterator.height) {
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
|
2022-09-08 01:13:56 -04:00
|
|
|
*const sb = PB_(as_branch)(sibling);
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(node) *temp = sb->child[0];
|
|
|
|
memcpy(sb->child, cb->child + TREE_SPLIT + 1,
|
|
|
|
sizeof *cb->child * (hole.idx + 1));
|
2022-11-02 00:06:43 -04:00
|
|
|
memcpy(sb->child + hole.idx + 2, cb->child + iterator.idx + 1,
|
|
|
|
sizeof *cb->child * (TREE_MAX - iterator.idx));
|
2022-07-06 13:02:28 -04:00
|
|
|
sb->child[hole.idx + 1] = temp;
|
|
|
|
}
|
|
|
|
} else { /* Equal split: leave the hole where it is. */
|
2022-11-02 00:06:43 -04:00
|
|
|
memcpy(sibling->key, iterator.node->key + TREE_SPLIT,
|
2022-05-28 02:09:38 -04:00
|
|
|
sizeof *sibling->key * (TREE_MAX - TREE_SPLIT));
|
|
|
|
#ifdef TREE_VALUE
|
2022-11-02 00:06:43 -04:00
|
|
|
memcpy(sibling->value, iterator.node->value + TREE_SPLIT,
|
2022-05-28 02:09:38 -04:00
|
|
|
sizeof *sibling->value * (TREE_MAX - TREE_SPLIT));
|
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
if(iterator.height) {
|
|
|
|
struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
|
2022-09-08 01:13:56 -04:00
|
|
|
*const sb = PB_(as_branch)(sibling);
|
2022-07-06 13:02:28 -04:00
|
|
|
memcpy(sb->child + 1, cb->child + TREE_SPLIT + 1,
|
|
|
|
sizeof *cb->child * (TREE_MAX - TREE_SPLIT));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Divide `TREE_MAX + 1` into two trees. */
|
2022-11-02 00:06:43 -04:00
|
|
|
iterator.node->size = TREE_SPLIT, sibling->size = TREE_MAX - TREE_SPLIT;
|
|
|
|
if(iterator.height) goto split; /* Loop max `\log_{TREE_MIN} size`. */
|
2022-07-06 13:02:28 -04:00
|
|
|
hole.node->key[hole.idx] = key;
|
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
if(value) *value = PB_(ref_to_valuep)(hole);
|
2022-07-06 13:02:28 -04:00
|
|
|
#endif
|
|
|
|
assert(!new_head);
|
2022-12-27 02:31:08 -05:00
|
|
|
return TREE_ABSENT;
|
2022-09-08 01:13:56 -04:00
|
|
|
} catch: /* Didn't work. Reset. */
|
2022-07-06 13:02:28 -04:00
|
|
|
while(new_head) {
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *const top = PB_(as_branch)(new_head);
|
2022-07-06 13:02:28 -04:00
|
|
|
new_head = top->child[0];
|
|
|
|
free(top);
|
|
|
|
}
|
|
|
|
if(!errno) errno = ERANGE; /* Non-POSIX OSs not mandated to set errno. */
|
|
|
|
return TREE_ERROR;
|
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
}
|
2022-07-06 13:02:28 -04:00
|
|
|
#endif
|
2022-09-08 01:13:56 -04:00
|
|
|
|
|
|
|
#ifdef TREE_VALUE /* <!-- map */
|
|
|
|
/** Adds or gets `key` in `tree`. If `key` is already in `tree`, uses the
|
|
|
|
old value, _vs_ <fn:<B>tree_assign>. (This is only significant in trees with
|
|
|
|
distinguishable keys.)
|
|
|
|
@param[valuep] Only present if `TREE_VALUE` (map) was specified. If this
|
|
|
|
parameter is non-null and a return value other then `TREE_ERROR`, this
|
|
|
|
receives the address of the value associated with the `key`. This pointer is
|
|
|
|
only guaranteed to be valid only while the `tree` doesn't undergo
|
2022-12-27 02:31:08 -05:00
|
|
|
structural changes, (such as calling <fn:<B>tree_try> with `TREE_ABSENT`
|
2022-09-08 01:13:56 -04:00
|
|
|
again.)
|
2022-12-27 02:31:08 -05:00
|
|
|
@return Either `TREE_ERROR` (false) and doesn't touch `tree`, `TREE_ABSENT`
|
2022-09-08 01:13:56 -04:00
|
|
|
and adds a new key with `key`, or `TREE_PRESENT` there was already an existing
|
|
|
|
key. @throws[malloc] @order \Theta(\log |`tree`|) @allow */
|
|
|
|
static enum tree_result B_(tree_try)(struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key, PB_(value) **const valuep)
|
|
|
|
{ return assert(tree), PB_(update)(&tree->root, key, 0, valuep); }
|
|
|
|
#else /* map --><!-- set */
|
|
|
|
/** Adds `key` to `tree` but in a set. */
|
|
|
|
static enum tree_result B_(tree_try)(struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key)
|
|
|
|
{ return assert(tree), PB_(update)(&tree->root, key, 0); }
|
|
|
|
#endif /* set --> */
|
|
|
|
|
|
|
|
#ifdef TREE_VALUE /* <!-- map */
|
|
|
|
/** Adds or updates `key` in `tree`.
|
|
|
|
@param[eject] If this parameter is non-null and a return value of
|
|
|
|
`TREE_PRESENT`, the old key is stored in `eject`, replaced by `key`. A null
|
|
|
|
value indicates that on conflict, the new key yields to the old key, as
|
|
|
|
<fn:<B>tree_try>. This is only significant in trees with distinguishable keys.
|
|
|
|
@param[value] Only present if `TREE_VALUE` (map) was specified. If this
|
|
|
|
parameter is non-null and a return value other then `TREE_ERROR`, this
|
|
|
|
receives the address of the value associated with the key.
|
|
|
|
@return Either `TREE_ERROR` (false,) `errno` is set and doesn't touch `tree`;
|
2022-12-27 02:31:08 -05:00
|
|
|
`TREE_ABSENT`, adds a new key; or `TREE_PRESENT`, there was already an
|
2022-09-08 01:13:56 -04:00
|
|
|
existing key. @throws[malloc] @order \Theta(\log |`tree`|) @allow */
|
|
|
|
static enum tree_result B_(tree_assign)(struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key, PB_(key) *const eject, PB_(value) **const value)
|
|
|
|
{ return assert(tree), PB_(update)(&tree->root, key, eject, value); }
|
|
|
|
#else /* map --><!-- set */
|
|
|
|
/** Replaces `eject` by `key` or adds `key` in `tree`, but in a set. */
|
|
|
|
static enum tree_result B_(tree_assign)(struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key, PB_(key) *const eject)
|
|
|
|
{ return assert(tree), PB_(update)(&tree->root, key, eject); }
|
|
|
|
#endif /* set --> */
|
|
|
|
|
|
|
|
/** Removes `x` from `tree` which must have contents. */
|
|
|
|
static int PB_(remove)(struct PB_(tree) *const tree, const PB_(key) x) {
|
|
|
|
struct PB_(ref) rm, parent /* Only if `key.size <= TREE_MIN`. */;
|
|
|
|
struct PB_(branch) *parentb;
|
|
|
|
struct { struct PB_(node) *less, *more; } sibling;
|
|
|
|
PB_(key) provisional_x = x;
|
|
|
|
parent.node = 0;
|
|
|
|
assert(tree && tree->node && tree->height != UINT_MAX);
|
|
|
|
/* Traverse down the tree until `key`, leaving breadcrumbs for parents of
|
|
|
|
minimum key nodes. */
|
|
|
|
if(!(rm = PB_(lookup_remove)(tree, x, &parent.node)).node) return 0;
|
|
|
|
/* Important when `rm = parent`; `find_idx` later. */
|
|
|
|
parent.height = rm.height + 1;
|
|
|
|
assert(rm.idx < rm.node->size);
|
|
|
|
if(rm.height) goto branch; else goto upward;
|
2022-07-06 13:02:28 -04:00
|
|
|
branch: {
|
2022-09-08 01:13:56 -04:00
|
|
|
struct { struct PB_(ref) leaf; struct PB_(node) *parent; unsigned top; }
|
|
|
|
pred, succ, chosen;
|
|
|
|
assert(rm.height);
|
|
|
|
/* Predecessor leaf. */
|
|
|
|
pred.leaf = rm, pred.top = UINT_MAX;
|
|
|
|
do {
|
|
|
|
struct PB_(node) *const up = pred.leaf.node;
|
|
|
|
pred.leaf.node = PB_(as_branch_c)(pred.leaf.node)->child[pred.leaf.idx];
|
|
|
|
pred.leaf.idx = pred.leaf.node->size;
|
|
|
|
pred.leaf.height--;
|
|
|
|
if(pred.leaf.node->size < TREE_MIN) /* Possible in bulk-add? */
|
|
|
|
{ pred.leaf.node = 0; goto no_pred; }
|
|
|
|
else if(pred.leaf.node->size > TREE_MIN) pred.top = pred.leaf.height;
|
|
|
|
else if(pred.leaf.height)
|
|
|
|
PB_(as_branch)(pred.leaf.node)->child[TREE_MAX] = up;
|
|
|
|
else pred.parent = up;
|
|
|
|
} while(pred.leaf.height);
|
|
|
|
pred.leaf.idx--;
|
|
|
|
no_pred:
|
|
|
|
/* Successor leaf. */
|
|
|
|
succ.leaf = rm, succ.top = UINT_MAX;
|
|
|
|
succ.leaf.idx++;
|
|
|
|
do {
|
|
|
|
struct PB_(node) *const up = succ.leaf.node;
|
|
|
|
succ.leaf.node = PB_(as_branch_c)(succ.leaf.node)->child[succ.leaf.idx];
|
|
|
|
succ.leaf.idx = 0;
|
|
|
|
succ.leaf.height--;
|
|
|
|
if(succ.leaf.node->size < TREE_MIN)
|
|
|
|
{ succ.leaf.node = 0; goto no_succ; }
|
|
|
|
else if(succ.leaf.node->size > TREE_MIN) succ.top = succ.leaf.height;
|
|
|
|
else if(succ.leaf.height)
|
|
|
|
PB_(as_branch)(succ.leaf.node)->child[TREE_MAX] = up;
|
|
|
|
else succ.parent = up;
|
|
|
|
} while(succ.leaf.height);
|
|
|
|
no_succ:
|
|
|
|
/* Choose the predecessor or successor. */
|
|
|
|
if(!pred.leaf.node) {
|
|
|
|
assert(succ.leaf.node);
|
|
|
|
chosen = succ;
|
|
|
|
} else if(!succ.leaf.node) {
|
|
|
|
assert(pred.leaf.node);
|
|
|
|
chosen = pred;
|
|
|
|
} else if(pred.leaf.node->size < succ.leaf.node->size) {
|
|
|
|
chosen = succ;
|
|
|
|
} else if(pred.leaf.node->size > succ.leaf.node->size) {
|
|
|
|
chosen = pred;
|
|
|
|
} else if(pred.top > succ.top) {
|
|
|
|
chosen = succ;
|
|
|
|
} else {
|
|
|
|
chosen = pred;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/* Replace `rm` with the predecessor or the successor leaf. */
|
|
|
|
provisional_x = rm.node->key[rm.idx]
|
|
|
|
= chosen.leaf.node->key[chosen.leaf.idx];
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
rm.node->value[rm.idx] = chosen.leaf.node->value[chosen.leaf.idx];
|
|
|
|
#endif
|
|
|
|
rm = chosen.leaf;
|
|
|
|
if(chosen.leaf.node->size <= TREE_MIN) parent.node = chosen.parent;
|
|
|
|
parent.height = 1;
|
|
|
|
goto upward;
|
|
|
|
} upward: /* The first iteration, this will be a leaf. */
|
|
|
|
assert(rm.node);
|
|
|
|
if(!parent.node) goto space;
|
|
|
|
assert(rm.node->size <= TREE_MIN); /* Condition on `parent.node`. */
|
|
|
|
/* Retrieve forgotten information about the index in parent. (This is not
|
|
|
|
as fast at it could be, but holding parent data in minimum keys allows it
|
|
|
|
to be in place, if a hack. We could go down, but new problems arise.) */
|
|
|
|
PB_(find_idx)(&parent, provisional_x);
|
|
|
|
parentb = PB_(as_branch)(parent.node);
|
|
|
|
assert(parent.idx <= parent.node->size
|
|
|
|
&& parentb->child[parent.idx] == rm.node);
|
|
|
|
/* Sibling edges. */
|
|
|
|
sibling.less = parent.idx ? parentb->child[parent.idx - 1] : 0;
|
|
|
|
sibling.more = parent.idx < parent.node->size
|
|
|
|
? parentb->child[parent.idx + 1] : 0;
|
2022-07-06 13:02:28 -04:00
|
|
|
assert(sibling.less || sibling.more);
|
2022-09-08 01:13:56 -04:00
|
|
|
/* It's not clear which of `{ <, <= }` would be better. */
|
|
|
|
if((sibling.more ? sibling.more->size : 0)
|
|
|
|
> (sibling.less ? sibling.less->size : 0)) goto balance_more;
|
|
|
|
else goto balance_less;
|
|
|
|
balance_less: {
|
|
|
|
const unsigned combined = rm.node->size + sibling.less->size;
|
|
|
|
unsigned promote, more, transfer;
|
|
|
|
assert(parent.idx);
|
|
|
|
if(combined < 2 * TREE_MIN + 1) goto merge_less; /* Don't have enough. */
|
|
|
|
assert(sibling.less->size > TREE_MIN); /* Since `rm.size <= TREE_MIN`. */
|
|
|
|
promote = (combined - 1 + 1) / 2, more = promote + 1;
|
|
|
|
transfer = sibling.less->size - more;
|
|
|
|
assert(transfer < TREE_MAX && rm.node->size <= TREE_MAX - transfer);
|
|
|
|
/* Make way for the keys from the less. */
|
|
|
|
memmove(rm.node->key + rm.idx + 1 + transfer, rm.node->key + rm.idx + 1,
|
|
|
|
sizeof *rm.node->key * (rm.node->size - rm.idx - 1));
|
|
|
|
memmove(rm.node->key + transfer + 1, rm.node->key,
|
|
|
|
sizeof *rm.node->key * rm.idx);
|
|
|
|
rm.node->key[transfer] = parent.node->key[parent.idx - 1];
|
|
|
|
memcpy(rm.node->key, sibling.less->key + more,
|
|
|
|
sizeof *sibling.less->key * transfer);
|
|
|
|
parent.node->key[parent.idx - 1] = sibling.less->key[promote];
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
memmove(rm.node->value + rm.idx + 1 + transfer, rm.node->value + rm.idx + 1,
|
|
|
|
sizeof *rm.node->value * (rm.node->size - rm.idx - 1));
|
|
|
|
memmove(rm.node->value + transfer + 1, rm.node->value,
|
|
|
|
sizeof *rm.node->value * rm.idx);
|
|
|
|
rm.node->value[transfer] = parent.node->value[parent.idx - 1];
|
|
|
|
memcpy(rm.node->value, sibling.less->value + more,
|
|
|
|
sizeof *sibling.less->value * transfer);
|
|
|
|
parent.node->value[parent.idx - 1] = sibling.less->value[promote];
|
|
|
|
#endif
|
|
|
|
if(rm.height) {
|
|
|
|
struct PB_(branch) *const lessb = PB_(as_branch)(sibling.less),
|
|
|
|
*const rmb = PB_(as_branch)(rm.node);
|
|
|
|
unsigned transferb = transfer + 1;
|
|
|
|
/* This is already moved; inefficient. */
|
|
|
|
memmove(rmb->child + transferb, rmb->child,
|
|
|
|
sizeof *rmb->child * (rm.node->size + 1 - 1));
|
|
|
|
memcpy(rmb->child, lessb->child + promote + 1,
|
|
|
|
sizeof *lessb->child * transferb);
|
|
|
|
}
|
|
|
|
rm.node->size += transfer;
|
|
|
|
sibling.less->size = promote;
|
|
|
|
goto end;
|
|
|
|
} balance_more: {
|
|
|
|
const unsigned combined = rm.node->size + sibling.more->size;
|
|
|
|
unsigned promote;
|
|
|
|
assert(rm.node->size);
|
|
|
|
if(combined < 2 * TREE_MIN + 1) goto merge_more; /* Don't have enough. */
|
|
|
|
assert(sibling.more->size > TREE_MIN); /* Since `rm.size <= TREE_MIN`. */
|
|
|
|
promote = (combined - 1) / 2 - rm.node->size; /* In `more`. Could be +1. */
|
|
|
|
assert(promote < TREE_MAX && rm.node->size <= TREE_MAX - promote);
|
|
|
|
/* Delete key. */
|
|
|
|
memmove(rm.node->key + rm.idx, rm.node->key + rm.idx + 1,
|
|
|
|
sizeof *rm.node->key * (rm.node->size - rm.idx - 1));
|
|
|
|
/* Demote into hole. */
|
|
|
|
rm.node->key[rm.node->size - 1] = parent.node->key[parent.idx];
|
|
|
|
/* Transfer some keys from more to child. */
|
|
|
|
memcpy(rm.node->key + rm.node->size, sibling.more->key,
|
|
|
|
sizeof *sibling.more->key * promote);
|
|
|
|
/* Promote one key from more. */
|
|
|
|
parent.node->key[parent.idx] = sibling.more->key[promote];
|
|
|
|
/* Move back in more. */
|
|
|
|
memmove(sibling.more->key, sibling.more->key + promote + 1,
|
|
|
|
sizeof *sibling.more->key * (sibling.more->size - promote - 1));
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
memmove(rm.node->value + rm.idx, rm.node->value + rm.idx + 1,
|
|
|
|
sizeof *rm.node->value * (rm.node->size - rm.idx - 1));
|
|
|
|
rm.node->value[rm.node->size - 1] = parent.node->value[parent.idx];
|
|
|
|
memcpy(rm.node->value + rm.node->size, sibling.more->value,
|
|
|
|
sizeof *sibling.more->value * promote);
|
|
|
|
parent.node->value[parent.idx] = sibling.more->value[promote];
|
|
|
|
memmove(sibling.more->value, sibling.more->value + promote + 1,
|
|
|
|
sizeof *sibling.more->value * (sibling.more->size - promote - 1));
|
|
|
|
#endif
|
|
|
|
if(rm.height) {
|
|
|
|
struct PB_(branch) *const moreb = PB_(as_branch)(sibling.more),
|
|
|
|
*const rmb = PB_(as_branch)(rm.node);
|
|
|
|
unsigned transferb = promote + 1;
|
|
|
|
/* This is already moved; inefficient. */
|
|
|
|
memcpy(rmb->child + rm.node->size, moreb->child,
|
|
|
|
sizeof *moreb->child * transferb);
|
|
|
|
memmove(moreb->child, moreb->child + transferb,
|
|
|
|
sizeof *rmb->child * (moreb->base.size + 1 - transferb));
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
rm.node->size += promote;
|
|
|
|
sibling.more->size -= promote + 1;
|
2022-07-06 13:02:28 -04:00
|
|
|
goto end;
|
2022-09-08 01:13:56 -04:00
|
|
|
} merge_less:
|
|
|
|
assert(parent.idx && parent.idx <= parent.node->size && parent.node->size
|
|
|
|
&& rm.idx < rm.node->size && rm.node->size == TREE_MIN
|
|
|
|
&& sibling.less->size == TREE_MIN
|
|
|
|
&& sibling.less->size + rm.node->size <= TREE_MAX);
|
|
|
|
/* There are (maybe) two spots that we can merge, this is the less. */
|
|
|
|
parent.idx--;
|
|
|
|
/* Bring down key from `parent` to append to `less`. */
|
|
|
|
sibling.less->key[sibling.less->size] = parent.node->key[parent.idx];
|
|
|
|
/* Copy the keys, leaving out deleted. */
|
|
|
|
memcpy(sibling.less->key + sibling.less->size + 1, rm.node->key,
|
|
|
|
sizeof *rm.node->key * rm.idx);
|
|
|
|
memcpy(sibling.less->key + sibling.less->size + 1 + rm.idx,
|
|
|
|
rm.node->key + rm.idx + 1,
|
|
|
|
sizeof *rm.node->key * (rm.node->size - rm.idx - 1));
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
sibling.less->value[sibling.less->size] = parent.node->value[parent.idx];
|
|
|
|
memcpy(sibling.less->value + sibling.less->size + 1, rm.node->value,
|
|
|
|
sizeof *rm.node->value * rm.idx);
|
|
|
|
memcpy(sibling.less->value + sibling.less->size + 1 + rm.idx,
|
|
|
|
rm.node->value + rm.idx + 1,
|
|
|
|
sizeof *rm.node->value * (rm.node->size - rm.idx - 1));
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
2022-09-08 01:13:56 -04:00
|
|
|
if(rm.height) { /* The `parent` links will have one less. Copying twice. */
|
|
|
|
struct PB_(branch) *const lessb = PB_(as_branch)(sibling.less),
|
|
|
|
*const rmb = PB_(as_branch)(rm.node);
|
|
|
|
memcpy(lessb->child + sibling.less->size + 1, rmb->child,
|
|
|
|
sizeof *rmb->child * rm.node->size); /* _Sic_. */
|
|
|
|
}
|
|
|
|
sibling.less->size += rm.node->size;
|
|
|
|
/* Remove references to `rm` from `parent`. The parent will have one less
|
|
|
|
link than key (_ie_, an equal number.) This is by design. */
|
|
|
|
memmove(parentb->child + parent.idx + 1, parentb->child + parent.idx + 2,
|
|
|
|
sizeof *parentb->child * (parent.node->size - parent.idx - 1));
|
|
|
|
/* This is the same pointer, but future-proof. */
|
|
|
|
if(rm.height) free(PB_(as_branch)(rm.node)); else free(rm.node);
|
|
|
|
goto ascend;
|
|
|
|
merge_more:
|
|
|
|
assert(parent.idx < parent.node->size && parent.node->size
|
|
|
|
&& rm.idx < rm.node->size && rm.node->size == TREE_MIN
|
|
|
|
&& sibling.more->size == TREE_MIN
|
|
|
|
&& rm.node->size + sibling.more->size <= TREE_MAX); /* Violated bulk? */
|
|
|
|
/* Remove `rm`. */
|
|
|
|
memmove(rm.node->key + rm.idx, rm.node->key + rm.idx + 1,
|
|
|
|
sizeof *rm.node->key * (rm.node->size - rm.idx - 1));
|
|
|
|
/* Bring down key from `parent` to append to `rm`. */
|
|
|
|
rm.node->key[rm.node->size - 1] = parent.node->key[parent.idx];
|
|
|
|
/* Merge `more` into `rm`. */
|
|
|
|
memcpy(rm.node->key + rm.node->size, sibling.more->key,
|
|
|
|
sizeof *sibling.more->key * sibling.more->size);
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
memmove(rm.node->value + rm.idx, rm.node->value + rm.idx + 1,
|
|
|
|
sizeof *rm.node->value * (rm.node->size - rm.idx - 1));
|
|
|
|
rm.node->value[rm.node->size - 1] = parent.node->value[parent.idx];
|
|
|
|
memcpy(rm.node->value + rm.node->size, sibling.more->value,
|
|
|
|
sizeof *sibling.more->value * sibling.more->size);
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
2022-09-08 01:13:56 -04:00
|
|
|
if(rm.height) { /* The `parent` links will have one less. */
|
|
|
|
struct PB_(branch) *const rmb = PB_(as_branch)(rm.node),
|
|
|
|
*const moreb = PB_(as_branch)(sibling.more);
|
|
|
|
memcpy(rmb->child + rm.node->size, moreb->child,
|
|
|
|
sizeof *moreb->child * (sibling.more->size + 1));
|
|
|
|
}
|
|
|
|
rm.node->size += sibling.more->size;
|
|
|
|
/* Remove references to `more` from `parent`. The parent will have one less
|
|
|
|
link than key (_ie_, an equal number.) This is by design. */
|
|
|
|
memmove(parentb->child + parent.idx + 1, parentb->child + parent.idx + 2,
|
|
|
|
sizeof *parentb->child * (parent.node->size - parent.idx - 1));
|
|
|
|
/* This is the same pointer, but future-proof. */
|
|
|
|
if(rm.height) free(PB_(as_branch)(sibling.more)); else free(sibling.more);
|
|
|
|
goto ascend;
|
|
|
|
ascend:
|
|
|
|
/* Fix the hole by moving it up the tree. */
|
|
|
|
rm = parent;
|
|
|
|
if(rm.node->size <= TREE_MIN) {
|
|
|
|
if(!(parent.node = PB_(as_branch)(rm.node)->child[TREE_MAX])) {
|
|
|
|
assert(tree->height == rm.height);
|
|
|
|
} else {
|
|
|
|
parent.height++;
|
|
|
|
}
|
2022-07-06 13:02:28 -04:00
|
|
|
} else {
|
2022-09-08 01:13:56 -04:00
|
|
|
parent.node = 0;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
goto upward;
|
|
|
|
space: /* Node is root or has more than `TREE_MIN`; branches taken care of. */
|
|
|
|
assert(rm.node);
|
|
|
|
assert(rm.idx < rm.node->size);
|
|
|
|
assert(rm.node->size > TREE_MIN || rm.node == tree->node);
|
2022-07-06 13:02:28 -04:00
|
|
|
memmove(rm.node->key + rm.idx, rm.node->key + rm.idx + 1,
|
|
|
|
sizeof *rm.node->key * (rm.node->size - rm.idx - 1));
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-07-06 13:02:28 -04:00
|
|
|
memmove(rm.node->value + rm.idx, rm.node->value + rm.idx + 1,
|
|
|
|
sizeof *rm.node->value * (rm.node->size - rm.idx - 1));
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
2022-09-08 01:13:56 -04:00
|
|
|
if(!--rm.node->size) {
|
|
|
|
assert(rm.node == tree->node);
|
|
|
|
if(tree->height) {
|
|
|
|
tree->node = PB_(as_branch)(rm.node)->child[0];
|
|
|
|
tree->height--;
|
|
|
|
free(PB_(as_branch)(rm.node));
|
|
|
|
} else { /* Just deleted the last one. Set flag for zero container. */
|
|
|
|
tree->height = UINT_MAX;
|
|
|
|
}
|
|
|
|
}
|
2022-07-06 13:02:28 -04:00
|
|
|
goto end;
|
|
|
|
end:
|
|
|
|
return 1;
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Tries to remove `key` from `tree`. @return Success, otherwise it was not in
|
|
|
|
`tree`. @order \Theta(\log |`tree`|) @allow */
|
|
|
|
static int B_(tree_remove)(struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key) { return !!tree && !!tree->root.node
|
|
|
|
&& tree->root.height != UINT_MAX && PB_(remove)(&tree->root, key); }
|
2022-07-06 13:02:28 -04:00
|
|
|
|
|
|
|
/* All these are used in clone; it's convenient to use `\O(\log size)` stack
|
|
|
|
space. [existing branches][new branches][existing leaves][new leaves] no */
|
|
|
|
struct PB_(scaffold) {
|
2022-09-08 01:13:56 -04:00
|
|
|
struct tree_node_count victim, source;
|
2022-07-06 13:02:28 -04:00
|
|
|
size_t no;
|
|
|
|
struct PB_(node) **data;
|
2022-11-02 00:06:43 -04:00
|
|
|
struct { struct PB_(node) **head, **fresh, **iterator; } branch, leaf;
|
2022-07-06 13:02:28 -04:00
|
|
|
};
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Counts the nodes `no` in `tree` for <fn:<PB>nodes>. */
|
|
|
|
static int PB_(nodes_r)(struct PB_(tree) tree,
|
|
|
|
struct tree_node_count *const no) {
|
2022-07-06 13:02:28 -04:00
|
|
|
assert(tree.node && tree.height);
|
|
|
|
if(!++no->branches) return 0;
|
|
|
|
if(tree.height == 1) {
|
|
|
|
/* Overflow; aren't guaranteed against this. */
|
|
|
|
if(no->leaves + tree.node->size + 1 < no->leaves) return 0;
|
|
|
|
no->leaves += tree.node->size + 1;
|
|
|
|
} else {
|
2022-09-08 01:13:56 -04:00
|
|
|
unsigned i;
|
2022-07-06 13:02:28 -04:00
|
|
|
for(i = 0; i <= tree.node->size; i++) {
|
|
|
|
struct PB_(tree) child;
|
2022-09-08 01:13:56 -04:00
|
|
|
child.node = PB_(as_branch)(tree.node)->child[i];
|
2022-07-06 13:02:28 -04:00
|
|
|
child.height = tree.height - 1;
|
2022-09-08 01:13:56 -04:00
|
|
|
if(!PB_(nodes_r)(child, no)) return 0;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Counts the nodes `no` in `tree`. */
|
|
|
|
static int PB_(nodes)(const struct B_(tree) *const tree,
|
|
|
|
struct tree_node_count *const no) {
|
2022-07-06 13:02:28 -04:00
|
|
|
assert(tree && no);
|
|
|
|
no->branches = no->leaves = 0;
|
|
|
|
if(!tree->root.node) { /* Idle. */
|
|
|
|
} else if(tree->root.height == UINT_MAX || !tree->root.height) {
|
|
|
|
no->leaves = 1;
|
|
|
|
} else { /* Complex. */
|
|
|
|
struct PB_(tree) sub = tree->root;
|
2022-09-08 01:13:56 -04:00
|
|
|
if(!PB_(nodes_r)(sub, no)) return 0;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** `ref` with `sc` work under <fn:<PB>cannibalize>. */
|
2022-07-06 13:02:28 -04:00
|
|
|
static void PB_(cannibalize_r)(struct PB_(ref) ref,
|
|
|
|
struct PB_(scaffold) *const sc) {
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *branch = PB_(as_branch)(ref.node);
|
2022-11-02 00:06:43 -04:00
|
|
|
const int keep_branch = sc->branch.iterator < sc->branch.fresh;
|
2022-07-06 13:02:28 -04:00
|
|
|
assert(ref.node && ref.height && sc);
|
2022-11-02 00:06:43 -04:00
|
|
|
if(keep_branch) *sc->branch.iterator = ref.node, sc->branch.iterator++;
|
2022-07-06 13:02:28 -04:00
|
|
|
if(ref.height == 1) { /* Children are leaves. */
|
|
|
|
unsigned n;
|
|
|
|
for(n = 0; n <= ref.node->size; n++) {
|
2022-11-02 00:06:43 -04:00
|
|
|
const int keep_leaf = sc->leaf.iterator < sc->leaf.fresh;
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(node) *child = branch->child[n];
|
2022-11-02 00:06:43 -04:00
|
|
|
if(keep_leaf) *sc->leaf.iterator = child, sc->leaf.iterator++;
|
2022-07-06 13:02:28 -04:00
|
|
|
else free(child);
|
|
|
|
}
|
|
|
|
} else while(ref.idx <= ref.node->size) {
|
|
|
|
struct PB_(ref) child;
|
2022-09-08 01:13:56 -04:00
|
|
|
child.node = PB_(as_branch)(ref.node)->child[ref.idx];
|
2022-07-06 13:02:28 -04:00
|
|
|
child.height = ref.height - 1;
|
|
|
|
child.idx = 0;
|
|
|
|
PB_(cannibalize_r)(child, sc);
|
|
|
|
ref.idx++;
|
|
|
|
}
|
|
|
|
if(!keep_branch) free(branch);
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Disassemble `tree` and put in into `sc`. */
|
2022-07-06 13:02:28 -04:00
|
|
|
static void PB_(cannibalize)(const struct B_(tree) *const tree,
|
|
|
|
struct PB_(scaffold) *const sc) {
|
|
|
|
struct PB_(ref) ref;
|
|
|
|
assert(tree && tree->root.height != UINT_MAX && sc);
|
|
|
|
/* Nothing to cannibalize. */
|
|
|
|
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;
|
2022-11-02 00:06:43 -04:00
|
|
|
sc->branch.iterator = sc->branch.head;
|
|
|
|
sc->leaf.iterator = sc->leaf.head;
|
2022-07-06 13:02:28 -04:00
|
|
|
if(ref.height) {
|
|
|
|
PB_(cannibalize_r)(ref, sc);
|
|
|
|
} else { /* Just one leaf. */
|
2022-11-02 00:06:43 -04:00
|
|
|
*sc->leaf.iterator = ref.node;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** Do the work of `src` cloned with `sc`. Called from <fn:<PB>clone>. */
|
2022-07-06 13:02:28 -04:00
|
|
|
static struct PB_(node) *PB_(clone_r)(struct PB_(tree) src,
|
|
|
|
struct PB_(scaffold) *const sc) {
|
|
|
|
struct PB_(node) *node;
|
|
|
|
if(src.height) {
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(branch) *const srcb = PB_(as_branch)(src.node),
|
2022-11-02 00:06:43 -04:00
|
|
|
*const branch = PB_(as_branch)(node = *sc->branch.iterator++);
|
2022-07-06 13:02:28 -04:00
|
|
|
unsigned i;
|
2022-09-08 01:13:56 -04:00
|
|
|
struct PB_(tree) child;
|
2022-07-06 13:02:28 -04:00
|
|
|
*node = *src.node; /* Copy node. */
|
2022-09-08 01:13:56 -04:00
|
|
|
child.height = src.height - 1;
|
2022-07-06 13:02:28 -04:00
|
|
|
for(i = 0; i <= src.node->size; i++) { /* Different links. */
|
2022-09-08 01:13:56 -04:00
|
|
|
child.node = srcb->child[i];
|
|
|
|
branch->child[i] = PB_(clone_r)(child, sc);
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
|
|
|
} else { /* Leaves. */
|
2022-11-02 00:06:43 -04:00
|
|
|
node = *sc->leaf.iterator++;
|
2022-07-06 13:02:28 -04:00
|
|
|
*node = *src.node;
|
|
|
|
}
|
|
|
|
return node;
|
|
|
|
}
|
2022-09-08 01:13:56 -04:00
|
|
|
/** `src` is copied with the cloning scaffold `sc`. */
|
2022-07-06 13:02:28 -04:00
|
|
|
static struct PB_(tree) PB_(clone)(const struct PB_(tree) *const src,
|
|
|
|
struct PB_(scaffold) *const sc) {
|
|
|
|
struct PB_(tree) sub;
|
|
|
|
assert(src && src->node && sc);
|
|
|
|
/* Go back to the beginning of the scaffold and pick off one by one. */
|
2022-11-02 00:06:43 -04:00
|
|
|
sc->branch.iterator = sc->branch.head;
|
|
|
|
sc->leaf.iterator = sc->leaf.head;
|
2022-07-06 13:02:28 -04:00
|
|
|
sub.node = PB_(clone_r)(*src, sc);
|
|
|
|
sub.height = src->height;
|
|
|
|
/* Used up all of them. No concurrent modifications, please. */
|
2022-11-02 00:06:43 -04:00
|
|
|
assert(sc->branch.iterator == sc->leaf.head
|
|
|
|
&& sc->leaf.iterator == sc->data + sc->no);
|
2022-07-06 13:02:28 -04:00
|
|
|
return sub;
|
|
|
|
}
|
|
|
|
/** `source` is copied to, and overwrites, `tree`.
|
|
|
|
@param[source] In the case where it's null or idle, if `tree` is empty, then
|
|
|
|
it continues to be.
|
|
|
|
@return Success, otherwise `tree` is not modified.
|
|
|
|
@throws[malloc] @throws[EDOM] `tree` is null. @throws[ERANGE] The size of
|
2022-09-08 01:13:56 -04:00
|
|
|
`source` nodes doesn't fit into `size_t`.
|
|
|
|
@order \O(|`source`| + |`tree`|) time and temporary space. @allow */
|
2022-07-06 13:02:28 -04:00
|
|
|
static int B_(tree_clone)(struct B_(tree) *const tree,
|
|
|
|
const struct B_(tree) *const source) {
|
|
|
|
struct PB_(scaffold) sc;
|
|
|
|
int success = 1;
|
|
|
|
sc.data = 0; /* Need to keep this updated to catch. */
|
|
|
|
if(!tree) { errno = EDOM; goto catch; }
|
|
|
|
/* Count the number of nodes and set up to copy. */
|
2022-09-08 01:13:56 -04:00
|
|
|
if(!PB_(nodes)(tree, &sc.victim) || !PB_(nodes)(source, &sc.source)
|
2022-07-06 13:02:28 -04:00
|
|
|
|| (sc.no = sc.source.branches + sc.source.leaves) < sc.source.branches)
|
|
|
|
{ errno = ERANGE; goto catch; } /* Overflow. */
|
|
|
|
if(!sc.no) { PB_(clear)(tree); goto finally; } /* No need to allocate. */
|
|
|
|
if(!(sc.data = malloc(sizeof *sc.data * sc.no)))
|
|
|
|
{ if(!errno) errno = ERANGE; goto catch; }
|
2022-09-08 01:13:56 -04:00
|
|
|
{ /* Makes debugging easier; not necessary. */
|
2022-07-06 13:02:28 -04:00
|
|
|
size_t i;
|
|
|
|
for(i = 0; i < sc.no; i++) sc.data[i] = 0;
|
|
|
|
}
|
|
|
|
{ /* Ready scaffold. */
|
2022-09-08 01:13:56 -04:00
|
|
|
struct tree_node_count need;
|
2022-07-06 13:02:28 -04:00
|
|
|
need.leaves = sc.source.leaves > sc.victim.leaves
|
|
|
|
? sc.source.leaves - sc.victim.leaves : 0;
|
|
|
|
need.branches = sc.source.branches > sc.victim.branches
|
|
|
|
? sc.source.branches - sc.victim.branches : 0;
|
|
|
|
sc.branch.head = sc.data;
|
2022-11-02 00:06:43 -04:00
|
|
|
sc.branch.fresh = sc.branch.iterator
|
2022-07-06 13:02:28 -04:00
|
|
|
= sc.branch.head + sc.source.branches - need.branches;
|
|
|
|
sc.leaf.head = sc.branch.fresh + need.branches;
|
2022-11-02 00:06:43 -04:00
|
|
|
sc.leaf.fresh = sc.leaf.iterator
|
2022-07-06 13:02:28 -04:00
|
|
|
= sc.leaf.head + sc.source.leaves - need.leaves;
|
|
|
|
assert(sc.leaf.fresh + need.leaves == sc.data + sc.no);
|
|
|
|
}
|
|
|
|
/* Add new nodes. */
|
2022-11-02 00:06:43 -04:00
|
|
|
while(sc.branch.iterator != sc.leaf.head) {
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(branch) *branch;
|
|
|
|
if(!(branch = malloc(sizeof *branch))) goto catch;
|
|
|
|
branch->base.size = 0;
|
|
|
|
branch->child[0] = 0;
|
2022-11-02 00:06:43 -04:00
|
|
|
*sc.branch.iterator++ = &branch->base;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
2022-11-02 00:06:43 -04:00
|
|
|
while(sc.leaf.iterator != sc.data + sc.no) {
|
2022-07-06 13:02:28 -04:00
|
|
|
struct PB_(node) *leaf;
|
|
|
|
if(!(leaf = malloc(sizeof *leaf))) goto catch;
|
|
|
|
leaf->size = 0;
|
2022-11-02 00:06:43 -04:00
|
|
|
*sc.leaf.iterator++ = leaf;
|
2022-07-06 13:02:28 -04:00
|
|
|
}
|
|
|
|
/* Resources acquired; now we don't care about tree. */
|
|
|
|
PB_(cannibalize)(tree, &sc);
|
|
|
|
/* The scaffold has the exact number of nodes we need. Overwrite. */
|
|
|
|
tree->root = PB_(clone)(&source->root, &sc);
|
|
|
|
goto finally;
|
2022-05-28 02:09:38 -04:00
|
|
|
catch:
|
2022-07-06 13:02:28 -04:00
|
|
|
success = 0;
|
|
|
|
if(!sc.data) goto finally;
|
2022-11-02 00:06:43 -04:00
|
|
|
while(sc.leaf.iterator != sc.leaf.fresh) {
|
|
|
|
struct PB_(node) *leaf = *(--sc.leaf.iterator);
|
2022-07-06 13:02:28 -04:00
|
|
|
assert(leaf);
|
|
|
|
free(leaf);
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
2022-11-02 00:06:43 -04:00
|
|
|
while(sc.branch.iterator != sc.branch.fresh) {
|
|
|
|
struct PB_(branch) *branch = PB_(as_branch)(*(--sc.branch.iterator));
|
2022-07-06 13:02:28 -04:00
|
|
|
assert(branch);
|
|
|
|
free(branch);
|
|
|
|
}
|
|
|
|
finally:
|
|
|
|
free(sc.data); /* Temporary memory. */
|
|
|
|
return success;
|
2022-05-28 02:09:38 -04:00
|
|
|
}
|
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
|
|
|
|
/** Adding, deleting, or changes in the topology of the tree invalidate it. */
|
2022-11-02 00:06:43 -04:00
|
|
|
struct B_(tree_iterator);
|
|
|
|
struct B_(tree_iterator) { struct PB_(iterator) _; };
|
2022-09-08 01:13:56 -04:00
|
|
|
|
|
|
|
|
|
|
|
/** @return Cursor before the first element of `tree`. Can be null.
|
|
|
|
@order \Theta(\log |`tree`|) @allow */
|
2022-11-02 00:06:43 -04:00
|
|
|
static struct B_(tree_iterator) B_(tree_begin)(struct B_(tree) *const tree)
|
2022-12-27 02:31:08 -05:00
|
|
|
{ struct B_(tree_iterator) it; it._ = PB_(begin)(tree); return it; }
|
|
|
|
/** @return Cursor after the last element of `tree`. Can be null.
|
|
|
|
@order \Theta(\log |`tree`|) @allow */
|
|
|
|
static struct B_(tree_iterator) B_(tree_end)(struct B_(tree) *const tree)
|
|
|
|
{ struct B_(tree_iterator) it; it._ = PB_(end)(tree); return it; }
|
|
|
|
/** @return Cursor in `tree` between elements, such
|
2022-09-08 01:13:56 -04:00
|
|
|
that if <fn:<B>tree_next> is called, it will be smallest key that is not
|
|
|
|
smaller than `x`, or, <fn:<B>tree_end> if `x` is greater than all in `tree`.
|
|
|
|
@order \Theta(\log |`tree`|) @allow */
|
2022-11-02 00:06:43 -04:00
|
|
|
static struct B_(tree_iterator) B_(tree_begin_at)(struct B_(tree) *const tree,
|
2022-09-08 01:13:56 -04:00
|
|
|
const PB_(key) x) {
|
2022-11-02 00:06:43 -04:00
|
|
|
struct B_(tree_iterator) cur;
|
2022-09-08 01:13:56 -04:00
|
|
|
if(!tree) return cur._.root = 0, cur;
|
|
|
|
cur._.ref = PB_(lower)(tree->root, x);
|
|
|
|
cur._.root = &tree->root;
|
|
|
|
cur._.seen = 0;
|
|
|
|
return cur;
|
|
|
|
}
|
2022-12-27 02:31:08 -05:00
|
|
|
#ifdef TREE_VALUE /* <!-- map */
|
|
|
|
/** @return Whether advancing `it` to the next element and filling `k`, (and
|
|
|
|
`v` if a map, otherwise absent,) if not-null.
|
|
|
|
@order \O(\log |`tree`|) @allow */
|
|
|
|
static int B_(tree_next)(struct B_(tree_iterator) *const it,
|
|
|
|
PB_(key) *const k, PB_(value) **v) {
|
|
|
|
#else /* map --><!-- set */
|
|
|
|
static int B_(tree_next)(struct B_(tree_iterator) *const it,
|
|
|
|
PB_(key) *const k) {
|
|
|
|
#endif /* set --> */
|
|
|
|
struct PB_(ref) *r;
|
|
|
|
if(!PB_(next)(&it->_, &r)) return 0;
|
|
|
|
if(k) *k = r->node->key[r->idx];
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
if(v) *v = r->node->value + r->idx;
|
|
|
|
#endif
|
|
|
|
return 1;
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef TREE_VALUE /* <!-- map */
|
|
|
|
/** @return Whether reversing `it` to the previous element and filling `k`,
|
|
|
|
(and `v` if a map, otherwise absent,) if not-null.
|
|
|
|
@order \O(\log |`tree`|) @allow */
|
|
|
|
static int B_(tree_previous)(struct B_(tree_iterator) *const it,
|
|
|
|
PB_(key) *const k, PB_(value) **v) {
|
|
|
|
#else /* map --><!-- set */
|
|
|
|
static int B_(tree_previous)(struct B_(tree_iterator) *const it,
|
|
|
|
PB_(key) *const k) {
|
|
|
|
#endif /* set --> */
|
|
|
|
struct PB_(ref) *r;
|
|
|
|
if(!PB_(previous)(&it->_, &r)) return 0;
|
|
|
|
if(k) *k = r->node->key[r->idx];
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
if(v) *v = r->node->value + r->idx;
|
|
|
|
#endif
|
|
|
|
return 1;
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-09-08 01:13:56 -04:00
|
|
|
|
|
|
|
#ifdef TREE_VALUE /* <!-- map */
|
2022-11-02 00:06:43 -04:00
|
|
|
/** Adds `key` and returns `value` to tree in iterator `it`. See
|
|
|
|
<fn:<B>tree_try>. @return If `it` is not pointing at a valid tree, returns
|
2022-09-08 01:13:56 -04:00
|
|
|
`TREE_ERROR` and doesn't set `errno`, otherwise the same. */
|
2022-11-02 00:06:43 -04:00
|
|
|
static enum tree_result B_(tree_iterator_try)(struct B_(tree_iterator) *const
|
|
|
|
it, const PB_(key) key, PB_(value) **const value) {
|
2022-09-08 01:13:56 -04:00
|
|
|
#else /* map --><!-- set */
|
2022-11-02 00:06:43 -04:00
|
|
|
static enum tree_result B_(tree_iterator_try)(struct B_(tree_iterator) *const
|
|
|
|
it, const PB_(key) key) {
|
2022-09-08 01:13:56 -04:00
|
|
|
#endif /* set --> */
|
2022-11-02 00:06:43 -04:00
|
|
|
enum { TREE_NONODE, TREE_ITERATING, TREE_END } where;
|
2022-09-08 01:13:56 -04:00
|
|
|
PB_(key) anchor;
|
|
|
|
enum tree_result ret;
|
|
|
|
memset(&anchor, 0, sizeof anchor); /* Silence warnings. */
|
2022-11-02 00:06:43 -04:00
|
|
|
if(!it || !it->_.root) return TREE_ERROR; /* No tree. */
|
|
|
|
if(it->_.ref.node && it->_.root->height != UINT_MAX) {
|
|
|
|
where = (it->_.ref.idx < it->_.ref.node->size)
|
|
|
|
? TREE_ITERATING : TREE_END;
|
2022-09-08 01:13:56 -04:00
|
|
|
} else {
|
2022-11-02 00:06:43 -04:00
|
|
|
where = TREE_NONODE;
|
2022-09-08 01:13:56 -04:00
|
|
|
}
|
2022-11-02 00:06:43 -04:00
|
|
|
if(where == TREE_ITERATING) anchor = it->_.ref.node->key[it->_.ref.idx];
|
|
|
|
/* Should be already. */
|
|
|
|
if(where == TREE_NONODE || where == TREE_END) it->_.seen = 0;
|
2022-09-08 01:13:56 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-11-02 00:06:43 -04:00
|
|
|
ret = PB_(update)(it->_.root, key, 0, value);
|
2022-09-08 01:13:56 -04:00
|
|
|
#else
|
2022-11-02 00:06:43 -04:00
|
|
|
ret = PB_(update)(it->_.root, key, 0);
|
2022-09-08 01:13:56 -04:00
|
|
|
#endif
|
|
|
|
if(ret == TREE_ERROR) return TREE_ERROR;
|
2022-11-02 00:06:43 -04:00
|
|
|
assert(it->_.root->height != UINT_MAX); /* Can't be empty. */
|
2022-09-08 01:13:56 -04:00
|
|
|
switch(where) {
|
2022-11-02 00:06:43 -04:00
|
|
|
case TREE_NONODE: it->_.ref.node = 0; it->_.seen = 0; break;
|
|
|
|
case TREE_ITERATING: it->_.ref = PB_(lower)(*it->_.root, anchor); break;
|
|
|
|
case TREE_END:
|
|
|
|
assert(it->_.root->node);
|
|
|
|
it->_.ref.node = it->_.root->node;
|
|
|
|
it->_.ref.height = it->_.root->height;
|
|
|
|
it->_.ref.idx = it->_.root->node->size;
|
|
|
|
while(it->_.ref.height) {
|
|
|
|
it->_.ref.node
|
|
|
|
= PB_(as_branch_c)(it->_.ref.node)->child[it->_.ref.idx];
|
|
|
|
it->_.ref.idx = it->_.ref.node->size;
|
|
|
|
it->_.ref.height--;
|
2022-09-08 01:13:56 -04:00
|
|
|
}
|
2022-11-02 00:06:43 -04:00
|
|
|
it->_.seen = 0;
|
2022-09-08 01:13:56 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
/** Removes the last entry returned by a valid `it`. All other iterators on the
|
2022-09-08 01:13:56 -04:00
|
|
|
same object are invalidated, but `cur` is now between on the removed node.
|
2022-11-02 00:06:43 -04:00
|
|
|
@return Success, otherwise `it` is not at a valid element.
|
2022-09-08 01:13:56 -04:00
|
|
|
@order \Theta(\log |`tree`|) */
|
2022-11-02 00:06:43 -04:00
|
|
|
static int B_(tree_iterator_remove)(struct B_(tree_iterator) *const it) {
|
2022-09-08 01:13:56 -04:00
|
|
|
PB_(key) remove;
|
2022-11-02 00:06:43 -04:00
|
|
|
if(!it || !it->_.seen || !it->_.root || !it->_.ref.node
|
|
|
|
|| it->_.root->height == UINT_MAX
|
|
|
|
|| it->_.ref.idx >= it->_.ref.node->size
|
|
|
|
|| (remove = it->_.ref.node->key[it->_.ref.idx],
|
|
|
|
!PB_(remove)(it->_.root, remove))) return 0;
|
2022-09-08 01:13:56 -04:00
|
|
|
/* <fn:<B>tree_begin_at>. */
|
2022-11-02 00:06:43 -04:00
|
|
|
it->_.ref = PB_(lower)(*it->_.root, remove);
|
|
|
|
it->_.seen = 0;
|
2022-09-08 01:13:56 -04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-05-28 02:09:38 -04:00
|
|
|
static void PB_(unused_base_coda)(void);
|
|
|
|
static void PB_(unused_base)(void) {
|
2022-09-08 01:13:56 -04:00
|
|
|
PB_(key) k; PB_(value) v; memset(&k, 0, sizeof k); memset(&v, 0, sizeof v);
|
|
|
|
B_(tree)(); B_(tree_)(0); B_(tree_clear)(0); B_(tree_count)(0);
|
|
|
|
B_(tree_contains)(0, k); B_(tree_get_or)(0, k, v); B_(tree_at_or)(0, k, v);
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifdef TREE_VALUE
|
2022-09-08 01:13:56 -04:00
|
|
|
B_(tree_bulk_add)(0, k, 0); B_(tree_try)(0, k, 0);
|
2022-11-02 00:06:43 -04:00
|
|
|
B_(tree_assign)(0, k, 0, 0); B_(tree_iterator_try)(0, k, 0);
|
2022-12-27 02:31:08 -05:00
|
|
|
B_(tree_next)(0, 0, 0); B_(tree_previous)(0, 0, 0);
|
2022-05-28 02:09:38 -04:00
|
|
|
#else
|
2022-09-08 01:13:56 -04:00
|
|
|
B_(tree_bulk_add)(0, k); B_(tree_try)(0, k);
|
2022-11-02 00:06:43 -04:00
|
|
|
B_(tree_assign)(0, k, 0); B_(tree_iterator_try)(0, k);
|
2022-12-27 02:31:08 -05:00
|
|
|
B_(tree_next)(0, 0); B_(tree_previous)(0, 0);
|
2022-05-28 02:09:38 -04:00
|
|
|
#endif
|
2022-07-06 13:02:28 -04:00
|
|
|
B_(tree_bulk_finish)(0); B_(tree_remove)(0, k); B_(tree_clone)(0, 0);
|
2022-09-08 01:13:56 -04:00
|
|
|
B_(tree_begin)(0); B_(tree_begin_at)(0, k); B_(tree_end)(0);
|
2022-11-02 00:06:43 -04:00
|
|
|
B_(tree_iterator_remove)(0);
|
2022-05-28 02:09:38 -04:00
|
|
|
PB_(unused_base_coda)();
|
|
|
|
}
|
|
|
|
static void PB_(unused_base_coda)(void) { PB_(unused_base)(); }
|
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
/* Box override information. */
|
|
|
|
#define BOX_TYPE struct B_(tree)
|
2022-12-27 02:31:08 -05:00
|
|
|
#define BOX_CONTENT struct PB_(ref)
|
2022-11-02 00:06:43 -04:00
|
|
|
#define BOX_ PB_
|
|
|
|
#define BOX_MAJOR_NAME tree
|
|
|
|
#define BOX_MINOR_NAME TREE_NAME
|
|
|
|
|
|
|
|
#endif /* base code --> */
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef TREE_TRAIT /* <-- trait: Will be different on different includes. */
|
|
|
|
#define BOX_TRAIT_NAME TREE_TRAIT
|
2022-12-27 02:31:08 -05:00
|
|
|
#define PBT_(n) PB_(TREE_CAT(TREE_TRAIT, n))
|
|
|
|
#define BT_(n) B_(TREE_CAT(TREE_TRAIT, n))
|
|
|
|
#else /* trait --><!-- !trait */
|
|
|
|
#define PBT_(n) PB_(n)
|
|
|
|
#define BT_(n) B_(n)
|
|
|
|
#endif /* !trait --> */
|
2022-11-02 00:06:43 -04:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef TREE_TO_STRING /* <!-- to string trait */
|
2022-12-27 02:31:08 -05:00
|
|
|
/** Thunk `r` -> `a`. */
|
|
|
|
static void PBT_(to_string)(const struct PB_(ref) *const r,
|
|
|
|
char (*const a)[12]) {
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
BT_(to_string)(r->node->key[r->idx], r->node->value + r->idx, a);
|
|
|
|
#else
|
|
|
|
BT_(to_string)(r->node->key[r->idx], a);
|
|
|
|
#endif
|
|
|
|
}
|
2022-11-02 00:06:43 -04:00
|
|
|
#define TO_STRING_LEFT '{'
|
|
|
|
#define TO_STRING_RIGHT '}'
|
|
|
|
#include "to_string.h" /** \include */
|
|
|
|
#undef TREE_TO_STRING
|
|
|
|
#ifndef TREE_TRAIT
|
|
|
|
#define TREE_HAS_TO_STRING
|
|
|
|
#endif
|
|
|
|
#endif /* to string trait --> */
|
2022-12-27 02:31:08 -05:00
|
|
|
#undef PBT_
|
|
|
|
#undef BT_
|
2022-11-02 00:06:43 -04:00
|
|
|
|
2022-05-28 02:09:38 -04:00
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
#if defined(TREE_TEST) && !defined(TREE_TRAIT) /* <!-- test base */
|
|
|
|
#include "../test/test_tree.h"
|
|
|
|
#endif /* test base --> */
|
2022-09-08 01:13:56 -04:00
|
|
|
|
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
#ifdef TREE_DEFAULT /* <!-- default trait */
|
|
|
|
#ifdef TREE_TRAIT
|
|
|
|
#define B_D_(n, m) TREE_CAT(B_(n), TREE_CAT(TREE_TRAIT, m))
|
2022-09-08 01:13:56 -04:00
|
|
|
#define PB_D_(n, m) TREE_CAT(tree, B_D_(n, m))
|
|
|
|
#else
|
|
|
|
#define B_D_(n, m) TREE_CAT(B_(n), m)
|
|
|
|
#define PB_D_(n, m) TREE_CAT(tree, B_D_(n, m))
|
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
/* `TREE_DEFAULT` is a valid <tag:<PB>value>. */
|
2022-09-08 01:13:56 -04:00
|
|
|
static const PB_(value) PB_D_(default, value) = (TREE_DEFAULT);
|
|
|
|
/** This is functionally identical to <fn:<B>tree_get_or>, but a with a trait
|
|
|
|
specifying a constant default value.
|
|
|
|
@return The value associated with `key` in `tree`, (which can be null.) If
|
|
|
|
no such value exists, the `TREE_DEFAULT` is returned.
|
|
|
|
@order \O(\log |`tree`|). @allow */
|
|
|
|
static PB_(value) B_D_(tree, get)(const struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key) {
|
|
|
|
struct PB_(ref) ref;
|
|
|
|
return tree && tree->root.node && tree->root.height != UINT_MAX
|
|
|
|
&& (ref = PB_(find)(&tree->root, key)).node
|
|
|
|
? *PB_(ref_to_valuep)(ref) : PB_D_(default, value);
|
|
|
|
}
|
|
|
|
/** This is functionally identical to <fn:<B>tree_at_or>, but a with a trait
|
|
|
|
specifying a constant default value.
|
|
|
|
@return The value associated with `key` in `tree`, (which can be null.) If
|
|
|
|
no such value exists, the `TREE_DEFAULT` is returned.
|
|
|
|
@order \O(\log |`tree`|). @allow */
|
|
|
|
static PB_(value) B_D_(tree, at)(const struct B_(tree) *const tree,
|
|
|
|
const PB_(key) key) {
|
|
|
|
struct PB_(ref) ref;
|
|
|
|
return tree && (ref = PB_(lower)(tree->root, key)).node
|
|
|
|
&& ref.idx < ref.node->size
|
|
|
|
? *PB_(ref_to_valuep)(ref) : PB_D_(default, value);
|
|
|
|
}
|
|
|
|
static void PB_D_(unused, default_coda)(void);
|
|
|
|
static void PB_D_(unused, default)(void) {
|
|
|
|
PB_(key) k; memset(&k, 0, sizeof k);
|
|
|
|
B_D_(tree, get)(0, k); B_D_(tree, at)(0, k);
|
|
|
|
PB_D_(unused, default_coda)();
|
|
|
|
}
|
|
|
|
static void PB_D_(unused, default_coda)(void) { PB_D_(unused, default)(); }
|
|
|
|
#undef B_D_
|
|
|
|
#undef PB_D_
|
|
|
|
#undef TREE_DEFAULT
|
2022-11-02 00:06:43 -04:00
|
|
|
#endif /* default trait --> */
|
2022-09-08 01:13:56 -04:00
|
|
|
|
|
|
|
|
2022-11-02 00:06:43 -04:00
|
|
|
#ifdef TREE_EXPECT_TRAIT /* <!-- more */
|
2022-05-28 02:09:38 -04:00
|
|
|
#undef TREE_EXPECT_TRAIT
|
2022-11-02 00:06:43 -04:00
|
|
|
#else /* more --><!-- done */
|
|
|
|
#undef BOX_TYPE
|
|
|
|
#undef BOX_CONTENT
|
|
|
|
#undef BOX_
|
|
|
|
#undef BOX_MAJOR_NAME
|
|
|
|
#undef BOX_MINOR_NAME
|
2022-05-28 02:09:38 -04:00
|
|
|
#undef TREE_NAME
|
|
|
|
#undef TREE_KEY
|
2022-11-02 00:06:43 -04:00
|
|
|
#undef TREE_ORDER
|
2022-05-28 02:09:38 -04:00
|
|
|
#undef TREE_COMPARE
|
|
|
|
#ifdef TREE_VALUE
|
|
|
|
#undef TREE_VALUE
|
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
#ifdef TREE_HAS_TO_STRING
|
|
|
|
#undef TREE_HAS_TO_STRING
|
|
|
|
#endif
|
2022-05-28 02:09:38 -04:00
|
|
|
#ifdef TREE_TEST
|
|
|
|
#undef TREE_TEST
|
|
|
|
#endif
|
2022-11-02 00:06:43 -04:00
|
|
|
#endif /* done --> */
|
|
|
|
#ifdef TREE_TRAIT
|
|
|
|
#undef TREE_TRAIT
|
|
|
|
#undef BOX_TRAIT_NAME
|
|
|
|
#endif
|