Updated array, tree.

This commit is contained in:
Neil 2022-11-01 21:06:43 -07:00
parent 3f203d4ac8
commit 82e79efaf2
6 changed files with 398 additions and 515 deletions

View File

@ -74,7 +74,7 @@ gperf := gperf
target := # -mwindows target := # -mwindows
optimize := -ffast-math optimize := -ffast-math
warnbasic := -Wall -pedantic -ansi # -std=c99 warnbasic := -Wall -pedantic -std=c11
# Some stuff is really new. # Some stuff is really new.
warnclang := -Wextra \ warnclang := -Wextra \
-Weverything \ -Weverything \

View File

@ -17,48 +17,35 @@
<typedef:<PA>type>, associated therewith; required. `<PA>` is private, whose <typedef:<PA>type>, associated therewith; required. `<PA>` is private, whose
names are prefixed in a manner to avoid collisions. names are prefixed in a manner to avoid collisions.
@param[ARRAY_EXPECT_TRAIT] @param[ARRAY_COMPARE, ARRAY_IS_EQUAL]
Do not un-define certain variables for subsequent inclusion in a parameterized Compare `<CMP>` trait contained in <src/compare.h>. Requires
trait. `<name>[<trait>]compare` to be declared as <typedef:<PCMP>compare_fn> or
`<name>[<trait>]is_equal` to be declared as <typedef:<PCMP>bipredicate_fn>,
respectfully, (but not both.)
@param[ARRAY_COMPARE_NAME, ARRAY_COMPARE, ARRAY_IS_EQUAL] @param[ARRAY_TO_STRING]
Compare trait contained in <src/compare.h>. An optional mangled name for To string `<STR>` trait contained in <src/to_string.h>. Requires
uniqueness and a function implementing either <typedef:<PCMP>compare_fn> or `<name>[<trait>]to_string` be declared as <typedef:<PSTR>to_string_fn>.
<typedef:<PCMP>bipredicate_fn>.
@param[ARRAY_TO_STRING_NAME, ARRAY_TO_STRING] @param[ARRAY_EXPECT_TRAIT, ARRAY_TRAIT]
To string trait contained in <src/to_string.h>. An optional mangled name for Named traits are obtained by including `array.h` multiple times with
uniqueness and function implementing <typedef:<PSTR>to_string_fn>. `ARRAY_EXPECT_TRAIT` and then subsequently including the name in
`ARRAY_TRAIT`.
@std C89 */ @std C89 */
#if !defined(ARRAY_NAME) || !defined(ARRAY_TYPE) #if !defined(ARRAY_NAME) || !defined(ARRAY_TYPE)
#error Name ARRAY_NAME or tag type ARRAY_TYPE undefined. #error Name or tag type undefined.
#endif #endif
#if defined(ARRAY_TO_STRING_NAME) || defined(ARRAY_TO_STRING) #if defined(ARRAY_TRAIT) ^ defined(BOX_TYPE)
#define ARRAY_TO_STRING_TRAIT 1 #error ARRAY_TRAIT name must come after ARRAY_EXPECT_TRAIT.
#else
#define ARRAY_TO_STRING_TRAIT 0
#endif #endif
#if defined(ARRAY_COMPARE_NAME) || defined(ARRAY_COMPARE) \ #if defined(ARRAY_COMPARE) && defined(ARRAY_IS_EQUAL)
|| defined(ARRAY_IS_EQUAL) #error Only one can be defined at a time.
#define ARRAY_COMPARE_TRAIT 1
#else
#define ARRAY_COMPARE_TRAIT 0
#endif #endif
#define ARRAY_TRAITS ARRAY_TO_STRING_TRAIT + ARRAY_COMPARE_TRAIT #if defined(ARRAY_TEST) && (!defined(ARRAY_TRAIT) && !defined(ARRAY_TO_STRING) \
#if ARRAY_TRAITS > 1 || defined(ARRAY_TRAIT) && !defined(ARRAY_HAS_TO_STRING))
#error Only one trait per include is allowed; use ARRAY_EXPECT_TRAIT. #error Test requires to string.
#endif
#if ARRAY_TRAITS && !defined(BOX)
#error Trying to define a trait without defining the base datatype.
#endif
#if defined(ARRAY_TO_STRING_NAME) && !defined(ARRAY_TO_STRING)
#error ARRAY_TO_STRING_NAME requires ARRAY_TO_STRING.
#endif
#if defined(ARRAY_COMPARE_NAME) \
&& (!(!defined(ARRAY_COMPARE) ^ !defined(ARRAY_IS_EQUAL)))
#error ARRAY_COMPARE_NAME requires ARRAY_COMPARE or ARRAY_IS_EQUAL not both.
#endif #endif
#ifndef ARRAY_H /* <!-- idempotent */ #ifndef ARRAY_H /* <!-- idempotent */
@ -84,8 +71,7 @@
#endif #endif
#if ARRAY_TRAITS == 0 /* <!-- base code */ #ifndef ARRAY_TRAIT /* <!-- base code */
#ifndef ARRAY_MIN_CAPACITY /* <!-- !min; */ #ifndef ARRAY_MIN_CAPACITY /* <!-- !min; */
#define ARRAY_MIN_CAPACITY 3 /* > 1 */ #define ARRAY_MIN_CAPACITY 3 /* > 1 */
@ -93,7 +79,6 @@
/** A valid tag type set by `ARRAY_TYPE`. */ /** A valid tag type set by `ARRAY_TYPE`. */
typedef ARRAY_TYPE PA_(type); typedef ARRAY_TYPE PA_(type);
typedef const ARRAY_TYPE PA_(type_c);
/** Manages the array field `data` which has `size` elements. The space is /** Manages the array field `data` which has `size` elements. The space is
indexed up to `capacity`, which is at least `size`. The fields should be indexed up to `capacity`, which is at least `size`. The fields should be
@ -104,23 +89,8 @@ typedef const ARRAY_TYPE PA_(type_c);
struct A_(array) { PA_(type) *data; size_t size, capacity; }; struct A_(array) { PA_(type) *data; size_t size, capacity; };
/* !data -> !size, data -> capacity >= min && size <= capacity <= max */ /* !data -> !size, data -> capacity >= min && size <= capacity <= max */
#define BOX_CONTENT PA_(type_c) * /** Returns null. */
/** Is `x` not null? @implements `is_element_c` */ static PA_(type) *PA_(null)(void) { return 0; }
static int PA_(is_element_c)(PA_(type_c) *const x) { return !!x; }
/* Enumerate the contents (`input_or_output_const_iterator`.)
@implements `forward` */
struct PA_(forward) { const struct A_(array) *a; size_t next; };
/** @return A pointer to null in `a`. @implements `forward` */
static struct PA_(forward) PA_(forward)(const struct A_(array) *const a) {
struct PA_(forward) it; it.a = a, it.next = 0; return it; }
/** Move to next `it`. @return Element or null. @implements `next_c` */
static PA_(type_c) *PA_(next_c)(struct PA_(forward) *const it) {
assert(it);
if(it->a && it->next < it->a->size) return it->a->data + it->next++;
else { it->next = 0; return 0; }
}
#define BOX_ITERATOR PA_(type) *
/** Is `x` not null? @implements `is_element` */ /** Is `x` not null? @implements `is_element` */
static int PA_(is_element)(const PA_(type) *const x) { return !!x; } static int PA_(is_element)(const PA_(type) *const x) { return !!x; }
/* @implements `iterator` */ /* @implements `iterator` */
@ -156,7 +126,7 @@ reset:
*it = PA_(iterator)(it->a); *it = PA_(iterator)(it->a);
return 0; return 0;
} }
/** Removes the element last returned by `it`. (Untested.) /** Removes the element last returned by `it`. (Untested. Unused.)
@return There was an element. @order \O(`a.size`). @implements `remove` */ @return There was an element. @order \O(`a.size`). @implements `remove` */
static int PA_(remove)(struct PA_(iterator) *const it) { static int PA_(remove)(struct PA_(iterator) *const it) {
assert(0 && 1); assert(0 && 1);
@ -165,29 +135,20 @@ static int PA_(remove)(struct PA_(iterator) *const it) {
sizeof *it->a->data * (--it->a->size - it->i)); sizeof *it->a->data * (--it->a->size - it->i));
return 1; return 1;
} }
/** @return Iterator at element `idx` of `a`.
#define BOX_ACCESS @implements `iterator_at` */
/** @return Iterator immediately before element `idx` of `a`. static struct PA_(iterator) PA_(iterator_at)(struct A_(array) *a, size_t idx)
@implements `before` */
static struct PA_(iterator) PA_(before)(struct A_(array) *a, size_t idx)
{ struct PA_(iterator) it; it.a = a, it.i = idx, it.seen = 0; return it; } { struct PA_(iterator) it; it.a = a, it.i = idx, it.seen = 0; return it; }
/** Size of `a`. @implements `size` */ /** Size of `a`. @implements `size` */
static size_t PA_(size)(const struct A_(array) *a) { return a ? a->size : 0; } static size_t PA_(size)(const struct A_(array) *a) { return a ? a->size : 0; }
/** @return Element `idx` of `a`. @implements `at` */ /** @return Element `idx` of `a`. @implements `at` */
static PA_(type) *PA_(at)(const struct A_(array) *a, const size_t idx) static PA_(type) *PA_(at)(const struct A_(array) *a, const size_t idx)
{ return a->data + idx; } { return a->data + idx; }
#define BOX_CONTIGUOUS /* Depends on `BOX_ACCESS`. Also, `append` later. */
/** Writes `size` to `a`. @implements `tell_size` */ /** Writes `size` to `a`. @implements `tell_size` */
static void PA_(tell_size)(struct A_(array) *a, const size_t size) static void PA_(tell_size)(struct A_(array) *a, const size_t size)
{ assert(a); a->size = size; } { assert(a); a->size = size; }
/* Box override information. */ /** May become invalid after a topological change to any items previous. */
#define BOX_ PA_
#define BOX struct A_(array)
/** Cursor; may become invalid after a topological change to any items
previous. */
struct A_(array_iterator); struct A_(array_iterator);
struct A_(array_iterator) { struct PA_(iterator) _; }; struct A_(array_iterator) { struct PA_(iterator) _; };
@ -204,9 +165,9 @@ static void A_(array_)(struct A_(array) *const a)
static struct A_(array_iterator) A_(array_iterator)(struct A_(array) *a) static struct A_(array_iterator) A_(array_iterator)(struct A_(array) *a)
{ struct A_(array_iterator) it; it._ = PA_(iterator)(a); return it; } { struct A_(array_iterator) it; it._ = PA_(iterator)(a); return it; }
/** @return An iterator at `idx` of `a`. */ /** @return An iterator at `idx` of `a`. */
static struct A_(array_iterator) A_(array_iterator_before)(struct A_(array) *a, static struct A_(array_iterator) A_(array_iterator_at)(struct A_(array) *a,
size_t idx) { struct A_(array_iterator) it; size_t idx) { struct A_(array_iterator) it;
it._ = PA_(before)(a, idx); return it; } it._ = PA_(iterator_at)(a, idx); return it; }
/** @return `it` next element. */ /** @return `it` next element. */
static PA_(type) *A_(array_next)(struct A_(array_iterator) *const it) static PA_(type) *A_(array_next)(struct A_(array_iterator) *const it)
{ return assert(it), PA_(next)(&it->_); } { return assert(it), PA_(next)(&it->_); }
@ -369,26 +330,25 @@ static int A_(array_splice)(struct A_(array) *restrict const a,
return 1; return 1;
} }
#ifdef HAVE_ITERATE_H /* <!-- iterate */ /* Box override information. */
#define ITR_(n) ARRAY_CAT(A_(array), n) #define BOX_TYPE struct A_(array)
#include "iterate.h" /** \include */ #define BOX_CONTENT PA_(type) *
#undef ITR_ #define BOX_ PA_
#endif /* iterate --> */ #define BOX_MAJOR_NAME array
#define BOX_MINOR_NAME ARRAY_NAME
#define BOX_ACCESS
#define BOX_CONTIGUOUS
#ifdef ARRAY_TEST /* <!-- test */ #ifdef HAVE_ITERATE_H /* <!-- iterate */
/* Forward-declare. */ #include "iterate.h" /** \include */
static void (*PA_(to_string))(const PA_(type) *, char (*)[12]); #endif /* iterate --> */
static const char *(*PA_(array_to_string))(const struct A_(array) *);
#include "../test/test_array.h"
#endif /* test --> */
static void PA_(unused_base_coda)(void); static void PA_(unused_base_coda)(void);
static void PA_(unused_base)(void) { static void PA_(unused_base)(void) {
PA_(is_element_c)(0); PA_(forward)(0); PA_(next_c)(0); PA_(null)(); PA_(is_element)(0); PA_(remove)(0); PA_(size)(0);
PA_(is_element)(0); PA_(remove)(0); PA_(size)(0); PA_(at)(0, 0); PA_(at)(0, 0); PA_(tell_size)(0, 0);
PA_(tell_size)(0, 0);
A_(array)(); A_(array_)(0); A_(array)(); A_(array_)(0);
A_(array_iterator)(0); A_(array_iterator_before)(0, 0); A_(array_iterator)(0); A_(array_iterator_at)(0, 0);
A_(array_previous)(0); A_(array_next)(0); A_(array_previous)(0); A_(array_previous)(0); A_(array_next)(0); A_(array_previous)(0);
A_(array_insert)(0, 0, 0); A_(array_new)(0); A_(array_insert)(0, 0, 0); A_(array_new)(0);
A_(array_shrink)(0); A_(array_remove)(0, 0); A_(array_lazy_remove)(0, 0); A_(array_shrink)(0); A_(array_remove)(0, 0); A_(array_lazy_remove)(0, 0);
@ -398,38 +358,29 @@ static void PA_(unused_base)(void) {
} }
static void PA_(unused_base_coda)(void) { PA_(unused_base)(); } static void PA_(unused_base_coda)(void) { PA_(unused_base)(); }
#endif /* base code --> */
#elif defined(ARRAY_TO_STRING) /* base code --><!-- to string trait */
#ifdef ARRAY_TO_STRING_NAME #ifdef ARRAY_TRAIT /* <-- trait: Will be different on different includes. */
#define STR_(n) ARRAY_CAT(A_(array), ARRAY_CAT(ARRAY_TO_STRING_NAME, n)) #define BOX_TRAIT_NAME ARRAY_TRAIT
#else #endif /* trait --> */
#define STR_(n) ARRAY_CAT(A_(array), n)
#endif
#define TO_STRING ARRAY_TO_STRING #ifdef ARRAY_TO_STRING /* <!-- to string trait */
#include "to_string.h" /** \include */ #include "to_string.h" /** \include */
#ifdef ARRAY_TEST /* <!-- expect: greedy satisfy forward-declared. */
#undef ARRAY_TEST
static PSTR_(to_string_fn) PA_(to_string) = PSTR_(to_string);
static const char *(*PA_(array_to_string))(const struct A_(array) *)
= &STR_(to_string);
#endif /* expect --> */
#undef STR_
#undef ARRAY_TO_STRING #undef ARRAY_TO_STRING
#ifdef ARRAY_TO_STRING_NAME #ifndef ARRAY_TRAIT
#undef ARRAY_TO_STRING_NAME #define ARRAY_HAS_TO_STRING
#endif #endif
#endif /* to string trait --> */
#else /* to string trait --><!-- compare trait */ #if defined(ARRAY_TEST) && !defined(ARRAY_TRAIT) /* <!-- test base */
#include "../test/test_array.h"
#endif /* test base --> */
#ifdef ARRAY_COMPARE_NAME #if defined(ARRAY_COMPARE) || defined(ARRAY_IS_EQUAL) /* <!-- compare trait */
#define CMP_(n) ARRAY_CAT(A_(array), ARRAY_CAT(ARRAY_COMPARE_NAME, n))
#else
#define CMP_(n) ARRAY_CAT(A_(array), n)
#endif
#ifdef ARRAY_COMPARE /* <!-- cmp */ #ifdef ARRAY_COMPARE /* <!-- cmp */
#define COMPARE ARRAY_COMPARE #define COMPARE ARRAY_COMPARE
#else /* cmp --><!-- eq */ #else /* cmp --><!-- eq */
@ -437,41 +388,42 @@ static const char *(*PA_(array_to_string))(const struct A_(array) *)
#endif /* eq --> */ #endif /* eq --> */
#include "compare.h" /** \include */ #include "compare.h" /** \include */
#ifdef ARRAY_TEST /* <!-- test: this detects and outputs compare test. */ #ifdef ARRAY_TEST /* <!-- test: this detects and outputs compare test. */
#include "../test/test_array.h" #include "../test/test_array_compare.h"
#endif /* test --> */ #endif /* test --> */
#undef CMP_ #undef CMP_ /* From <compare.h>. */
#ifdef ARRAY_COMPARE_NAME #undef CMPEXTERN_
#undef ARRAY_COMPARE_NAME
#endif
#ifdef ARRAY_COMPARE #ifdef ARRAY_COMPARE
#undef ARRAY_COMPARE #undef ARRAY_COMPARE
#endif #else
#ifdef ARRAY_IS_EQUAL
#undef ARRAY_IS_EQUAL #undef ARRAY_IS_EQUAL
#endif #endif
#endif /* compare trait --> */
#endif /* traits --> */ #ifdef ARRAY_EXPECT_TRAIT /* <!-- more */
#ifdef ARRAY_EXPECT_TRAIT /* <!-- trait */
#undef ARRAY_EXPECT_TRAIT #undef ARRAY_EXPECT_TRAIT
#else /* trait --><!-- !trait */ #else /* more --><!-- done */
#ifdef ARRAY_TEST #undef BOX_TYPE
#error No ARRAY_TO_STRING traits defined for ARRAY_TEST.
#endif
#undef ARRAY_NAME
#undef ARRAY_TYPE
#undef BOX_
#undef BOX
#undef BOX_CONTENT #undef BOX_CONTENT
#undef BOX_ITERATOR #undef BOX_
#undef BOX_MAJOR_NAME
#undef BOX_MINOR_NAME
#undef BOX_ACCESS #undef BOX_ACCESS
#undef BOX_CONTIGUOUS #undef BOX_CONTIGUOUS
#endif /* !trait --> */ #undef ARRAY_NAME
#undef ARRAY_TO_STRING_TRAIT #undef ARRAY_TYPE
#undef ARRAY_COMPARE_TRAIT #undef ARRAY_MIN_CAPACITY
#undef ARRAY_TRAITS #ifdef ARRAY_HAS_TO_STRING
#undef ARRAY_HAS_TO_STRING
#endif
#ifdef ARRAY_TEST
#undef ARRAY_TEST
#endif
#endif /* done --> */
#ifdef ARRAY_TRAIT
#undef ARRAY_TRAIT
#undef BOX_TRAIT_NAME
#endif
#ifdef ARRAY_RESTRICT #ifdef ARRAY_RESTRICT
#undef ARRAY_RESTRICT #undef ARRAY_RESTRICT
#undef restrict #undef restrict

View File

@ -17,9 +17,7 @@ static void int_to_string(const int *const n, char (*const a)[12])
{ sprintf(*a, "%d", *n); } { sprintf(*a, "%d", *n); }
#define ARRAY_NAME int #define ARRAY_NAME int
#define ARRAY_TYPE int #define ARRAY_TYPE int
#define ARRAY_EXPECT_TRAIT #define ARRAY_TO_STRING
#include "array.h"
#define ARRAY_TO_STRING &int_to_string
#include "array.h" #include "array.h"
static int int_cmp(const int *const a, const int *const b) static int int_cmp(const int *const a, const int *const b)
{ return (*b < *a) - (*a < *b); } { return (*b < *a) - (*a < *b); }
@ -73,7 +71,8 @@ union date32 {
uint32_t u32; uint32_t u32;
struct { unsigned day : 5, month : 4, year : 23; }; struct { unsigned day : 5, month : 4, year : 23; };
}; };
static int date_mixup(union date32 a, union date32 b) { return a.u32 > b.u32; } static int page_compare(const union date32 a, const union date32 b)
{ return a.u32 > b.u32; }
static void date32_to_string(const union date32 d, char (*const z)[12]) { static void date32_to_string(const union date32 d, char (*const z)[12]) {
assert(d.year < 10000 && d.month && d.month <= 31 && d.day && d.day <= 31); assert(d.year < 10000 && d.month && d.month <= 31 && d.day && d.day <= 31);
sprintf(*z, "%u-%2.2u-%2.2u", d.year % 10000, d.month, d.day); sprintf(*z, "%u-%2.2u-%2.2u", d.year % 10000, d.month, d.day);
@ -97,19 +96,19 @@ no:
} }
/** Tomohiko Sakamoto comp.lang.c 1993-04-10. */ /** Tomohiko Sakamoto comp.lang.c 1993-04-10. */
static unsigned weekday(union date32 d) { /*static unsigned weekday(union date32 d) {
d.year -= d.month < 3; d.year -= d.month < 3;
return (d.year + d.year / 4 - d.year / 100 + d.year / 400 return (d.year + d.year / 4 - d.year / 100 + d.year / 400
+ "-bed=pen+mad."[d.month] + d.day) % 7; + "-bed=pen+mad."[d.month] + d.day) % 7;
} }*/
/* Contained in <lex.h> to share with <lex.re_c.c>. */ /* Contained in <lex.h> to share with <lex.re_c.c>. */
#define ARRAY_NAME lex #define ARRAY_NAME lex
#define ARRAY_TYPE struct lex #define ARRAY_TYPE struct lex
#include "array.h" #include "array.h"
struct page_tree_entry_c; struct page_tree_entry;
static void entry_to_string(struct page_tree_entry_c, char (*)[12]); static void page_to_string(struct page_tree_entry, char (*)[12]);
struct page { struct page {
struct char_array entry; struct char_array entry;
struct lex_array meaning; struct lex_array meaning;
@ -117,12 +116,10 @@ struct page {
#define TREE_NAME page #define TREE_NAME page
#define TREE_KEY union date32 #define TREE_KEY union date32
#define TREE_VALUE struct page #define TREE_VALUE struct page
#define TREE_COMPARE &date_mixup #define TREE_COMPARE &page_compare
#define TREE_EXPECT_TRAIT #define TREE_TO_STRING
#include "tree.h" #include "tree.h"
#define TREE_TO_STRING &entry_to_string static void page_to_string(const struct page_tree_entry entry,
#include "tree.h"
static void entry_to_string(const struct page_tree_entry_c entry,
char (*const z)[12]) { date32_to_string(*entry.key, z); } char (*const z)[12]) { date32_to_string(*entry.key, z); }
struct source { char *key, *desc; }; struct source { char *key, *desc; };
@ -165,7 +162,7 @@ static int bible_graph(/*const*/ struct page_tree *const journal) {
struct page_tree_entry entry = { 0, 0 }; struct page_tree_entry entry = { 0, 0 };
struct lex *lex = 0; struct lex *lex = 0;
size_t count = 0; size_t count = 0;
for(struct page_tree_iterator p_it = page_tree_iterator(journal); for(struct page_tree_iterator p_it = page_tree_begin(journal);
(entry = page_tree_next(&p_it)).key; ) { (entry = page_tree_next(&p_it)).key; ) {
struct page *const page = entry.value; struct page *const page = entry.value;
for(struct lex_array_iterator l_it = lex_array_iterator(&page->meaning); for(struct lex_array_iterator l_it = lex_array_iterator(&page->meaning);
@ -218,11 +215,11 @@ catch:
return 0; return 0;
} }
#define C_BLACK "\033[0;30m" /*#define C_BLACK "\033[0;30m"
#define C_RED "\033[0;31m" #define C_RED "\033[0;31m"
#define C_GREEN "\033[0;32m" #define C_GREEN "\033[0;32m"*/
#define C_YELLOW "\033[0;33m" #define C_YELLOW "\033[0;33m"
#define C_BLUE "\033[0;34m" /*#define C_BLUE "\033[0;34m"
#define C_PURPLE "\033[0;35m" #define C_PURPLE "\033[0;35m"
#define C_CYAN "\033[0;36m" #define C_CYAN "\033[0;36m"
#define C_WHITE "\033[0;37m" #define C_WHITE "\033[0;37m"
@ -234,7 +231,7 @@ catch:
#define CB_BLUE "\033[1;34m" #define CB_BLUE "\033[1;34m"
#define CB_PURPLE "\033[1;35m" #define CB_PURPLE "\033[1;35m"
#define CB_CYAN "\033[1;36m" #define CB_CYAN "\033[1;36m"
#define CB_WHITE "\033[1;37m" #define CB_WHITE "\033[1;37m"*/
#define C_RESET "\033[0m" #define C_RESET "\033[0m"
@ -346,7 +343,7 @@ int main(int argc, char **argv) {
(int)(lex->s1 - lex->s0), lex->s0); break; (int)(lex->s1 - lex->s0), lex->s0); break;
case KJV_CHAPTER_VERSE: printf(" ch. %.*s", case KJV_CHAPTER_VERSE: printf(" ch. %.*s",
(int)(lex->s1 - lex->s0), lex->s0); break; (int)(lex->s1 - lex->s0), lex->s0); break;
case KJV_TEXT: printf("%s%.*s", case KJV_TEXT: printf("%.*s",
(int)(lex->s1 - lex->s0), lex->s0); break; (int)(lex->s1 - lex->s0), lex->s0); break;
case KJV_NEXT: printf("(next)\n"); break; case KJV_NEXT: printf("(next)\n"); break;
default: default:
@ -411,7 +408,7 @@ finally:
if(dir && closedir(dir)) success = EXIT_FAILURE, perror("dir"); if(dir && closedir(dir)) success = EXIT_FAILURE, perror("dir");
int_array_(&years), int_array_(&months), int_array_(&days); int_array_(&years), int_array_(&months), int_array_(&days);
struct page_tree_entry entry; struct page_tree_entry entry;
for(struct page_tree_iterator it = page_tree_iterator(&journal); for(struct page_tree_iterator it = page_tree_begin(&journal);
(entry = page_tree_next(&it)).key; ) { (entry = page_tree_next(&it)).key; ) {
struct page *const page = entry.value; struct page *const page = entry.value;
char z[12]; char z[12];

View File

@ -21,7 +21,7 @@ re2c:define:YYCTYPE = char;
int lex_looks_like_year(const char *const a, int *const year) { int lex_looks_like_year(const char *const a, int *const year) {
const char *YYCURSOR = a, *YYMARKER = a, *s0; const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */ /*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt2; (void)yyt2, (void)yyt3;
assert(a && year); assert(a && year);
/*!re2c /*!re2c
@s0 ("-"? [1-9][0-9]* | "0") "\x00" { @s0 ("-"? [1-9][0-9]* | "0") "\x00" {
@ -43,7 +43,7 @@ int lex_looks_like_year(const char *const a, int *const year) {
int lex_looks_like_month(const char *const a) { int lex_looks_like_month(const char *const a) {
const char *YYCURSOR = a, *YYMARKER = a, *s0; const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */ /*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt1, (void)yyt2; (void)yyt1, (void)yyt2, (void)yyt3;
assert(a); assert(a);
/*!re2c /*!re2c
@s0 [0-1][0-9] "\x00" { @s0 [0-1][0-9] "\x00" {
@ -58,7 +58,7 @@ int lex_looks_like_month(const char *const a) {
int lex_looks_like_day(const char *const a) { int lex_looks_like_day(const char *const a) {
const char *YYCURSOR = a, *YYMARKER = a, *s0; const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */ /*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt1, (void)yyt2; (void)yyt1, (void)yyt2, (void)yyt3;
assert(a); assert(a);
/*!re2c /*!re2c
@s0 [0-3][0-9] ".txt\x00" { @s0 [0-3][0-9] ".txt\x00" {
@ -85,7 +85,7 @@ int lex_looks_like_day(const char *const a) {
concurrent: convenient and bad. */ concurrent: convenient and bad. */
static struct scan { static struct scan {
/* `re2c` variables; these point directly into `buffer`. */ /* `re2c` variables; these point directly into `buffer`. */
const char *marker, *ctx_marker, *from, *cursor; const char *marker, /**ctx_marker,*/ *from, *cursor;
/* Weird `c2re` stuff: these fields have to come after when >5? */ /* Weird `c2re` stuff: these fields have to come after when >5? */
const char *label, *buffer; const char *label, *buffer;
enum condition condition; enum condition condition;
@ -100,7 +100,7 @@ static struct scan {
/** Resets the buffer to some `buffer`. */ /** Resets the buffer to some `buffer`. */
void lex_reset(const char *const buffer) { void lex_reset(const char *const buffer) {
scan.marker = scan.ctx_marker = scan.from = scan.cursor = scan.label scan.marker = /*scan.ctx_marker =*/ scan.from = scan.cursor = scan.label
= scan.buffer = buffer; = scan.buffer = buffer;
scan.condition = yycline; scan.condition = yycline;
scan.line = 1; scan.line = 1;
@ -124,7 +124,7 @@ int lex_next(struct lex *const x) {
re2c:flags:tags = 1; re2c:flags:tags = 1;
re2c:define:YYCURSOR = scan.cursor; re2c:define:YYCURSOR = scan.cursor;
re2c:define:YYMARKER = scan.marker; re2c:define:YYMARKER = scan.marker;
re2c:define:YYCTXMARKER = scan.ctx_marker; /*re2c:define:YYCTXMARKER = scan.ctx_marker;*/
re2c:define:YYCONDTYPE = 'condition'; re2c:define:YYCONDTYPE = 'condition';
re2c:define:YYGETCONDITION = 'scan.condition'; re2c:define:YYGETCONDITION = 'scan.condition';
re2c:define:YYGETCONDITION:naked = 1; re2c:define:YYGETCONDITION:naked = 1;
@ -170,7 +170,7 @@ scan:
<line> "^" => text { return x->symbol = CANCELLED, 1; } <line> "^" => text { return x->symbol = CANCELLED, 1; }
<line> "#" => text { return x->symbol = HEADING, 1; } <line> "#" => text { return x->symbol = HEADING, 1; }
/* Just plain text. */ /* Just plain text. */
<line> ws* / glyph :=> text /* match-empty-string: text takes care of it. */ <line> ws* / glyph :=> text /* Match-empty-string: text takes care of it. */
<text> newline => line { x->line = ++scan.line; goto scan; } <text> newline => line { x->line = ++scan.line; goto scan; }
<text, bible> ws+ { goto scan; } <text, bible> ws+ { goto scan; }

View File

@ -3,16 +3,8 @@
@subtitle To string trait @subtitle To string trait
Interface defined by `BOX_`, `BOX`, and `BOX_CONTENT`. Interface defined by box. Requires `<NAME>[_<TRAIT>]_to_string` be declared as
a <typedef:<PSTR>to_string_fn>.
@param[STR_(n)]
A one-argument macro producing a name that is responsible for the name of the
to string function. Should be something like
`STR_(to_string) -> widget_foo_to_string`. The caller is responsible for
undefining `STR_`.
@param[TO_STRING]
Function implementing <typedef:<PZ>to_string_fn>.
@param[TO_STRING_LEFT, TO_STRING_RIGHT] @param[TO_STRING_LEFT, TO_STRING_RIGHT]
7-bit characters, defaults to '(' and ')'. 7-bit characters, defaults to '(' and ')'.
@ -27,8 +19,9 @@
@std C89 */ @std C89 */
#if !defined(BOX_) || !defined(BOX) || !defined(BOX_CONTENT) \ #if !defined(BOX_TYPE) || !defined(BOX_CONTENT) || !defined(BOX_) \
|| !defined(STR_) || !defined(TO_STRING) || !defined(BOX_MAJOR_NAME) || !defined(BOX_MINOR_NAME) \
|| defined(STR_) || defined(STREXTERN_)
#error Unexpected preprocessor symbols. #error Unexpected preprocessor symbols.
#endif #endif
@ -45,7 +38,7 @@
#define TO_STRING_H #define TO_STRING_H
#include <string.h> #include <string.h>
#if defined(TO_STRING_CAT_) || defined(TO_STRING_CAT) || defined(PSTR_) #if defined(TO_STRING_CAT_) || defined(TO_STRING_CAT) || defined(PSTR_)
#error Unexpected defines. #error Unexpected preprocessor symbols.
#endif #endif
/* <Kernighan and Ritchie, 1988, p. 231>. */ /* <Kernighan and Ritchie, 1988, p. 231>. */
#define TO_STRING_CAT_(n, m) n ## _ ## m #define TO_STRING_CAT_(n, m) n ## _ ## m
@ -78,19 +71,39 @@ static unsigned to_string_buffer_i;
#define TO_STRING_RIGHT ')' #define TO_STRING_RIGHT ')'
#endif #endif
typedef BOX PSTR_(box); #ifndef BOX_TRAIT_NAME /* <!-- !trait */
typedef BOX_CONTENT PSTR_(element_c); #define STR_(n) TO_STRING_CAT(TO_STRING_CAT(BOX_MINOR_NAME, BOX_MAJOR_NAME), n)
#define STREXTERN_(n) TO_STRING_CAT(BOX_MINOR_NAME, n)
#else /* !trait --><!-- trait */
#define STR_(n) TO_STRING_CAT(TO_STRING_CAT(BOX_MINOR_NAME, BOX_MAJOR_NAME), \
TO_STRING_CAT(BOX_TRAIT_NAME, n))
#define STREXTERN_(n) TO_STRING_CAT(TO_STRING_CAT(BOX_MINOR_NAME, \
BOX_TRAIT_NAME), n)
#endif /* trait --> */
/** <src/to_string.h>: responsible for turning the argument into a 12-`char` /* Provides an extra level of indirection for boxes if they need it. */
null-terminated output string. */ #ifndef TO_STRING_THUNK_
typedef void (*PSTR_(to_string_fn))(PSTR_(element_c), char (*)[12]); #define TO_STRING_THUNK_(n) n
/* Check that `TO_STRING` is a function implementing #endif
<typedef:<PSTR>to_string>. */
static const PSTR_(to_string_fn) PSTR_(to_string) = (TO_STRING); /* Hopefully gets rid of any nestled-qualifiers, but only when appropriate. */
#ifndef TO_STRING_CAST
#define TO_STRING_CAST (void *)
#endif
typedef BOX_TYPE PSTR_(box);
typedef BOX_CONTENT PSTR_(element);
typedef const BOX_CONTENT PSTR_(element_c); /* Assumes a lot. */
/** <src/to_string.h>: responsible for turning the read-only argument into a
12-`char` null-terminated output string. The first argument should be a
read-only reference to an element and the second a pointer to the bytes. */
typedef void (*PSTR_(to_string_fn))(const PSTR_(element), char (*)[12]);
/* _Nb_: this is for documentation only; there is no way to get a general
read-only type which what we are supplied. Think of nested pointers. */
/** <src/to_string.h>: print the contents of `box` in a static string buffer of /** <src/to_string.h>: print the contents of `box` in a static string buffer of
256 bytes, with limitations of only printing 4 things at a time. `<STR>` is 256 bytes, with limitations of only printing 4 things at a time.
loosely contracted to be a name `<X>box[<X_TO_STRING_NAME>]`.
@return Address of the static buffer. @order \Theta(1) @allow */ @return Address of the static buffer. @order \Theta(1) @allow */
static const char *STR_(to_string)(const PSTR_(box) *const box) { static const char *STR_(to_string)(const PSTR_(box) *const box) {
const char comma = ',', space = ' ', ellipsis[] = "", const char comma = ',', space = ' ', ellipsis[] = "",
@ -98,25 +111,31 @@ static const char *STR_(to_string)(const PSTR_(box) *const box) {
const size_t ellipsis_len = sizeof ellipsis - 1; const size_t ellipsis_len = sizeof ellipsis - 1;
char *const buffer = to_string_buffers[to_string_buffer_i++], *b = buffer; char *const buffer = to_string_buffers[to_string_buffer_i++], *b = buffer;
size_t advance; size_t advance;
PSTR_(element_c) x; PSTR_(element) x;
struct BOX_(forward) it; struct BOX_(iterator) it;
int is_sep = 0; int is_sep = 0;
/* Minimum size: "(" "XXXXXXXXXXX" "," "…" ")" "\0". */ /* Minimum size: "(" "XXXXXXXXXXX" "," "…" ")" "\0". */
assert(box && !(to_string_buffers_no & (to_string_buffers_no - 1)) assert(box && !(to_string_buffers_no & (to_string_buffers_no - 1))
&& to_string_buffer_size >= 1 + 11 + 1 + ellipsis_len + 1 + 1); && to_string_buffer_size >= 1 + 11 + 1 + ellipsis_len + 1 + 1);
/* Advance the buffer for next time. */ /* Advance the buffer for next time. */
to_string_buffer_i &= to_string_buffers_no - 1; to_string_buffer_i &= to_string_buffers_no - 1;
it = BOX_(forward)(box); { /* We do not modify `box`, but the compiler doesn't know that. */
PSTR_(box) *promise_box;
memcpy(&promise_box, &box, sizeof box);
it = BOX_(iterator)(promise_box);
}
*b++ = left; *b++ = left;
while(BOX_(is_element_c)(x = BOX_(next_c)(&it))) { while(BOX_(is_element)(x = BOX_(next)(&it))) {
PSTR_(to_string)(x, (char (*)[12])b); /* One must have this function declared! */
/* Paranoid about '\0'. */ TO_STRING_THUNK_(STREXTERN_(to_string))(TO_STRING_CAST
x, (char (*)[12])b);
/* Paranoid about '\0'; wastes 1 byte of 12, but otherwise confusing. */
for(advance = 0; *b != '\0' && advance < 11; b++, advance++); for(advance = 0; *b != '\0' && advance < 11; b++, advance++);
is_sep = 1, *b++ = comma, *b++ = space; is_sep = 1, *b++ = comma, *b++ = space;
/* Greedy typesetting: enough for "XXXXXXXXXXX" "," "…" ")" "\0". */ /* Greedy typesetting: enough for "XXXXXXXXXXX" "," "…" ")" "\0". */
if((size_t)(b - buffer) if((size_t)(b - buffer)
> to_string_buffer_size - 11 - 1 - ellipsis_len - 1 - 1) { > to_string_buffer_size - 11 - 1 - ellipsis_len - 1 - 1) {
if(BOX_(is_element_c)(BOX_(next_c)(&it))) goto ellipsis; if(BOX_(is_element)(BOX_(next)(&it))) goto ellipsis;
else break; else break;
} }
} }
@ -138,10 +157,10 @@ static void PSTR_(unused_to_string)(void)
{ STR_(to_string)(0); PSTR_(unused_to_string_coda)(); } { STR_(to_string)(0); PSTR_(unused_to_string_coda)(); }
static void PSTR_(unused_to_string_coda)(void) { PSTR_(unused_to_string)(); } static void PSTR_(unused_to_string_coda)(void) { PSTR_(unused_to_string)(); }
#undef TO_STRING #undef STR_
#ifdef TO_STRING_NAME #undef STREXTERN_
#undef TO_STRING_NAME #undef TO_STRING_CAST
#endif #undef TO_STRING_THUNK_
#ifdef TO_STRING_EXTERN #ifdef TO_STRING_EXTERN
#undef TO_STRING_EXTERN #undef TO_STRING_EXTERN
#endif #endif

View File

@ -32,46 +32,31 @@
should be okay for most variations. 4 is isomorphic to left-leaning red-black should be okay for most variations. 4 is isomorphic to left-leaning red-black
tree, <Sedgewick, 2008, LLRB>. The above illustration is 5. tree, <Sedgewick, 2008, LLRB>. The above illustration is 5.
@param[TREE_EXPECT_TRAIT] @param[TREE_DEFAULT]
Do not un-define certain variables for subsequent inclusion in a parameterized
trait.
@param[TREE_DEFAULT_NAME, TREE_DEFAULT]
Default trait; a name that satisfies `C` naming conventions when mangled and a Default trait; a name that satisfies `C` naming conventions when mangled and a
<typedef:<PB>value> used in <fn:<B>tree<D>get>. There can be multiple <typedef:<PB>value> used in <fn:<B>tree<D>get>.
defaults, but only one can omit `TREE_DEFAULT_NAME`.
@param[TREE_TO_STRING_NAME, TREE_TO_STRING] @param[TREE_TO_STRING]
To string trait contained in <src/to_string.h>; an optional unique `<SZ>` To string trait `<STR>` contained in <src/to_string.h>. Require
that satisfies `C` naming conventions when mangled and function implementing `<name>[<trait>]to_string` be declared as <typedef:<PSTR>to_string_fn>.
<typedef:<PSTR>to_string_fn>.
@param[TREE_EXPECT_TRAIT, TREE_TRAIT]
Named traits are obtained by including `tree.h` multiple times with
`TREE_EXPECT_TRAIT` and then subsequently including the name in `TREE_TRAIT`.
@fixme merge, difference @fixme merge, difference
@std C89 */ @std C89 */
#if !defined(TREE_NAME) #if !defined(TREE_NAME)
#error Name TREE_NAME undefined. #error Name undefined.
#endif #endif
#if defined(TREE_DEFAULT_NAME) || defined(TREE_DEFAULT) #if defined(TREE_TRAIT) ^ defined(BOX_TYPE)
#define TREE_DEFAULT_TRAIT 1 #error TREE_TRAIT name must come after TREE_EXPECT_TRAIT.
#else
#define TREE_DEFAULT_TRAIT 0
#endif #endif
#if defined(TREE_TO_STRING_NAME) || defined(TREE_TO_STRING) #if defined(TREE_TEST) && (!defined(TREE_TRAIT) && !defined(TREE_TO_STRING) \
#define TREE_TO_STRING_TRAIT 1 || defined(TREE_TRAIT) && !defined(TREE_HAS_TO_STRING))
#else #error Test requires to string.
#define TREE_TO_STRING_TRAIT 0
#endif
#define TREE_TRAITS TREE_DEFAULT_TRAIT + TREE_TO_STRING_TRAIT
#if TREE_TRAITS > 1
#error Only one trait per include is allowed; use TREE_EXPECT_TRAIT.
#endif
#if defined(TREE_DEFAULT_NAME) && !defined(TREE_DEFAULT)
#error TREE_DEFAULT_NAME requires TREE_DEFAULT.
#endif
#if defined(TREE_TO_STRING_NAME) && !defined(TREE_TO_STRING)
#error TREE_TO_STRING_NAME requires TREE_TO_STRING.
#endif #endif
#ifndef TREE_H /* <!-- idempotent */ #ifndef TREE_H /* <!-- idempotent */
@ -117,8 +102,7 @@ struct tree_node_count { size_t branches, leaves; };
#endif /* idempotent --> */ #endif /* idempotent --> */
#if TREE_TRAITS == 0 /* <!-- base code */ #ifndef TREE_TRAIT /* <!-- base code */
#ifndef TREE_ORDER #ifndef TREE_ORDER
#define TREE_ORDER 65 /* Maximum branching factor. This sets the granularity. */ #define TREE_ORDER 65 /* Maximum branching factor. This sets the granularity. */
@ -143,10 +127,9 @@ typedef const TREE_VALUE PB_(value_c);
/** Returns a positive result if `a` is out-of-order with respect to `b`, /** 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 inducing a strict weak order. This is compatible, but less strict then the
comparators from `bsearch` and `qsort`; it only needs to divide entries comparators from `bsearch` and `qsort`; it only needs to divide entries into
into two instead of three categories. */ two instead of three categories. */
typedef int (*PB_(compare_fn))(PB_(key_c) a, PB_(key_c) b); typedef int (*PB_(compare_fn))(PB_(key_c) a, PB_(key_c) b);
#ifndef TREE_COMPARE /* <!-- !cmp */ #ifndef TREE_COMPARE /* <!-- !cmp */
/** The default `TREE_COMPARE` on `a` and `b` is integer comparison that /** The default `TREE_COMPARE` on `a` and `b` is integer comparison that
results in ascending order, `a > b`. @implements <typedef:<PB>compare_fn> */ results in ascending order, `a > b`. @implements <typedef:<PB>compare_fn> */
@ -154,7 +137,6 @@ static int PB_(default_compare)(PB_(key_c) a, PB_(key_c) b)
{ return a > b; } { return a > b; }
#define TREE_COMPARE &PB_(default_compare) #define TREE_COMPARE &PB_(default_compare)
#endif /* !cmp --> */ #endif /* !cmp --> */
/* Check that `TREE_COMPARE` is a function implementing /* Check that `TREE_COMPARE` is a function implementing
<typedef:<PB>compare_fn>, if defined. */ <typedef:<PB>compare_fn>, if defined. */
static const PB_(compare_fn) PB_(compare) = (TREE_COMPARE); static const PB_(compare_fn) PB_(compare) = (TREE_COMPARE);
@ -198,7 +180,6 @@ static const struct PB_(branch) *PB_(as_branch_c)(const struct PB_(node) *
/* Address of a specific key by node. There is a need for node plus index /* 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. */ without height, but we'll just let height be unused. */
struct PB_(ref) { struct PB_(node) *node; unsigned height, idx; }; struct PB_(ref) { struct PB_(node) *node; unsigned height, idx; };
struct PB_(ref_c) { const struct PB_(node) *node; unsigned height, idx; };
/* Node plus height is a sub-tree. A <tag:<B>tree> is a sub-tree of the tree. */ /* Node plus height is a sub-tree. A <tag:<B>tree> is a sub-tree of the tree. */
struct PB_(tree) { struct PB_(node) *node; unsigned height; }; struct PB_(tree) { struct PB_(node) *node; unsigned height; };
/** To initialize it to an idle state, see <fn:<B>tree>, `{0}` (`C99`), or /** To initialize it to an idle state, see <fn:<B>tree>, `{0}` (`C99`), or
@ -214,26 +195,15 @@ struct B_(tree) { struct PB_(tree) root; };
pointer-to-<typedef:<PB>value>. The reason these are pointers is because it pointer-to-<typedef:<PB>value>. The reason these are pointers is because it
is not contiguous in memory. */ is not contiguous in memory. */
struct B_(tree_entry) { PB_(key) *key; PB_(value) *value; }; struct B_(tree_entry) { PB_(key) *key; PB_(value) *value; };
/* FIXME: are you sure that this doesn't allow you to movify keys? we do not
want modification of keys (right?? otoh, it is the *placement* not the actual
value that is fixed.) */
struct B_(tree_entry_c) { PB_(key_c) *key; const PB_(value) *value; };
/** On `TREE_VALUE`, otherwise it's just an alias for /** On `TREE_VALUE`, otherwise it's just an alias for
pointer-to-<typedef:<PB>key>. */ pointer-to-<typedef:<PB>key>. */
typedef struct B_(tree_entry) PB_(entry); typedef struct B_(tree_entry) PB_(entry);
typedef struct B_(tree_entry_c) PB_(entry_c);
static PB_(entry) PB_(null_entry)(void) static PB_(entry) PB_(null_entry)(void)
{ const PB_(entry) e = { 0, 0 }; return e; } { const PB_(entry) e = { 0, 0 }; return e; }
static PB_(entry_c) PB_(null_entry_c)(void)
{ const PB_(entry_c) e = { 0, 0 }; return e; }
/** Constructs entry from `node` and `i`. */ /** Constructs entry from `node` and `i`. */
static PB_(entry) PB_(cons_entry)(struct PB_(node) *const node, static PB_(entry) PB_(cons_entry)(struct PB_(node) *const node,
const unsigned i) { PB_(entry) e; const unsigned i) { PB_(entry) e;
e.key = node->key + i, e.value = node->value + i; return e; } e.key = node->key + i, e.value = node->value + i; return e; }
/** Constructs entry from `node` and `i`. */
static PB_(entry_c) PB_(cons_entry_c)(const struct PB_(node) *const node,
const unsigned i) { PB_(entry_c) e;
e.key = node->key + i, e.value = node->value + i; return e; }
/** Gets the value of `ref`. */ /** Gets the value of `ref`. */
static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref) static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
{ return ref.node ? ref.node->value + ref.idx : 0; } { return ref.node ? ref.node->value + ref.idx : 0; }
@ -242,15 +212,10 @@ static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
typedef PB_(key) PB_(value); typedef PB_(key) PB_(value);
typedef PB_(key) *PB_(entry); typedef PB_(key) *PB_(entry);
typedef PB_(key_c) *PB_(entry_c);
static PB_(entry_c) PB_(null_entry_c)(void) { return 0; }
static PB_(entry) PB_(null_entry)(void) { return 0; } static PB_(entry) PB_(null_entry)(void) { return 0; }
/** Constructs entry from `node` and `i`. */ /** Constructs entry from `node` and `i`. */
static PB_(entry) PB_(cons_entry)(struct PB_(node) *const node, static PB_(entry) PB_(cons_entry)(struct PB_(node) *const node,
const unsigned i) { return node->key + i; } const unsigned i) { return node->key + i; }
/** Constructs entry from `node` and `i`. */
static PB_(entry_c) PB_(cons_entry_c)(const struct PB_(node) *const node,
const unsigned i) { return node->key + i; }
/** Gets the value of `ref`. */ /** Gets the value of `ref`. */
static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref) static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
{ return ref.node ? ref.node->key + ref.idx : 0; } { return ref.node ? ref.node->key + ref.idx : 0; }
@ -296,69 +261,39 @@ static int PB_(to_predecessor)(struct PB_(tree) tree,
*ref = prev; *ref = prev;
} return 1; /* Jumped nodes. */ } return 1; /* Jumped nodes. */
} }
/* @return If `ref_c` in `tree` has a successor, then it increments. */ /** @return If `ref` in `tree` has a successor, then it increments. */
#define TREE_TO_SUCCESSOR(to_successor_c, ref_c) \ static int PB_(to_successor)(struct PB_(tree) tree,
static int PB_(to_successor_c)(struct PB_(tree) tree, \ struct PB_(ref) *const ref) {
struct PB_(ref_c) *const ref) { \ assert(ref);
assert(ref); \ if(!tree.node || tree.height == UINT_MAX) return 0; /* Empty. */
if(!tree.node || tree.height == UINT_MAX) return 0; /* Empty. */ \ if(!ref->node)
if(!ref->node) \ ref->node = tree.node, ref->height = tree.height, ref->idx = 0;
ref->node = tree.node, ref->height = tree.height, ref->idx = 0; \ else
else \ ref->idx++;
ref->idx++; \ while(ref->height) ref->height--,
while(ref->height) ref->height--, \ ref->node = PB_(as_branch_c)(ref->node)->child[ref->idx], ref->idx = 0;
ref->node = PB_(as_branch_c)(ref->node)->child[ref->idx], ref->idx = 0; \ if(ref->idx < ref->node->size) return 1; /* Likely. */
if(ref->idx < ref->node->size) return 1; /* Likely. */ \ if(!ref->node->size) return 0; /* When bulk-loading. */
if(!ref->node->size) return 0; /* When bulk-loading. */ \ { /* Re-descend; pick the minimum height node that has a next key. */
{ /* Re-descend; pick the minimum height node that has a next key. */ \ struct PB_(ref) next;
struct PB_(ref_c) next; \ unsigned a0;
unsigned a0; \ PB_(key) x;
PB_(key) x; \ for(next.node = 0, x = ref->node->key[ref->node->size - 1]; tree.height;
for(next.node = 0, x = ref->node->key[ref->node->size - 1]; tree.height; \ tree.node = PB_(as_branch_c)(tree.node)->child[a0], tree.height--) {
tree.node = PB_(as_branch_c)(tree.node)->child[a0], tree.height--) { \ unsigned a1 = tree.node->size;
unsigned a1 = tree.node->size; \ a0 = 0;
a0 = 0; \ while(a0 < a1) {
while(a0 < a1) { \ const unsigned m = (a0 + a1) / 2;
const unsigned m = (a0 + a1) / 2; \ if(PB_(compare)(x, tree.node->key[m]) > 0) a0 = m + 1; else a1 = m;
if(PB_(compare)(x, tree.node->key[m]) > 0) a0 = m + 1; else a1 = m;\ }
} \ if(a0 < tree.node->size)
if(a0 < tree.node->size) \ next.node = tree.node, next.height = tree.height, next.idx = a0;
next.node = tree.node, next.height = tree.height, next.idx = a0; \ }
} \ if(!next.node) return 0; /* Off right. */
if(!next.node) return 0; /* Off right. */ \ *ref = next;
*ref = next; \ } return 1; /* Jumped nodes. */
} return 1; /* Jumped nodes. */ \
}
TREE_TO_SUCCESSOR(to_successor, ref) /* For cursor. */
TREE_TO_SUCCESSOR(to_successor_c, ref_c) /* For forward iteration. */
#undef TREE_TO_SUCCESSOR
#define BOX_CONTENT PB_(entry_c)
/** Is `e` not null? @implements `is_element_c` */
static int PB_(is_element_c)(PB_(entry_c) e) {
#ifdef TREE_VALUE
return !!e.key;
#else
return !!e;
#endif
} }
/* @implements `forward` */
struct PB_(forward) { const struct PB_(tree) *root; struct PB_(ref_c) next; };
/** @return Before `tree`, (can be null.) @implements `forward` */
static struct PB_(forward) PB_(forward)(const struct B_(tree) *const tree) {
struct PB_(forward) it;
it.root = tree ? &tree->root : 0, it.next.node = 0;
return it;
}
/** Move to next `it`. @return Element or null. @implements `next_c` */
static PB_(entry_c) PB_(next_c)(struct PB_(forward) *const it) {
return assert(it), PB_(to_successor_c)(*it->root, &it->next) ?
PB_(cons_entry_c)(it->next.node, it->next.idx) : PB_(null_entry_c)();
}
#define BOX_ITERATOR PB_(entry)
/** Is `e` not null? @implements `is_element` */ /** Is `e` not null? @implements `is_element` */
static int PB_(is_element)(const PB_(entry) e) { static int PB_(is_element)(const PB_(entry) e) {
#ifdef TREE_VALUE #ifdef TREE_VALUE
@ -367,14 +302,11 @@ static int PB_(is_element)(const PB_(entry) e) {
return !!e; return !!e;
#endif #endif
} }
struct PB_(iterator) { struct PB_(tree) *root; struct PB_(ref) ref; int seen; };
/* @implements `cursor` */ /** Eliminates code-re-use from <fn:<PB>iterator> and <fn:<PB>end>.
struct PB_(cursor) { struct PB_(tree) *root; struct PB_(ref) ref; int seen; };
/** Eliminates code-re-use from <fn:<PB>begin> and <fn:<PB>end>.
@return Fills `it` and returns if `tree` has contents, in which case, `idx` @return Fills `it` and returns if `tree` has contents, in which case, `idx`
is uninitialized. */ is uninitialized. */
static int PB_(cursor_fill_part)(struct PB_(cursor) *const it, static int PB_(iterator_fill_part)(struct PB_(iterator) *const it,
struct B_(tree) *const tree) { struct B_(tree) *const tree) {
assert(it); assert(it);
it->seen = 0; it->seen = 0;
@ -389,20 +321,21 @@ static int PB_(cursor_fill_part)(struct PB_(cursor) *const it,
return 1; return 1;
} }
/** @return Before the start of `tree`, (can be null.) @implements `begin` */ /** @return Before the start of `tree`, (can be null.) @implements `begin` */
static struct PB_(cursor) PB_(begin)(struct B_(tree) *const tree) { static struct PB_(iterator) PB_(iterator)(struct B_(tree) *const tree) {
struct PB_(cursor) it; struct PB_(iterator) it;
if(PB_(cursor_fill_part)(&it, tree)) { if(PB_(iterator_fill_part)(&it, tree)) {
for(it.ref.node = tree->root.node; it.ref.height; for(it.ref.node = tree->root.node; it.ref.height;
it.ref.node = PB_(as_branch)(it.ref.node)->child[0], it.ref.height--); it.ref.node = PB_(as_branch)(it.ref.node)->child[0],
it.ref.height--);
it.ref.idx = 0; it.ref.idx = 0;
} }
return it; return it;
} }
/** @return Iterator after the end of `tree`, (can be null.) /** @return Iterator after the end of `tree`, (can be null.)
@implements `end` */ @implements `end` */
static struct PB_(cursor) PB_(end)(struct B_(tree) *const tree) { static struct PB_(iterator) PB_(end)(struct B_(tree) *const tree) {
struct PB_(cursor) it; struct PB_(iterator) it;
if(PB_(cursor_fill_part)(&it, tree)) { if(PB_(iterator_fill_part)(&it, tree)) {
for(it.ref.node = tree->root.node; it.ref.height; for(it.ref.node = tree->root.node; it.ref.height;
it.ref.node = PB_(as_branch)(it.ref.node)->child[it.ref.node->size], it.ref.node = PB_(as_branch)(it.ref.node)->child[it.ref.node->size],
it.ref.height--); it.ref.height--);
@ -410,9 +343,8 @@ static struct PB_(cursor) PB_(end)(struct B_(tree) *const tree) {
} }
return it; return it;
} }
/** Advances `it`. @return Element or null. @implements `next` */ /** Advances `it`. @return Element or null. @implements `next` */
static PB_(entry) PB_(next)(struct PB_(cursor) *const it) { static PB_(entry) PB_(next)(struct PB_(iterator) *const it) {
assert(it); assert(it);
if(!it->root || (it->seen || !it->ref.node) if(!it->root || (it->seen || !it->ref.node)
&& !PB_(to_successor)(*it->root, &it->ref)) && !PB_(to_successor)(*it->root, &it->ref))
@ -423,7 +355,7 @@ static PB_(entry) PB_(next)(struct PB_(cursor) *const it) {
: (it->seen = 0, PB_(null_entry)()); : (it->seen = 0, PB_(null_entry)());
} }
/** Move to previous `it`. @return Element or null. @implements `previous` */ /** Move to previous `it`. @return Element or null. @implements `previous` */
static PB_(entry) PB_(previous)(struct PB_(cursor) *const it) { static PB_(entry) PB_(previous)(struct PB_(iterator) *const it) {
assert(it); assert(it);
if(!it->root || !PB_(to_predecessor)(*it->root, &it->ref)) if(!it->root || !PB_(to_predecessor)(*it->root, &it->ref))
return it->ref.node = 0, it->seen = 0, PB_(null_entry)(); return it->ref.node = 0, it->seen = 0, PB_(null_entry)();
@ -534,7 +466,6 @@ static struct PB_(ref) PB_(lookup_remove)(struct PB_(tree) *const tree,
#undef TREE_FORNODE #undef TREE_FORNODE
#undef TREE_FLIPPED #undef TREE_FLIPPED
/** Zeroed data (not all-bits-zero) is initialized. @return An idle tree. /** Zeroed data (not all-bits-zero) is initialized. @return An idle tree.
@order \Theta(1) @allow */ @order \Theta(1) @allow */
static struct B_(tree) B_(tree)(void) { static struct B_(tree) B_(tree)(void) {
@ -853,7 +784,7 @@ static enum tree_result PB_(update)(struct PB_(tree) *const root,
PB_(key) key, PB_(key) *const eject) { PB_(key) key, PB_(key) *const eject) {
#endif /* set --> */ #endif /* set --> */
struct PB_(node) *new_head = 0; struct PB_(node) *new_head = 0;
struct PB_(ref) add, hole, cursor; struct PB_(ref) add, hole, iterator;
assert(root); assert(root);
if(!(add.node = root->node)) goto idle; if(!(add.node = root->node)) goto idle;
else if(root->height == UINT_MAX) goto empty; else if(root->height == UINT_MAX) goto empty;
@ -937,93 +868,93 @@ grow: /* Leaf is full. */ {
new_root->child[0] = root->node, root->node = hole.node; new_root->child[0] = root->node, root->node = hole.node;
hole.node->size = 1; hole.node->size = 1;
} }
cursor = hole; /* Go down; (as opposed to doing it on paper.) */ iterator = hole; /* Go down; (as opposed to doing it on paper.) */
goto split; goto split;
} split: { /* Split between the new and existing nodes. */ } split: { /* Split between the new and existing nodes. */
struct PB_(node) *sibling; struct PB_(node) *sibling;
assert(cursor.node && cursor.node->size && cursor.height); assert(iterator.node && iterator.node->size && iterator.height);
sibling = new_head; sibling = new_head;
/*PB_(graph_usual)(tree, "graph/work.gv");*/ /*PB_(graph_usual)(tree, "graph/work.gv");*/
/* Descend now while split hasn't happened -- easier. */ /* Descend now while split hasn't happened -- easier. */
new_head = --cursor.height ? PB_(as_branch)(new_head)->child[0] : 0; new_head = --iterator.height ? PB_(as_branch)(new_head)->child[0] : 0;
cursor.node = PB_(as_branch)(cursor.node)->child[cursor.idx]; iterator.node = PB_(as_branch)(iterator.node)->child[iterator.idx];
PB_(find_idx)(&cursor, key); PB_(find_idx)(&iterator, key);
assert(!sibling->size && cursor.node->size == TREE_MAX); /* Atomic. */ assert(!sibling->size && iterator.node->size == TREE_MAX); /* Atomic. */
/* Expand `cursor`, which is full, to multiple nodes. */ /* Expand `iterator`, which is full, to multiple nodes. */
if(cursor.idx < TREE_SPLIT) { /* Descend hole to `cursor`. */ if(iterator.idx < TREE_SPLIT) { /* Descend hole to `iterator`. */
memcpy(sibling->key, cursor.node->key + TREE_SPLIT, memcpy(sibling->key, iterator.node->key + TREE_SPLIT,
sizeof *sibling->key * (TREE_MAX - TREE_SPLIT)); sizeof *sibling->key * (TREE_MAX - TREE_SPLIT));
#ifdef TREE_VALUE #ifdef TREE_VALUE
memcpy(sibling->value, cursor.node->value + TREE_SPLIT, memcpy(sibling->value, iterator.node->value + TREE_SPLIT,
sizeof *sibling->value * (TREE_MAX - TREE_SPLIT)); sizeof *sibling->value * (TREE_MAX - TREE_SPLIT));
#endif #endif
hole.node->key[hole.idx] = cursor.node->key[TREE_SPLIT - 1]; hole.node->key[hole.idx] = iterator.node->key[TREE_SPLIT - 1];
#ifdef TREE_VALUE #ifdef TREE_VALUE
hole.node->value[hole.idx] = cursor.node->value[TREE_SPLIT - 1]; hole.node->value[hole.idx] = iterator.node->value[TREE_SPLIT - 1];
#endif #endif
memmove(cursor.node->key + cursor.idx + 1, memmove(iterator.node->key + iterator.idx + 1,
cursor.node->key + cursor.idx, iterator.node->key + iterator.idx,
sizeof *cursor.node->key * (TREE_SPLIT - 1 - cursor.idx)); sizeof *iterator.node->key * (TREE_SPLIT - 1 - iterator.idx));
#ifdef TREE_VALUE #ifdef TREE_VALUE
memmove(cursor.node->value + cursor.idx + 1, memmove(iterator.node->value + iterator.idx + 1,
cursor.node->value + cursor.idx, iterator.node->value + iterator.idx,
sizeof *cursor.node->value * (TREE_SPLIT - 1 - cursor.idx)); sizeof *iterator.node->value * (TREE_SPLIT - 1 - iterator.idx));
#endif #endif
if(cursor.height) { if(iterator.height) {
struct PB_(branch) *const cb = PB_(as_branch)(cursor.node), struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
*const sb = PB_(as_branch)(sibling); *const sb = PB_(as_branch)(sibling);
struct PB_(node) *temp = sb->child[0]; struct PB_(node) *temp = sb->child[0];
memcpy(sb->child, cb->child + TREE_SPLIT, memcpy(sb->child, cb->child + TREE_SPLIT,
sizeof *cb->child * (TREE_MAX - TREE_SPLIT + 1)); sizeof *cb->child * (TREE_MAX - TREE_SPLIT + 1));
memmove(cb->child + cursor.idx + 2, cb->child + cursor.idx + 1, memmove(cb->child + iterator.idx + 2, cb->child + iterator.idx + 1,
sizeof *cb->child * (TREE_SPLIT - 1 - cursor.idx)); sizeof *cb->child * (TREE_SPLIT - 1 - iterator.idx));
cb->child[cursor.idx + 1] = temp; cb->child[iterator.idx + 1] = temp;
} }
hole = cursor; hole = iterator;
} else if(cursor.idx > TREE_SPLIT) { /* Descend hole to `sibling`. */ } else if(iterator.idx > TREE_SPLIT) { /* Descend hole to `sibling`. */
hole.node->key[hole.idx] = cursor.node->key[TREE_SPLIT]; hole.node->key[hole.idx] = iterator.node->key[TREE_SPLIT];
#ifdef TREE_VALUE #ifdef TREE_VALUE
hole.node->value[hole.idx] = cursor.node->value[TREE_SPLIT]; hole.node->value[hole.idx] = iterator.node->value[TREE_SPLIT];
#endif #endif
hole.node = sibling, hole.height = cursor.height, hole.node = sibling, hole.height = iterator.height,
hole.idx = cursor.idx - TREE_SPLIT - 1; hole.idx = iterator.idx - TREE_SPLIT - 1;
memcpy(sibling->key, cursor.node->key + TREE_SPLIT + 1, memcpy(sibling->key, iterator.node->key + TREE_SPLIT + 1,
sizeof *sibling->key * hole.idx); sizeof *sibling->key * hole.idx);
memcpy(sibling->key + hole.idx + 1, cursor.node->key + cursor.idx, memcpy(sibling->key + hole.idx + 1, iterator.node->key + iterator.idx,
sizeof *sibling->key * (TREE_MAX - cursor.idx)); sizeof *sibling->key * (TREE_MAX - iterator.idx));
#ifdef TREE_VALUE #ifdef TREE_VALUE
memcpy(sibling->value, cursor.node->value + TREE_SPLIT + 1, memcpy(sibling->value, iterator.node->value + TREE_SPLIT + 1,
sizeof *sibling->value * hole.idx); sizeof *sibling->value * hole.idx);
memcpy(sibling->value + hole.idx + 1, cursor.node->value + cursor.idx, memcpy(sibling->value + hole.idx + 1, iterator.node->value + iterator.idx,
sizeof *sibling->value * (TREE_MAX - cursor.idx)); sizeof *sibling->value * (TREE_MAX - iterator.idx));
#endif #endif
if(cursor.height) { if(iterator.height) {
struct PB_(branch) *const cb = PB_(as_branch)(cursor.node), struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
*const sb = PB_(as_branch)(sibling); *const sb = PB_(as_branch)(sibling);
struct PB_(node) *temp = sb->child[0]; struct PB_(node) *temp = sb->child[0];
memcpy(sb->child, cb->child + TREE_SPLIT + 1, memcpy(sb->child, cb->child + TREE_SPLIT + 1,
sizeof *cb->child * (hole.idx + 1)); sizeof *cb->child * (hole.idx + 1));
memcpy(sb->child + hole.idx + 2, cb->child + cursor.idx + 1, memcpy(sb->child + hole.idx + 2, cb->child + iterator.idx + 1,
sizeof *cb->child * (TREE_MAX - cursor.idx)); sizeof *cb->child * (TREE_MAX - iterator.idx));
sb->child[hole.idx + 1] = temp; sb->child[hole.idx + 1] = temp;
} }
} else { /* Equal split: leave the hole where it is. */ } else { /* Equal split: leave the hole where it is. */
memcpy(sibling->key, cursor.node->key + TREE_SPLIT, memcpy(sibling->key, iterator.node->key + TREE_SPLIT,
sizeof *sibling->key * (TREE_MAX - TREE_SPLIT)); sizeof *sibling->key * (TREE_MAX - TREE_SPLIT));
#ifdef TREE_VALUE #ifdef TREE_VALUE
memcpy(sibling->value, cursor.node->value + TREE_SPLIT, memcpy(sibling->value, iterator.node->value + TREE_SPLIT,
sizeof *sibling->value * (TREE_MAX - TREE_SPLIT)); sizeof *sibling->value * (TREE_MAX - TREE_SPLIT));
#endif #endif
if(cursor.height) { if(iterator.height) {
struct PB_(branch) *const cb = PB_(as_branch)(cursor.node), struct PB_(branch) *const cb = PB_(as_branch)(iterator.node),
*const sb = PB_(as_branch)(sibling); *const sb = PB_(as_branch)(sibling);
memcpy(sb->child + 1, cb->child + TREE_SPLIT + 1, memcpy(sb->child + 1, cb->child + TREE_SPLIT + 1,
sizeof *cb->child * (TREE_MAX - TREE_SPLIT)); sizeof *cb->child * (TREE_MAX - TREE_SPLIT));
} }
} }
/* Divide `TREE_MAX + 1` into two trees. */ /* Divide `TREE_MAX + 1` into two trees. */
cursor.node->size = TREE_SPLIT, sibling->size = TREE_MAX - TREE_SPLIT; iterator.node->size = TREE_SPLIT, sibling->size = TREE_MAX - TREE_SPLIT;
if(cursor.height) goto split; /* Loop max `\log_{TREE_MIN} size`. */ if(iterator.height) goto split; /* Loop max `\log_{TREE_MIN} size`. */
hole.node->key[hole.idx] = key; hole.node->key[hole.idx] = key;
#ifdef TREE_VALUE #ifdef TREE_VALUE
if(value) *value = PB_(ref_to_valuep)(hole); if(value) *value = PB_(ref_to_valuep)(hole);
@ -1391,7 +1322,7 @@ struct PB_(scaffold) {
struct tree_node_count victim, source; struct tree_node_count victim, source;
size_t no; size_t no;
struct PB_(node) **data; struct PB_(node) **data;
struct { struct PB_(node) **head, **fresh, **cursor; } branch, leaf; struct { struct PB_(node) **head, **fresh, **iterator; } branch, leaf;
}; };
/** Counts the nodes `no` in `tree` for <fn:<PB>nodes>. */ /** Counts the nodes `no` in `tree` for <fn:<PB>nodes>. */
static int PB_(nodes_r)(struct PB_(tree) tree, static int PB_(nodes_r)(struct PB_(tree) tree,
@ -1431,15 +1362,15 @@ static int PB_(nodes)(const struct B_(tree) *const tree,
static void PB_(cannibalize_r)(struct PB_(ref) ref, static void PB_(cannibalize_r)(struct PB_(ref) ref,
struct PB_(scaffold) *const sc) { struct PB_(scaffold) *const sc) {
struct PB_(branch) *branch = PB_(as_branch)(ref.node); struct PB_(branch) *branch = PB_(as_branch)(ref.node);
const int keep_branch = sc->branch.cursor < sc->branch.fresh; const int keep_branch = sc->branch.iterator < sc->branch.fresh;
assert(ref.node && ref.height && sc); assert(ref.node && ref.height && sc);
if(keep_branch) *sc->branch.cursor = ref.node, sc->branch.cursor++; if(keep_branch) *sc->branch.iterator = ref.node, sc->branch.iterator++;
if(ref.height == 1) { /* Children are leaves. */ if(ref.height == 1) { /* Children are leaves. */
unsigned n; unsigned n;
for(n = 0; n <= ref.node->size; n++) { for(n = 0; n <= ref.node->size; n++) {
const int keep_leaf = sc->leaf.cursor < sc->leaf.fresh; const int keep_leaf = sc->leaf.iterator < sc->leaf.fresh;
struct PB_(node) *child = branch->child[n]; struct PB_(node) *child = branch->child[n];
if(keep_leaf) *sc->leaf.cursor = child, sc->leaf.cursor++; if(keep_leaf) *sc->leaf.iterator = child, sc->leaf.iterator++;
else free(child); else free(child);
} }
} else while(ref.idx <= ref.node->size) { } else while(ref.idx <= ref.node->size) {
@ -1461,12 +1392,12 @@ static void PB_(cannibalize)(const struct B_(tree) *const tree,
if(!sc->victim.branches && !sc->victim.leaves) return; if(!sc->victim.branches && !sc->victim.leaves) return;
assert(tree->root.node); assert(tree->root.node);
ref.node = tree->root.node, ref.height = tree->root.height, ref.idx = 0; ref.node = tree->root.node, ref.height = tree->root.height, ref.idx = 0;
sc->branch.cursor = sc->branch.head; sc->branch.iterator = sc->branch.head;
sc->leaf.cursor = sc->leaf.head; sc->leaf.iterator = sc->leaf.head;
if(ref.height) { if(ref.height) {
PB_(cannibalize_r)(ref, sc); PB_(cannibalize_r)(ref, sc);
} else { /* Just one leaf. */ } else { /* Just one leaf. */
*sc->leaf.cursor = ref.node; *sc->leaf.iterator = ref.node;
} }
} }
/** Do the work of `src` cloned with `sc`. Called from <fn:<PB>clone>. */ /** Do the work of `src` cloned with `sc`. Called from <fn:<PB>clone>. */
@ -1475,7 +1406,7 @@ static struct PB_(node) *PB_(clone_r)(struct PB_(tree) src,
struct PB_(node) *node; struct PB_(node) *node;
if(src.height) { if(src.height) {
struct PB_(branch) *const srcb = PB_(as_branch)(src.node), struct PB_(branch) *const srcb = PB_(as_branch)(src.node),
*const branch = PB_(as_branch)(node = *sc->branch.cursor++); *const branch = PB_(as_branch)(node = *sc->branch.iterator++);
unsigned i; unsigned i;
struct PB_(tree) child; struct PB_(tree) child;
*node = *src.node; /* Copy node. */ *node = *src.node; /* Copy node. */
@ -1485,7 +1416,7 @@ static struct PB_(node) *PB_(clone_r)(struct PB_(tree) src,
branch->child[i] = PB_(clone_r)(child, sc); branch->child[i] = PB_(clone_r)(child, sc);
} }
} else { /* Leaves. */ } else { /* Leaves. */
node = *sc->leaf.cursor++; node = *sc->leaf.iterator++;
*node = *src.node; *node = *src.node;
} }
return node; return node;
@ -1496,13 +1427,13 @@ static struct PB_(tree) PB_(clone)(const struct PB_(tree) *const src,
struct PB_(tree) sub; struct PB_(tree) sub;
assert(src && src->node && sc); assert(src && src->node && sc);
/* Go back to the beginning of the scaffold and pick off one by one. */ /* Go back to the beginning of the scaffold and pick off one by one. */
sc->branch.cursor = sc->branch.head; sc->branch.iterator = sc->branch.head;
sc->leaf.cursor = sc->leaf.head; sc->leaf.iterator = sc->leaf.head;
sub.node = PB_(clone_r)(*src, sc); sub.node = PB_(clone_r)(*src, sc);
sub.height = src->height; sub.height = src->height;
/* Used up all of them. No concurrent modifications, please. */ /* Used up all of them. No concurrent modifications, please. */
assert(sc->branch.cursor == sc->leaf.head assert(sc->branch.iterator == sc->leaf.head
&& sc->leaf.cursor == sc->data + sc->no); && sc->leaf.iterator == sc->data + sc->no);
return sub; return sub;
} }
/** `source` is copied to, and overwrites, `tree`. /** `source` is copied to, and overwrites, `tree`.
@ -1536,26 +1467,26 @@ static int B_(tree_clone)(struct B_(tree) *const tree,
need.branches = sc.source.branches > sc.victim.branches need.branches = sc.source.branches > sc.victim.branches
? sc.source.branches - sc.victim.branches : 0; ? sc.source.branches - sc.victim.branches : 0;
sc.branch.head = sc.data; sc.branch.head = sc.data;
sc.branch.fresh = sc.branch.cursor sc.branch.fresh = sc.branch.iterator
= sc.branch.head + sc.source.branches - need.branches; = sc.branch.head + sc.source.branches - need.branches;
sc.leaf.head = sc.branch.fresh + need.branches; sc.leaf.head = sc.branch.fresh + need.branches;
sc.leaf.fresh = sc.leaf.cursor sc.leaf.fresh = sc.leaf.iterator
= sc.leaf.head + sc.source.leaves - need.leaves; = sc.leaf.head + sc.source.leaves - need.leaves;
assert(sc.leaf.fresh + need.leaves == sc.data + sc.no); assert(sc.leaf.fresh + need.leaves == sc.data + sc.no);
} }
/* Add new nodes. */ /* Add new nodes. */
while(sc.branch.cursor != sc.leaf.head) { while(sc.branch.iterator != sc.leaf.head) {
struct PB_(branch) *branch; struct PB_(branch) *branch;
if(!(branch = malloc(sizeof *branch))) goto catch; if(!(branch = malloc(sizeof *branch))) goto catch;
branch->base.size = 0; branch->base.size = 0;
branch->child[0] = 0; branch->child[0] = 0;
*sc.branch.cursor++ = &branch->base; *sc.branch.iterator++ = &branch->base;
} }
while(sc.leaf.cursor != sc.data + sc.no) { while(sc.leaf.iterator != sc.data + sc.no) {
struct PB_(node) *leaf; struct PB_(node) *leaf;
if(!(leaf = malloc(sizeof *leaf))) goto catch; if(!(leaf = malloc(sizeof *leaf))) goto catch;
leaf->size = 0; leaf->size = 0;
*sc.leaf.cursor++ = leaf; *sc.leaf.iterator++ = leaf;
} }
/* Resources acquired; now we don't care about tree. */ /* Resources acquired; now we don't care about tree. */
PB_(cannibalize)(tree, &sc); PB_(cannibalize)(tree, &sc);
@ -1565,13 +1496,13 @@ static int B_(tree_clone)(struct B_(tree) *const tree,
catch: catch:
success = 0; success = 0;
if(!sc.data) goto finally; if(!sc.data) goto finally;
while(sc.leaf.cursor != sc.leaf.fresh) { while(sc.leaf.iterator != sc.leaf.fresh) {
struct PB_(node) *leaf = *(--sc.leaf.cursor); struct PB_(node) *leaf = *(--sc.leaf.iterator);
assert(leaf); assert(leaf);
free(leaf); free(leaf);
} }
while(sc.branch.cursor != sc.branch.fresh) { while(sc.branch.iterator != sc.branch.fresh) {
struct PB_(branch) *branch = PB_(as_branch)(*(--sc.branch.cursor)); struct PB_(branch) *branch = PB_(as_branch)(*(--sc.branch.iterator));
assert(branch); assert(branch);
free(branch); free(branch);
} }
@ -1581,27 +1512,22 @@ finally:
} }
/* Box override information. */
#define BOX_ PB_
#define BOX struct B_(tree)
/** Adding, deleting, or changes in the topology of the tree invalidate it. */ /** Adding, deleting, or changes in the topology of the tree invalidate it. */
struct B_(tree_cursor); struct B_(tree_iterator);
struct B_(tree_cursor) { struct PB_(cursor) _; }; struct B_(tree_iterator) { struct PB_(iterator) _; };
/** @return Cursor before the first element of `tree`. Can be null. /** @return Cursor before the first element of `tree`. Can be null.
@order \Theta(\log |`tree`|) @allow */ @order \Theta(\log |`tree`|) @allow */
static struct B_(tree_cursor) B_(tree_begin)(struct B_(tree) *const tree) static struct B_(tree_iterator) B_(tree_begin)(struct B_(tree) *const tree)
{ struct B_(tree_cursor) cur; cur._ = PB_(begin)(tree); return cur; } { struct B_(tree_iterator) it; it._ = PB_(iterator)(tree); return it; }
/** @param[tree] Can be null. @return Cursor in `tree` between elements, such /** @param[tree] Can be null. @return Cursor in `tree` between elements, such
that if <fn:<B>tree_next> is called, it will be smallest key that is not 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`. smaller than `x`, or, <fn:<B>tree_end> if `x` is greater than all in `tree`.
@order \Theta(\log |`tree`|) @allow */ @order \Theta(\log |`tree`|) @allow */
static struct B_(tree_cursor) B_(tree_begin_at)(struct B_(tree) *const tree, static struct B_(tree_iterator) B_(tree_begin_at)(struct B_(tree) *const tree,
const PB_(key) x) { const PB_(key) x) {
struct B_(tree_cursor) cur; struct B_(tree_iterator) cur;
if(!tree) return cur._.root = 0, cur; if(!tree) return cur._.root = 0, cur;
cur._.ref = PB_(lower)(tree->root, x); cur._.ref = PB_(lower)(tree->root, x);
cur._.root = &tree->root; cur._.root = &tree->root;
@ -1610,65 +1536,67 @@ static struct B_(tree_cursor) B_(tree_begin_at)(struct B_(tree) *const tree,
} }
/** @return Cursor after the last element of `tree`. Can be null. /** @return Cursor after the last element of `tree`. Can be null.
@order \Theta(\log |`tree`|) @allow */ @order \Theta(\log |`tree`|) @allow */
static struct B_(tree_cursor) B_(tree_end)(struct B_(tree) *const tree) static struct B_(tree_iterator) B_(tree_end)(struct B_(tree) *const tree)
{ struct B_(tree_cursor) cur; cur._ = PB_(end)(tree); return cur; } { struct B_(tree_iterator) cur; cur._ = PB_(end)(tree); return cur; }
/** Advances `cur` to the next element. @return A pointer to the current /** Advances `cur` to the next element. @return A pointer to the current
element, or null if it ran out of elements. The type is either a set element, or null if it ran out of elements. The type is either a set
pointer-to-key or a map <tag:<B>tree_entry> (with `TREE_VALUE`, both fields pointer-to-key or a map <tag:<B>tree_entry> (with `TREE_VALUE`, both fields
are null if null). @order \O(\log |`tree`|) @allow */ are null if null). @order \O(\log |`tree`|) @allow */
static PB_(entry) B_(tree_next)(struct B_(tree_cursor) *const cur) static PB_(entry) B_(tree_next)(struct B_(tree_iterator) *const cur)
{ return PB_(next)(&cur->_); } { return PB_(next)(&cur->_); }
/** Reverses `cur` to the previous element. @return A pointer to the previous /** Reverses `cur` to the previous element. @return A pointer to the previous
element, or null if it ran out of elements. The type is either a set element, or null if it ran out of elements. The type is either a set
pointer-to-key or a map <tag:<B>tree_entry> (with `TREE_VALUE`, both fields pointer-to-key or a map <tag:<B>tree_entry> (with `TREE_VALUE`, both fields
are null if null). @order \O(\log |`tree`|) @allow */ are null if null). @order \O(\log |`tree`|) @allow */
static PB_(entry) B_(tree_previous)(struct B_(tree_cursor) *const cur) static PB_(entry) B_(tree_previous)(struct B_(tree_iterator) *const cur)
{ return PB_(previous)(&cur->_); } { return PB_(previous)(&cur->_); }
#ifdef TREE_VALUE /* <!-- map */ #ifdef TREE_VALUE /* <!-- map */
/** Adds `key` and returns `value` to tree in cursor `cur`. See /** Adds `key` and returns `value` to tree in iterator `it`. See
<fn:<B>tree_try>. @return If `cur` is not pointing at a valid tree, returns <fn:<B>tree_try>. @return If `it` is not pointing at a valid tree, returns
`TREE_ERROR` and doesn't set `errno`, otherwise the same. */ `TREE_ERROR` and doesn't set `errno`, otherwise the same. */
static enum tree_result B_(tree_cursor_try)(struct B_(tree_cursor) *const static enum tree_result B_(tree_iterator_try)(struct B_(tree_iterator) *const
cur, const PB_(key) key, PB_(value) **const value) { it, const PB_(key) key, PB_(value) **const value) {
#else /* map --><!-- set */ #else /* map --><!-- set */
static enum tree_result B_(tree_cursor_try)(struct B_(tree_cursor) *const static enum tree_result B_(tree_iterator_try)(struct B_(tree_iterator) *const
cur, const PB_(key) key) { it, const PB_(key) key) {
#endif /* set --> */ #endif /* set --> */
enum { NONODE, ITERATING, END } where; enum { TREE_NONODE, TREE_ITERATING, TREE_END } where;
PB_(key) anchor; PB_(key) anchor;
enum tree_result ret; enum tree_result ret;
memset(&anchor, 0, sizeof anchor); /* Silence warnings. */ memset(&anchor, 0, sizeof anchor); /* Silence warnings. */
if(!cur || !cur->_.root) return TREE_ERROR; /* No tree. */ if(!it || !it->_.root) return TREE_ERROR; /* No tree. */
if(cur->_.ref.node && cur->_.root->height != UINT_MAX) { if(it->_.ref.node && it->_.root->height != UINT_MAX) {
where = (cur->_.ref.idx < cur->_.ref.node->size) ? ITERATING : END; where = (it->_.ref.idx < it->_.ref.node->size)
? TREE_ITERATING : TREE_END;
} else { } else {
where = NONODE; where = TREE_NONODE;
} }
if(where == ITERATING) anchor = cur->_.ref.node->key[cur->_.ref.idx]; if(where == TREE_ITERATING) anchor = it->_.ref.node->key[it->_.ref.idx];
if(where == NONODE || where == END) cur->_.seen = 0; /* Should be already. */ /* Should be already. */
if(where == TREE_NONODE || where == TREE_END) it->_.seen = 0;
#ifdef TREE_VALUE #ifdef TREE_VALUE
ret = PB_(update)(cur->_.root, key, 0, value); ret = PB_(update)(it->_.root, key, 0, value);
#else #else
ret = PB_(update)(cur->_.root, key, 0); ret = PB_(update)(it->_.root, key, 0);
#endif #endif
if(ret == TREE_ERROR) return TREE_ERROR; if(ret == TREE_ERROR) return TREE_ERROR;
assert(cur->_.root->height != UINT_MAX); /* Can't be empty. */ assert(it->_.root->height != UINT_MAX); /* Can't be empty. */
switch(where) { switch(where) {
case NONODE: cur->_.ref.node = 0; cur->_.seen = 0; break; case TREE_NONODE: it->_.ref.node = 0; it->_.seen = 0; break;
case ITERATING: cur->_.ref = PB_(lower)(*cur->_.root, anchor); break; case TREE_ITERATING: it->_.ref = PB_(lower)(*it->_.root, anchor); break;
case END: case TREE_END:
assert(cur->_.root->node); assert(it->_.root->node);
cur->_.ref.node = cur->_.root->node; it->_.ref.node = it->_.root->node;
cur->_.ref.height = cur->_.root->height; it->_.ref.height = it->_.root->height;
cur->_.ref.idx = cur->_.root->node->size; it->_.ref.idx = it->_.root->node->size;
while(cur->_.ref.height) { while(it->_.ref.height) {
cur->_.ref.node it->_.ref.node
= PB_(as_branch_c)(cur->_.ref.node)->child[cur->_.ref.idx]; = PB_(as_branch_c)(it->_.ref.node)->child[it->_.ref.idx];
cur->_.ref.idx = cur->_.ref.node->size; it->_.ref.idx = it->_.ref.node->size;
cur->_.ref.height--; it->_.ref.height--;
} }
cur->_.seen = 0; it->_.seen = 0;
break; break;
} }
return ret; return ret;
@ -1678,68 +1606,86 @@ static enum tree_result B_(tree_cursor_try)(struct B_(tree_cursor) *const
} }
#endif #endif
/** Removes the last entry returned by a valid `cur`. All other cursors on the /** Removes the last entry returned by a valid `it`. All other iterators on the
same object are invalidated, but `cur` is now between on the removed node. same object are invalidated, but `cur` is now between on the removed node.
@return Success, otherwise `cur` is not at a valid element. @return Success, otherwise `it` is not at a valid element.
@order \Theta(\log |`tree`|) */ @order \Theta(\log |`tree`|) */
static int B_(tree_cursor_remove)(struct B_(tree_cursor) *const cur) { static int B_(tree_iterator_remove)(struct B_(tree_iterator) *const it) {
PB_(key) remove; PB_(key) remove;
if(!cur || !cur->_.seen || !cur->_.root || !cur->_.ref.node if(!it || !it->_.seen || !it->_.root || !it->_.ref.node
|| cur->_.root->height == UINT_MAX || it->_.root->height == UINT_MAX
|| cur->_.ref.idx >= cur->_.ref.node->size || it->_.ref.idx >= it->_.ref.node->size
|| (remove = cur->_.ref.node->key[cur->_.ref.idx], || (remove = it->_.ref.node->key[it->_.ref.idx],
!PB_(remove)(cur->_.root, remove))) return 0; !PB_(remove)(it->_.root, remove))) return 0;
/* <fn:<B>tree_begin_at>. */ /* <fn:<B>tree_begin_at>. */
cur->_.ref = PB_(lower)(*cur->_.root, remove); it->_.ref = PB_(lower)(*it->_.root, remove);
cur->_.seen = 0; it->_.seen = 0;
return 1; return 1;
} }
#ifdef TREE_TEST /* <!-- test */
/* Forward-declare. */
static void (*PB_(to_string))(PB_(entry_c), char (*)[12]);
static const char *(*PB_(tree_to_string))(const struct B_(tree) *);
#include "../test/test_tree.h"
#endif /* test --> */
static void PB_(unused_base_coda)(void); static void PB_(unused_base_coda)(void);
static void PB_(unused_base)(void) { static void PB_(unused_base)(void) {
PB_(key) k; PB_(value) v; memset(&k, 0, sizeof k); memset(&v, 0, sizeof v); PB_(key) k; PB_(value) v; memset(&k, 0, sizeof k); memset(&v, 0, sizeof v);
PB_(is_element_c); PB_(forward); PB_(next_c); PB_(is_element); PB_(is_element);
B_(tree)(); B_(tree_)(0); B_(tree_clear)(0); B_(tree_count)(0); 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); B_(tree_contains)(0, k); B_(tree_get_or)(0, k, v); B_(tree_at_or)(0, k, v);
#ifdef TREE_VALUE #ifdef TREE_VALUE
B_(tree_bulk_add)(0, k, 0); B_(tree_try)(0, k, 0); B_(tree_bulk_add)(0, k, 0); B_(tree_try)(0, k, 0);
B_(tree_assign)(0, k, 0, 0); B_(tree_cursor_try)(0, k, 0); B_(tree_assign)(0, k, 0, 0); B_(tree_iterator_try)(0, k, 0);
#else #else
B_(tree_bulk_add)(0, k); B_(tree_try)(0, k); B_(tree_bulk_add)(0, k); B_(tree_try)(0, k);
B_(tree_assign)(0, k, 0); B_(tree_cursor_try)(0, k); B_(tree_assign)(0, k, 0); B_(tree_iterator_try)(0, k);
#endif #endif
B_(tree_bulk_finish)(0); B_(tree_remove)(0, k); B_(tree_clone)(0, 0); B_(tree_bulk_finish)(0); B_(tree_remove)(0, k); B_(tree_clone)(0, 0);
B_(tree_begin)(0); B_(tree_begin_at)(0, k); B_(tree_end)(0); B_(tree_begin)(0); B_(tree_begin_at)(0, k); B_(tree_end)(0);
B_(tree_previous)(0); B_(tree_next)(0); B_(tree_previous)(0); B_(tree_next)(0);
B_(tree_cursor_remove)(0); B_(tree_iterator_remove)(0);
PB_(unused_base_coda)(); PB_(unused_base_coda)();
} }
static void PB_(unused_base_coda)(void) { PB_(unused_base)(); } static void PB_(unused_base_coda)(void) { PB_(unused_base)(); }
/* Box override information. */
#define BOX_TYPE struct B_(tree)
#define BOX_CONTENT PB_(entry)
#define BOX_ PB_
#define BOX_MAJOR_NAME tree
#define BOX_MINOR_NAME TREE_NAME
#elif defined(TREE_DEFAULT) /* base code --><!-- default */ #endif /* base code --> */
#ifdef TREE_DEFAULT_NAME #ifdef TREE_TRAIT /* <-- trait: Will be different on different includes. */
#define B_D_(n, m) TREE_CAT(B_(n), TREE_CAT(TREE_DEFAULT_NAME, m)) #define BOX_TRAIT_NAME TREE_TRAIT
#endif /* trait --> */
#ifdef TREE_TO_STRING /* <!-- to string trait */
#define TO_STRING_LEFT '{'
#define TO_STRING_RIGHT '}'
#define TO_STRING_CAST
#include "to_string.h" /** \include */
#undef TREE_TO_STRING
#ifndef TREE_TRAIT
#define TREE_HAS_TO_STRING
#endif
#endif /* to string trait --> */
#if defined(TREE_TEST) && !defined(TREE_TRAIT) /* <!-- test base */
#include "../test/test_tree.h"
#endif /* test base --> */
#ifdef TREE_DEFAULT /* <!-- default trait */
#ifdef TREE_TRAIT
#define B_D_(n, m) TREE_CAT(B_(n), TREE_CAT(TREE_TRAIT, m))
#define PB_D_(n, m) TREE_CAT(tree, B_D_(n, m)) #define PB_D_(n, m) TREE_CAT(tree, B_D_(n, m))
#else #else
#define B_D_(n, m) TREE_CAT(B_(n), m) #define B_D_(n, m) TREE_CAT(B_(n), m)
#define PB_D_(n, m) TREE_CAT(tree, B_D_(n, m)) #define PB_D_(n, m) TREE_CAT(tree, B_D_(n, m))
#endif #endif
/* `TREE_DEFAULT` is a valid <tag:<PB>value>. */
/* Check that `TREE_DEFAULT` is a valid <tag:<PB>value> and that only one
`TREE_DEFAULT_NAME` is omitted. */
static const PB_(value) PB_D_(default, value) = (TREE_DEFAULT); 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 /** This is functionally identical to <fn:<B>tree_get_or>, but a with a trait
specifying a constant default value. specifying a constant default value.
@return The value associated with `key` in `tree`, (which can be null.) If @return The value associated with `key` in `tree`, (which can be null.) If
@ -1752,7 +1698,6 @@ static PB_(value) B_D_(tree, get)(const struct B_(tree) *const tree,
&& (ref = PB_(find)(&tree->root, key)).node && (ref = PB_(find)(&tree->root, key)).node
? *PB_(ref_to_valuep)(ref) : PB_D_(default, value); ? *PB_(ref_to_valuep)(ref) : PB_D_(default, value);
} }
/** This is functionally identical to <fn:<B>tree_at_or>, but a with a trait /** This is functionally identical to <fn:<B>tree_at_or>, but a with a trait
specifying a constant default value. specifying a constant default value.
@return The value associated with `key` in `tree`, (which can be null.) If @return The value associated with `key` in `tree`, (which can be null.) If
@ -1765,7 +1710,6 @@ static PB_(value) B_D_(tree, at)(const struct B_(tree) *const tree,
&& ref.idx < ref.node->size && ref.idx < ref.node->size
? *PB_(ref_to_valuep)(ref) : PB_D_(default, value); ? *PB_(ref_to_valuep)(ref) : PB_D_(default, value);
} }
static void PB_D_(unused, default_coda)(void); static void PB_D_(unused, default_coda)(void);
static void PB_D_(unused, default)(void) { static void PB_D_(unused, default)(void) {
PB_(key) k; memset(&k, 0, sizeof k); PB_(key) k; memset(&k, 0, sizeof k);
@ -1773,64 +1717,35 @@ static void PB_D_(unused, default)(void) {
PB_D_(unused, default_coda)(); PB_D_(unused, default_coda)();
} }
static void PB_D_(unused, default_coda)(void) { PB_D_(unused, default)(); } static void PB_D_(unused, default_coda)(void) { PB_D_(unused, default)(); }
#undef B_D_ #undef B_D_
#undef PB_D_ #undef PB_D_
#undef TREE_DEFAULT #undef TREE_DEFAULT
#ifdef TREE_DEFAULT_NAME #endif /* default trait --> */
#undef TREE_DEFAULT_NAME
#endif
#elif defined(TREE_TO_STRING) /* default --><!-- to string trait */ #ifdef TREE_EXPECT_TRAIT /* <!-- more */
#ifdef TREE_TO_STRING_NAME
#define STR_(n) TREE_CAT(B_(tree), TREE_CAT(TREE_TO_STRING_NAME, n))
#else
#define STR_(n) TREE_CAT(B_(tree), n)
#endif
#define TO_STRING TREE_TO_STRING
#define TO_STRING_LEFT '{'
#define TO_STRING_RIGHT '}'
#include "to_string.h" /** \include */
#ifdef TREE_TEST /* <!-- expect: greedy satisfy forward-declared. */
#undef TREE_TEST
static PSTR_(to_string_fn) PB_(to_string) = PSTR_(to_string);
static const char *(*PB_(tree_to_string))(const struct B_(tree) *)
= &STR_(to_string);
#endif /* expect --> */
#undef STR_
#undef TREE_TO_STRING
#ifdef TREE_TO_STRING_NAME
#undef TREE_TO_STRING_NAME
#endif
#endif /* traits --> */
#ifdef TREE_EXPECT_TRAIT /* <!-- trait */
#undef TREE_EXPECT_TRAIT #undef TREE_EXPECT_TRAIT
#else /* trait --><!-- !trait */ #else /* more --><!-- done */
#ifdef TREE_TEST #undef BOX_TYPE
#error No TREE_TO_STRING traits defined for TREE_TEST. #undef BOX_CONTENT
#endif #undef BOX_
#undef TREE_ORDER #undef BOX_MAJOR_NAME
#undef BOX_MINOR_NAME
#undef TREE_NAME #undef TREE_NAME
#undef TREE_KEY #undef TREE_KEY
#undef TREE_ORDER
#undef TREE_COMPARE #undef TREE_COMPARE
#ifdef TREE_VALUE #ifdef TREE_VALUE
#undef TREE_VALUE #undef TREE_VALUE
#endif #endif
#ifdef TREE_HAS_TO_STRING
#undef TREE_HAS_TO_STRING
#endif
#ifdef TREE_TEST #ifdef TREE_TEST
#undef TREE_TEST #undef TREE_TEST
#endif #endif
#undef BOX_ #endif /* done --> */
#undef BOX #ifdef TREE_TRAIT
#undef BOX_CONTENT #undef TREE_TRAIT
#undef BOX_ITERATOR #undef BOX_TRAIT_NAME
#endif /* !trait --> */ #endif
#undef TREE_DEFAULT_TRAIT
#undef TREE_TO_STRING_TRAIT
#undef TREE_TRAITS