/** @license 2022 Neil Edelman, distributed under the terms of the [MIT License](https://opensource.org/licenses/MIT). @abstract Stand-alone header ; examples . On a compatible workstation, `make` creates the test suite of the examples. @subtitle Ordered tree A tree> is an ordered set or map. @param[TREE_NAME, TREE_KEY] `` that satisfies `C` naming conventions when mangled, required, and `TREE_KEY`, a comparable type, key>, whose default is `unsigned int`. `` is private, whose names are prefixed in a manner to avoid collisions. @param[TREE_VALUE] `TRIE_VALUE` is an optional payload to go with the type, value>. The makes it a map of tree_entry> instead of a set. @param[TREE_COMPARE] A function satisfying compare_fn>. Defaults to ascending order. Required if `TREE_KEY` is changed to an incomparable type. @param[TREE_EXPECT_TRAIT] Do not un-define certain variables for subsequent inclusion in a parameterized trait. @param[TREE_TO_STRING_NAME, TREE_TO_STRING] To string trait contained in ; an optional unique `` that satisfies `C` naming conventions when mangled and function implementing to_string_fn>. @fixme multi-key; implementation of order statistic tree @fixme merge, difference @std C89 */ #if !defined(TREE_NAME) #error Name TREE_NAME undefined. #endif #if defined(TREE_TO_STRING_NAME) || defined(TREE_TO_STRING) #define TREE_TO_STRING_TRAIT 1 #else #define TREE_TO_STRING_TRAIT 0 #endif #define TREE_TRAITS TREE_TO_STRING_TRAIT #if TREE_TRAITS > 1 #error Only one trait per include is allowed; use TREE_EXPECT_TRAIT. #endif #if defined(TREE_TO_STRING_NAME) && !defined(TREE_TO_STRING) #error TREE_TO_STRING_NAME requires TREE_TO_STRING. #endif #ifndef TREE_H /* */ #if TREE_TRAITS == 0 /* */ /* Check that `TREE_COMPARE` is a function implementing compare_fn>, if defined. */ static const PB_(compare_fn) PB_(compare) = (TREE_COMPARE); /* B-tree node, as . These rules are more lazy than the original so as to not exhibit worst-case behaviour in small trees, as , but lookup is potentially slower after deleting; this is a design decision that nodes are not cached. In the terminology of , * 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 to other nodes. (The height is one less then the original paper, as , for computational simplicity.) * 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`. * Bulk-loading always is on the right side. * A branch node is a specialization of a (leaf) node with children. One can tell if it's a branch by the non-zero height. */ struct PB_(node) { unsigned char size; /* `[0, TREE_MAX]`. */ PB_(key) key[TREE_MAX]; /* Cache-friendly lookup. */ #ifdef TREE_VALUE PB_(value) value[TREE_MAX]; #endif }; /* B-tree branch is a node> and links to `size + 1` nodes. */ struct PB_(branch) { struct PB_(node) base, *child[TREE_ORDER]; }; /** @return Upcasts `as_node` to a branch. */ static struct PB_(branch) *PB_(branch)(struct PB_(node) *const as_leaf) { return (struct PB_(branch) *)(void *) ((char *)as_leaf - offsetof(struct PB_(branch), base)); } /** @return Upcasts `as_node` to a branch. */ static const struct PB_(branch) *PB_(branch_c)(const struct PB_(node) * const as_node) { return (const struct PB_(branch) *)(const void *) ((const char *)as_node - offsetof(struct PB_(branch), base)); } /* Subtree is a node with a height. */ struct PB_(sub) { struct PB_(node) *node; unsigned height; }; /* Address specific entry. */ struct PB_(ref) { struct PB_(node) *node; unsigned height, idx; }; struct PB_(ref_c) { const struct PB_(node) *node; unsigned height, idx; }; #ifdef TREE_VALUE /* */ /** To initialize it to an idle state, see tree>, `TRIE_IDLE`, `{0}` (`C99`), or being `static`. This is a B-tree, as . ![States.](../doc/states.png) */ struct B_(tree); struct B_(tree) { struct PB_(sub) root; }; #define BOX_CONTENT PB_(entry_c) /** Is `e` not null? @implements `is_element_c` */ static int PB_(is_element_c)(PB_(entry_c) e) { #ifdef TREE_VALUE return !!e.key; #else return !!e; #endif } /* Two copies of the same code, with and without `const`. @param[sub] A copy of the tree's root. @param[ref] If it has a null node, starts at the first key; if it's past the node's limits, uses `sub` to go to the next node. @return True unless there are no more `ref`. */ #define TREE_PIN(pin_c, ref_c) \ static int PB_(pin_c)(struct PB_(sub) sub, struct PB_(ref_c) *const ref) { \ struct PB_(ref_c) next; \ unsigned a0; \ PB_(key) x; \ assert(ref); \ if(!sub.node || sub.height == UINT_MAX) return 0; \ /* Start. */ \ if(!ref->node) \ ref->node = sub.node, ref->height = sub.height, ref->idx = 0; \ /* Descend. */ \ while(ref->height) ref->height--, \ ref->node = PB_(branch_c)(ref->node)->child[ref->idx], ref->idx = 0; \ if(ref->idx < ref->node->size) return 1; /* Likely. */ \ /* Empty nodes are always at the end, (when bulk loading.) */ \ if(!ref->node->size) return 0; \ /* Re-descend tree and note the minimum height node that has a next key. */\ for(next.node = 0, x = ref->node->key[ref->node->size - 1]; sub.height; \ sub.node = PB_(branch_c)(sub.node)->child[a0], sub.height--) { \ unsigned a1 = sub.node->size; a0 = 0; \ while(a0 < a1) { \ const unsigned m = (a0 + a1) / 2; \ if(PB_(compare)(x, sub.node->key[m]) > 0) a0 = m + 1; else a1 = m; \ } \ if(a0 < sub.node->size) \ next.node = sub.node, next.height = sub.height, next.idx = a0; \ } \ if(!next.node) return 0; /* Off the right. */ \ *ref = next; \ return 1; /* Jumped nodes. */ \ } TREE_PIN(pin_c, ref_c) TREE_PIN(pin, ref) #undef TREE_PIN /* This could be expanded! */ /* A constant iterator. @implements `forward` */ struct PB_(forward) { const struct PB_(sub) *root; struct PB_(ref_c) ref; }; /** @return Before `tree`. @implements `forward_begin` */ static struct PB_(forward) PB_(forward_begin)(const struct B_(tree) *const tree) { struct PB_(forward) it; it.root = tree ? &tree->root : 0, it.ref.node = 0, it.ref.height = 0, it.ref.idx = 0; return it; } /** Advances `it` to the next element. @return A pointer to the current element or null. @implements `forward_next` */ static PB_(entry_c) PB_(forward_next)(struct PB_(forward) *const it) { return assert(it), PB_(pin_c)(*it->root, &it->ref) ? PB_(leaf_to_entry_c)(it->ref.node, it->ref.idx++) : PB_(null_entry_c)(); } #define BOX_ITERATOR PB_(entry) /** Is `x` not null? @implements `is_element` */ static int PB_(is_element)(const PB_(entry) e) { #ifdef TREE_VALUE return !!e.key; #else return !!e; #endif } /* A certain position and the top level tree for backtracking. @implements `iterator` */ struct PB_(iterator) { struct PB_(sub) *root; struct PB_(ref) ref; }; /** @return Before `tree`. @implements `forward_begin` */ static struct PB_(iterator) PB_(begin)(struct B_(tree) *const tree) { struct PB_(iterator) it; it.root = tree ? &tree->root : 0, it.ref.node = 0, it.ref.height = 0, it.ref.idx = 0; return it; } /** Advances `it` to the next element. @return A pointer to the current element or null. @implements `next` */ static PB_(entry) PB_(next)(struct PB_(iterator) *const it) { return assert(it), PB_(pin)(*it->root, &it->ref) ? PB_(leaf_to_entry)(it->ref.node, it->ref.idx++) : PB_(null_entry)(); } //#include "../test/orcish.h" static void PB_(find_idx)(struct PB_(ref) *const lo, const PB_(key) key) { unsigned hi = lo->node->size; lo->idx = 0; if(!hi) return; do { const unsigned m = (lo->idx + hi) / 2; if(PB_(compare)(key, lo->node->key[m]) > 0) lo->idx = m + 1; else hi = m; } while(lo->idx < hi); } /** Assume `tree` and `x` are checked for non-empty validity. */ static struct PB_(ref) PB_(lower_r)(struct PB_(sub) *const tree, const PB_(key) key, struct PB_(ref) *const unfull, int *const is_equal) { struct PB_(ref) lo; for(lo.node = tree->node, lo.height = tree->height; ; lo.node = PB_(branch_c)(lo.node)->child[lo.idx], lo.height--) { unsigned hi = lo.node->size; lo.idx = 0; if(unfull && hi < TREE_MAX) *unfull = lo; if(!hi) continue; /* No nodes; bulk-add? */ do { const unsigned m = (lo.idx + hi) / 2; if(PB_(compare)(key, lo.node->key[m]) > 0) lo.idx = m + 1; else hi = m; } while(lo.idx < hi); if(unfull && hi < TREE_MAX) unfull->idx = lo.idx; /* Update. */ if(!lo.height) break; /* Leaf node. */ if(lo.idx == lo.node->size) continue; /* Off the end. */ /* Total order and monotonic, otherwise have to check right. */ if(PB_(compare)(lo.node->key[lo.idx], key) > 0) continue; if(is_equal) *is_equal = 1; break; } return lo; } /** @param[tree] Can be null. @return Lower bound of `x` in `tree`. @order \O(\log |`tree`|) */ static struct PB_(ref) PB_(lower)(struct PB_(sub) sub, const PB_(key) x, struct PB_(ref) *const unfull, int *const is_equal) { if(!sub.node || sub.height == UINT_MAX) { struct PB_(ref) ref; ref.node = 0; return ref; } else { return PB_(lower_r)(&sub, x, unfull, is_equal); } } /** Clears non-empty `tree` and it's children recursively, but doesn't put it to idle or clear pointers. If `one` is valid, tries to keep one leaf. */ static void PB_(clear_r)(struct PB_(sub) sub, struct PB_(node) **const one) { assert(sub.node); if(!sub.height) { if(one && !*one) *one = sub.node; else free(sub.node); } else { struct PB_(sub) child; unsigned i; child.height = sub.height - 1; for(i = 0; i <= sub.node->size; i++) child.node = PB_(branch)(sub.node)->child[i], PB_(clear_r)(child, one); free(PB_(branch)(sub.node)); } } /* Box override information. */ #define BOX_ PB_ #define BOX struct B_(tree) /** Initializes `tree` to idle. @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; } /** Returns an initialized `tree` to idle, `tree` can be null. @allow */ 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. */ assert(tree->root.node); free(tree->root.node); } else { PB_(clear_r)(tree->root, 0); } *tree = B_(tree)(); } /** Stores an iteration in a tree. Generally, changes in the topology of the tree invalidate it. */ struct B_(tree_iterator) { struct PB_(iterator) _; }; /** @return An iterator before the first element of `tree`. Can be null. @allow */ static struct B_(tree_iterator) B_(tree_begin)(struct B_(tree) *const tree) { struct B_(tree_iterator) it; it._ = PB_(begin)(tree); return it; } /** Advances `it` to the next element. @return A pointer to the current element or null. @allow */ static PB_(entry) B_(tree_next)(struct B_(tree_iterator) *const it) { return PB_(next)(&it->_); } /** @param[tree] Can be null. @return Finds the smallest entry in `tree` that is at the lower bound of `x`. If `x` is higher than any of `tree`, it will be placed just passed the end. @order \O(\log |`tree`|) @allow */ static struct B_(tree_iterator) B_(tree_lower)(struct B_(tree) *const tree, const PB_(key) x) { struct B_(tree_iterator) it; if(!tree) return it._.root = 0, it; it._.ref = PB_(lower)(tree->root, x, 0, 0); it._.root = &tree->root; return it; } /** For example, `tree = { 10 }`, `x = 5 -> 10`, `x = 10 -> 10`, `x = 11 -> null`. @return Lower-bound value match for `x` in `tree` or null if `x` is greater than all in `tree`. @order \O(\log |`tree`|) @allow */ static PB_(value) *B_(tree_get_next)(struct B_(tree) *const tree, const PB_(key) x) { struct PB_(ref) ref; return tree && (ref = PB_(lower)(tree->root, x, 0, 0), PB_(pin)(tree->root, &ref)) ? PB_(ref_to_value)(ref) : 0; } //#include "../test/orcish.h" static void PB_(print)(const struct B_(tree) *const tree); #ifndef TREE_TEST static void PB_(print)(const struct B_(tree) *const tree) { (void)tree, printf("not printable\n"); } #endif #ifdef TREE_VALUE /* */ static void PB_(unused_base_coda)(void); static void PB_(unused_base)(void) { PB_(key) k; memset(&k, 0, sizeof k); PB_(is_element_c); PB_(forward_begin); PB_(forward_next); PB_(is_element); B_(tree)(); B_(tree_)(0); B_(tree_begin)(0); B_(tree_next)(0); B_(tree_lower)(0, k); B_(tree_get_next)(0, k); #ifdef TREE_VALUE B_(tree_bulk_add)(0, k, 0); B_(tree_add)(0, k, 0); #else B_(tree_bulk_add)(0, k); B_(tree_add)(0, k); #endif B_(tree_bulk_finish)(0); PB_(unused_base_coda)(); } static void PB_(unused_base_coda)(void) { PB_(unused_base)(); } #elif defined(TREE_TO_STRING) /* base code --> */ #undef STR_ #undef TREE_TO_STRING #ifdef TREE_TO_STRING_NAME #undef TREE_TO_STRING_NAME #endif #endif /* traits --> */ #ifdef TREE_EXPECT_TRAIT /* */ #undef TREE_TO_STRING_TRAIT #undef TREE_TRAITS