Got the source working; fixed some mistakes.

This commit is contained in:
Neil 2023-02-03 22:00:55 -08:00
parent e963765d30
commit 90e84e3774
8 changed files with 97 additions and 72 deletions

View File

@ -1,9 +0,0 @@
#include <stdint.h>
/** djb2 <http://www.cse.yorku.ca/~oz/hash.html> */
static uint32_t djb2(const char *s) {
const unsigned char *str = (const unsigned char *)s;
uint32_t hash = 5381, c;
while(c = *str++) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}

View File

@ -1,29 +0,0 @@
#include <stdint.h>
#include <errno.h>
/** Parse unsigned; [`s`,`e`) => `n`. */
static int helper_natural(const char *s, const char *const e, uint32_t *const n)
{
uint32_t accum = 0;
while(s < e) {
unsigned next = accum * 10 + (unsigned)(*s - '0');
if(accum >= next) return errno = ERANGE, 0;
accum = next;
s++;
}
*n = accum;
return 1;
}
/** djb2 <http://www.cse.yorku.ca/~oz/hash.html> */
static uint32_t djb2(const char *s) {
const unsigned char *str = (const unsigned char *)s;
uint32_t hash = 5381, c;
while(c = *str++) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
static void unused_helper_coda(void);
static void unused_helper(void)
{ helper_natural(0, 0, 0); djb2(0); unused_helper_coda(); }
static void unused_helper_coda(void) { unused_helper(); }

View File

@ -1,6 +1,7 @@
#include "pair.h"
#include <stdint.h>
#include <errno.h>
#include <assert.h>
/** @return Constructs `a` and `b` as a pair. */
struct pair pair(const char *const a, const char *const b) {
@ -22,3 +23,21 @@ int pair_to_natural(const char *s, const char *const e, uint32_t *const n) {
*n = accum;
return 1;
}
int pair_is_equal(struct pair x, struct pair y) {
assert(x.a <= x.b && y.a <= y.b);
if(!x.a) return !y.a;
if(x.b - x.a != y.b - y.a) return 0;
while(x.a < x.b) { if(*x.a != *y.a) return 0; x.a++, y.a++; }
return 1;
}
/** djb2 <http://www.cse.yorku.ca/~oz/hash.html> */
uint32_t pair_djb2(struct pair p) {
uint32_t hash = 5381, c;
while(p.a < p.b) {
c = (unsigned char)*p.a++;
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
}

View File

@ -3,3 +3,5 @@
struct pair { const char *a, *b; };
struct pair pair(const char *const a, const char *const b);
int pair_to_natural(const char *, const char *, uint32_t *);
int pair_is_equal(struct pair, struct pair);
uint32_t pair_djb2(const struct pair p);

View File

@ -1,12 +1,13 @@
#if defined BASE \
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- base */
//#include "lorem.h"
/*void kjvcite_to_string(const union kjvcite, char (*)[12]);*/
#include "pair.h"
struct source { struct pair name, desc; };
#endif /* base --> */
#if defined GENERIC \
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- generic */
struct tree_source_node;
struct tree_source_tree { struct tree_source_node *node; unsigned height; };
struct source_tree { struct tree_source_tree root; };
@ -15,13 +16,26 @@ struct tree_source_iterator {
struct tree_source_tree *root; struct tree_source_ref ref; int seen;
};
struct source_tree_iterator { struct tree_source_iterator _; };
struct sourcelist_array { struct source *data; size_t size, capacity; };
struct sourcelook_bucket;
struct sourcelook_table {
struct sourcelook_bucket *buckets;
uint32_t log_capacity, size, top;
};
#endif /* generic --> */
#if defined PROTO \
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- proto */
#include <stddef.h>
struct sources { struct source_tree _; };
struct sources {
struct sourcelist_array list;
struct sourcelook_table look;
struct source_tree dates;
};
struct source *sources_add(struct sources *, const union line64);
struct sources sources(struct journal *);
void sources_(struct sources *);

View File

@ -4,39 +4,44 @@
#define BASE
#include "../src/source.h" /* base */
#include "../src/journal.h"
#include "../src/hash.h" /* djb2 */
#include "../src/pair.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
/* fixme: ...wait, why would you copy? modify the table to use substring. */
/* This is a lookup table for source strings ("2000glider") to substring the
first description ("Glider pilot log book"). */
static int lookup_is_equal(const char *const x, const char *const y)
{ return !strcmp(x, y); }
static uint32_t lookup_hash(const char *const x) { return djb2(x); }
static void lookup_to_string(const char *x, const struct pair desc,
char (*const a)[12]) { (void)desc; sprintf(*a, "%.11s", x); }
static struct pair lookup_default = { 0, 0 };
#define TABLE_NAME lookup
#define TABLE_KEY char *
static void sourcelist_to_string(const struct source *const s,
char (*const z)[12]) {
const char *a = s->name.a, *b;
char *y = *z;
b = s->name.b <= a + 11 ? s->name.b : a + 11;
while(a < b) *(y++) = *(a++);
*y = '\0';
}
#define ARRAY_NAME sourcelist
#define ARRAY_TYPE struct source
#define ARRAY_TO_STRING
#include "../src/array.h"
static int sourcelook_is_equal(const struct pair a, const struct pair b)
{ return pair_is_equal(a, b); }
static uint32_t sourcelook_hash(const struct pair p) { return pair_djb2(p); }
#define TABLE_NAME sourcelook
#define TABLE_KEY struct pair
#define TABLE_UINT uint32_t
#define TABLE_VALUE struct pair
#define TABLE_DEFAULT lookup_default
#define TABLE_TO_STRING
#define TABLE_VALUE size_t /* Index into `lookup_sources`. */
#define TABLE_DEFAULT 0
#include "../src/table.h"
static void source_to_string(const union line64 line, char *const*const u,
static void source_to_string(const union line64 line, const size_t *const u,
char (*const a)[12]) { (void)u; date32_to_string(line.date, a); }
static int source_compare(const union line64 a, const union line64 b)
{ return a.u64 > b.u64; }
#define TREE_NAME source
#define TREE_KEY union line64
#define TREE_VALUE char *
#define TREE_VALUE size_t /* Index into `lookup_sources`. */
#define TREE_COMPARE
#define TREE_TO_STRING
#include "../src/tree.h"
@ -81,16 +86,32 @@ static int scan(union date32 date, const char *const buffer,
<line> "--" / [^-] :=> source
<source> * { why = "default source unrecognized"; goto catch; }
<source> @s0 keyword @s1 / "\n" => skip {
<source> @s0 keyword @s1 / "\n" => skip { also_add_to_tree: {
struct pair p = pair(s0, s1);
const char *label;
size_t i;
if(!(i = sourcelook_table_get(&s->look, p)))
{ why = "keyword not introduced"; goto catch; }
printf("extracted <%.*s>\n", (int)(s1 - s0), s0);
continue;
}
} }
/* This is lazy and will pickup trailing spaces. */
<source> @s0 keyword @s1 ":" [^\x00\n]+ / "\n" => skip {
printf("new keyword <%.*s>\n", (int)(s1 - s0), s0);
continue;
struct pair keyword = pair(s0, s1);
size_t *idx;
struct source *source;
switch(sourcelook_table_assign(&s->look, keyword, &idx)) {
case TABLE_PRESENT: errno = EDOM; why = "new keyword already used";
case TABLE_ERROR: goto catch; /* /\ _Sic_. */
case TABLE_ABSENT: break; /* Good. */
}
*idx = 0; /* Clean. */
if(!(source = sourcelist_array_new(&s->list))) goto catch;
*idx = (size_t)(source - s->list.data);
source->name.a = s0, source->name.b = s1;
source->desc.a = 0, source->desc.b = 0;
fprintf(stderr, "New keyword <%.*s> stored in list at %zu.\n",
(int)(s1 - s0), s0, *idx);
goto also_add_to_tree;
}
*/ }
assert(0); /* Never gets here. */
@ -105,22 +126,29 @@ catch:
be false. */
void sources_(struct sources *const s) {
if(!s) return;
source_tree_(&s->_);
source_tree_(&s->dates);
sourcelook_table_(&s->look);
sourcelist_array_(&s->list);
}
struct sources sources(struct journal *const j) {
struct sources s;
struct sources s
= { sourcelist_array(), sourcelook_table(), source_tree() };
struct journal_iterator it;
union date32 k;
const char *v;
assert(j);
s._ = source_tree();
{ /* Null is the first item for convenience, (TABLE_DEFAULT). */
struct source *nul;
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);
while(journal_next(&it, &k, &v)) if(!scan(k, v, &s)) goto catch;
printf("%s\n", sourcelist_array_to_string(&s.list));
goto finally;
catch:
sources_(&s);
finally:
//char_array_(&temp); /* Erase the temporary buffer. */
return s;
}

View File

@ -626,7 +626,7 @@ static void N_(table_clear)(struct N_(table) *const table) {
}
/** @return Whether `key` is in `table` (which can be null.) @allow */
static int N_(table_is)(struct N_(table) *const table, const PN_(key) key) {
static int N_(table_contains)(struct N_(table) *const table, const PN_(key) key) {
/* This function must be defined by the user. */
return table && table->buckets
? !!PN_(query)(table, key, N_(hash)(key)) : 0;
@ -635,7 +635,7 @@ static int N_(table_is)(struct N_(table) *const table, const PN_(key) key) {
#ifdef TABLE_VALUE /* <!-- map */
/** If the entire entry space is filled, use this. Otherwise, a more convenient
function is <fn:<N>table_get_or>.
@param[result] If null, behaves like <fn:<N>table_is>, otherwise, a
@param[result] If null, behaves like <fn:<N>table_contains>, otherwise, a
<typedef:<PN>key> which gets filled on true.
@param[value] Only on a map with `TABLE_VALUE`. If not-null, stores the value.
@return Whether `key` is in `table` (which can be null.) @allow */
@ -794,7 +794,7 @@ 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);
N_(table_buffer)(0, 0); N_(table_clear)(0); N_(table_is)(0, k);
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);

View File

@ -15,7 +15,7 @@ int main(void) {
const char *value;
if(!(journal_next(&it, &date, &value))) goto catch;
printf("%u-%u-%u\n"
"<%s>", date.year, date.month, date.day, value);
"<%s>\n", date.year, date.month, date.day, value);
}
goto finally;
catch: