updating boxes for head/body new; better
This commit is contained in:
parent
a52d8ce0ba
commit
2844eeffd5
31
src/array.h
31
src/array.h
@ -31,6 +31,13 @@
|
||||
`ARRAY_EXPECT_TRAIT` and then subsequently including the name in
|
||||
`ARRAY_TRAIT`.
|
||||
|
||||
@param[ARRAY_HEAD, ARRAY_BODY]
|
||||
These go together to allow exporting non-static data between compilation units
|
||||
by separating the `ARRAY_HEAD`, which is intended to go in the header, with
|
||||
`ARRAY_NAME` and `ARRAY_TYPE`, and `ARRAY_BODY` functions. [All static
|
||||
functions will have `s_` prepended for ease of creating a public thunk
|
||||
functions, which most likely will conflict with static functions.]
|
||||
|
||||
@std C89 */
|
||||
|
||||
#if !defined(ARRAY_NAME) || !defined(ARRAY_TYPE)
|
||||
@ -46,6 +53,9 @@
|
||||
|| defined(ARRAY_TRAIT) && !defined(ARRAY_HAS_TO_STRING))
|
||||
#error Test requires to string.
|
||||
#endif
|
||||
#if defined ARRAY_HEAD && defined ARRAY_BODY
|
||||
#error Can not be ARRAY_HEAD and ARRAY_BODY.
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_H /* <!-- idempotent */
|
||||
#define ARRAY_H
|
||||
@ -76,6 +86,8 @@
|
||||
#define ARRAY_MIN_CAPACITY 3 /* > 1 */
|
||||
#endif /* !min --> */
|
||||
|
||||
#ifndef ARRAY_BODY /* <!-- head */
|
||||
|
||||
/** A valid tag type set by `ARRAY_TYPE`. */
|
||||
typedef ARRAY_TYPE PA_(type);
|
||||
|
||||
@ -88,6 +100,13 @@ struct A_(array) { PA_(type) *data; size_t size, capacity; };
|
||||
|
||||
/* `a` non-null; `i >= elements` empty; insert-delete on left like C++. */
|
||||
struct PA_(iterator) { struct A_(array) *a; size_t i; };
|
||||
/** May become invalid after a topological change to any items previous. */
|
||||
struct A_(array_iterator);
|
||||
struct A_(array_iterator) { struct PA_(iterator) _; };
|
||||
|
||||
#endif /* head --> */
|
||||
#ifndef ARRAY_HEAD /* <!-- body */
|
||||
|
||||
/** @return Iterator at end of (non-null) valid `a`. */
|
||||
static struct PA_(iterator) PA_(iterator)(struct A_(array) *const a) {
|
||||
struct PA_(iterator) it;
|
||||
@ -126,10 +145,6 @@ static PA_(type) *PA_(at)(const struct A_(array) *a, const size_t idx)
|
||||
static void PA_(tell_size)(struct A_(array) *a, const size_t size)
|
||||
{ assert(a); a->size = size; }
|
||||
|
||||
/** May become invalid after a topological change to any items previous. */
|
||||
struct A_(array_iterator);
|
||||
struct A_(array_iterator) { struct PA_(iterator) _; };
|
||||
|
||||
/** Zeroed data (not all-bits-zero) is initialized.
|
||||
@return An idle array. @order \Theta(1) @allow */
|
||||
static struct A_(array) A_(array)(void)
|
||||
@ -321,6 +336,8 @@ static void PA_(unused_base)(void) {
|
||||
}
|
||||
static void PA_(unused_base_coda)(void) { PA_(unused_base)(); }
|
||||
|
||||
#endif /* body --> */
|
||||
|
||||
#endif /* base code --> */
|
||||
|
||||
|
||||
@ -392,6 +409,12 @@ static void PAT_(to_string)(const PA_(type) *e, char (*const a)[12])
|
||||
#ifdef ARRAY_TEST
|
||||
#undef ARRAY_TEST
|
||||
#endif
|
||||
#ifdef ARRAY_BODY
|
||||
#undef ARRAY_BODY
|
||||
#endif
|
||||
#ifdef ARRAY_HEAD
|
||||
#undef ARRAY_HEAD
|
||||
#endif
|
||||
#endif /* done --> */
|
||||
#ifdef ARRAY_TRAIT
|
||||
#undef ARRAY_TRAIT
|
||||
|
@ -31,7 +31,7 @@ struct day_tree_iterator { struct tree_day_iterator _; };
|
||||
#if defined PROTO \
|
||||
|| !defined BASE && !defined PRIVATE && !defined PROTO /* <!-- proto */
|
||||
#include "text.h"
|
||||
struct journal { struct day_tree days; struct text backing; };
|
||||
struct journal { struct day_tree days; struct char_array backing; };
|
||||
struct journal_iterator { struct day_tree_iterator _; };
|
||||
struct journal journal(void);
|
||||
void journal_(struct journal *);
|
||||
|
@ -198,7 +198,7 @@ struct journal journal(void) {
|
||||
}
|
||||
/* Because it's in a flat array, the pointers are not stable
|
||||
while we are loading it, and we need to store the offsets. */
|
||||
*v.offset = (uintptr_t)(contents - j.backing.a.data);
|
||||
*v.offset = (uintptr_t)(contents - j.backing.data);
|
||||
}
|
||||
d = 0, int_array_clear(&days);
|
||||
if(chdir("..") == -1) goto catch;
|
||||
@ -214,7 +214,7 @@ struct journal journal(void) {
|
||||
while(day_tree_next(&it)) {
|
||||
v.text = day_tree_value(&it);
|
||||
/*printf("[%zu]...", *v.offset);*/
|
||||
*v.text = j.backing.a.data + *v.offset;
|
||||
*v.text = j.backing.data + *v.offset;
|
||||
/*printf("<%.32s>\n", *v.text);*/
|
||||
}
|
||||
/*fprintf(stderr, "Journal has entries: %s\n",
|
||||
@ -234,7 +234,7 @@ finally:
|
||||
|
||||
/** @return `j` read in some data? */
|
||||
int journal_is_empty(const struct journal *const j) {
|
||||
return !j || !j->days.root.node || !j->backing.a.data;
|
||||
return !j || !j->days.root.node || !j->backing.data;
|
||||
}
|
||||
|
||||
/** @return `j` as a string. */
|
||||
|
@ -160,7 +160,7 @@ void kjvcount_(struct kjvcount *const count) {
|
||||
<fn:kjvcount_is_empty> to tell. */
|
||||
struct kjvcount kjvcount(void) {
|
||||
const char *const dir_kjv = "kjv";
|
||||
struct text backing = text();
|
||||
struct char_array backing = text();
|
||||
struct kjvcount count = {0};
|
||||
DIR *dir = 0;
|
||||
struct dirent *de = 0;
|
||||
@ -183,7 +183,7 @@ struct kjvcount kjvcount(void) {
|
||||
if(!(unstable_backing = text_append_file(&backing, de->d_name)))
|
||||
goto catch;
|
||||
build[b].is = 1;
|
||||
build[b].offset = (size_t)(unstable_backing - backing.a.data);
|
||||
build[b].offset = (size_t)(unstable_backing - backing.data);
|
||||
}
|
||||
if(closedir(dir) == -1) { dir = 0; goto catch; } dir = 0;
|
||||
|
||||
@ -192,7 +192,7 @@ struct kjvcount kjvcount(void) {
|
||||
struct lex x;
|
||||
if(!build[b].is) { fprintf(stderr, "Missing book [%u]%s.\n",
|
||||
b + 1, kjv_book_string[b]); errno = EDOM; goto catch; }
|
||||
x = lex(backing.a.data + build[b].offset);
|
||||
x = lex(backing.data + build[b].offset);
|
||||
while(lex_next_verse(&x)) {
|
||||
const union kjvcite cite
|
||||
= { .book = b, .chapter = x.chapter, .verse = x.verse };
|
||||
|
56
src/source.h
56
src/source.h
@ -1,36 +1,29 @@
|
||||
#if defined BASE \
|
||||
|| !defined BASE && !defined PRIVATE && !defined PROTO /* <!-- base */
|
||||
#include "pair.h"
|
||||
#include "pair.h" /* pair */
|
||||
struct source { struct pair name, desc; };
|
||||
#endif /* base --> */
|
||||
|
||||
#define ARRAY_NAME sourcelist
|
||||
#define ARRAY_TYPE struct source
|
||||
#define ARRAY_HEAD
|
||||
#include "../src/array.h"
|
||||
|
||||
#if defined PRIVATE \
|
||||
|| !defined BASE && !defined PRIVATE && !defined PROTO /* <!-- private */
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <stdint.h> /* uint32_t */
|
||||
|
||||
struct tree_source_node;
|
||||
struct tree_source_tree { struct tree_source_node *node; unsigned height; };
|
||||
struct source_tree { struct tree_source_tree root; };
|
||||
struct tree_source_ref { struct tree_source_node *node; unsigned height, idx; };
|
||||
struct tree_source_iterator {
|
||||
struct tree_source_tree *root; struct tree_source_ref ref; int seen;
|
||||
};
|
||||
struct source_tree_iterator { struct tree_source_iterator _; };
|
||||
#define TABLE_NAME sourcemap
|
||||
#define TABLE_KEY struct pair
|
||||
#define TABLE_UINT uint32_t
|
||||
#define TABLE_VALUE size_t
|
||||
#define TABLE_HEAD
|
||||
#include "../src/table.h"
|
||||
|
||||
struct sourcelist_array { struct source *data; size_t size, capacity; };
|
||||
#include "../src/journal.h" /* line64 */
|
||||
|
||||
struct sourcemap_bucket;
|
||||
struct sourcemap_table {
|
||||
struct sourcemap_bucket *buckets;
|
||||
uint32_t log_capacity, size, top;
|
||||
};
|
||||
#define TREE_NAME source
|
||||
#define TREE_KEY union line64
|
||||
#define TREE_VALUE size_t
|
||||
#define TREE_HEAD
|
||||
#include "../src/tree.h"
|
||||
|
||||
#endif /* private --> */
|
||||
|
||||
|
||||
#if defined PROTO \
|
||||
|| !defined BASE && !defined PRIVATE && !defined PROTO /* <!-- proto */
|
||||
#include <stddef.h>
|
||||
struct sources {
|
||||
struct sourcelist_array list;
|
||||
struct sourcemap_table map;
|
||||
@ -42,14 +35,3 @@ void sources_(struct sources *);
|
||||
int sources_is_empty(const struct sources *);
|
||||
const char *sources_to_string(const struct sources *);
|
||||
const struct source *source_lookup(struct sources *s, const union line64 range);
|
||||
#endif /* proto --> */
|
||||
|
||||
#ifdef BASE
|
||||
#undef BASE
|
||||
#endif
|
||||
#ifdef PRIVATE
|
||||
#undef PRIVATE
|
||||
#endif
|
||||
#ifdef PROTO
|
||||
#undef PROTO
|
||||
#endif
|
||||
|
@ -1,9 +1,7 @@
|
||||
/** @license 2023 Neil Edelman, distributed under the terms of the
|
||||
[MIT License](https://opensource.org/licenses/MIT).
|
||||
@std C11 */
|
||||
#define BASE
|
||||
#include "../src/source.h" /* base */
|
||||
#include "../src/journal.h"
|
||||
#include "../src/source.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -22,6 +20,7 @@ static void sourcelist_to_string(const struct source *const s,
|
||||
#define ARRAY_NAME sourcelist
|
||||
#define ARRAY_TYPE struct source
|
||||
#define ARRAY_TO_STRING
|
||||
#define ARRAY_BODY
|
||||
#include "../src/array.h"
|
||||
|
||||
|
||||
@ -35,8 +34,9 @@ static uint32_t sourcemap_hash(const struct pair p) { return pair_djb2(p); }
|
||||
#define TABLE_KEY struct pair
|
||||
#define TABLE_UINT uint32_t
|
||||
#define TABLE_VALUE size_t /* Index into source list. */
|
||||
#define TABLE_DEFAULT 0
|
||||
#define TABLE_DEFAULT 0 /* Default set at zero. */
|
||||
#define TABLE_TO_STRING
|
||||
#define TABLE_BODY
|
||||
#include "../src/table.h"
|
||||
|
||||
|
||||
@ -51,13 +51,10 @@ static int source_compare(const union line64 a, const union line64 b)
|
||||
#define TREE_COMPARE
|
||||
#define TREE_TO_STRING
|
||||
#define TREE_DEFAULT 0
|
||||
#define TREE_BODY
|
||||
#include "../src/tree.h"
|
||||
|
||||
|
||||
#define PROTO
|
||||
#include "../src/source.h" /* proto */
|
||||
|
||||
|
||||
/*!conditions:re2c*/
|
||||
|
||||
static int scan(union date32 date, const char *const buffer,
|
||||
|
88
src/table.h
88
src/table.h
@ -41,6 +41,11 @@
|
||||
`TABLE_EXPECT_TRAIT` and then subsequently including the name in
|
||||
`TABLE_TRAIT`.
|
||||
|
||||
@param[TABLE_HEAD, TABLE_BODY]
|
||||
These go together to allow exporting non-static data between compilation units
|
||||
by separating the `TABLE_BODY` refers to `TABLE_HEAD`, and identical
|
||||
`TABLE_NAME`, `TABLE_KEY`, `TABLE_UNHASH`, `TABLE_VALUE`, and `TABLE_UINT`.
|
||||
|
||||
@fixme Remove entry as public struct, this should be entirely private.
|
||||
@fixme Why not have two `to_string` arguments on map? It's C, after all. This
|
||||
would be useful in some practical cases.
|
||||
@ -56,6 +61,9 @@
|
||||
|| defined(TABLE_TRAIT) && !defined(TABLE_HAS_TO_STRING))
|
||||
#error Test requires to string.
|
||||
#endif
|
||||
#if defined TABLE_HEAD && defined TABLE_BODY
|
||||
#error Can not be TABLE_HEAD and TABLE_BODY.
|
||||
#endif
|
||||
|
||||
#ifndef TABLE_H /* <!-- idempotent */
|
||||
#define TABLE_H
|
||||
@ -99,6 +107,9 @@ static const char *const table_result_str[] = { TABLE_RESULT };
|
||||
#ifndef TABLE_UINT
|
||||
#define TABLE_UINT size_t
|
||||
#endif
|
||||
|
||||
#ifndef TABLE_BODY /* <!-- head */
|
||||
|
||||
/** <typedef:<PN>hash_fn> returns this hash type by `TABLE_UINT`, which must be
|
||||
be an unsigned integer. Places a simplifying limit on the maximum number of
|
||||
elements of half the cardinality. */
|
||||
@ -160,6 +171,39 @@ struct PN_(bucket) {
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Returns true if the `replace` replaces the `original`.
|
||||
(Shouldn't it be entry?) */
|
||||
typedef int (*PN_(policy_fn))(PN_(key) original, PN_(key) replace);
|
||||
|
||||
/** To initialize, see <fn:<N>table>, `TABLE_IDLE`, `{0}` (`C99`,) or being
|
||||
`static`. The fields should be treated as read-only; any modification is
|
||||
liable to cause the table to go into an invalid state.
|
||||
|
||||
![States.](../doc/table/states.png) */
|
||||
struct N_(table) { /* "Padding size," good. */
|
||||
struct PN_(bucket) *buckets; /* @ has zero/one key specified by `next`. */
|
||||
/* `size <= capacity`; size is not needed but convenient and allows
|
||||
short-circuiting. Top is an index of the stack, potentially lazy: MSB
|
||||
stores whether this is a step ahead (which would make it less, the stack
|
||||
grows from the bottom,) otherwise it is right at the top, */
|
||||
PN_(uint) log_capacity, size, top;
|
||||
};
|
||||
|
||||
/* In no particular order, usually, but deterministic up to topology changes. */
|
||||
struct PN_(iterator) { struct N_(table) *table; PN_(uint) i; };
|
||||
|
||||
/** ![States](../doc/table/it.png)
|
||||
|
||||
Adding, deleting, successfully looking up entries, or any modification of the
|
||||
table's topology invalidates the iterator.
|
||||
Iteration usually not in any particular order. The asymptotic runtime of
|
||||
iterating though the whole table is proportional to the capacity. */
|
||||
struct N_(table_iterator);
|
||||
struct N_(table_iterator) { struct PN_(iterator) _; };
|
||||
|
||||
#endif /* head --> */
|
||||
#ifndef TABLE_HEAD /* <!-- body */
|
||||
|
||||
/** Gets the key of an occupied `bucket`. */
|
||||
static PN_(key) PN_(bucket_key)(const struct PN_(bucket) *const bucket) {
|
||||
assert(bucket && bucket->next != TABLE_NULL);
|
||||
@ -182,24 +226,6 @@ static PN_(value) PN_(bucket_value)(const struct PN_(bucket) *const bucket) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Returns true if the `replace` replaces the `original`.
|
||||
(Shouldn't it be entry?) */
|
||||
typedef int (*PN_(policy_fn))(PN_(key) original, PN_(key) replace);
|
||||
|
||||
/** To initialize, see <fn:<N>table>, `TABLE_IDLE`, `{0}` (`C99`,) or being
|
||||
`static`. The fields should be treated as read-only; any modification is
|
||||
liable to cause the table to go into an invalid state.
|
||||
|
||||
![States.](../doc/table/states.png) */
|
||||
struct N_(table) { /* "Padding size," good. */
|
||||
struct PN_(bucket) *buckets; /* @ has zero/one key specified by `next`. */
|
||||
/* `size <= capacity`; size is not needed but convenient and allows
|
||||
short-circuiting. Top is an index of the stack, potentially lazy: MSB
|
||||
stores whether this is a step ahead (which would make it less, the stack
|
||||
grows from the bottom,) otherwise it is right at the top, */
|
||||
PN_(uint) log_capacity, size, top;
|
||||
};
|
||||
|
||||
/** The capacity of a non-idle `table` is always a power-of-two. */
|
||||
static PN_(uint) PN_(capacity)(const struct N_(table) *const table)
|
||||
{ return assert(table && table->buckets && table->log_capacity >= 3),
|
||||
@ -487,8 +513,6 @@ static enum table_result PN_(put_key)(struct N_(table) *const table,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* In no particular order, usually, but deterministic up to topology changes. */
|
||||
struct PN_(iterator) { struct N_(table) *table; PN_(uint) i; };
|
||||
/** @return Before `table`. */
|
||||
static struct PN_(iterator) PN_(iterator)(struct N_(table) *const table)
|
||||
{ struct PN_(iterator) it; it.table = table, it.i = 0, it.i--; return it; }
|
||||
@ -539,15 +563,6 @@ static int PN_(remove)(struct PN_(iterator) *const it) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** ![States](../doc/table/it.png)
|
||||
|
||||
Adding, deleting, successfully looking up entries, or any modification of the
|
||||
table's topology invalidates the iterator.
|
||||
Iteration usually not in any particular order. The asymptotic runtime of
|
||||
iterating though the whole table is proportional to the capacity. */
|
||||
struct N_(table_iterator);
|
||||
struct N_(table_iterator) { struct PN_(iterator) _; };
|
||||
|
||||
/** Zeroed data (not all-bits-zero) is initialized. @return An idle array.
|
||||
@order \Theta(1) @allow */
|
||||
static struct N_(table) N_(table)(void) {
|
||||
@ -790,6 +805,8 @@ static void PN_(unused_base)(void) {
|
||||
}
|
||||
static void PN_(unused_base_coda)(void) { PN_(unused_base)(); }
|
||||
|
||||
#endif /* body --> */
|
||||
|
||||
#endif /* base code --> */
|
||||
|
||||
|
||||
@ -802,13 +819,6 @@ static void PN_(unused_base_coda)(void) { PN_(unused_base)(); }
|
||||
#define NT_(n) N_(n)
|
||||
#endif /* !trait --> */
|
||||
|
||||
/* #ifdef TABLE_TRAIT
|
||||
#define N_D_(n, m) TABLE_CAT(N_(n), TABLE_CAT(TABLE_TRAIT, m))
|
||||
#else
|
||||
#define N_D_(n, m) TABLE_CAT(N_(n), m)
|
||||
#endif
|
||||
#define PN_D_(n, m) TABLE_CAT(table, N_D_(n, m)) */
|
||||
|
||||
|
||||
#ifdef TABLE_TO_STRING /* <!-- to string trait */
|
||||
/** Thunk `b` -> `a`. */
|
||||
@ -897,6 +907,12 @@ static void PN_D_(unused, default_coda)(void) { PN_D_(unused, default)(); }
|
||||
#ifdef TABLE_TEST
|
||||
#undef TABLE_TEST
|
||||
#endif
|
||||
#ifdef TABLE_BODY
|
||||
#undef TABLE_BODY
|
||||
#endif
|
||||
#ifdef TABLE_HEAD
|
||||
#undef TABLE_HEAD
|
||||
#endif
|
||||
#endif /* done --> */
|
||||
#ifdef TABLE_TRAIT
|
||||
#undef TABLE_TRAIT
|
||||
|
19
src/text.c
19
src/text.c
@ -1,18 +1,22 @@
|
||||
/** Dynamic contiguous string that is used to load files. */
|
||||
|
||||
#include "text.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define ARRAY_NAME char
|
||||
#define ARRAY_TYPE char
|
||||
#define ARRAY_BODY
|
||||
#include "../src/array.h"
|
||||
#define HAVE_CHAR_ARRAY
|
||||
#include "text.h"
|
||||
#include <stdio.h>
|
||||
|
||||
struct char_array text(void) { return char_array(); }
|
||||
void text_(struct char_array *const text) { char_array_(text); }
|
||||
|
||||
/** Append a text file, `fn`, to `c`, and add a '\0'.
|
||||
@return The start of the appended file or null on error. A partial read is a
|
||||
failure. @throws[fopen, fread, malloc]
|
||||
@throws[EISEQ] The text file has embedded nulls.
|
||||
@throws[ERANGE] If the standard library does not follow POSIX. */
|
||||
static char *append_file(struct char_array *text, const char *const fn) {
|
||||
@throws[ERANGE] If the standard library does not follow POSIX? */
|
||||
char *text_append_file(struct char_array *text, const char *const fn) {
|
||||
FILE *fp = 0;
|
||||
const size_t granularity = 1024;
|
||||
size_t nread, start;
|
||||
@ -40,8 +44,3 @@ finally:
|
||||
if(fp) fclose(fp);
|
||||
return success ? text->data + start : 0;
|
||||
}
|
||||
|
||||
struct text text(void) { struct text text; text.a = char_array(); return text; }
|
||||
void text_(struct text *const text) { char_array_(&text->a); }
|
||||
char *text_append_file(struct text *text, const char *const fn)
|
||||
{ return append_file(&text->a, fn); }
|
||||
|
17
src/text.h
17
src/text.h
@ -1,11 +1,8 @@
|
||||
#include <stddef.h>
|
||||
#define ARRAY_NAME char
|
||||
#define ARRAY_TYPE char
|
||||
#define ARRAY_HEAD
|
||||
#include "../src/array.h"
|
||||
|
||||
#ifndef HAVE_CHAR_ARRAY
|
||||
struct char_array { char *data; size_t size, capacity; };
|
||||
#endif
|
||||
|
||||
struct text { struct char_array a; };
|
||||
|
||||
struct text text(void);
|
||||
void text_(struct text *);
|
||||
char *text_append_file(struct text *, const char *);
|
||||
struct char_array text(void);
|
||||
void text_(struct char_array *);
|
||||
char *text_append_file(struct char_array *, const char *);
|
||||
|
84
src/tree.h
84
src/tree.h
@ -44,6 +44,11 @@
|
||||
Named traits are obtained by including `tree.h` multiple times with
|
||||
`TREE_EXPECT_TRAIT` and then subsequently including the name in `TREE_TRAIT`.
|
||||
|
||||
@param[TREE_HEAD, TREE_BODY]
|
||||
These go together to allow exporting non-static data between compilation units
|
||||
by separating the `TABLE_BODY` refers to `TABLE_HEAD`, and identical
|
||||
`TREE_NAME`, `TREE_KEY`, `TREE_VALUE`, and `TREE_ORDER`.
|
||||
|
||||
@fixme merge, difference
|
||||
|
||||
@std C89 */
|
||||
@ -58,6 +63,9 @@
|
||||
|| defined(TREE_TRAIT) && !defined(TREE_HAS_TO_STRING))
|
||||
#error Test requires to string.
|
||||
#endif
|
||||
#if defined TREE_HEAD && defined TREE_BODY
|
||||
#error Can not be TREE_HEAD and TREE_BODY.
|
||||
#endif
|
||||
|
||||
#ifndef TREE_H /* <!-- idempotent */
|
||||
#define TREE_H
|
||||
@ -114,6 +122,8 @@ struct tree_node_count { size_t branches, leaves; };
|
||||
#define TREE_KEY unsigned
|
||||
#endif
|
||||
|
||||
#ifndef TREE_BODY /* <!-- head */
|
||||
|
||||
/** Ordered type used by <typedef:<PB>compare_fn>; defaults to `unsigned`. */
|
||||
typedef TREE_KEY PB_(key);
|
||||
|
||||
@ -123,20 +133,6 @@ typedef TREE_KEY PB_(key);
|
||||
typedef TREE_VALUE PB_(value);
|
||||
#endif
|
||||
|
||||
/** Returns a positive result if `a` is out-of-order with respect to `b`,
|
||||
inducing a strict weak order. This is compatible, but less strict then the
|
||||
comparators from `bsearch` and `qsort`; it only needs to divide entries into
|
||||
two instead of three categories. */
|
||||
typedef int (*PB_(compare_fn))(const PB_(key) a, const PB_(key) b);
|
||||
#ifndef TREE_COMPARE /* <!-- !cmp */
|
||||
/** The default `TREE_COMPARE` on `a` and `b` is integer comparison that
|
||||
results in ascending order, `a > b`. Use `TREE_COMPARE` to supply one's own.
|
||||
@implements <typedef:<PB>compare_fn> */
|
||||
static int B_(compare)(const PB_(key) a, const PB_(key) b)
|
||||
{ return a > b; }
|
||||
#define TREE_COMPARE &PB_(default_compare)
|
||||
#endif /* !cmp --> */
|
||||
|
||||
/* These rules are more lazy than the original so as to not exhibit worst-case
|
||||
behaviour in small trees, as <Johnson, Shasha, 1993, Free-at-Empty>, (lookup
|
||||
is potentially slower after deleting.) In the terminology of
|
||||
@ -165,14 +161,7 @@ struct PB_(node) {
|
||||
};
|
||||
/* B-tree branch is a <tag:<PB>node> and links to `size + 1` nodes. */
|
||||
struct PB_(branch) { struct PB_(node) base, *child[TREE_ORDER]; };
|
||||
/** @return Downcasts `as_leaf` to a branch. */
|
||||
static struct PB_(branch) *PB_(as_branch)(struct PB_(node) *const as_leaf)
|
||||
{ return (struct PB_(branch) *)(void *)
|
||||
((char *)as_leaf - offsetof(struct PB_(branch), base)); }
|
||||
/** @return Downcasts `as_node` to a branch. */
|
||||
static const struct PB_(branch) *PB_(as_branch_c)(const struct PB_(node) *
|
||||
const as_node) { return (const struct PB_(branch) *)(const void *)
|
||||
((const char *)as_node - offsetof(struct PB_(branch), base)); }
|
||||
|
||||
/* Node plus height is a [sub]-tree. */
|
||||
struct PB_(tree) { struct PB_(node) *node; unsigned height; };
|
||||
/** To initialize it to an idle state, see <fn:<B>tree>, `{0}` (`C99`), or
|
||||
@ -189,6 +178,42 @@ struct PB_(ref) {
|
||||
struct PB_(node) *node; /* If null, others ignored. */
|
||||
unsigned height, idx; /* `idx < node.size` means valid. */
|
||||
};
|
||||
|
||||
struct PB_(iterator) { struct PB_(tree) *root; struct PB_(ref) ref; };
|
||||
|
||||
/** Adding, deleting, or changes in the topology of the tree invalidate the
|
||||
iterator. To modify the tree while iterating, take the <fn:<B>tree_key> and
|
||||
restart the iterator with <fn:<B>tree_less> or <fn:<B>tree_more> as
|
||||
appropriate. */
|
||||
struct B_(tree_iterator);
|
||||
struct B_(tree_iterator) { struct PB_(iterator) _; };
|
||||
|
||||
#endif /* head --> */
|
||||
#ifndef TREE_HEAD /* <!-- body */
|
||||
|
||||
/** 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. */
|
||||
typedef int (*PB_(compare_fn))(const PB_(key) a, const PB_(key) b);
|
||||
#ifndef TREE_COMPARE /* <!-- !cmp */
|
||||
/** The default `TREE_COMPARE` on `a` and `b` is integer comparison that
|
||||
results in ascending order, `a > b`. Use `TREE_COMPARE` to supply one's own.
|
||||
@implements <typedef:<PB>compare_fn> */
|
||||
static int B_(compare)(const PB_(key) a, const PB_(key) b)
|
||||
{ return a > b; }
|
||||
#define TREE_COMPARE &PB_(default_compare)
|
||||
#endif /* !cmp --> */
|
||||
|
||||
/** @return Downcasts `as_leaf` to a branch. */
|
||||
static struct PB_(branch) *PB_(as_branch)(struct PB_(node) *const as_leaf)
|
||||
{ return (struct PB_(branch) *)(void *)
|
||||
((char *)as_leaf - offsetof(struct PB_(branch), base)); }
|
||||
/** @return Downcasts `as_node` to a branch. */
|
||||
static const struct PB_(branch) *PB_(as_branch_c)(const struct PB_(node) *
|
||||
const as_node) { return (const struct PB_(branch) *)(const void *)
|
||||
((const char *)as_node - offsetof(struct PB_(branch), base)); }
|
||||
|
||||
#ifdef TREE_VALUE /* <!-- value */
|
||||
/** Gets the value of `ref`. */
|
||||
static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
|
||||
@ -200,7 +225,6 @@ static PB_(value) *PB_(ref_to_valuep)(const struct PB_(ref) ref)
|
||||
{ return ref.node ? ref.node->key + ref.idx : 0; }
|
||||
#endif /* !value --> */
|
||||
|
||||
struct PB_(iterator) { struct PB_(tree) *root; struct PB_(ref) ref; };
|
||||
/** Iterator for `tree` in empty state. */
|
||||
static struct PB_(iterator) PB_(iterator)(struct B_(tree) *const tree) {
|
||||
struct PB_(iterator) it;
|
||||
@ -1480,12 +1504,6 @@ finally:
|
||||
}
|
||||
|
||||
|
||||
/** Adding, deleting, or changes in the topology of the tree invalidate the
|
||||
iterator. To modify the tree while iterating, take the <fn:<B>tree_key> and
|
||||
restart the iterator with <fn:<B>tree_less> or <fn:<B>tree_more> as
|
||||
appropriate. */
|
||||
struct B_(tree_iterator);
|
||||
struct B_(tree_iterator) { struct PB_(iterator) _; };
|
||||
/** @return Cursor at null in valid `tree`. @order \Theta(1) @allow */
|
||||
static struct B_(tree_iterator) B_(tree_iterator)(struct B_(tree) *const tree)
|
||||
{ struct B_(tree_iterator) it; it._ = PB_(iterator)(tree); return it; }
|
||||
@ -1565,6 +1583,8 @@ static void PB_(unused_base_coda)(void) { PB_(unused_base)(); }
|
||||
#define BOX_MAJOR_NAME tree
|
||||
#define BOX_MINOR_NAME TREE_NAME
|
||||
|
||||
#endif /* body --> */
|
||||
|
||||
#endif /* base code --> */
|
||||
|
||||
|
||||
@ -1660,6 +1680,12 @@ static void PB_D_(unused, default_coda)(void) { PB_D_(unused, default)(); }
|
||||
#ifdef TREE_TEST
|
||||
#undef TREE_TEST
|
||||
#endif
|
||||
#ifdef TREE_BODY
|
||||
#undef TREE_BODY
|
||||
#endif
|
||||
#ifdef TREE_HEAD
|
||||
#undef TREE_HEAD
|
||||
#endif
|
||||
#endif /* done --> */
|
||||
#ifdef TREE_TRAIT
|
||||
#undef TREE_TRAIT
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include "../src/journal.h"
|
||||
#include "../src/source.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
int main(void) {
|
||||
struct text t = text();
|
||||
struct char_array t = text();
|
||||
char *content;
|
||||
int success = EXIT_SUCCESS;
|
||||
errno = 0; /* `errno` is not set correctly to 0 in some debug situations. */
|
||||
|
Loading…
Reference in New Issue
Block a user