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
optimize := -ffast-math
warnbasic := -Wall -pedantic -ansi # -std=c99
warnbasic := -Wall -pedantic -std=c11
# Some stuff is really new.
warnclang := -Wextra \
-Weverything \

View File

@ -17,48 +17,35 @@
<typedef:<PA>type>, associated therewith; required. `<PA>` is private, whose
names are prefixed in a manner to avoid collisions.
@param[ARRAY_EXPECT_TRAIT]
Do not un-define certain variables for subsequent inclusion in a parameterized
trait.
@param[ARRAY_COMPARE, ARRAY_IS_EQUAL]
Compare `<CMP>` trait contained in <src/compare.h>. Requires
`<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]
Compare trait contained in <src/compare.h>. An optional mangled name for
uniqueness and a function implementing either <typedef:<PCMP>compare_fn> or
<typedef:<PCMP>bipredicate_fn>.
@param[ARRAY_TO_STRING]
To string `<STR>` trait contained in <src/to_string.h>. Requires
`<name>[<trait>]to_string` be declared as <typedef:<PSTR>to_string_fn>.
@param[ARRAY_TO_STRING_NAME, ARRAY_TO_STRING]
To string trait contained in <src/to_string.h>. An optional mangled name for
uniqueness and function implementing <typedef:<PSTR>to_string_fn>.
@param[ARRAY_EXPECT_TRAIT, ARRAY_TRAIT]
Named traits are obtained by including `array.h` multiple times with
`ARRAY_EXPECT_TRAIT` and then subsequently including the name in
`ARRAY_TRAIT`.
@std C89 */
#if !defined(ARRAY_NAME) || !defined(ARRAY_TYPE)
#error Name ARRAY_NAME or tag type ARRAY_TYPE undefined.
#error Name or tag type undefined.
#endif
#if defined(ARRAY_TO_STRING_NAME) || defined(ARRAY_TO_STRING)
#define ARRAY_TO_STRING_TRAIT 1
#else
#define ARRAY_TO_STRING_TRAIT 0
#if defined(ARRAY_TRAIT) ^ defined(BOX_TYPE)
#error ARRAY_TRAIT name must come after ARRAY_EXPECT_TRAIT.
#endif
#if defined(ARRAY_COMPARE_NAME) || defined(ARRAY_COMPARE) \
|| defined(ARRAY_IS_EQUAL)
#define ARRAY_COMPARE_TRAIT 1
#else
#define ARRAY_COMPARE_TRAIT 0
#if defined(ARRAY_COMPARE) && defined(ARRAY_IS_EQUAL)
#error Only one can be defined at a time.
#endif
#define ARRAY_TRAITS ARRAY_TO_STRING_TRAIT + ARRAY_COMPARE_TRAIT
#if ARRAY_TRAITS > 1
#error Only one trait per include is allowed; use ARRAY_EXPECT_TRAIT.
#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.
#if defined(ARRAY_TEST) && (!defined(ARRAY_TRAIT) && !defined(ARRAY_TO_STRING) \
|| defined(ARRAY_TRAIT) && !defined(ARRAY_HAS_TO_STRING))
#error Test requires to string.
#endif
#ifndef ARRAY_H /* <!-- idempotent */
@ -84,8 +71,7 @@
#endif
#if ARRAY_TRAITS == 0 /* <!-- base code */
#ifndef ARRAY_TRAIT /* <!-- base code */
#ifndef ARRAY_MIN_CAPACITY /* <!-- !min; */
#define ARRAY_MIN_CAPACITY 3 /* > 1 */
@ -93,7 +79,6 @@
/** A valid tag type set by `ARRAY_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
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; };
/* !data -> !size, data -> capacity >= min && size <= capacity <= max */
#define BOX_CONTENT PA_(type_c) *
/** Is `x` not null? @implements `is_element_c` */
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) *
/** Returns null. */
static PA_(type) *PA_(null)(void) { return 0; }
/** Is `x` not null? @implements `is_element` */
static int PA_(is_element)(const PA_(type) *const x) { return !!x; }
/* @implements `iterator` */
@ -156,7 +126,7 @@ reset:
*it = PA_(iterator)(it->a);
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` */
static int PA_(remove)(struct PA_(iterator) *const it) {
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));
return 1;
}
#define BOX_ACCESS
/** @return Iterator immediately before element `idx` of `a`.
@implements `before` */
static struct PA_(iterator) PA_(before)(struct A_(array) *a, size_t idx)
/** @return Iterator at element `idx` of `a`.
@implements `iterator_at` */
static struct PA_(iterator) PA_(iterator_at)(struct A_(array) *a, size_t idx)
{ struct PA_(iterator) it; it.a = a, it.i = idx, it.seen = 0; return it; }
/** Size of `a`. @implements `size` */
static size_t PA_(size)(const struct A_(array) *a) { return a ? a->size : 0; }
/** @return Element `idx` of `a`. @implements `at` */
static PA_(type) *PA_(at)(const struct A_(array) *a, const size_t idx)
{ return a->data + idx; }
#define BOX_CONTIGUOUS /* Depends on `BOX_ACCESS`. Also, `append` later. */
/** Writes `size` to `a`. @implements `tell_size` */
static void PA_(tell_size)(struct A_(array) *a, const size_t size)
{ assert(a); a->size = size; }
/* Box override information. */
#define BOX_ PA_
#define BOX struct A_(array)
/** Cursor; may become invalid after a topological change to any items
previous. */
/** May become invalid after a topological change to any items previous. */
struct A_(array_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)
{ struct A_(array_iterator) it; it._ = PA_(iterator)(a); return it; }
/** @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;
it._ = PA_(before)(a, idx); return it; }
it._ = PA_(iterator_at)(a, idx); return it; }
/** @return `it` next element. */
static PA_(type) *A_(array_next)(struct A_(array_iterator) *const it)
{ return assert(it), PA_(next)(&it->_); }
@ -369,26 +330,25 @@ static int A_(array_splice)(struct A_(array) *restrict const a,
return 1;
}
#ifdef HAVE_ITERATE_H /* <!-- iterate */
#define ITR_(n) ARRAY_CAT(A_(array), n)
#include "iterate.h" /** \include */
#undef ITR_
#endif /* iterate --> */
/* Box override information. */
#define BOX_TYPE struct A_(array)
#define BOX_CONTENT PA_(type) *
#define BOX_ PA_
#define BOX_MAJOR_NAME array
#define BOX_MINOR_NAME ARRAY_NAME
#define BOX_ACCESS
#define BOX_CONTIGUOUS
#ifdef ARRAY_TEST /* <!-- test */
/* Forward-declare. */
static void (*PA_(to_string))(const PA_(type) *, char (*)[12]);
static const char *(*PA_(array_to_string))(const struct A_(array) *);
#include "../test/test_array.h"
#endif /* test --> */
#ifdef HAVE_ITERATE_H /* <!-- iterate */
#include "iterate.h" /** \include */
#endif /* iterate --> */
static void PA_(unused_base_coda)(void);
static void PA_(unused_base)(void) {
PA_(is_element_c)(0); PA_(forward)(0); PA_(next_c)(0);
PA_(is_element)(0); PA_(remove)(0); PA_(size)(0); PA_(at)(0, 0);
PA_(tell_size)(0, 0);
PA_(null)(); PA_(is_element)(0); PA_(remove)(0); PA_(size)(0);
PA_(at)(0, 0); PA_(tell_size)(0, 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_insert)(0, 0, 0); A_(array_new)(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)(); }
#elif defined(ARRAY_TO_STRING) /* base code --><!-- to string trait */
#endif /* base code --> */
#ifdef ARRAY_TO_STRING_NAME
#define STR_(n) ARRAY_CAT(A_(array), ARRAY_CAT(ARRAY_TO_STRING_NAME, n))
#else
#define STR_(n) ARRAY_CAT(A_(array), n)
#endif
#define TO_STRING ARRAY_TO_STRING
#ifdef ARRAY_TRAIT /* <-- trait: Will be different on different includes. */
#define BOX_TRAIT_NAME ARRAY_TRAIT
#endif /* trait --> */
#ifdef ARRAY_TO_STRING /* <!-- to string trait */
#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
#ifdef ARRAY_TO_STRING_NAME
#undef ARRAY_TO_STRING_NAME
#ifndef ARRAY_TRAIT
#define ARRAY_HAS_TO_STRING
#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
#define CMP_(n) ARRAY_CAT(A_(array), ARRAY_CAT(ARRAY_COMPARE_NAME, n))
#else
#define CMP_(n) ARRAY_CAT(A_(array), n)
#endif
#if defined(ARRAY_COMPARE) || defined(ARRAY_IS_EQUAL) /* <!-- compare trait */
#ifdef ARRAY_COMPARE /* <!-- cmp */
#define COMPARE ARRAY_COMPARE
#else /* cmp --><!-- eq */
@ -437,41 +388,42 @@ static const char *(*PA_(array_to_string))(const struct A_(array) *)
#endif /* eq --> */
#include "compare.h" /** \include */
#ifdef ARRAY_TEST /* <!-- test: this detects and outputs compare test. */
#include "../test/test_array.h"
#include "../test/test_array_compare.h"
#endif /* test --> */
#undef CMP_
#ifdef ARRAY_COMPARE_NAME
#undef ARRAY_COMPARE_NAME
#endif
#undef CMP_ /* From <compare.h>. */
#undef CMPEXTERN_
#ifdef ARRAY_COMPARE
#undef ARRAY_COMPARE
#endif
#ifdef ARRAY_IS_EQUAL
#else
#undef ARRAY_IS_EQUAL
#endif
#endif /* compare trait --> */
#endif /* traits --> */
#ifdef ARRAY_EXPECT_TRAIT /* <!-- trait */
#ifdef ARRAY_EXPECT_TRAIT /* <!-- more */
#undef ARRAY_EXPECT_TRAIT
#else /* trait --><!-- !trait */
#ifdef ARRAY_TEST
#error No ARRAY_TO_STRING traits defined for ARRAY_TEST.
#endif
#undef ARRAY_NAME
#undef ARRAY_TYPE
#undef BOX_
#undef BOX
#else /* more --><!-- done */
#undef BOX_TYPE
#undef BOX_CONTENT
#undef BOX_ITERATOR
#undef BOX_
#undef BOX_MAJOR_NAME
#undef BOX_MINOR_NAME
#undef BOX_ACCESS
#undef BOX_CONTIGUOUS
#endif /* !trait --> */
#undef ARRAY_TO_STRING_TRAIT
#undef ARRAY_COMPARE_TRAIT
#undef ARRAY_TRAITS
#undef ARRAY_NAME
#undef ARRAY_TYPE
#undef ARRAY_MIN_CAPACITY
#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
#undef ARRAY_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); }
#define ARRAY_NAME int
#define ARRAY_TYPE int
#define ARRAY_EXPECT_TRAIT
#include "array.h"
#define ARRAY_TO_STRING &int_to_string
#define ARRAY_TO_STRING
#include "array.h"
static int int_cmp(const int *const a, const int *const b)
{ return (*b < *a) - (*a < *b); }
@ -73,7 +71,8 @@ union date32 {
uint32_t u32;
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]) {
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);
@ -97,19 +96,19 @@ no:
}
/** 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;
return (d.year + d.year / 4 - d.year / 100 + d.year / 400
+ "-bed=pen+mad."[d.month] + d.day) % 7;
}
}*/
/* Contained in <lex.h> to share with <lex.re_c.c>. */
#define ARRAY_NAME lex
#define ARRAY_TYPE struct lex
#include "array.h"
struct page_tree_entry_c;
static void entry_to_string(struct page_tree_entry_c, char (*)[12]);
struct page_tree_entry;
static void page_to_string(struct page_tree_entry, char (*)[12]);
struct page {
struct char_array entry;
struct lex_array meaning;
@ -117,12 +116,10 @@ struct page {
#define TREE_NAME page
#define TREE_KEY union date32
#define TREE_VALUE struct page
#define TREE_COMPARE &date_mixup
#define TREE_EXPECT_TRAIT
#define TREE_COMPARE &page_compare
#define TREE_TO_STRING
#include "tree.h"
#define TREE_TO_STRING &entry_to_string
#include "tree.h"
static void entry_to_string(const struct page_tree_entry_c entry,
static void page_to_string(const struct page_tree_entry entry,
char (*const z)[12]) { date32_to_string(*entry.key, z); }
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 lex *lex = 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; ) {
struct page *const page = entry.value;
for(struct lex_array_iterator l_it = lex_array_iterator(&page->meaning);
@ -218,11 +215,11 @@ catch:
return 0;
}
#define C_BLACK "\033[0;30m"
/*#define C_BLACK "\033[0;30m"
#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_BLUE "\033[0;34m"
/*#define C_BLUE "\033[0;34m"
#define C_PURPLE "\033[0;35m"
#define C_CYAN "\033[0;36m"
#define C_WHITE "\033[0;37m"
@ -234,7 +231,7 @@ catch:
#define CB_BLUE "\033[1;34m"
#define CB_PURPLE "\033[1;35m"
#define CB_CYAN "\033[1;36m"
#define CB_WHITE "\033[1;37m"
#define CB_WHITE "\033[1;37m"*/
#define C_RESET "\033[0m"
@ -346,7 +343,7 @@ int main(int argc, char **argv) {
(int)(lex->s1 - lex->s0), lex->s0); break;
case KJV_CHAPTER_VERSE: printf(" ch. %.*s",
(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;
case KJV_NEXT: printf("(next)\n"); break;
default:
@ -411,7 +408,7 @@ finally:
if(dir && closedir(dir)) success = EXIT_FAILURE, perror("dir");
int_array_(&years), int_array_(&months), int_array_(&days);
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; ) {
struct page *const page = entry.value;
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) {
const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt2;
(void)yyt2, (void)yyt3;
assert(a && year);
/*!re2c
@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) {
const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt1, (void)yyt2;
(void)yyt1, (void)yyt2, (void)yyt3;
assert(a);
/*!re2c
@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) {
const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt1, (void)yyt2;
(void)yyt1, (void)yyt2, (void)yyt3;
assert(a);
/*!re2c
@s0 [0-3][0-9] ".txt\x00" {
@ -85,7 +85,7 @@ int lex_looks_like_day(const char *const a) {
concurrent: convenient and bad. */
static struct scan {
/* `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? */
const char *label, *buffer;
enum condition condition;
@ -100,7 +100,7 @@ static struct scan {
/** Resets the buffer to some `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.condition = yycline;
scan.line = 1;
@ -124,7 +124,7 @@ int lex_next(struct lex *const x) {
re2c:flags:tags = 1;
re2c:define:YYCURSOR = scan.cursor;
re2c:define:YYMARKER = scan.marker;
re2c:define:YYCTXMARKER = scan.ctx_marker;
/*re2c:define:YYCTXMARKER = scan.ctx_marker;*/
re2c:define:YYCONDTYPE = 'condition';
re2c:define:YYGETCONDITION = 'scan.condition';
re2c:define:YYGETCONDITION:naked = 1;
@ -170,7 +170,7 @@ scan:
<line> "^" => text { return x->symbol = CANCELLED, 1; }
<line> "#" => text { return x->symbol = HEADING, 1; }
/* 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, bible> ws+ { goto scan; }

View File

@ -3,16 +3,8 @@
@subtitle To string trait
Interface defined by `BOX_`, `BOX`, and `BOX_CONTENT`.
@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>.
Interface defined by box. Requires `<NAME>[_<TRAIT>]_to_string` be declared as
a <typedef:<PSTR>to_string_fn>.
@param[TO_STRING_LEFT, TO_STRING_RIGHT]
7-bit characters, defaults to '(' and ')'.
@ -27,8 +19,9 @@
@std C89 */
#if !defined(BOX_) || !defined(BOX) || !defined(BOX_CONTENT) \
|| !defined(STR_) || !defined(TO_STRING)
#if !defined(BOX_TYPE) || !defined(BOX_CONTENT) || !defined(BOX_) \
|| !defined(BOX_MAJOR_NAME) || !defined(BOX_MINOR_NAME) \
|| defined(STR_) || defined(STREXTERN_)
#error Unexpected preprocessor symbols.
#endif
@ -45,7 +38,7 @@
#define TO_STRING_H
#include <string.h>
#if defined(TO_STRING_CAT_) || defined(TO_STRING_CAT) || defined(PSTR_)
#error Unexpected defines.
#error Unexpected preprocessor symbols.
#endif
/* <Kernighan and Ritchie, 1988, p. 231>. */
#define TO_STRING_CAT_(n, m) n ## _ ## m
@ -78,19 +71,39 @@ static unsigned to_string_buffer_i;
#define TO_STRING_RIGHT ')'
#endif
typedef BOX PSTR_(box);
typedef BOX_CONTENT PSTR_(element_c);
#ifndef BOX_TRAIT_NAME /* <!-- !trait */
#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`
null-terminated output string. */
typedef void (*PSTR_(to_string_fn))(PSTR_(element_c), char (*)[12]);
/* Check that `TO_STRING` is a function implementing
<typedef:<PSTR>to_string>. */
static const PSTR_(to_string_fn) PSTR_(to_string) = (TO_STRING);
/* Provides an extra level of indirection for boxes if they need it. */
#ifndef TO_STRING_THUNK_
#define TO_STRING_THUNK_(n) n
#endif
/* 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
256 bytes, with limitations of only printing 4 things at a time. `<STR>` is
loosely contracted to be a name `<X>box[<X_TO_STRING_NAME>]`.
256 bytes, with limitations of only printing 4 things at a time.
@return Address of the static buffer. @order \Theta(1) @allow */
static const char *STR_(to_string)(const PSTR_(box) *const box) {
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;
char *const buffer = to_string_buffers[to_string_buffer_i++], *b = buffer;
size_t advance;
PSTR_(element_c) x;
struct BOX_(forward) it;
PSTR_(element) x;
struct BOX_(iterator) it;
int is_sep = 0;
/* Minimum size: "(" "XXXXXXXXXXX" "," "…" ")" "\0". */
assert(box && !(to_string_buffers_no & (to_string_buffers_no - 1))
&& to_string_buffer_size >= 1 + 11 + 1 + ellipsis_len + 1 + 1);
/* Advance the buffer for next time. */
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;
while(BOX_(is_element_c)(x = BOX_(next_c)(&it))) {
PSTR_(to_string)(x, (char (*)[12])b);
/* Paranoid about '\0'. */
while(BOX_(is_element)(x = BOX_(next)(&it))) {
/* One must have this function declared! */
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++);
is_sep = 1, *b++ = comma, *b++ = space;
/* Greedy typesetting: enough for "XXXXXXXXXXX" "," "…" ")" "\0". */
if((size_t)(b - buffer)
> 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;
}
}
@ -138,10 +157,10 @@ static void PSTR_(unused_to_string)(void)
{ STR_(to_string)(0); PSTR_(unused_to_string_coda)(); }
static void PSTR_(unused_to_string_coda)(void) { PSTR_(unused_to_string)(); }
#undef TO_STRING
#ifdef TO_STRING_NAME
#undef TO_STRING_NAME
#endif
#undef STR_
#undef STREXTERN_
#undef TO_STRING_CAST
#undef TO_STRING_THUNK_
#ifdef TO_STRING_EXTERN
#undef TO_STRING_EXTERN
#endif

View File

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