almost make flight work
This commit is contained in:
parent
7923a9e0f6
commit
82852d94b0
4
Makefile
4
Makefile
@ -39,14 +39,14 @@ bin/test-text: build/text.o build/test_text.o
|
||||
bin/test-kjv: build/text.o build/kjv.o build/test_kjv.o
|
||||
bin/test-journal: build/text.o build/journal.o build/test_journal.o
|
||||
bin/kjv: build/text.o build/journal.o build/kjv.o build/scan_kjv.o
|
||||
bin/flight: build/text.o build/journal.o build/scan_flight.o
|
||||
bin/flight: build/text.o build/journal.o build/scan_flight.o build/driver_flighthours.o
|
||||
|
||||
bin/%:
|
||||
@echo "\033[1;36mlinking $@\033[0m"
|
||||
@mkdir -p bin
|
||||
$(CC) $(OF) -o $@ $^
|
||||
|
||||
build/%.o: src/%.c src/%.h
|
||||
build/%.o: src/%.c #src/%.h
|
||||
@echo "\033[0;36mcompile src $@\033[0m"
|
||||
@mkdir -p build
|
||||
$(CC) $(CF) -c -o $@ $<
|
||||
|
50
src/driver_flighthours.c
Normal file
50
src/driver_flighthours.c
Normal file
@ -0,0 +1,50 @@
|
||||
/** @license 2023 Neil Edelman, distributed under the terms of the
|
||||
[MIT License](https://opensource.org/licenses/MIT).
|
||||
|
||||
Date _vs_ hours flown. */
|
||||
|
||||
#include "journal.h"
|
||||
#include "scan_flight.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main(void) {
|
||||
int success = EXIT_SUCCESS;
|
||||
struct journal j;
|
||||
struct journal_iterator it;
|
||||
union date32 k;
|
||||
union load *v;
|
||||
size_t i;
|
||||
j = journal();
|
||||
if(!journal_is_valid(&j)) goto catch;
|
||||
fprintf(stderr, "Journal: %s.\n", journal_to_string(&j));
|
||||
printf("set term postscript eps enhanced\n"
|
||||
"set output \"flighthours.eps\"\n"
|
||||
"$Data <<EOD\n"
|
||||
"# date\tminutes\tcumulative\n");
|
||||
it = journal_begin(&j), i = 0; while(journal_next(&it, &k, &v))
|
||||
if(!scan(k, v->text, &kj)) goto catch;
|
||||
printf("EOD\n"
|
||||
"set monochrome\n"
|
||||
"set xdata time\n"
|
||||
"set timefmt \"%%Y-%%m-%%d\"\n"
|
||||
"set xtics format \"%%Y-%%m-%%d\" rotate by -30\n"
|
||||
"set ylabel \"words in KJV\"\n"
|
||||
"set format y \"%%g%%%%\"\n"
|
||||
"set key top left\n"
|
||||
"set grid\n"
|
||||
"unset border\n"
|
||||
"#set style fill solid 0.1 #pattern 5 (better, but restarts)\n"
|
||||
"plot $Data using 1:($3)*100/%zu with fillsteps lw 2 title \"set\", \\\n"
|
||||
"$Data using 1:($4)*100/%zu with steps lw 1 title \"cumulative\"\n",
|
||||
kj.words.total, kj.words.total);
|
||||
goto finally;
|
||||
catch:
|
||||
success = EXIT_FAILURE;
|
||||
perror("journal");
|
||||
finally:
|
||||
journal_(&j);
|
||||
return success;
|
||||
}
|
60
src/flight.h
60
src/flight.h
@ -22,41 +22,51 @@ static const char *flight_type_string[] = { FLIGHT_TYPE };
|
||||
#undef X
|
||||
#undef FLIGHT_TYPE
|
||||
|
||||
struct glider {
|
||||
struct substring type, reg, launch;
|
||||
enum launch_type how;
|
||||
unsigned height_ft, pilot_min, dual_min, instr_min;
|
||||
struct substring remarks;
|
||||
};
|
||||
|
||||
struct power {
|
||||
struct substring type, reg, launch, landing, pilot, copilot;
|
||||
unsigned dual_min, pilot_min, ifrsim_min, ifr_min;
|
||||
struct substring remarks;
|
||||
};
|
||||
|
||||
struct flight {
|
||||
enum { GLIDER, POWER } type;
|
||||
union { struct glider glider; struct power power; };
|
||||
};
|
||||
|
||||
/*void kjvcite_to_string(const union kjvcite, char (*)[12]);*/
|
||||
#else /* base --><!-- !base */
|
||||
#undef OMIT_BASE
|
||||
#endif /* !base --> */
|
||||
|
||||
|
||||
#ifndef OMIT_VERSES /* <!-- verses: For external inclusion. */
|
||||
struct table_kjvset_bucket;
|
||||
struct kjvset_table {
|
||||
struct table_kjvset_bucket *buckets;
|
||||
uint32_t log_capacity, size, top;
|
||||
#ifndef OMIT_INTERNAL /* <!-- external */
|
||||
struct tree_flight_node;
|
||||
struct tree_flight_tree { struct tree_flight_node *node; unsigned height; };
|
||||
struct flight_tree { struct tree_flight_tree root; };
|
||||
struct tree_flight_ref { struct tree_flight_node *node; unsigned height, idx; };
|
||||
struct tree_flight_iterator {
|
||||
struct tree_flight_tree *root; struct tree_flight_ref ref; int seen;
|
||||
};
|
||||
struct table_verse_bucket;
|
||||
struct verse_table {
|
||||
struct table_verse_bucket *buckets;
|
||||
uint32_t log_capacity, size, top;
|
||||
};
|
||||
#else /* verses --><!-- !verses */
|
||||
#undef OMIT_VERSES
|
||||
#endif /* !verses --> */
|
||||
|
||||
struct flight_tree_iterator { struct tree_flight_iterator _; };
|
||||
#else /* external --><!-- internal */
|
||||
#undef OMIT_INTERNAL
|
||||
#endif /* internal --> */
|
||||
|
||||
#ifndef OMIT_PROTO /* <!-- proto */
|
||||
#include <stddef.h>
|
||||
struct flights {
|
||||
struct kjvset_table set;
|
||||
struct verse_table verses;
|
||||
struct { size_t total, cumulative, set, verse; } words;
|
||||
};
|
||||
struct kjv kjv(void);
|
||||
void kjv_(struct kjv *);
|
||||
int kjv_is_valid(const struct kjv *const kjv);
|
||||
int kjv_add(struct kjv *const kjv, const union kjvcite cite);
|
||||
const char *kjv_to_string(const struct kjv *const kjv);
|
||||
const char *kjv_set_to_string(const struct kjv *const kjv);
|
||||
struct flights { struct flight_tree flights; };
|
||||
struct flights flights(void);
|
||||
void flights_(struct flights *);
|
||||
int flights_is_valid(const struct flights *);
|
||||
int flights_add(struct flights *, const struct flight);
|
||||
const char *flight_to_string(const struct flight *);
|
||||
#else /* proto --><!-- !proto */
|
||||
#undef OMIT_PROTO
|
||||
#endif /* !proto --> */
|
||||
|
@ -1,6 +1,9 @@
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** `printf`-compatible substring. */
|
||||
struct substring { const char *sub; int size; };
|
||||
|
||||
/** Parse unsigned; [`s`,`e`) => `n`. */
|
||||
static int helper_natural(const char *s, const char *const e, uint32_t *const n)
|
||||
{
|
||||
|
@ -2,13 +2,17 @@
|
||||
#include <stddef.h>
|
||||
union load { const char *text; size_t offset; };
|
||||
#include <stdint.h> /* C99 */
|
||||
/** Assumes: reverse ordering of byte-fields; unsigned is defined; C11 and GNU
|
||||
/** Assumes: reverse ordering of byte-fields; unsigned is defined; C11 or GNU
|
||||
anonymous unions. */
|
||||
union date32 {
|
||||
struct { uint32_t day : 5, month : 4, year : 23; }; /* C11, reverse */
|
||||
uint32_t u32;
|
||||
};
|
||||
void date32_to_string(const union date32 d, char (*const a)[12]);
|
||||
union line64 {
|
||||
struct { union date32 date; uint32_t line; }; /* C11, endian? */
|
||||
uint64_t u64; /* C99 optional */
|
||||
};
|
||||
#else /* base --><!-- !base */
|
||||
#undef OMIT_BASE
|
||||
#endif /* !base --> */
|
||||
|
@ -244,12 +244,12 @@ struct journal_iterator journal_begin(struct journal *const j) {
|
||||
return it;
|
||||
}
|
||||
|
||||
struct journal_iterator journal_begin_at(struct journal *const j,
|
||||
/*struct journal_iterator journal_begin_at(struct journal *const j,
|
||||
const union date32 x) {
|
||||
struct journal_iterator it;
|
||||
it._ = day_tree_begin_at(&j->days, x);
|
||||
return it;
|
||||
}
|
||||
}*/
|
||||
|
||||
int journal_next(struct journal_iterator *const it,
|
||||
union date32 *const k, union load **v) {
|
||||
|
4
src/scan_flight.h
Normal file
4
src/scan_flight.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include "helper.h"
|
||||
#include "flight.h"
|
||||
|
||||
int scan(union date32, const char *, struct flights *);
|
@ -4,53 +4,24 @@
|
||||
Scan journal entries for kjv references. */
|
||||
|
||||
#include "../src/journal.h"
|
||||
#include "../src/helper.h"
|
||||
#include "../src/scan_flight.h"
|
||||
#include <inttypes.h> /* C99 */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
struct substring { const char *str; int len; };
|
||||
|
||||
/** type, reg, launch, how, height, landing, pilot_min, dual_min, instr_min,
|
||||
remarks */
|
||||
struct glider {
|
||||
struct substring type, reg, launch;
|
||||
enum launch how;
|
||||
unsigned height_ft, pilot_min, dual_min, instr_min;
|
||||
struct substring remarks;
|
||||
};
|
||||
|
||||
/** type, reg, launch -- landing, pilot, copilot, dual_min, pilot_min,
|
||||
ifrsim_min, ifr_min, remarks */
|
||||
struct power {
|
||||
struct substring type, reg, launch, landing, pilot, copilot;
|
||||
unsigned dual_min, pilot_min, ifrsim_min, ifr_min;
|
||||
struct substring remarks;
|
||||
};
|
||||
|
||||
/** Could be a glider or power. */
|
||||
struct flight {
|
||||
enum { GLIDER, POWER } type;
|
||||
union { struct glider glider; struct power power; };
|
||||
};
|
||||
|
||||
struct flights {
|
||||
};
|
||||
|
||||
/*!conditions:re2c*/
|
||||
|
||||
static int scan(union date32 date, const char *const buffer,
|
||||
int scan(union date32 date, const char *const buffer,
|
||||
struct flights *const f) {
|
||||
const char *YYCURSOR, *YYMARKER, *yyt1, *yyt2, *yyt3, *s0, *s1, *t0, *t1;
|
||||
enum flight_type type = Glider;
|
||||
uint32_t chapter = 0, verse = 0, verse_end = 0;
|
||||
enum YYCONDTYPE condition = yycline;
|
||||
size_t line = 1;
|
||||
char datestr[12] = {0};
|
||||
const char *why = "unexpected";
|
||||
assert(buffer && kj);
|
||||
assert(buffer && f);
|
||||
YYCURSOR = YYMARKER = yyt1 = buffer;
|
||||
/*!re2c /**/
|
||||
re2c:define:YYCTYPE = char;
|
||||
@ -64,62 +35,25 @@ static int scan(union date32 date, const char *const buffer,
|
||||
ws = [ \t];
|
||||
glyph = [^] \ ("\x00" | "\n" | unix_control | ws);
|
||||
natural = [1-9][0-9]*;
|
||||
lookat = ws* natural ":" natural [ab]? ("-" natural [ab]?)? engage;
|
||||
*/
|
||||
for( ; ; ) { /*!re2c /**/
|
||||
/* Default ignore. */
|
||||
<skip> [^\n\x00] { continue; }
|
||||
<skip> "\x00" { why = "no newline at end of file"; goto catch; }
|
||||
<skip> "\n" => line { line++; continue; }
|
||||
<line> "\x00" { return 1; }
|
||||
<line> "\n" { line++; continue; }
|
||||
<line> * :=> skip /* Guess it can't be simplified? */
|
||||
<line, skip> "\n" => line { line++; continue; }
|
||||
<line> * :=> skip
|
||||
|
||||
/* Except these two. */
|
||||
<line> "[glider]" :=> glider
|
||||
<line> "[flight]" :=> flight
|
||||
|
||||
/* "M" - Motor Car Tow
|
||||
"W" - Winch
|
||||
"A" - Aero Tow */
|
||||
/* type; registration; launch -- landing; pic; sic;
|
||||
single engine day dual; pilot; instrument simulated; actual; remarks */
|
||||
<book> * { why = "default unrecognized"; goto catch; }
|
||||
/* 19:15a, just ignore the a. */
|
||||
<book> ws+ @s0 natural @s1 ":" @t0 natural @t1 [ab]? {
|
||||
if(chapter || verse || verse_end)
|
||||
{ why = "reference unrecognized"; goto catch; }
|
||||
if(!helper_natural(s0, s1, &chapter)
|
||||
|| !helper_natural(t0, t1, &verse))
|
||||
{ why = "reference numerical error"; goto catch; }
|
||||
continue;
|
||||
}
|
||||
<book> "-" @s0 natural @s1 [ab]? { /* Verse range. */
|
||||
if(!chapter || !verse || verse_end)
|
||||
{ why = "range unrecognized"; goto catch; }
|
||||
if(!helper_natural(s0, s1, &verse_end))
|
||||
{ why = "range numerical error"; goto catch; }
|
||||
continue;
|
||||
}
|
||||
<book> engage => skip {
|
||||
char citestr[12];
|
||||
if(!chapter || !verse) { why = "missing information"; goto catch; }
|
||||
if(verse_end && verse_end <= verse)
|
||||
{ why = "interval error"; goto catch; }
|
||||
union kjvcite cite
|
||||
= { .book = book, .chapter = chapter, .verse = verse };
|
||||
if(!datestr[0]) date32_to_string(date, &datestr); /* Only once. */
|
||||
kjvcite_to_string(cite, &citestr);
|
||||
for( ; ; verse++, cite.verse++) {
|
||||
if(!kjv_add(kj, cite)) { why = "add to set"; goto catch; }
|
||||
if(!verse_end || verse_end <= verse) break;
|
||||
}
|
||||
printf("%s\t%zu\t%zu\t%zu\t# ",
|
||||
datestr, kj->words.verse, kj->words.set, kj->words.cumulative);
|
||||
if(verse_end) {
|
||||
printf("%s-%" PRIu32 "\n", citestr, verse_end);
|
||||
} else {
|
||||
printf("%s\n", citestr);
|
||||
}
|
||||
book = Revelation, chapter = 0, verse = 0, verse_end = 0;
|
||||
continue;
|
||||
}
|
||||
<glider, flight> * { why = "default unrecognized"; goto catch; }
|
||||
*/ }
|
||||
assert(0); /* Never gets here. */
|
||||
catch:
|
||||
@ -129,43 +63,3 @@ catch:
|
||||
"%s line %zu: %s.\n", buffer, datestr, line, why);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int success = EXIT_SUCCESS;
|
||||
struct journal j;
|
||||
struct journal_iterator it;
|
||||
struct kjv kj = kjv();
|
||||
union date32 k;
|
||||
union load *v;
|
||||
size_t i;
|
||||
j = journal();
|
||||
if(!journal_is_valid(&j)) goto catch;
|
||||
fprintf(stderr, "Journal: %s.\n", journal_to_string(&j));
|
||||
printf("set term postscript eps enhanced\n"
|
||||
"set output \"kjv.eps\"\n"
|
||||
"$Data <<EOD\n"
|
||||
"# date\tverse\tset\tcumulative / %zu\n", kj.words.total);
|
||||
it = journal_begin(&j), i = 0; while(journal_next(&it, &k, &v))
|
||||
if(!scan(k, v->text, &kj)) goto catch;
|
||||
printf("EOD\n"
|
||||
"set monochrome\n"
|
||||
"set xdata time\n"
|
||||
"set timefmt \"%%Y-%%m-%%d\"\n"
|
||||
"set xtics format \"%%Y-%%m-%%d\" rotate by -30\n"
|
||||
"set ylabel \"words in KJV\"\n"
|
||||
"set format y \"%%g%%%%\"\n"
|
||||
"set key top left\n"
|
||||
"set grid\n"
|
||||
"unset border\n"
|
||||
"#set style fill solid 0.1 #pattern 5 (better, but restarts)\n"
|
||||
"plot $Data using 1:($3)*100/%zu with fillsteps lw 2 title \"set\", \\\n"
|
||||
"$Data using 1:($4)*100/%zu with steps lw 1 title \"cumulative\"\n",
|
||||
kj.words.total, kj.words.total);
|
||||
goto finally;
|
||||
catch:
|
||||
success = EXIT_FAILURE;
|
||||
perror("journal");
|
||||
finally:
|
||||
journal_(&j);
|
||||
return success;
|
||||
}
|
||||
|
@ -46,12 +46,14 @@ static int scan(union date32 date, const char *const buffer,
|
||||
third = ("III" | "3") " "?;
|
||||
*/
|
||||
for( ; ; ) { /*!re2c /**/
|
||||
/* Default ignore. */
|
||||
<skip> [^\n\x00] { continue; }
|
||||
<skip> "\x00" { why = "no newline at end of file"; goto catch; }
|
||||
<skip> "\n" => line { line++; continue; }
|
||||
<line> "\x00" { return 1; }
|
||||
<line> "\n" { line++; continue; }
|
||||
<line> * :=> skip /* Guess it can't be simplified? */
|
||||
<line, skip> "\n" => line { line++; continue; }
|
||||
<line> * :=> skip
|
||||
|
||||
/* Books. */
|
||||
<line> "Genesis" / lookat => book { book = Genesis; continue; }
|
||||
<line> "Exodus" / lookat => book { book = Exodus; continue; }
|
||||
<line> "Leviticus" / lookat => book { book = Leviticus; continue; }
|
||||
@ -127,6 +129,8 @@ static int scan(union date32 date, const char *const buffer,
|
||||
<line> third "John" / lookat => book { book = IIIJohn; continue; }
|
||||
<line> "Jude" / lookat => book { book = Jude; continue; }
|
||||
<line> "Revelation" / lookat => book { book = Revelation; continue; }
|
||||
|
||||
/* Extract further information. */
|
||||
<book> * { why = "default unrecognized"; goto catch; }
|
||||
/* 19:15a, just ignore the a. */
|
||||
<book> ws+ @s0 natural @s1 ":" @t0 natural @t1 [ab]? {
|
||||
|
329
src/tree.h
329
src/tree.h
@ -173,11 +173,7 @@ static struct PB_(branch) *PB_(as_branch)(struct PB_(node) *const as_leaf)
|
||||
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)); }
|
||||
/* 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; };
|
||||
/* Node plus height is a sub-tree. A <tag:<B>tree> is a sub-tree of the tree.
|
||||
fixme: 0-based height is problematic. UINT_MAX? No. */
|
||||
/* 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
|
||||
being `static`.
|
||||
@ -186,19 +182,21 @@ struct PB_(tree) { struct PB_(node) *node; unsigned height; };
|
||||
struct B_(tree);
|
||||
struct B_(tree) { struct PB_(tree) root; };
|
||||
|
||||
/* Address of a specific key by node. Height might not be used, but there's too
|
||||
many structs in this file anyway. */
|
||||
struct PB_(ref) {
|
||||
struct PB_(node) *node; /* If null, others ignored. */
|
||||
unsigned height, idx; /* `idx < node.size` means valid. */
|
||||
};
|
||||
#ifdef TREE_VALUE /* <!-- value */
|
||||
|
||||
/** 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; }
|
||||
|
||||
#else /* value --><!-- !value */
|
||||
|
||||
typedef PB_(key) PB_(value);
|
||||
/** 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; }
|
||||
|
||||
#endif /* !value --> */
|
||||
|
||||
struct PB_(iterator) { struct PB_(tree) *root; struct PB_(ref) ref; int seen; };
|
||||
@ -209,7 +207,7 @@ static struct PB_(iterator) PB_(begin)(struct B_(tree) *const tree) {
|
||||
it.ref.height = tree ? tree->root.height : 0;
|
||||
if(tree && tree->root.height != UINT_MAX)
|
||||
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_c)(it.ref.node)->child[0], it.ref.height--);
|
||||
else it.ref.node = 0;
|
||||
it.ref.idx = 0;
|
||||
it.seen = 0;
|
||||
@ -315,109 +313,172 @@ predecessor:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Want to find slightly different things; code re-use is bad. Confusing.
|
||||
This is the lower-bound. */
|
||||
#define TREE_FORTREE(i) i.node = tree->node, i.height = tree->height; ; \
|
||||
i.node = PB_(as_branch_c)(i.node)->child[i.idx], i.height--
|
||||
#define TREE_START(i) unsigned hi = i.node->size; i.idx = 0;
|
||||
#define TREE_FORNODE(i) do { \
|
||||
const unsigned m = (i.idx + hi) / 2; \
|
||||
if(B_(compare)(key, i.node->key[m]) > 0) i.idx = m + 1; \
|
||||
else hi = m; \
|
||||
} while(i.idx < hi);
|
||||
#define TREE_FLIPPED(i) B_(compare)(i.node->key[i.idx], key) <= 0
|
||||
/** Finds `key` in `lo` one node at a time. */
|
||||
static void PB_(find_idx)(struct PB_(ref) *const lo, const PB_(key) key) {
|
||||
TREE_START((*lo))
|
||||
if(!lo) return;
|
||||
TREE_FORNODE((*lo))
|
||||
/** Finds `idx` of 'greatest lower-bound' (C++ parlance) minorant of `x` in
|
||||
`lo` only in one node at a time. */
|
||||
static void PB_(node_lb)(struct PB_(ref) *const lo, const PB_(key) x) {
|
||||
unsigned hi = lo->node->size; lo->idx = 0;
|
||||
assert(lo && lo->node && hi);
|
||||
do {
|
||||
const unsigned mid = (lo->idx + hi) / 2; /* Will not overflow. */
|
||||
if(B_(compare)(x, lo->node->key[mid]) > 0) lo->idx = mid + 1;
|
||||
else hi = mid;
|
||||
} while(lo->idx < hi);
|
||||
}
|
||||
/** Finds lower-bound of `key` in non-empty `tree`, or, if `key` is greater
|
||||
than all `tree`, one off the end. */
|
||||
static struct PB_(ref) PB_(lower_r)(struct PB_(tree) *const tree,
|
||||
const PB_(key) key) {
|
||||
struct PB_(ref) i, lo = { 0, 0, 0 };
|
||||
for(TREE_FORTREE(i)) {
|
||||
TREE_START(i)
|
||||
/** Finds `idx` of 'least upper-bound' (C++ parlance) majorant of `x` in `hi`
|
||||
only in one node at a time. */
|
||||
static void PB_(node_ub)(struct PB_(ref) *const hi, const PB_(key) x) {
|
||||
unsigned lo = 0;
|
||||
assert(hi->node && hi->idx);
|
||||
do {
|
||||
const unsigned mid = (lo + hi->idx) / 2;
|
||||
if(B_(compare)(hi->node->key[mid], x) <= 0) lo = mid + 1;
|
||||
else hi->idx = mid;
|
||||
} while(lo < hi->idx);
|
||||
}
|
||||
|
||||
/** @return A reference to the element first element at or less than `x` in
|
||||
`tree`, or `node` will be null if the `x` is less than all `tree`. */
|
||||
static struct PB_(ref) PB_(lookup_left)(const struct PB_(tree) tree,
|
||||
const PB_(key) x) {
|
||||
struct PB_(ref) hi, found;
|
||||
found.node = 0;
|
||||
if(!tree.node) return found;
|
||||
for(hi.node = tree.node, hi.height = tree.height; ;
|
||||
hi.node = PB_(as_branch_c)(hi.node)->child[hi.idx], hi.height--) {
|
||||
if(!(hi.idx = hi.node->size)) continue;
|
||||
PB_(node_ub)(&hi, x);
|
||||
if(hi.idx) { /* Within bounds to record the current predecessor. */
|
||||
found = hi, found.idx--;
|
||||
/* Equal. */
|
||||
if(B_(compare)(x, found.node->key[found.idx]) <= 0) break;
|
||||
}
|
||||
if(!hi.height) break; /* Reached the bottom. */
|
||||
}
|
||||
return found;
|
||||
}
|
||||
/** Iterator version of <fn:<PB>lookup_left> of `x` in `tree` that goes
|
||||
one-off the end. */
|
||||
static struct PB_(ref) PB_(ref_left)(const struct PB_(tree) tree,
|
||||
const PB_(key) x) {
|
||||
struct PB_(ref) hi, found;
|
||||
found.node = 0;
|
||||
if(!tree.node) return found;
|
||||
for(hi.node = tree.node, hi.height = tree.height; ;
|
||||
hi.node = PB_(as_branch_c)(hi.node)->child[hi.idx], hi.height--) {
|
||||
if(!(hi.idx = hi.node->size)) continue;
|
||||
PB_(node_ub)(&hi, x);
|
||||
if(hi.idx < hi.node->size) {
|
||||
found = hi;
|
||||
if(hi.idx && B_(compare)(x, found.node->key[found.idx - 1]) <= 0)
|
||||
break;
|
||||
}
|
||||
if(!hi.height) { if(!found.node) found = hi; break; }
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/** @return A reference the element at the greatest lower bound of `x` in
|
||||
`tree`, or if the element doesn't exist, `node` will be null. */
|
||||
static struct PB_(ref) PB_(lookup_right)(const struct PB_(tree) tree,
|
||||
const PB_(key) x) {
|
||||
struct PB_(ref) lo, found;
|
||||
found.node = 0;
|
||||
if(!tree.node || tree.height == UINT_MAX) return found;
|
||||
for(lo.node = tree.node, lo.height = tree.height; ;
|
||||
lo.node = PB_(as_branch_c)(lo.node)->child[lo.idx], lo.height--) {
|
||||
unsigned hi = lo.node->size; lo.idx = 0;
|
||||
if(!hi) continue;
|
||||
TREE_FORNODE(i)
|
||||
if(i.idx < i.node->size) {
|
||||
lo = i;
|
||||
if(TREE_FLIPPED(i)) break; /* Multi-keys go here. */
|
||||
PB_(node_lb)(&lo, x);
|
||||
if(lo.idx < lo.node->size) {
|
||||
found = lo;
|
||||
if(B_(compare)(x, lo.node->key[lo.idx]) > 0) break;
|
||||
}
|
||||
if(!i.height) {
|
||||
if(!lo.node) lo = i; /* Want one-off-end if last. */
|
||||
if(!lo.height) break;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
/** Iterator version of <fn:<PB>lookup_right> of `x` in `tree` that goes
|
||||
one-off the end. */
|
||||
static struct PB_(ref) PB_(ref_right)(const struct PB_(tree) tree,
|
||||
const PB_(key) x) {
|
||||
struct PB_(ref) lo, found;
|
||||
found.node = 0;
|
||||
if(!tree.node || tree.height == UINT_MAX) return found;
|
||||
for(lo.node = tree.node, lo.height = tree.height; ;
|
||||
lo.node = PB_(as_branch_c)(lo.node)->child[lo.idx], lo.height--) {
|
||||
unsigned hi = lo.node->size; lo.idx = 0;
|
||||
if(!hi) continue;
|
||||
PB_(node_lb)(&lo, x);
|
||||
if(lo.idx < lo.node->size) {
|
||||
found = lo;
|
||||
if(B_(compare)(x, lo.node->key[lo.idx]) > 0) break;
|
||||
}
|
||||
if(!lo.height) { if(!found.node) found = lo; break; }
|
||||
}
|
||||
return found;
|
||||
}
|
||||
/** Finds an exact key `x` in non-empty `tree`. */
|
||||
static struct PB_(ref) PB_(lookup_find)(const struct PB_(tree) tree,
|
||||
const PB_(key) x) {
|
||||
struct PB_(ref) lo;
|
||||
if(!tree.node || tree.height == UINT_MAX) return lo.node = 0, lo;
|
||||
for(lo.node = tree.node, lo.height = tree.height; ;
|
||||
lo.node = PB_(as_branch_c)(lo.node)->child[lo.idx], lo.height--) {
|
||||
unsigned hi = lo.node->size; lo.idx = 0;
|
||||
if(!hi) continue;
|
||||
PB_(node_lb)(&lo, x);
|
||||
/* Absolutely will not equivalent `x > lo`, investigate? */
|
||||
if(lo.idx < lo.node->size && B_(compare)(lo.node->key[lo.idx], x) <= 0)
|
||||
break;
|
||||
}
|
||||
if(!lo.height) { lo.node = 0; break; }
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
/** @return Lower bound of `x` in `tree`. @order \O(\log |`tree`|) */
|
||||
static struct PB_(ref) PB_(lower)(struct PB_(tree) tree, const PB_(key) x) {
|
||||
if(!tree.node || tree.height == UINT_MAX) {
|
||||
struct PB_(ref) ref; ref.node = 0; return ref;
|
||||
} else {
|
||||
return PB_(lower_r)(&tree, x);
|
||||
}
|
||||
}
|
||||
/** Finds an exact `key` in non-empty `tree`. */
|
||||
static struct PB_(ref) PB_(find)(const struct PB_(tree) *const tree,
|
||||
const PB_(key) key) {
|
||||
struct PB_(ref) i;
|
||||
for(TREE_FORTREE(i)) {
|
||||
TREE_START(i)
|
||||
if(!hi) continue;
|
||||
TREE_FORNODE(i)
|
||||
if(i.idx < i.node->size && TREE_FLIPPED(i)) break;
|
||||
if(!i.height) { i.node = 0; return i; }
|
||||
}
|
||||
return i;
|
||||
}
|
||||
/** Finds lower-bound of `key` in non-empty `tree` while counting the
|
||||
/** Finds lower-bound of key `x` in non-empty `tree` while counting the
|
||||
non-filled `hole` and `is_equal`. */
|
||||
static struct PB_(ref) PB_(lookup_insert)(struct PB_(tree) *const tree,
|
||||
const PB_(key) key, struct PB_(ref) *const hole, int *const is_equal) {
|
||||
static struct PB_(ref) PB_(lookup_insert)(struct PB_(tree) tree,
|
||||
const PB_(key) x, struct PB_(ref) *const hole, int *const is_equal) {
|
||||
struct PB_(ref) lo;
|
||||
hole->node = 0;
|
||||
for(TREE_FORTREE(lo)) {
|
||||
TREE_START(lo)
|
||||
for(lo.node = tree.node, lo.height = tree.height; ;
|
||||
lo.node = PB_(as_branch_c)(lo.node)->child[lo.idx], lo.height--) {
|
||||
unsigned hi = lo.node->size; lo.idx = 0;
|
||||
if(hi < TREE_MAX) *hole = lo;
|
||||
if(!hi) continue;
|
||||
TREE_FORNODE(lo)
|
||||
PB_(node_lb)(&lo, x);
|
||||
if(lo.node->size < TREE_MAX) hole->idx = lo.idx;
|
||||
if(lo.idx < lo.node->size && TREE_FLIPPED(lo)) { *is_equal = 1; break; }
|
||||
if(lo.idx < lo.node->size && B_(compare)(lo.node->key[lo.idx], x) <= 0)
|
||||
{ *is_equal = 1; break; }
|
||||
if(!lo.height) break;
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
/** Finds exact `key` in non-empty `tree`. If `node` is found, temporarily, the
|
||||
nodes that have `TREE_MIN` keys have
|
||||
/** Finds exact key `x` in non-empty `tree`. If `node` is found, temporarily,
|
||||
the nodes that have `TREE_MIN` keys have
|
||||
`as_branch(node).child[TREE_MAX] = parent` or, for leaves, `leaf_parent`,
|
||||
which must be set. (Patently terrible for running concurrently; hack, would be
|
||||
nice to go down tree maybe.) */
|
||||
static struct PB_(ref) PB_(lookup_remove)(struct PB_(tree) *const tree,
|
||||
const PB_(key) key, struct PB_(node) **leaf_parent) {
|
||||
static struct PB_(ref) PB_(lookup_remove)(struct PB_(tree) tree,
|
||||
const PB_(key) x, struct PB_(node) **leaf_parent) {
|
||||
struct PB_(node) *parent = 0;
|
||||
struct PB_(ref) lo;
|
||||
for(TREE_FORTREE(lo)) {
|
||||
TREE_START(lo)
|
||||
for(lo.node = tree.node, lo.height = tree.height; ;
|
||||
lo.node = PB_(as_branch_c)(lo.node)->child[lo.idx], lo.height--) {
|
||||
unsigned hi = lo.node->size; lo.idx = 0;
|
||||
/* Cannot delete bulk add. */
|
||||
if(parent && hi < TREE_MIN || !parent && !hi) { lo.node = 0; break; }
|
||||
if(hi <= TREE_MIN) { /* Remember the parent temporarily. */
|
||||
if(lo.height) PB_(as_branch)(lo.node)->child[TREE_MAX] = parent;
|
||||
else *leaf_parent = parent;
|
||||
}
|
||||
TREE_FORNODE(lo)
|
||||
if(lo.idx < lo.node->size && TREE_FLIPPED(lo)) break;
|
||||
PB_(node_lb)(&lo, x);
|
||||
if(lo.idx < lo.node->size && B_(compare)(lo.node->key[lo.idx], x) <= 0)
|
||||
break;
|
||||
if(!lo.height) { lo.node = 0; break; } /* Was not in. */
|
||||
parent = lo.node;
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
#undef TREE_FORTREE
|
||||
#undef TREE_START
|
||||
#undef TREE_FORNODE
|
||||
#undef TREE_FLIPPED
|
||||
|
||||
/** Zeroed data (not all-bits-zero) is initialized. @return An idle tree.
|
||||
@order \Theta(1) @allow */
|
||||
@ -497,12 +558,10 @@ static size_t B_(tree_count)(const struct B_(tree) *const tree) {
|
||||
? PB_(count_r)(tree->root) : 0;
|
||||
}
|
||||
|
||||
/** @return Is `x` in `tree`? @order \O(\log |`tree`|) @allow */
|
||||
/** @return Is `x` in `tree` (which can be null)?
|
||||
@order \O(\log |`tree`|) @allow */
|
||||
static int B_(tree_contains)(const struct B_(tree) *const tree,
|
||||
const PB_(key) x) {
|
||||
return tree && tree->root.node && tree->root.height != UINT_MAX
|
||||
&& PB_(find)(&tree->root, x).node ? 1 : 0;
|
||||
}
|
||||
const PB_(key) x) { return tree && PB_(lookup_find)(tree->root, x).node; }
|
||||
/* fixme: entry <B>tree_query -- there is no functionality that returns the
|
||||
key. */
|
||||
|
||||
@ -513,20 +572,33 @@ static PB_(value) B_(tree_get_or)(const struct B_(tree) *const tree,
|
||||
const PB_(key) key, const PB_(value) default_value) {
|
||||
struct PB_(ref) ref;
|
||||
return tree && tree->root.node && tree->root.height != UINT_MAX
|
||||
&& (ref = PB_(find)(&tree->root, key)).node
|
||||
&& (ref = PB_(lookup_find)(tree->root, key)).node
|
||||
? *PB_(ref_to_valuep)(ref) : default_value;
|
||||
}
|
||||
|
||||
/** For example, `tree = { 10 }`, `x = 5 -> 10`, `x = 10 -> 10`,
|
||||
`x = 11 -> null`. (There is no upper value.)
|
||||
@return Lower-bound value match for `key` in `tree` or `default_value` if
|
||||
`key` is greater than all in `tree`. The map type is `TREE_VALUE` and the set
|
||||
type is `TREE_KEY`. @order \O(\log |`tree`|) @allow */
|
||||
static PB_(value) B_(tree_at_or)(const struct B_(tree) *const tree,
|
||||
const PB_(key) key, const PB_(value) default_value) {
|
||||
/** For example, `tree = { 10 }`, `x = 5 -> default_value`, `x = 10 -> 10`,
|
||||
`x = 11 -> 10`.
|
||||
@return Value in `tree` less-then-or-equal to `x` or `default_value` if `x`
|
||||
is smaller than all in `tree`.
|
||||
@order \O(\log |`tree`|) @allow */
|
||||
static PB_(value) B_(tree_left_or)(const struct B_(tree) *const tree,
|
||||
const PB_(key) x, const PB_(value) default_value) {
|
||||
struct PB_(ref) ref;
|
||||
return tree && (ref = PB_(lower)(tree->root, key)).node
|
||||
&& ref.idx < ref.node->size ? *PB_(ref_to_valuep)(ref) : default_value;
|
||||
return tree && (ref = PB_(lookup_left)(tree->root, x)).node ?
|
||||
(assert(ref.idx < ref.node->size), *PB_(ref_to_valuep)(ref))
|
||||
: default_value;
|
||||
}
|
||||
|
||||
/** For example, `tree = { 10 }`, `x = 5 -> 10`, `x = 10 -> 10`,
|
||||
`x = 11 -> default_value`.
|
||||
@return Value in `tree` greater-than-or-equal to `x` or `default_value` if `x`
|
||||
is greater than all in `tree`.
|
||||
@order \O(\log |`tree`|) @allow */
|
||||
static PB_(value) B_(tree_right_or)(const struct B_(tree) *const tree,
|
||||
const PB_(key) x, const PB_(value) default_value) {
|
||||
struct PB_(ref) ref;
|
||||
return tree && (ref = PB_(lookup_right)(tree->root, x)).node
|
||||
? *PB_(ref_to_valuep)(ref) : default_value;
|
||||
}
|
||||
|
||||
#ifdef TREE_VALUE /* <!-- map */
|
||||
@ -746,7 +818,7 @@ empty: /* Reserved dynamic memory, but tree is empty. */
|
||||
descend: /* Record last node that has space. */
|
||||
{
|
||||
int is_equal = 0;
|
||||
add = PB_(lookup_insert)(root, key, &hole, &is_equal);
|
||||
add = PB_(lookup_insert)(*root, key, &hole, &is_equal);
|
||||
if(is_equal) {
|
||||
if(eject) {
|
||||
*eject = add.node->key[add.idx];
|
||||
@ -820,7 +892,7 @@ grow: /* Leaf is full. */ {
|
||||
/* Descend now while split hasn't happened -- easier. */
|
||||
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);
|
||||
PB_(node_lb)(&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`. */
|
||||
@ -972,7 +1044,7 @@ static int PB_(remove)(struct PB_(tree) *const tree, const PB_(key) x) {
|
||||
assert(tree && tree->node && tree->height != UINT_MAX);
|
||||
/* Traverse down the tree until `key`, leaving breadcrumbs for parents of
|
||||
minimum key nodes. */
|
||||
if(!(rm = PB_(lookup_remove)(tree, x, &parent.node)).node) return 0;
|
||||
if(!(rm = PB_(lookup_remove)(*tree, x, &parent.node)).node) return 0;
|
||||
/* Important when `rm = parent`; `find_idx` later. */
|
||||
parent.height = rm.height + 1;
|
||||
assert(rm.idx < rm.node->size);
|
||||
@ -1046,7 +1118,7 @@ no_succ:
|
||||
/* Retrieve forgotten information about the index in parent. (This is not
|
||||
as fast at it could be, but holding parent data in minimum keys allows it
|
||||
to be in place, if a hack. We could go down, but new problems arise.) */
|
||||
PB_(find_idx)(&parent, provisional_x);
|
||||
PB_(node_lb)(&parent, provisional_x);
|
||||
parentb = PB_(as_branch)(parent.node);
|
||||
assert(parent.idx <= parent.node->size
|
||||
&& parentb->child[parent.idx] == rm.node);
|
||||
@ -1467,19 +1539,31 @@ static struct B_(tree_iterator) B_(tree_begin)(struct B_(tree) *const tree)
|
||||
@order \Theta(\log |`tree`|) @allow */
|
||||
static struct B_(tree_iterator) B_(tree_end)(struct B_(tree) *const tree)
|
||||
{ struct B_(tree_iterator) it; it._ = PB_(end)(tree); return it; }
|
||||
/** @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_iterator) B_(tree_begin_at)(struct B_(tree) *const tree,
|
||||
const PB_(key) x) {
|
||||
/** @return Cursor in `tree` such that <fn:<B>tree_previous> is the greatest
|
||||
key that is less-than-or-equal to `x`, or, <fn:<B>tree_begin> if `x` is less
|
||||
than all in `tree`. @order \Theta(\log |`tree`|) @allow */
|
||||
static struct B_(tree_iterator) B_(tree_left_previous)(struct B_(tree) *const
|
||||
tree, const PB_(key) x) {
|
||||
struct B_(tree_iterator) cur;
|
||||
if(!tree) return cur._.root = 0, cur;
|
||||
cur._.ref = PB_(lower)(tree->root, x);
|
||||
cur._.ref = PB_(ref_left)(tree->root, x);
|
||||
cur._.root = &tree->root;
|
||||
cur._.seen = 0;
|
||||
return cur;
|
||||
}
|
||||
/** @return Cursor in `tree` such that <fn:<B>tree_next> is the least key that
|
||||
is greater-than-or-equal to `x`, or, <fn:<B>tree_end> if `x` is greater than
|
||||
all in `tree`. @order \Theta(\log |`tree`|) @allow */
|
||||
static struct B_(tree_iterator) B_(tree_right_next)(struct B_(tree) *const
|
||||
tree, const PB_(key) x) {
|
||||
struct B_(tree_iterator) cur;
|
||||
if(!tree) return cur._.root = 0, cur;
|
||||
cur._.ref = PB_(ref_right)(tree->root, x);
|
||||
cur._.root = &tree->root;
|
||||
cur._.seen = 0;
|
||||
return cur;
|
||||
}
|
||||
|
||||
#ifdef TREE_VALUE /* <!-- map */
|
||||
/** @return Whether advancing `it` to the next element and filling `k`, (and
|
||||
`v` if a map, otherwise absent,) if not-null.
|
||||
@ -1559,7 +1643,8 @@ static enum tree_result B_(tree_iterator_try)(struct B_(tree_iterator) *const
|
||||
assert(it->_.root->height != UINT_MAX); /* Can't be empty. */
|
||||
switch(where) {
|
||||
case TREE_NONODE: it->_.ref.node = 0; it->_.seen = 0; break;
|
||||
case TREE_ITERATING: it->_.ref = PB_(lower)(*it->_.root, anchor); break;
|
||||
case TREE_ITERATING:
|
||||
it->_.ref = PB_(lookup_right)(*it->_.root, anchor); break;
|
||||
case TREE_END:
|
||||
assert(it->_.root->node);
|
||||
it->_.ref.node = it->_.root->node;
|
||||
@ -1593,7 +1678,7 @@ static int B_(tree_iterator_remove)(struct B_(tree_iterator) *const it) {
|
||||
|| (remove = it->_.ref.node->key[it->_.ref.idx],
|
||||
!PB_(remove)(it->_.root, remove))) return 0;
|
||||
/* <fn:<B>tree_begin_at>. */
|
||||
it->_.ref = PB_(lower)(*it->_.root, remove);
|
||||
it->_.ref = PB_(lookup_right)(*it->_.root, remove);
|
||||
it->_.seen = 0;
|
||||
return 1;
|
||||
}
|
||||
@ -1602,7 +1687,8 @@ 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);
|
||||
B_(tree)(); B_(tree_)(0); B_(tree_clear)(0); B_(tree_count)(0);
|
||||
B_(tree_contains)(0, k); B_(tree_get_or)(0, k, v); B_(tree_at_or)(0, k, v);
|
||||
B_(tree_contains)(0, k); B_(tree_get_or)(0, k, v);
|
||||
B_(tree_left_or)(0, k, v); B_(tree_right_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_iterator_try)(0, k, 0);
|
||||
@ -1613,7 +1699,8 @@ static void PB_(unused_base)(void) {
|
||||
B_(tree_next)(0, 0); B_(tree_previous)(0, 0);
|
||||
#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_begin)(0); B_(tree_end)(0);
|
||||
B_(tree_left_previous)(0, k); B_(tree_right_next)(0, k);
|
||||
B_(tree_iterator_remove)(0);
|
||||
PB_(unused_base_coda)();
|
||||
}
|
||||
@ -1685,25 +1772,37 @@ static PB_(value) B_D_(tree, get)(const struct B_(tree) *const tree,
|
||||
const PB_(key) key) {
|
||||
struct PB_(ref) ref;
|
||||
return tree && tree->root.node && tree->root.height != UINT_MAX
|
||||
&& (ref = PB_(find)(&tree->root, key)).node
|
||||
&& (ref = PB_(lookup_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
|
||||
/** This is functionally identical to <fn:<B>tree_left_or>, but a with a trait
|
||||
specifying a constant default value.
|
||||
@return The value associated with `key` in `tree`, (which can be null.) If
|
||||
no such value exists, the `TREE_DEFAULT` is returned.
|
||||
@order \O(\log |`tree`|). @allow */
|
||||
static PB_(value) B_D_(tree, at)(const struct B_(tree) *const tree,
|
||||
static PB_(value) B_D_(tree, left)(const struct B_(tree) *const tree,
|
||||
const PB_(key) key) {
|
||||
struct PB_(ref) ref;
|
||||
return tree && (ref = PB_(lower)(tree->root, key)).node
|
||||
return tree && (ref = PB_(lookup_left)(tree->root, key)).node ?
|
||||
(assert(ref.idx < ref.node->size), *PB_(ref_to_valuep)(ref))
|
||||
: PB_D_(default, value);
|
||||
}
|
||||
/** This is functionally identical to <fn:<B>tree_right_or>, but a with a trait
|
||||
specifying a constant default value.
|
||||
@return The value associated with `key` in `tree`, (which can be null.) If
|
||||
no such value exists, the `TREE_DEFAULT` is returned.
|
||||
@order \O(\log |`tree`|). @allow */
|
||||
static PB_(value) B_D_(tree, right)(const struct B_(tree) *const tree,
|
||||
const PB_(key) key) {
|
||||
struct PB_(ref) ref;
|
||||
return tree && (ref = PB_(lookup_right)(tree->root, key)).node
|
||||
&& 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);
|
||||
B_D_(tree, get)(0, k); B_D_(tree, at)(0, k);
|
||||
B_D_(tree, get)(0, k); B_D_(tree, left)(0, k); B_D_(tree, right)(0, k);
|
||||
PB_D_(unused, default_coda)();
|
||||
}
|
||||
static void PB_D_(unused, default_coda)(void) { PB_D_(unused, default)(); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user