Got the source working; fixed some mistakes.
This commit is contained in:
parent
e963765d30
commit
90e84e3774
|
@ -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;
|
|
||||||
}
|
|
29
src/helper.h
29
src/helper.h
|
@ -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(); }
|
|
19
src/pair.c
19
src/pair.c
|
@ -1,6 +1,7 @@
|
||||||
#include "pair.h"
|
#include "pair.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
/** @return Constructs `a` and `b` as a pair. */
|
/** @return Constructs `a` and `b` as a pair. */
|
||||||
struct pair pair(const char *const a, const char *const b) {
|
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;
|
*n = accum;
|
||||||
return 1;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -3,3 +3,5 @@
|
||||||
struct pair { const char *a, *b; };
|
struct pair { const char *a, *b; };
|
||||||
struct pair pair(const char *const a, const char *const b);
|
struct pair pair(const char *const a, const char *const b);
|
||||||
int pair_to_natural(const char *, const char *, uint32_t *);
|
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);
|
||||||
|
|
20
src/source.h
20
src/source.h
|
@ -1,12 +1,13 @@
|
||||||
#if defined BASE \
|
#if defined BASE \
|
||||||
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- base */
|
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- base */
|
||||||
//#include "lorem.h"
|
#include "pair.h"
|
||||||
/*void kjvcite_to_string(const union kjvcite, char (*)[12]);*/
|
struct source { struct pair name, desc; };
|
||||||
#endif /* base --> */
|
#endif /* base --> */
|
||||||
|
|
||||||
|
|
||||||
#if defined GENERIC \
|
#if defined GENERIC \
|
||||||
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- generic */
|
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- generic */
|
||||||
|
|
||||||
struct tree_source_node;
|
struct tree_source_node;
|
||||||
struct tree_source_tree { struct tree_source_node *node; unsigned height; };
|
struct tree_source_tree { struct tree_source_node *node; unsigned height; };
|
||||||
struct source_tree { struct tree_source_tree root; };
|
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 tree_source_tree *root; struct tree_source_ref ref; int seen;
|
||||||
};
|
};
|
||||||
struct source_tree_iterator { struct tree_source_iterator _; };
|
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 --> */
|
#endif /* generic --> */
|
||||||
|
|
||||||
|
|
||||||
#if defined PROTO \
|
#if defined PROTO \
|
||||||
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- proto */
|
|| !defined BASE && !defined GENERIC && !defined PROTO /* <!-- proto */
|
||||||
#include <stddef.h>
|
#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 source *sources_add(struct sources *, const union line64);
|
||||||
struct sources sources(struct journal *);
|
struct sources sources(struct journal *);
|
||||||
void sources_(struct sources *);
|
void sources_(struct sources *);
|
||||||
|
|
|
@ -4,39 +4,44 @@
|
||||||
#define BASE
|
#define BASE
|
||||||
#include "../src/source.h" /* base */
|
#include "../src/source.h" /* base */
|
||||||
#include "../src/journal.h"
|
#include "../src/journal.h"
|
||||||
#include "../src/hash.h" /* djb2 */
|
|
||||||
#include "../src/pair.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.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
|
static void sourcelist_to_string(const struct source *const s,
|
||||||
first description ("Glider pilot log book"). */
|
char (*const z)[12]) {
|
||||||
static int lookup_is_equal(const char *const x, const char *const y)
|
const char *a = s->name.a, *b;
|
||||||
{ return !strcmp(x, y); }
|
char *y = *z;
|
||||||
static uint32_t lookup_hash(const char *const x) { return djb2(x); }
|
b = s->name.b <= a + 11 ? s->name.b : a + 11;
|
||||||
static void lookup_to_string(const char *x, const struct pair desc,
|
while(a < b) *(y++) = *(a++);
|
||||||
char (*const a)[12]) { (void)desc; sprintf(*a, "%.11s", x); }
|
*y = '\0';
|
||||||
static struct pair lookup_default = { 0, 0 };
|
}
|
||||||
#define TABLE_NAME lookup
|
#define ARRAY_NAME sourcelist
|
||||||
#define TABLE_KEY char *
|
#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_UINT uint32_t
|
||||||
#define TABLE_VALUE struct pair
|
#define TABLE_VALUE size_t /* Index into `lookup_sources`. */
|
||||||
#define TABLE_DEFAULT lookup_default
|
#define TABLE_DEFAULT 0
|
||||||
#define TABLE_TO_STRING
|
|
||||||
#include "../src/table.h"
|
#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); }
|
char (*const a)[12]) { (void)u; date32_to_string(line.date, a); }
|
||||||
static int source_compare(const union line64 a, const union line64 b)
|
static int source_compare(const union line64 a, const union line64 b)
|
||||||
{ return a.u64 > b.u64; }
|
{ return a.u64 > b.u64; }
|
||||||
#define TREE_NAME source
|
#define TREE_NAME source
|
||||||
#define TREE_KEY union line64
|
#define TREE_KEY union line64
|
||||||
#define TREE_VALUE char *
|
#define TREE_VALUE size_t /* Index into `lookup_sources`. */
|
||||||
#define TREE_COMPARE
|
#define TREE_COMPARE
|
||||||
#define TREE_TO_STRING
|
#define TREE_TO_STRING
|
||||||
#include "../src/tree.h"
|
#include "../src/tree.h"
|
||||||
|
@ -81,16 +86,32 @@ static int scan(union date32 date, const char *const buffer,
|
||||||
<line> "--" / [^-] :=> source
|
<line> "--" / [^-] :=> source
|
||||||
|
|
||||||
<source> * { why = "default source unrecognized"; goto catch; }
|
<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);
|
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);
|
printf("extracted <%.*s>\n", (int)(s1 - s0), s0);
|
||||||
continue;
|
continue;
|
||||||
}
|
} }
|
||||||
/* This is lazy and will pickup trailing spaces. */
|
/* This is lazy and will pickup trailing spaces. */
|
||||||
<source> @s0 keyword @s1 ":" [^\x00\n]+ / "\n" => skip {
|
<source> @s0 keyword @s1 ":" [^\x00\n]+ / "\n" => skip {
|
||||||
printf("new keyword <%.*s>\n", (int)(s1 - s0), s0);
|
struct pair keyword = pair(s0, s1);
|
||||||
continue;
|
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. */
|
assert(0); /* Never gets here. */
|
||||||
|
@ -105,22 +126,29 @@ catch:
|
||||||
be false. */
|
be false. */
|
||||||
void sources_(struct sources *const s) {
|
void sources_(struct sources *const s) {
|
||||||
if(!s) return;
|
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 sources(struct journal *const j) {
|
||||||
struct sources s;
|
struct sources s
|
||||||
|
= { sourcelist_array(), sourcelook_table(), source_tree() };
|
||||||
struct journal_iterator it;
|
struct journal_iterator it;
|
||||||
union date32 k;
|
union date32 k;
|
||||||
const char *v;
|
const char *v;
|
||||||
assert(j);
|
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);
|
it = journal_begin(j);
|
||||||
while(journal_next(&it, &k, &v)) if(!scan(k, v, &s)) goto catch;
|
while(journal_next(&it, &k, &v)) if(!scan(k, v, &s)) goto catch;
|
||||||
|
printf("%s\n", sourcelist_array_to_string(&s.list));
|
||||||
goto finally;
|
goto finally;
|
||||||
catch:
|
catch:
|
||||||
sources_(&s);
|
sources_(&s);
|
||||||
finally:
|
finally:
|
||||||
//char_array_(&temp); /* Erase the temporary buffer. */
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
/** @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. */
|
/* This function must be defined by the user. */
|
||||||
return table && table->buckets
|
return table && table->buckets
|
||||||
? !!PN_(query)(table, key, N_(hash)(key)) : 0;
|
? !!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 */
|
#ifdef TABLE_VALUE /* <!-- map */
|
||||||
/** If the entire entry space is filled, use this. Otherwise, a more convenient
|
/** If the entire entry space is filled, use this. Otherwise, a more convenient
|
||||||
function is <fn:<N>table_get_or>.
|
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.
|
<typedef:<PN>key> which gets filled on true.
|
||||||
@param[value] Only on a map with `TABLE_VALUE`. If not-null, stores the value.
|
@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 */
|
@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;
|
PN_(entry) e; PN_(key) k; PN_(value) v;
|
||||||
memset(&e, 0, sizeof e); memset(&k, 0, sizeof k); memset(&v, 0, sizeof 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)(); 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_get_or)(0, k, v);
|
||||||
N_(table_update)(0, k, 0); N_(table_policy)(0, k, 0, 0);
|
N_(table_update)(0, k, 0); N_(table_policy)(0, k, 0, 0);
|
||||||
N_(table_remove)(0, k); N_(table_iterator_remove)(0);
|
N_(table_remove)(0, k); N_(table_iterator_remove)(0);
|
||||||
|
|
|
@ -15,7 +15,7 @@ int main(void) {
|
||||||
const char *value;
|
const char *value;
|
||||||
if(!(journal_next(&it, &date, &value))) goto catch;
|
if(!(journal_next(&it, &date, &value))) goto catch;
|
||||||
printf("%u-%u-%u\n"
|
printf("%u-%u-%u\n"
|
||||||
"<%s>", date.year, date.month, date.day, value);
|
"<%s>\n", date.year, date.month, date.day, value);
|
||||||
}
|
}
|
||||||
goto finally;
|
goto finally;
|
||||||
catch:
|
catch:
|
||||||
|
|
Loading…
Reference in New Issue