Updated array, tree.
This commit is contained in:
parent
3f203d4ac8
commit
82e79efaf2
2
Makefile
2
Makefile
@ -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 \
|
||||
|
214
src/array.h
214
src/array.h
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
559
src/tree.h
559
src/tree.h
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user