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 <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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
20
src/source.h
20
src/source.h
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user