diff --git a/src/array.h b/src/array.h index 1fb286e..9b3c0f6 100644 --- a/src/array.h +++ b/src/array.h @@ -86,46 +86,37 @@ typedef ARRAY_TYPE PA_(type); struct A_(array) { PA_(type) *data; size_t size, capacity; }; /* !data -> !size, data -> capacity >= min && size <= capacity <= max */ -/* Size 3 iterator: |_ |_ |_ |. Size 0: |. `size` and `!up` is invalid. */ -struct PA_(iterator) { struct A_(array) *a; size_t i; int seen; }; -/** @return Initialize before beginning of a valid `a`. */ -static struct PA_(iterator) PA_(begin)(struct A_(array) *const a) { +/* `a` non-null; `i >= elements` empty; insert-delete on left like C++. */ +struct PA_(iterator) { struct A_(array) *a; size_t i; }; +/** @return Iterator at end of (non-null) valid `a`. */ +static struct PA_(iterator) PA_(iterator)(struct A_(array) *const a) { struct PA_(iterator) it; - assert(a); - it.a = a, it.i = 0, it.seen = 0; + assert(a), it.a = a, it.i = (size_t)~0; return it; } -/** @return Initialize after the end of a valid `a`. */ -static struct PA_(iterator) PA_(end)(struct A_(array) *const a) { - struct PA_(iterator) it; - assert(a); - it.a = a, it.i = a->size, it.seen = 0; - return it; -} -/** @return Iterator before element `i` of `a`. */ +/** @return Iterator at element `i` of non-null `a`. */ static struct PA_(iterator) PA_(iterator_at)(struct A_(array) *a, size_t i) { struct PA_(iterator) it; - assert(a); - it.a = a, it.i = i > a->size ? a->size : i, it.seen = 0; return it; + assert(a), it.a = a, it.i = i < a->size ? i : (size_t)~0; + return it; } -/** @return Whether it moved `it` forwards and picked-up `e`. */ -static int PA_(next)(struct PA_(iterator) *const it, PA_(type) **const e) { +/** @return Dereference the element pointed to by valid `it`. */ +static PA_(type) *PA_(element)(struct PA_(iterator) *const it) + { return it->a->data + it->i; } +/** Next `it`. @return Valid element? */ +static int PA_(next)(struct PA_(iterator) *const it) { assert(it && it->a); - it->i += !!it->seen, it->seen = 1; - if(it->i >= it->a->size) return it->i = it->a->size, it->seen = 0, 0; - if(e) *e = it->a->data + it->i; - return 1; + if(it->i >= it->a->size) it->i = (size_t)~0; + return ++it->i < it->a->size; } -/** @return Whether it moved `it` backwards and picked-up `e`. */ -static int PA_(previous)(struct PA_(iterator) *const it, PA_(type) **const e) { +/** Previous `it`. @return Valid element? */ +static int PA_(previous)(struct PA_(iterator) *const it) { assert(it && it->a); - if(it->i > it->a->size) it->i = it->a->size, it->seen = 0; /* Clip. */ - if(!it->i) return it->seen = 0, 0; /* First. */ - it->i--, it->seen = 1; - if(e) *e = it->a->data + it->i; - return 1; + if(it->i > it->a->size) it->i = it->a->size; /* Clip. */ + return --it->i < it->a->size; } -/* fixme: static int PA_(remove)(struct PA_(iterator) *const it) */ +/* fixme: static struct PA_(iterator) + PA_(remove)(struct PA_(iterator) *const 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` */ @@ -148,24 +139,6 @@ static struct A_(array) A_(array)(void) static void A_(array_)(struct A_(array) *const a) { if(a) free(a->data), *a = A_(array)(); } -/** @return An iterator before the start of `a`. */ -static struct A_(array_iterator) A_(array_begin)(struct A_(array) *a) - { struct A_(array_iterator) it; it._ = PA_(begin)(a); return it; } -/** @return An iterator after the end of `a`. */ -static struct A_(array_iterator) A_(array_end)(struct A_(array) *a) - { struct A_(array_iterator) it; it._ = PA_(end)(a); return it; } -/** @return An iterator before `idx` of `a`. */ -static struct A_(array_iterator) A_(array_at)(struct A_(array) *a, size_t idx) - { struct A_(array_iterator) it; it._ = PA_(iterator_at)(a, idx); return it; } -/** Move initialized `it` to the next cursor position. @return Pointer to the - element through which it moved, or null if at the end. */ -static PA_(type) *A_(array_next)(struct A_(array_iterator) *const it) - { PA_(type) *v; return assert(it), PA_(next)(&it->_, &v) ? v : 0; } -/** Move initialized `it` to the previous cursor position. @return Pointer to - the element through which it moved, or null if at the beginning. */ -static PA_(type) *A_(array_previous)(struct A_(array_iterator) *const it) - { PA_(type) *v; return assert(it), PA_(previous)(&it->_, &v) ? v : 0; } - /** Ensures `min` capacity of `a`. Invalidates pointers in `a`. @param[min] If zero, does nothing. @return Success; otherwise, `errno` will be set. @throws[ERANGE] Tried allocating more then can fit in `size_t` or `realloc` @@ -336,10 +309,10 @@ static int A_(array_splice)(struct A_(array) *restrict const a, static void PA_(unused_base_coda)(void); static void PA_(unused_base)(void) { + PA_(iterator)(0); PA_(iterator_at)(0, 0); PA_(element)(0); + PA_(next)(0); PA_(previous)(0); PA_(size)(0); PA_(at)(0, 0); PA_(tell_size)(0, 0); A_(array)(); A_(array_)(0); - A_(array_begin)(0); A_(array_end)(0); A_(array_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); A_(array_clear)(0); A_(array_peek)(0); A_(array_pop)(0); diff --git a/src/journal.h b/src/journal.h index c1a89c4..da3006d 100644 --- a/src/journal.h +++ b/src/journal.h @@ -22,9 +22,8 @@ struct tree_day_node; struct tree_day_tree { struct tree_day_node *node; unsigned height; }; struct day_tree { struct tree_day_tree root; }; struct tree_day_ref { struct tree_day_node *node; unsigned height, idx; }; -struct tree_day_iterator { - struct tree_day_tree *root; struct tree_day_ref ref; int seen; -}; +struct tree_day_iterator + { struct tree_day_tree *root; struct tree_day_ref ref; }; struct day_tree_iterator { struct tree_day_iterator _; }; #endif /* generic --> */ @@ -38,7 +37,7 @@ struct journal journal(void); void journal_(struct journal *); int journal_is_valid(const struct journal *); const char *journal_to_string(const struct journal *); -struct journal_iterator journal_begin(struct journal *const j); +struct journal_iterator journal_iterator(struct journal *const j); int journal_next(struct journal_iterator *, union date32 *, const char **); #endif /* proto --> */ diff --git a/src/journal.re.c b/src/journal.re.c index 190b5c6..3479af4 100644 --- a/src/journal.re.c +++ b/src/journal.re.c @@ -204,11 +204,12 @@ struct journal journal(void) { /* Structure is now stable because we aren't going to move it; convert all of offsets back to pointers. */ - it = day_tree_begin(&j.days); - while(day_tree_next(&it, 0, &v.text)) { - /*printf("[%zu]...", *v.offset);*/ + it = day_tree_iterator(&j.days); + while(day_tree_next(&it)) { + v.text = day_tree_value(&it); + printf("[%zu]...", *v.offset); *v.text = j.backing.a.data + *v.offset; - /*printf("<%.32s>\n", *v.text);*/ + printf("<%.32s>\n", *v.text); } /*fprintf(stderr, "Journal has entries: %s\n", day_tree_to_string(&j.days));*/ @@ -234,9 +235,9 @@ int journal_is_valid(const struct journal *const j) { const char *journal_to_string(const struct journal *const j) { return day_tree_to_string(&j->days); } -struct journal_iterator journal_begin(struct journal *const j) { +struct journal_iterator journal_iterator(struct journal *const j) { struct journal_iterator it; - it._ = day_tree_begin(&j->days); + it._ = day_tree_iterator(&j->days); return it; } @@ -249,8 +250,9 @@ struct journal_iterator journal_begin(struct journal *const j) { int journal_next(struct journal_iterator *const it, union date32 *const k, const char **v) { - const char **needless_modifiable; - if(!day_tree_next(&it->_, k, &needless_modifiable)) return 0; - *v = *needless_modifiable; + assert(it && k && v); + if(!day_tree_next(&it->_)) return 0; + *k = day_tree_key(&it->_); + *v = *day_tree_value(&it->_); return 1; } diff --git a/src/scan_kjv.re.c b/src/scan_kjv.re.c index 236147b..2d37843 100644 --- a/src/scan_kjv.re.c +++ b/src/scan_kjv.re.c @@ -196,7 +196,7 @@ int main(void) { "set output \"kjv.eps\"\n" "$Data < */ #ifdef BASE diff --git a/src/source.re.c b/src/source.re.c index c966069..ae24589 100644 --- a/src/source.re.c +++ b/src/source.re.c @@ -50,7 +50,7 @@ static int source_compare(const union line64 a, const union line64 b) #define TREE_VALUE size_t /* Index into source list. */ #define TREE_COMPARE #define TREE_TO_STRING -#define TREE_DEFAULT 0 +#define TREE_DEFAULT (size_t)0 #include "../src/tree.h" @@ -157,7 +157,7 @@ struct sources sources(struct journal *const j) { if(!(nul = sourcelist_array_new(&s.list))) goto catch; nul->name.a = nul->name.b = nul->desc.a = nul->desc.b = 0; } - it = journal_begin(j); + it = journal_iterator(j); while(journal_next(&it, &k, &v)) if(!scan(k, v, &s)) goto catch; fprintf(stderr, "List of sources: %s.\n" "Mapped to indices: %s.\n" @@ -172,10 +172,11 @@ finally: /** Lookup the last source in `range` in sources `s`. They are invalidated on adding a source, (probably fine.) */ -const struct source *source_lookup(const struct sources *const s, +const struct source *source_lookup(struct sources *const s, const union line64 range) { - size_t idx; + union line64 line_source; assert(s); - idx = source_tree_left(&s->dates, range); + line_source = source_tree_less_or(&s->dates, range, (union line64){0}); + sourcemap_table_get(&s->map, line_source); return s->list.data + idx; } diff --git a/src/table.h b/src/table.h index cebd773..cc7ce4f 100644 --- a/src/table.h +++ b/src/table.h @@ -17,7 +17,7 @@ key> associated therewith; required. `` is private, whose names are prefixed in a manner to avoid collisions. - @param[TABLE_INVERSE] + @param[TABLE_UNHASH] By default it assumes that `is_equal` is supplied; with this, instead requires `unhash` satisfying unhash_fn>. @@ -26,7 +26,7 @@ associative array. @param[TABLE_UINT] - This is uint>, the unsigned type of hash hash of the key given by + This is uint>, the unsigned type of hash of the key given by hash_fn>; defaults to `size_t`. @param[TABLE_DEFAULT] @@ -76,9 +76,9 @@ less.) Choose representations that may save power? We cannot save this in an `enum` because we don't know maximum. */ #define TABLE_M1 ((PN_(uint))~(PN_(uint))0) /* 2's compliment -1. */ -#define TABLE_HIGH ((TABLE_M1 >> 1) + 1) /* Cardinality must be 1111... */ -#define TABLE_END (TABLE_HIGH) -#define TABLE_NULL (TABLE_HIGH + 1) +#define TABLE_HIGH ((TABLE_M1 >> 1) + 1) /* High-bit set: max cardinality. */ +#define TABLE_END (TABLE_HIGH) /* Out-of-band signalling end of chain. */ +#define TABLE_NULL (TABLE_HIGH + 1) /* Out-of-band signalling no item. */ #define TABLE_RESULT X(ERROR), X(ABSENT), X(PRESENT) #define X(n) TABLE_##n /** A result of modifying the table, of which `TABLE_ERROR` is false. @@ -104,7 +104,7 @@ static const char *const table_result_str[] = { TABLE_RESULT }; elements of half the cardinality. */ typedef TABLE_UINT PN_(uint); -/** Valid tag type defined by `TABLE_KEY` used for keys. If `TABLE_INVERSE` is +/** Valid tag type defined by `TABLE_KEY` used for keys. If `TABLE_UNHASH` is not defined, a copy of this value will be stored in the internal buckets. */ typedef TABLE_KEY PN_(key); typedef const TABLE_KEY PN_(key_c); /* Works 90%? */ @@ -115,8 +115,8 @@ typedef const TABLE_KEY PN_(key_c); /* Works 90%? */ Must be consistent for each value while in the table. If key> is a pointer, one is permitted to have null in the domain. */ typedef PN_(uint) (*PN_(hash_fn))(const PN_(key)); -#ifdef TABLE_INVERSE /* */ @@ -152,7 +152,7 @@ typedef PN_(key) PN_(entry); struct PN_(bucket) { PN_(uint) next; /* Bucket index, including `TABLE_NULL` and `TABLE_END`. */ PN_(uint) hash; -#ifndef TABLE_INVERSE +#ifndef TABLE_UNHASH PN_(key) key; #endif #ifdef TABLE_VALUE @@ -163,8 +163,8 @@ struct PN_(bucket) { /** 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); -#ifdef TABLE_INVERSE - /* On `TABLE_INVERSE`, this function must be defined by the user. */ +#ifdef TABLE_UNHASH + /* On `TABLE_UNHASH`, this function must be defined by the user. */ return N_(unhash)(bucket->hash); #else return bucket->key; @@ -205,23 +205,23 @@ static PN_(uint) PN_(capacity)(const struct N_(table) *const table) { return assert(table && table->buckets && table->log_capacity >= 3), (PN_(uint))((PN_(uint))1 << table->log_capacity); } -/** @return Indexes the first closed bucket in the set of buckets with the same - address from non-idle `table` given the `hash`. If the bucket is empty, it - will have `next = TABLE_NULL` or it's own to_bucket_no> not equal to - the index. */ -static PN_(uint) PN_(to_bucket_no)(const struct N_(table) *const table, +/** @return Indexes the first (closed) bucket in the set of buckets with the + same address from non-idle `table` given the `hash`. If the bucket is empty, + it will have `next = TABLE_NULL` or it's own chain_head> not equal + to the index (another open bucket). */ +static PN_(uint) PN_(chain_head)(const struct N_(table) *const table, const PN_(uint) hash) { return hash & (PN_(capacity)(table) - 1); } /** @return Search for the previous link in the bucket to `b` in `table`, if it - exists, (by restarting and going though the list.) This is not the same as the - iterator. @order \O(`bucket size`) */ + exists, (by restarting and going though the list.) + @order \O(`bucket size`) */ static struct PN_(bucket) *PN_(prev)(const struct N_(table) *const table, const PN_(uint) b) { const struct PN_(bucket) *const bucket = table->buckets + b; PN_(uint) to_next = TABLE_NULL, next; assert(table && bucket->next != TABLE_NULL); /* Note that this does not check for corrupted tables; would get assert. */ - for(next = PN_(to_bucket_no)(table, bucket->hash); + for(next = PN_(chain_head)(table, bucket->hash); /* assert(next < capacity), */ next != b; to_next = next, next = table->buckets[next].next); return to_next != TABLE_NULL ? table->buckets + to_next : 0; @@ -246,7 +246,7 @@ static void PN_(force_stack)(struct N_(table) *const table) { top &= ~TABLE_HIGH; do bucket = table->buckets + ++top/*, assert(top < capacity)*/; while(bucket->next != TABLE_NULL - && PN_(to_bucket_no)(table, bucket->hash) == top); + && PN_(chain_head)(table, bucket->hash) == top); table->top = top; /* Eager. */ } } @@ -287,10 +287,10 @@ static void PN_(move_to_top)(struct N_(table) *const table, const PN_(uint) m) { } /* stack --> */ -/** `TABLE_INVERSE` is injective, so in that case, we only compare hashes. +/** `TABLE_UNHASH` is injective, so in that case, we only compare hashes. @return `a` and `b`. */ static int PN_(equal_buckets)(PN_(key_c) a, PN_(key_c) b) { -#ifdef TABLE_INVERSE +#ifdef TABLE_UNHASH return (void)a, (void)b, 1; #else /* Must have this function declared. */ @@ -304,11 +304,11 @@ static struct PN_(bucket) *PN_(query)(struct N_(table) *const table, struct PN_(bucket) *bucket1; PN_(uint) head, b0 = TABLE_NULL, b1, b2; assert(table && table->buckets && table->log_capacity); - bucket1 = table->buckets + (head = b1 = PN_(to_bucket_no)(table, hash)); + bucket1 = table->buckets + (head = b1 = PN_(chain_head)(table, hash)); /* Not the start of a bucket: empty or in the collision stack. */ if((b2 = bucket1->next) == TABLE_NULL || PN_(in_stack_range)(table, b1) - && b1 != PN_(to_bucket_no)(table, bucket1->hash)) return 0; + && b1 != PN_(chain_head)(table, bucket1->hash)) return 0; while(hash != bucket1->hash || !PN_(equal_buckets)(key, PN_(bucket_key)(bucket1))) { if(b2 == TABLE_END) return 0; @@ -377,7 +377,7 @@ static int PN_(buffer)(struct N_(table) *const table, const PN_(uint) n) { PN_(uint) g, hash; idx = table->buckets + i; if(idx->next == TABLE_NULL) continue; - g = PN_(to_bucket_no)(table, hash = idx->hash); + g = PN_(chain_head)(table, hash = idx->hash); /* It's a power-of-two size, so, like consistent hashing, `E[old/new]` capacity that a closed bucket will remain where it is. */ if(i == g) { idx->next = TABLE_END; continue; } @@ -387,7 +387,7 @@ static int PN_(buffer)(struct N_(table) *const table, const PN_(uint) n) { PN_(uint) h = g & ~mask; assert(h <= g); if(h < g && i < h && (head = table->buckets + h, assert(head->next != TABLE_NULL), - PN_(to_bucket_no)(table, head->hash) == g)) { + PN_(chain_head)(table, head->hash) == g)) { memcpy(go, head, sizeof *head); go->next = TABLE_END, head->next = TABLE_NULL; /* Fall-though -- the bucket still needs to be put on wait. */ @@ -404,7 +404,7 @@ static int PN_(buffer)(struct N_(table) *const table, const PN_(uint) n) { /* Search waiting stack for buckets that moved concurrently. */ { PN_(uint) prev = TABLE_END, w = wait; while(w != TABLE_END) { struct PN_(bucket) *waiting = table->buckets + w; - PN_(uint) cl = PN_(to_bucket_no)(table, waiting->hash); + PN_(uint) cl = PN_(chain_head)(table, waiting->hash); struct PN_(bucket) *const closed = table->buckets + cl; assert(cl != w); if(closed->next == TABLE_NULL) { @@ -421,7 +421,7 @@ static int PN_(buffer)(struct N_(table) *const table, const PN_(uint) n) { /* Rebuild the top stack at the high numbers from the waiting at low. */ while(wait != TABLE_END) { struct PN_(bucket) *const waiting = table->buckets + wait; - PN_(uint) h = PN_(to_bucket_no)(table, waiting->hash); + PN_(uint) h = PN_(chain_head)(table, waiting->hash); struct PN_(bucket) *const head = table->buckets + h; struct PN_(bucket) *top; assert(h != wait && head->next != TABLE_NULL); @@ -439,7 +439,7 @@ static void PN_(replace_key)(struct PN_(bucket) *const bucket, const PN_(key) key, const PN_(uint) hash) { (void)key; bucket->hash = hash; -#ifndef TABLE_INVERSE +#ifndef TABLE_UNHASH bucket->key = key; #endif } @@ -451,9 +451,9 @@ static struct PN_(bucket) *PN_(evict)(struct N_(table) *const table, PN_(uint) i; struct PN_(bucket) *bucket; if(!PN_(buffer)(table, 1)) return 0; /* Amortized. */ - bucket = table->buckets + (i = PN_(to_bucket_no)(table, hash));/* Closed. */ + bucket = table->buckets + (i = PN_(chain_head)(table, hash));/* Closed. */ if(bucket->next != TABLE_NULL) { /* Occupied. */ - int in_stack = PN_(to_bucket_no)(table, bucket->hash) != i; + int in_stack = PN_(chain_head)(table, bucket->hash) != i; PN_(move_to_top)(table, i); bucket->next = in_stack ? TABLE_END : table->top; } else { /* Unoccupied. */ @@ -487,52 +487,42 @@ 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. - @implements `iterator` */ -struct PN_(iterator) { struct N_(table) *table; PN_(uint) cur, prev; }; -/** Helper to skip the buckets of `it` that are not there. - @return Whether it found another index. */ -static int PN_(skip)(struct PN_(iterator) *const it) { +/* 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; } +/** @return Element at valid non-null `it`. */ +static struct PN_(bucket) *PN_(element)(const struct PN_(iterator) *const it) + { return it->table->buckets + it->i; } +/** @return Whether `it` even has a next. */ +static int PN_(next)(struct PN_(iterator) *const it) { const struct N_(table) *const t = it->table; const PN_(uint) limit = PN_(capacity)(t); - assert(it && it->table && it->table->buckets); - while(it->cur < limit) { - struct PN_(bucket) *const bucket = t->buckets + it->cur; - if(bucket->next != TABLE_NULL) return 1; - it->cur++; - } + assert(it && it->table); + if(!it->table->buckets) return 0; /* Idle. */ + while(++it->i < limit) if(t->buckets[it->i].next != TABLE_NULL) return 1; return 0; } -/** @return Before `table`. @implements `begin` */ -static struct PN_(iterator) PN_(begin)(struct N_(table) *const table) { - struct PN_(iterator) it; it.table = table, it.cur = 0; it.prev = TABLE_NULL; - return it; -} -/** @return Whether `it` advances and `v`. */ -static int PN_(next)(struct PN_(iterator) *const it, - struct PN_(bucket) **const v) { - assert(it); - if(!it->table || !it->table->buckets) return 0; - if(!PN_(skip)(it)) return it->table = 0, it->cur = 0, 0; - if(v) *v = it->table->buckets + it->cur; - it->prev = it->cur, it->cur++; - return 1; -} -/** Removes the entry at `it`. @return Success. */ + +/** Removes the entry at `it` and possibly corrects `it` so that calling + next> will go through the entire list. @return Success. */ static int PN_(remove)(struct PN_(iterator) *const it) { - struct N_(table) *table; - PN_(uint) prev = it->prev; + struct N_(table) *table = it->table; struct PN_(bucket) *previous = 0, *current; PN_(uint) prv = TABLE_NULL, crnt; - assert(it); - if(prev == TABLE_NULL) return 0; - table = it->table; - assert(it->table == it->table - && it->table->buckets && prev < PN_(capacity)(it->table)); - /* Egregious code reuse. :[ */ - current = it->table->buckets + prev, assert(current->next != TABLE_NULL); - crnt = PN_(to_bucket_no)(it->table, current->hash); - while(crnt != prev) assert(crnt < PN_(capacity)(it->table)), + assert(it && table); + if(!it->table->buckets) return 0; + assert(it->i < PN_(capacity)(it->table)); + if(it->i >= PN_(capacity)(it->table)) return 0; + /* This should be possible to simplify with prev>? + if(previous = PN_(prev)(table, it->i)) */ + /* Egregious code reuse from table_remove>; because `it` contains + `i` and remove has a `key`, the counting is different. But the rest is the + same? Get the last bucket. */ + current = it->table->buckets + it->i, assert(current->next != TABLE_NULL); + crnt = PN_(chain_head)(it->table, current->hash); + while(crnt != it->i) assert(crnt < PN_(capacity)(it->table)), crnt = (previous = it->table->buckets + (prv = crnt))->next; if(prv != TABLE_NULL) { /* Open entry. */ previous->next = current->next; @@ -541,11 +531,11 @@ static int PN_(remove)(struct PN_(iterator) *const it) { struct PN_(bucket) *const second = table->buckets + scnd; assert(scnd < PN_(capacity)(table)); memcpy(current, second, sizeof *second); - if(crnt < scnd) it->cur = it->prev; /* Iterate new entry. */ - crnt = scnd; current = second; + /* Because we replace current with a bucket we haven't seen yet. */ + if(crnt < scnd) it->i--; + crnt = scnd, current = second; } current->next = TABLE_NULL, table->size--, PN_(shrink_stack)(table, crnt); - it->prev = TABLE_NULL; return 1; } @@ -570,34 +560,25 @@ static struct N_(table) N_(table)(void) { static void N_(table_)(struct N_(table) *const table) { if(table) free(table->buckets), *table = N_(table)(); } -/** Loads `table` (can be null) into `it`. @allow */ -static struct N_(table_iterator) N_(table_begin)(struct N_(table) *const - table) { struct N_(table_iterator) it; it._ = PN_(begin)(table); +/** Loads a non-null `table` into `it`. @allow */ +static struct N_(table_iterator) N_(table_iterator)(struct N_(table) *const + table) { struct N_(table_iterator) it; it._ = PN_(iterator)(table); return it; } -#ifdef TABLE_VALUE /* */ +/** @return If `it` has an element, returns it's key. */ +static PN_(key) N_(table_key)(const struct N_(table_iterator) *const it) + { return PN_(bucket_key)(it->_.table->buckets + it->_.i); } +#ifdef TABLE_VALUE /* */ /** Removes the entry at `it`. Whereas table_remove> invalidates the - iterator, this corrects for a signal `it`. + iterator, this corrects `it` so table_next> is the next entry. To use + the iterator after this, one must move to the next. @return Success, or there was no entry at the iterator's position, (anymore.) @allow */ static int N_(table_iterator_remove)(struct N_(table_iterator) *const it) @@ -748,33 +729,33 @@ static enum table_result N_(table_policy)(struct N_(table) *const table, static int N_(table_remove)(struct N_(table) *const table, const PN_(key) key) { struct PN_(bucket) *current; - /* This function must be defined by the user. */ - PN_(uint) crnt, prv = TABLE_NULL, nxt, hash = N_(hash)(key); + PN_(uint) c, p = TABLE_NULL, n, hash = N_(hash)(key); if(!table || !table->size) return 0; assert(table->buckets); /* Find item and keep track of previous. */ - current = table->buckets + (crnt = PN_(to_bucket_no)(table, hash)); - if((nxt = current->next) == TABLE_NULL - || PN_(in_stack_range)(table, crnt) - && crnt != PN_(to_bucket_no)(table, current->hash)) return 0; + current = table->buckets + (c = PN_(chain_head)(table, hash)); + if((n = current->next) == TABLE_NULL /* No entry here. */ + || PN_(in_stack_range)(table, c) + && c != PN_(chain_head)(table, current->hash)) return 0; + /* Find prev? Why not prev>? */ while(hash != current->hash && !PN_(equal_buckets)(key, PN_(bucket_key)(current))) { - if(nxt == TABLE_END) return 0; - prv = crnt, current = table->buckets + (crnt = nxt); - assert(crnt < PN_(capacity)(table) && PN_(in_stack_range)(table, crnt) - && crnt != TABLE_NULL); - nxt = current->next; + if(n == TABLE_END) return 0; + p = c, current = table->buckets + (c = n); + assert(c < PN_(capacity)(table) && PN_(in_stack_range)(table, c) + && c != TABLE_NULL); + n = current->next; } - if(prv != TABLE_NULL) { /* Open entry. */ - struct PN_(bucket) *previous = table->buckets + prv; + if(p != TABLE_NULL) { /* Open entry. */ + struct PN_(bucket) *previous = table->buckets + p; previous->next = current->next; } else if(current->next != TABLE_END) { /* Head closed entry and others. */ struct PN_(bucket) *const second - = table->buckets + (crnt = current->next); + = table->buckets + (c = current->next); assert(current->next < PN_(capacity)(table)); memcpy(current, second, sizeof *second); current = second; } - current->next = TABLE_NULL, table->size--, PN_(shrink_stack)(table, crnt); + current->next = TABLE_NULL, table->size--, PN_(shrink_stack)(table, c); return 1; } @@ -793,16 +774,17 @@ static void PN_(unused_base_coda)(void); static void PN_(unused_base)(void) { PN_(entry) e; PN_(key) k; PN_(value) v; memset(&e, 0, sizeof e); memset(&k, 0, sizeof k); memset(&v, 0, sizeof v); - N_(table)(); N_(table_)(0); N_(table_begin)(0); + PN_(element)(0); + N_(table)(); N_(table_)(0); + N_(table_iterator)(0); N_(table_key)(0); N_(table_next)(0); N_(table_buffer)(0, 0); N_(table_clear)(0); N_(table_contains)(0, k); N_(table_get_or)(0, k, v); N_(table_update)(0, k, 0); N_(table_policy)(0, k, 0, 0); N_(table_remove)(0, k); N_(table_iterator_remove)(0); #ifdef TABLE_VALUE - N_(table_query)(0, k, 0, 0); N_(table_next)(0, 0, 0); - N_(table_assign)(0, k, 0); + N_(table_value)(0); N_(table_query)(0, k, 0, 0); N_(table_assign)(0, k, 0); #else - N_(table_query)(0, k, 0); N_(table_next)(0, 0); N_(table_try)(0, e); + N_(table_query)(0, k, 0); N_(table_try)(0, e); #endif PN_(unused_base_coda)(); } @@ -904,7 +886,7 @@ static void PN_D_(unused, default_coda)(void) { PN_D_(unused, default)(); } #ifdef TABLE_IS_EQUAL #undef TABLE_IS_EQUAL #else -#undef TABLE_INVERSE +#undef TABLE_UNHASH #endif #ifdef TABLE_VALUE #undef TABLE_VALUE diff --git a/src/to_string.h b/src/to_string.h index f09310d..e3ca4bb 100644 --- a/src/to_string.h +++ b/src/to_string.h @@ -106,7 +106,6 @@ 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) *v; struct BOX_(iterator) it; int is_sep = 0; /* Minimum size: "(" "XXXXXXXXXXX" "," "…" ")" "\0". */ @@ -117,18 +116,18 @@ static const char *STR_(to_string)(const PSTR_(box) *const 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_(begin)(promise_box); + it = BOX_(iterator)(promise_box); } *b++ = left; - while(BOX_(next)(&it, &v)) { - STRCALL_(to_string)(v, (char (*)[12])b); + while(BOX_(next)(&it)) { + STRCALL_(to_string)(BOX_(element)(&it), (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_(next)(&it, 0)) goto ellipsis; else break; } + { if(BOX_(next)(&it)) goto ellipsis; else break; } } if(is_sep) b -= 2; *b++ = right; diff --git a/src/tree.h b/src/tree.h index 73f8eee..7152da6 100644 --- a/src/tree.h +++ b/src/tree.h @@ -181,6 +181,7 @@ struct PB_(tree) { struct PB_(node) *node; unsigned height; }; ![States.](../doc/tree/states.png) */ struct B_(tree); struct B_(tree) { struct PB_(tree) root; }; +/* fixme: height 1-based, fix pointer. */ /* Address of a specific key by node. Height might not be used, but there's too many structs in this file anyway. */ @@ -199,57 +200,48 @@ 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; }; -/** @return Before the start of `tree`, (can be null.) @implements `begin` */ -static struct PB_(iterator) PB_(begin)(struct B_(tree) *const tree) { +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; - it.root = tree ? &tree->root : 0; - 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_c)(it.ref.node)->child[0], it.ref.height--); - else it.ref.node = 0; - it.ref.idx = 0; - it.seen = 0; + assert(tree); + it.root = &tree->root; + it.ref.node = 0, it.ref.height = 0, it.ref.idx = 0; return it; } -/** @return After the end of `tree`, (can be null.) @implements `end` */ -static struct PB_(iterator) PB_(end)(struct B_(tree) *const tree) { - struct PB_(iterator) it; - it.root = tree ? &tree->root : 0; - 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[it.ref.node->size], - it.ref.height--); - else it.ref.node = 0; - it.ref.idx = it.ref.node ? it.ref.node->size : 0; - it.seen = 0; - return it; -} -/** @return Whether `it` advances, filling `ref`. @implements `next` */ -static int PB_(next)(struct PB_(iterator) *const it, - struct PB_(ref) **const ref) { - struct PB_(ref) adv; - assert(it); - if(!it->root || !it->ref.node) return it->seen = 0, 0; - if(!it->root->node || it->root->height == UINT_MAX) - return it->ref.node = 0, 0; /* Concurrent modification? */ - adv = it->ref; /* Shorten keystrokes and work with a copy. */ - if(!it->seen && adv.idx < adv.node->size) goto successor; - adv.idx++; - if(adv.height && adv.idx > adv.node->size) - return it->ref.node = 0, 0; /* Concurrent modification? */ - while(adv.height) adv.height--, - adv.node = PB_(as_branch)(adv.node)->child[adv.idx], adv.idx = 0; - if(adv.idx < adv.node->size) goto successor; /* Likely. */ - /* Bulk-loading or concurrent modification? */ - if(adv.idx > adv.node->size) return it->ref.node = 0, 0; - { /* Re-descend; pick the minimum height node that has a next key. */ - struct PB_(ref) next; +/** @return Dereference the next (pointing to valid element) `it`. */ +static struct PB_(ref) *PB_(element)(struct PB_(iterator) *const it) + { return &it->ref; } +/** @return Whether `it` pointing to a valid element. */ +static int PB_(next)(struct PB_(iterator) *const it) { + struct PB_(ref) next; + assert(it && it->root); + + /* Tree empty. */ + if(!it->root->node || it->root->height == UINT_MAX) return 0; + + /* Iterator empty; tree non-empty; point at first. */ + if(!it->ref.node) { + it->ref.height = it->root->height; + for(it->ref.node = it->root->node; it->ref.height; + it->ref.node = PB_(as_branch_c)(it->ref.node)->child[0], + it->ref.height--); + it->ref.idx = 0; + return 1; + } + + /* Next is a copy of the next element. Clip. */ + next = it->ref, next.idx++; + if(next.height && next.idx > next.node->size) next.idx = next.node->size; + while(next.height) next.node = PB_(as_branch)(next.node)->child[next.idx], + next.idx = 0, next.height--; /* Fall from branch. */ + it->ref = next; /* Possibly one beyond bounds. */ + if(next.idx >= next.node->size) { /* Maybe re-descend reveals more keys. */ struct PB_(tree) tree = *it->root; unsigned a0; - const PB_(key) x = adv.node->key[adv.node->size - 1]; /* Target. */ + /* Target; this will not work with duplicate keys. */ + const PB_(key) x = next.node->key[next.node->size - 1]; + assert(next.node->size); for(next.node = 0; tree.height; tree.node = PB_(as_branch)(tree.node)->child[a0], tree.height--) { unsigned a1 = tree.node->size; @@ -262,36 +254,44 @@ static int PB_(next)(struct PB_(iterator) *const it, if(a0 < tree.node->size) next.node = tree.node, next.height = tree.height, next.idx = a0; } - if(!next.node) return it->seen = 0, 0; /* Off right. */ - adv = next; + if(!next.node) return it->ref.node = 0, 0; /* Off right. */ } /* Jumped nodes. */ -successor: - it->seen = 1; - it->ref = adv; - if(ref) *ref = &it->ref; + it->ref = next; return 1; } -/** @return Whether `it` recedes, filling `v`. @implements `next` */ -static int PB_(previous)(struct PB_(iterator) *const it, - struct PB_(ref) **const v) { +/** @return Whether `it` is pointing to a valid element. */ +static int PB_(previous)(struct PB_(iterator) *const it) { struct PB_(ref) prd; - assert(it); - if(!it->root || !it->ref.node) return it->seen = 0, 0; - if(!it->root->node || it->root->height == UINT_MAX) - return it->ref.node = 0, 0; /* Concurrent modification? */ - prd = it->ref; /* Shorten keystrokes and work with a copy. */ - if(prd.idx > prd.node->size) prd.idx = prd.node->size; /* Clip. */ - if(!it->seen && prd.idx) { prd.idx--; goto predecessor; } + assert(it && it->root); + + /* Tree empty. */ + if(!it->root->node || it->root->height == UINT_MAX) return 0; + + /* Iterator empty; tree non-empty; point at last. */ + if(!it->ref.node) { + it->ref.height = it->root->height; + for(it->ref.node = it->root->node; it->ref.height; it->ref.node + = PB_(as_branch)(it->ref.node)->child[it->ref.node->size], + it->ref.height--); + /* Did you forget tree_bulk_load_finish>? */ + if(!it->ref.node->size) return it->ref.node = 0, 0; + it->ref.idx = it->ref.node->size - 1; + return 1; + } + + /* Predecessor? Clip. */ + prd = it->ref; + if(prd.height && prd.idx > prd.node->size) prd.idx = prd.node->size; while(prd.height) prd.height--, prd.node = PB_(as_branch)(prd.node)->child[prd.idx], prd.idx = prd.node->size; - if(prd.idx) { prd.idx--; goto predecessor; } /* Likely. */ - { /* Re-descend; pick the minimum height node that has a previous key. */ - struct PB_(ref) prev; + if(prd.idx) { + prd.idx--; + } else { /* Maybe re-descend reveals more keys. */ struct PB_(tree) tree = *it->root; unsigned a0; const PB_(key) x = prd.node->key[0]; /* Target. */ - for(prev.node = 0; tree.height; + for(prd.node = 0; tree.height; tree.node = PB_(as_branch)(tree.node)->child[a0], tree.height--) { unsigned a1 = tree.node->size; a0 = 0; @@ -300,16 +300,12 @@ static int PB_(previous)(struct PB_(iterator) *const it, if(B_(compare)(x, tree.node->key[m]) > 0) a0 = m + 1; else a1 = m; } - if(a0) prev.node = tree.node, prev.height = tree.height, - prev.idx = a0 - 1; + if(a0) prd.node = tree.node, prd.height = tree.height, + prd.idx = a0 - 1; } - if(!prev.node) return it->seen = 0, 0; /* Off left. */ - prd = prev; + if(!prd.node) return it->ref.node = 0, 0; /* Off left. */ } /* Jumped nodes. */ -predecessor: - it->seen = 1; it->ref = prd; - if(v) *v = &it->ref; return 1; } @@ -336,13 +332,13 @@ static void PB_(node_ub)(struct PB_(ref) *const hi, const PB_(key) x) { } 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, +/** @return A reference to the greatest key at or less than `x` in `tree`, or + the reference will be empty if the `x` is less than all `tree`. */ +static struct PB_(ref) PB_(less)(const struct PB_(tree) tree, const PB_(key) x) { struct PB_(ref) hi, found; found.node = 0; - if(!tree.node) return found; + if(!tree.node || tree.height == UINT_MAX) 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; @@ -356,30 +352,9 @@ static struct PB_(ref) PB_(lookup_left)(const struct PB_(tree) tree, } return found; } -/** Iterator version of 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, +/** @return A reference to the smallest key at or more than `x` in `tree`, or + the reference will be empty if the `x` is more than all `tree`. */ +static struct PB_(ref) PB_(more)(const struct PB_(tree) tree, const PB_(key) x) { struct PB_(ref) lo, found; found.node = 0; @@ -397,26 +372,6 @@ static struct PB_(ref) PB_(lookup_right)(const struct PB_(tree) tree, } return found; } -/** Iterator version of 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) { @@ -563,7 +518,7 @@ static size_t B_(tree_count)(const struct B_(tree) *const tree) { static int B_(tree_contains)(const struct B_(tree) *const tree, const PB_(key) x) { return tree && PB_(lookup_find)(tree->root, x).node; } /* fixme: entry tree_query -- there is no functionality that returns the - key. */ + key, which might be important with distinguishable keys. */ /** @return Get the value of `key` in `tree`, or if no key, `default_value`. The map type is `TREE_VALUE` and the set type is `TREE_KEY`. @@ -578,27 +533,26 @@ static PB_(value) B_(tree_get_or)(const struct B_(tree) *const tree, /** 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) { + @return Key in `tree` less-then-or-equal to `x` or `default_key` if `x` is + smaller than all in `tree`. @order \O(\log |`tree`|) @allow */ +static PB_(key) B_(tree_less_or)(const struct B_(tree) *const tree, + const PB_(key) x, const PB_(key) default_key) { struct PB_(ref) ref; - return tree && (ref = PB_(lookup_left)(tree->root, x)).node ? - (assert(ref.idx < ref.node->size), *PB_(ref_to_valuep)(ref)) - : default_value; + return tree && (ref = PB_(less)(tree->root, x)).node ? + (assert(ref.idx < ref.node->size), ref.node->key[ref.idx]) + : default_key; } /** 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`. + @return Key in `tree` greater-than-or-equal to `x` or `default_key` 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) { +static PB_(key) B_(tree_more_or)(const struct B_(tree) *const tree, + const PB_(key) x, const PB_(key) default_key) { struct PB_(ref) ref; - return tree && (ref = PB_(lookup_right)(tree->root, x)).node - ? *PB_(ref_to_valuep)(ref) : default_value; + return tree && (ref = PB_(more)(tree->root, x)).node + ? ref.node->key[ref.idx] : default_key; } #ifdef TREE_VALUE /* */ - struct PB_(ref) *r; - if(!PB_(next)(&it->_, &r)) return 0; - if(k) *k = r->node->key[r->idx]; -#ifdef TREE_VALUE - if(v) *v = r->node->value + r->idx; -#endif - return 1; -#ifdef TREE_VALUE -} -#else -} -#endif -#ifdef TREE_VALUE /* */ - struct PB_(ref) *r; - if(!PB_(previous)(&it->_, &r)) return 0; - if(k) *k = r->node->key[r->idx]; -#ifdef TREE_VALUE - if(v) *v = r->node->value + r->idx; -#endif - return 1; -#ifdef TREE_VALUE -} -#else -} -#endif +/** @return Extract the value from `it` when it points at a valid index, if + `TREE_VALUE`. @allow */ +static PB_(value) *B_(tree_value)(const struct B_(tree_iterator) *const it) + { return it->_.ref.node->value + it->_.ref.idx; } +#endif /* map --> */ -#ifdef TREE_VALUE /* */ - enum { TREE_NONODE, TREE_ITERATING, TREE_END } where; - PB_(key) anchor; - enum tree_result ret; - memset(&anchor, 0, sizeof anchor); /* Silence warnings. */ - 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 = TREE_NONODE; - } - 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)(it->_.root, key, 0, value); -#else - ret = PB_(update)(it->_.root, key, 0); -#endif - if(ret == TREE_ERROR) return TREE_ERROR; - 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_(lookup_right)(*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--; - } - it->_.seen = 0; - break; - } - return ret; -#ifdef TREE_VALUE -} -#else -} -#endif - -/** 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 `it` is not at a valid element. - @order \Theta(\log |`tree`|) */ -static int B_(tree_iterator_remove)(struct B_(tree_iterator) *const it) { - PB_(key) remove; - 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; - /* tree_begin_at>. */ - it->_.ref = PB_(lookup_right)(*it->_.root, remove); - it->_.seen = 0; - return 1; -} - 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_(element)(0); B_(tree)(); B_(tree_)(0); B_(tree_clear)(0); B_(tree_count)(0); B_(tree_contains)(0, k); B_(tree_get_or)(0, k, v); - B_(tree_left_or)(0, k, v); B_(tree_right_or)(0, k, v); + B_(tree_less_or)(0, k, k); B_(tree_more_or)(0, k, k); + B_(tree_next)(0); B_(tree_has_element)(0); #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); - B_(tree_next)(0, 0, 0); B_(tree_previous)(0, 0, 0); + B_(tree_assign)(0, k, 0, 0); B_(tree_value)(0); #else B_(tree_bulk_add)(0, k); B_(tree_try)(0, k); - B_(tree_assign)(0, k, 0); B_(tree_iterator_try)(0, k); - B_(tree_next)(0, 0); B_(tree_previous)(0, 0); + B_(tree_assign)(0, k, 0); #endif B_(tree_bulk_finish)(0); B_(tree_remove)(0, k); B_(tree_clone)(0, 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); + B_(tree_iterator)(0); B_(tree_less)(0, k); B_(tree_more)(0, k); + B_(tree_next)(0); B_(tree_previous)(0); B_(tree_key)(0); PB_(unused_base_coda)(); } static void PB_(unused_base_coda)(void) { PB_(unused_base)(); } @@ -1775,35 +1627,10 @@ static PB_(value) B_D_(tree, get)(const struct B_(tree) *const tree, && (ref = PB_(lookup_find)(tree->root, key)).node ? *PB_(ref_to_valuep)(ref) : PB_D_(default, value); } -/** This is functionally identical to 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, left)(const struct B_(tree) *const tree, - const PB_(key) key) { - struct PB_(ref) ref; - 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 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, left)(0, k); B_D_(tree, right)(0, k); - PB_D_(unused, default_coda)(); + B_D_(tree, get)(0, k); PB_D_(unused, default_coda)(); } static void PB_D_(unused, default_coda)(void) { PB_D_(unused, default)(); } #undef B_D_ diff --git a/test/test_journal.c b/test/test_journal.c index 3ec8108..27edc00 100644 --- a/test/test_journal.c +++ b/test/test_journal.c @@ -10,7 +10,7 @@ int main(void) { if(!journal_is_valid(&j)) goto catch; printf("Journal: %s.\n", journal_to_string(&j)); { - struct journal_iterator it = journal_begin(&j); + struct journal_iterator it = journal_iterator(&j); union date32 date; const char *value; if(!(journal_next(&it, &date, &value))) goto catch;