ur: refactors unsafe cue variants into a handle-based api

This commit is contained in:
Joe Bryan 2020-09-17 15:12:30 -07:00
parent 06cf6386aa
commit efe4479f23
3 changed files with 194 additions and 71 deletions

View File

@ -261,8 +261,7 @@ _cue_bench(void)
gettimeofday(&b4, 0);
{
ur_dict_t dic_u = {0};
u3_noun out;
ur_cue_test_t *t = ur_cue_test_init();
c3_w len_w = u3r_met(3, vat);
// XX assumes little-endian
@ -271,20 +270,17 @@ _cue_bench(void)
? (c3_y*)&vat
: (c3_y*)((u3a_atom*)u3a_to_ptr(vat))->buf_w;
ur_dict_grow((ur_root_t*)0, &dic_u, ur_fib10, ur_fib11);
for ( i_w = 0; i_w < max_w; i_w++ ) {
ur_cue_test_unsafe(&dic_u, len_w, byt_y);
ur_dict_wipe(&dic_u);
ur_cue_test_with(t, len_w, byt_y);
}
ur_dict_free(&dic_u);
ur_cue_test_done(t);
}
gettimeofday(&f2, 0);
timersub(&f2, &b4, &d0);
mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000);
fprintf(stderr, " cue test unsafe: %u ms\r\n", mil_w);
fprintf(stderr, " cue test with: %u ms\r\n", mil_w);
}
{

View File

@ -29,28 +29,58 @@ ur_jam(ur_root_t *r, ur_nref ref, uint64_t *len, uint8_t **byt);
** supports up to 62-bits of bit-addressed input (511 PiB).
** returns [ur_cue_good] on success.
**
** unsafe variant is unsafe wrt its [dict] parameter, which must be empty,
** (present in order to skip reallocation inside hot loops).
** cue_with factors out stack/dict (re)allocation,
** for better performance of hot loops.
**
** test variant does not allocate nouns, but merely parses the input.
** cue_test does not allocate nouns, but merely parses the input;
** cue_test_with* api factors out stack/dict (re)allocation,
** for better performance of repeated tests.
**
*/
ur_cue_res_e
ur_cue_unsafe(ur_root_t *r,
ur_dict64_t *dict,
uint64_t len,
const uint8_t *byt,
ur_nref *out);
typedef struct ur_cue_test_s ur_cue_test_t;
typedef struct ur_cue_s ur_cue_t;
ur_cue_res_e
ur_cue(ur_root_t *r, uint64_t len, const uint8_t *byt, ur_nref *out);
ur_cue_t*
ur_cue_init_with(ur_root_t *r,
uint64_t d_prev,
uint64_t d_size,
uint32_t s_prev,
uint32_t s_size);
ur_cue_t*
ur_cue_init(ur_root_t *r);
ur_cue_res_e
ur_cue_test_unsafe(ur_dict_t *dict,
uint64_t len,
const uint8_t *byt);
ur_cue_with(ur_cue_t *c,
uint64_t len,
const uint8_t *byt,
ur_nref *out);
void
ur_cue_done(ur_cue_t *c);
ur_bool_t
ur_cue_test(uint64_t len, const uint8_t *byt);
ur_cue_test_t*
ur_cue_test_init_with(uint64_t d_prev,
uint64_t d_size,
uint32_t s_prev,
uint32_t s_size);
ur_cue_test_t*
ur_cue_test_init(void);
ur_bool_t
ur_cue_test_with(ur_cue_test_t *t,
uint64_t len,
const uint8_t *byt);
void
ur_cue_test_done(ur_cue_test_t *t);
#endif

View File

@ -216,15 +216,25 @@ _cue_next(ur_root_t *r,
}
}
ur_cue_res_e
ur_cue_unsafe(ur_root_t *r,
ur_dict64_t *dict,
uint64_t len,
const uint8_t *byt,
ur_nref *out)
/*
** define opaque struct ur_cue_s (ie, ur_cue_t)
*/
struct ur_cue_s {
ur_root_t *r;
_cue_stack_t s;
ur_dict64_t dict;
};
static ur_cue_res_e
_cue(ur_cue_t *c,
uint64_t len,
const uint8_t *byt,
ur_nref *out)
{
ur_bsr_t bsr = {0};
_cue_stack_t s = {0};
ur_bsr_t bsr = {0};
ur_root_t *r = c->r;
_cue_stack_t *s = &c->s;
ur_dict64_t *dict = &c->dict;
ur_cue_res_e res;
ur_nref ref;
@ -239,58 +249,99 @@ ur_cue_unsafe(ur_root_t *r,
return ur_cue_meme;
}
// setup stack
//
s.prev = ur_fib10;
s.size = ur_fib11;
s.f = _oom("cue stack", malloc(s.size * sizeof(*s.f)));
// advance into stream
//
res = _cue_next(r, &s, &bsr, dict, &ref);
res = _cue_next(r, s, &bsr, dict, &ref);
// process result
//
while ( s.fill && (ur_cue_good == res) ) {
while ( s->fill && (ur_cue_good == res) ) {
// peek at the top of the stack
//
_cue_frame_t *f = &(s.f[s.fill - 1]);
_cue_frame_t *f = &(s->f[s->fill - 1]);
// f is a head-frame; stash result and read the tail from the stream
//
if ( CUE_HEAD == f->ref ) {
f->ref = ref;
res = _cue_next(r, &s, &bsr, dict, &ref);
res = _cue_next(r, s, &bsr, dict, &ref);
}
// f is a tail-frame; pop the stack and continue
//
else {
ref = ur_cons(r, f->ref, ref);
ur_dict64_put(r, dict, f->bits, (uint64_t)ref);
s.fill--;
s->fill--;
}
}
free(s.f);
if ( ur_cue_good == res ) {
*out = ref;
}
return res;
}
ur_cue_t*
ur_cue_init_with(ur_root_t *r,
uint64_t d_prev,
uint64_t d_size,
uint32_t s_prev,
uint32_t s_size)
{
ur_cue_t* c = _oom("cue_init", calloc(sizeof(*c), 1));
c->r = r;
ur_dict64_grow(r, &c->dict, d_prev, d_size);
c->s.prev = s_prev;
c->s.size = s_size;
c->s.f = _oom("cue_test_init", malloc(s_size * sizeof(*c->s.f)));
return c;
}
ur_cue_t*
ur_cue_init(ur_root_t *r)
{
return ur_cue_init_with(r, ur_fib11, ur_fib12, // dict sizes
ur_fib10, ur_fib11); // stack sizes
}
ur_cue_res_e
ur_cue_with(ur_cue_t *c,
uint64_t len,
const uint8_t *byt,
ur_nref *out)
{
ur_cue_res_e res = _cue(c, len, byt, out);
// XX check size, shrink if above threshold
//
ur_dict64_wipe(&c->dict);
c->s.fill = 0;
return res;
}
void
ur_cue_done(ur_cue_t *c)
{
ur_dict_free((ur_dict_t*)&c->dict);
free(c->s.f);
free(c);
}
ur_cue_res_e
ur_cue(ur_root_t *r,
uint64_t len,
const uint8_t *byt,
ur_nref *out)
{
ur_dict64_t dict = {0};
ur_dict64_grow(r, &dict, ur_fib11, ur_fib12);
ur_cue_t *c = ur_cue_init(r);
ur_cue_res_e res = _cue(c, len, byt, out);
ur_cue_res_e res = ur_cue_unsafe(r, &dict, len, byt, out);
ur_dict_free((ur_dict_t*)&dict);
ur_cue_done(c);
return res;
}
@ -378,14 +429,23 @@ _cue_test_next(_cue_test_stack_t *s,
}
}
ur_cue_res_e
ur_cue_test_unsafe(ur_dict_t *dict,
uint64_t len,
const uint8_t *byt)
/*
** define opaque struct ur_cue_test_s (ie, ur_cue_test_t)
*/
struct ur_cue_test_s {
_cue_test_stack_t s;
ur_dict_t dict;
};
static ur_cue_res_e
_cue_test(ur_cue_test_t *t,
uint64_t len,
const uint8_t *byt)
{
ur_bsr_t bsr = {0};
_cue_test_stack_t s = {0};
ur_cue_res_e res;
ur_bsr_t bsr = {0};
_cue_test_stack_t *s = &t->s;
ur_dict_t *dict = &t->dict;
ur_cue_res_e res;
// init bitstream-reader
//
@ -398,50 +458,87 @@ ur_cue_test_unsafe(ur_dict_t *dict,
return ur_cue_meme;
}
// setup stack
//
s.prev = ur_fib10;
s.size = ur_fib11;
s.f = _oom("cue_test", malloc(s.size * sizeof(*s.f)));
// advance into stream
//
res = _cue_test_next(&s, &bsr, dict);
res = _cue_test_next(s, &bsr, dict);
// process result
//
while ( s.fill && (ur_cue_good == res) ) {
while ( s->fill && (ur_cue_good == res) ) {
// peek at the top of the stack
//
_cue_test_frame_t *f = &(s.f[s.fill - 1]);
_cue_test_frame_t *f = &(s->f[s->fill - 1]);
// f is a head-frame; stash result and read the tail from the stream
//
if ( !f->tal ) {
f->tal = 1;
res = _cue_test_next(&s, &bsr, dict);
res = _cue_test_next(s, &bsr, dict);
}
// f is a tail-frame; pop the stack and continue
//
else {
ur_dict_put((ur_root_t*)0, dict, f->bits);
s.fill--;
s->fill--;
}
}
free(s.f);
return res;
}
ur_cue_test_t*
ur_cue_test_init_with(uint64_t d_prev,
uint64_t d_size,
uint32_t s_prev,
uint32_t s_size)
{
ur_cue_test_t* t = _oom("cue_test_init", calloc(sizeof(*t), 1));
ur_dict_grow((ur_root_t*)0, &t->dict, d_prev, d_size);
t->s.prev = s_prev;
t->s.size = s_size;
t->s.f = _oom("cue_test_init", malloc(s_size * sizeof(*t->s.f)));
return t;
}
ur_cue_test_t*
ur_cue_test_init(void)
{
return ur_cue_test_init_with(ur_fib11, ur_fib12, // dict sizes
ur_fib10, ur_fib11); // stack sizes
}
ur_bool_t
ur_cue_test_with(ur_cue_test_t *t,
uint64_t len,
const uint8_t *byt)
{
ur_bool_t ret = ur_cue_good == _cue_test(t, len, byt);
// XX check size, shrink if above threshold
//
ur_dict_wipe(&t->dict);
t->s.fill = 0;
return ret;
}
void
ur_cue_test_done(ur_cue_test_t *t)
{
ur_dict_free(&t->dict);
free(t->s.f);
free(t);
}
ur_bool_t
ur_cue_test(uint64_t len, const uint8_t *byt)
{
ur_dict_t dict = {0};
ur_dict_grow((ur_root_t*)0, &dict, ur_fib11, ur_fib12);
ur_cue_test_t *t = ur_cue_test_init();
ur_bool_t ret = ur_cue_good == _cue_test(t, len, byt);
ur_bool_t ret = ur_cue_good == ur_cue_test_unsafe(&dict, len, byt);
ur_dict_free(&dict);
ur_cue_test_done(t);
return ret;
}