diff options
Diffstat (limited to 'vere/pkg/noun')
245 files changed, 63301 insertions, 0 deletions
diff --git a/vere/pkg/noun/allocate.c b/vere/pkg/noun/allocate.c new file mode 100644 index 0000000..96a09b2 --- /dev/null +++ b/vere/pkg/noun/allocate.c @@ -0,0 +1,2012 @@ +/// @file + +#include "allocate.h" + +#include "hashtable.h" +#include "log.h" +#include "manage.h" +#include "options.h" +#include "retrieve.h" +#include "trace.h" +#include "vortex.h" + +#include "palloc.c" + +u3_road* u3a_Road; +u3a_mark u3a_Mark; +u3a_gack u3a_Gack; +u3a_hunk_dose u3a_Hunk[u3a_crag_no]; + +#ifdef U3_MEMORY_DEBUG +c3_w u3_Code; +#endif + +c3_w u3a_to_pug(c3_w off); +c3_w u3a_to_pom(c3_w off); + +void +u3a_drop(const u3a_pile* pil_u); +void* +u3a_peek(const u3a_pile* pil_u); +void* +u3a_pop(const u3a_pile* pil_u); +void* +u3a_push(const u3a_pile* pil_u); +c3_o +u3a_pile_done(const u3a_pile* pil_u); + +void* +u3a_into_fn(u3_post som_p) +{ + return u3a_into(som_p); +} + +u3_post +u3a_outa_fn(void* som_v) +{ + return u3a_outa(som_v); +} + +u3_post +u3a_to_off_fn(u3_noun som) +{ + return u3a_to_off(som); +} + +u3a_noun* +u3a_to_ptr_fn(u3_noun som) +{ + return u3a_to_ptr(som); +} + +u3_noun +u3a_head(u3_noun som) +{ + return u3h(som); +} + +u3_noun +u3a_tail(u3_noun som) +{ + return u3t(som); +} + +void +u3a_post_info(u3_post som_p) +{ + _post_status(som_p); +} + +void +u3a_init_once(void) +{ + _init_once(); +} + +void +u3a_init_heap(void) +{ + _init_heap(); +} + +void +u3a_drop_heap(u3_post cap_p, u3_post ear_p) +{ +#ifdef ASAN_ENABLED + if ( cap_p > ear_p ) { // in north, drop inner south + _drop(ear_p, cap_p - ear_p); + } + else { // in south, drop inner north + _drop(cap_p, ear_p - cap_p); + } +#else + (void)cap_p; + (void)ear_p; +#endif +} + +void +u3a_mark_init(void) +{ + c3_w bit_w = (u3R->hep.len_w + 31) >> 5; + + u3a_Mark.bit_w = c3_calloc(sizeof(c3_w) * bit_w); + u3a_Mark.siz_w = u3R->hep.siz_w * 2; + u3a_Mark.len_w = u3R->hep.len_w; + u3a_Mark.buf_w = c3_calloc(sizeof(c3_w) * u3a_Mark.siz_w); + + memset(u3a_Mark.wee_w, 0, sizeof(c3_w) * u3a_crag_no); +} + +void +u3a_mark_done(void) +{ + c3_free(u3a_Mark.bit_w); + c3_free(u3a_Mark.buf_w); + memset(&u3a_Mark, 0, sizeof(u3a_Mark)); +} + +void* +u3a_mark_alloc(c3_w len_w) // words +{ + void* ptr_v; + + if ( len_w > (u3a_Mark.siz_w - u3a_Mark.len_w) ) { + u3a_Mark.siz_w += c3_max(u3a_Mark.len_w, len_w); + u3a_Mark.buf_w = c3_realloc(u3a_Mark.buf_w, sizeof(c3_w) * u3a_Mark.siz_w); + } + + ptr_v = &(u3a_Mark.buf_w[u3a_Mark.len_w]); + u3a_Mark.len_w += len_w; + + return ptr_v; +} + +void +u3a_pack_init(void) +{ + c3_w bit_w = (u3R->hep.len_w + 31) >> 5; + u3a_Gack.bit_w = c3_calloc(sizeof(c3_w) * bit_w); + u3a_Gack.pap_w = c3_calloc(sizeof(c3_w) * bit_w); + u3a_Gack.pum_w = c3_calloc(sizeof(c3_w) * bit_w); + + u3a_Gack.siz_w = u3R->hep.siz_w * 2; + u3a_Gack.len_w = u3R->hep.len_w; + u3a_Gack.buf_w = c3_calloc(sizeof(c3_w) * u3a_Gack.siz_w); +} + +void* +u3a_pack_alloc(c3_w len_w) // words +{ + void* ptr_v; + + if ( len_w > (u3a_Gack.siz_w - u3a_Gack.len_w) ) { + u3a_Gack.siz_w += c3_max(u3a_Gack.len_w, len_w); + u3a_Gack.buf_w = c3_realloc(u3a_Gack.buf_w, sizeof(c3_w) * u3a_Gack.siz_w); + } + + ptr_v = &(u3a_Gack.buf_w[u3a_Gack.len_w]); + u3a_Gack.len_w += len_w; + + return ptr_v; +} + +void +u3a_pack_done(void) +{ + c3_free(u3a_Gack.pap_w); + c3_free(u3a_Gack.pum_w); + c3_free(u3a_Gack.buf_w); +} + +/* _box_count(): adjust memory count. +*/ +#ifdef U3_CPU_DEBUG +static void +_box_count(c3_ws siz_ws) +{ + u3R->all.fre_w += siz_ws; + + { + c3_w end_w = u3a_heap(u3R); + c3_w all_w = (end_w - u3R->all.fre_w); + + if ( all_w > u3R->all.max_w ) { + u3R->all.max_w = all_w; + } + } +} +#else +static void +_box_count(c3_ws siz_ws) { } +#endif + +/* _ca_reclaim_half(): reclaim from memoization cache. +*/ +static void +_ca_reclaim_half(void) +{ + // XX u3l_log avoid here, as it can + // cause problems when handling errors + + if ( (0 == u3R->cax.har_p) || + (0 == u3to(u3h_root, u3R->cax.har_p)->use_w) ) + { + fprintf(stderr, "allocate: reclaim: memo cache: empty\r\n"); + u3m_bail(c3__meme); + } + +#if 1 + fprintf(stderr, "allocate: reclaim: half of %d entries\r\n", + u3to(u3h_root, u3R->cax.har_p)->use_w); + + u3h_trim_to(u3R->cax.har_p, u3to(u3h_root, u3R->cax.har_p)->use_w / 2); +#else + /* brutal and guaranteed effective + */ + u3h_free(u3R->cax.har_p); + u3R->cax.har_p = u3h_new(); +#endif +} + +/* u3a_walloc(): allocate storage words on hat heap. +*/ +void* +u3a_walloc(c3_w len_w) +{ + return u3a_into(_imalloc(len_w)); +} + +/* u3a_wealloc(): realloc in words. +*/ +void* +u3a_wealloc(void* lag_v, c3_w len_w) +{ + if ( !lag_v ) { + return u3a_walloc(len_w); + } + + return u3a_into(_irealloc(u3a_outa(lag_v), len_w)); +} + +/* u3a_pile_prep(): initialize stack control. +*/ +void +u3a_pile_prep(u3a_pile* pil_u, c3_w len_w) +{ + // frame size, in words + // + c3_w wor_w = (len_w + 3) >> 2; + c3_o nor_o = u3a_is_north(u3R); + + pil_u->mov_ws = (c3y == nor_o) ? -wor_w : wor_w; + pil_u->off_ws = (c3y == nor_o) ? 0 : -wor_w; + pil_u->top_p = u3R->cap_p; + +#ifdef U3_MEMORY_DEBUG + pil_u->rod_u = u3R; +#endif +} + +/* u3a_wfree(): free storage. +*/ +void +u3a_wfree(void* tox_v) +{ + if ( tox_v ) { + _ifree(u3a_outa(tox_v)); + } +} + +/* u3a_wtrim(): trim storage. + + old_w - old length + len_w - new length +*/ +void +u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w) +{ + // XX realloc? +} + +/* u3a_calloc(): allocate and zero-initialize array +*/ +void* +u3a_calloc(size_t num_i, size_t len_i) +{ + size_t byt_i = num_i * len_i; + c3_w* out_w; + + u3_assert(byt_i / len_i == num_i); + out_w = u3a_malloc(byt_i); + memset(out_w, 0, byt_i); + + return out_w; +} + +/* u3a_malloc(): aligned storage measured in bytes. + + Internally pads allocations to 16-byte alignment independent of DWORD + alignment ensured for word sized allocations. + +*/ +void* +u3a_malloc(size_t len_i) +{ + return u3a_walloc((len_i + 3) >> 2); +} + +/* u3a_celloc(): allocate a cell. +*/ +c3_w* +u3a_celloc(void) +{ + u3a_cell *cel_u; + u3_post *cel_p; + + if ( u3R->cel.cel_p ) { + cel_p = u3to(u3_post, u3R->cel.cel_p); + + if ( !u3R->cel.hav_w ) { + _rake_chunks(c3_wiseof(*cel_u), (1U << u3a_page), + (u3R->cel.bat_w++ & 1), &u3R->cel.hav_w, cel_p); + } + + cel_u = u3to(u3a_cell, cel_p[--u3R->cel.hav_w]); + } + else { + cel_u = u3a_walloc(c3_wiseof(*cel_u)); + } + +#ifdef U3_CPU_DEBUG + u3R->pro.cel_d++; +#endif + + return (c3_w*)cel_u; +} + + +/* u3a_cfree(): free a cell. +*/ +void +u3a_cfree(c3_w* cel_w) +{ + u3_post *cel_p; + + if ( u3R->cel.cel_p ) { + if ( u3R->cel.hav_w < (1U << u3a_page) ) { + cel_p = u3to(u3_post, u3R->cel.cel_p); + cel_p[u3R->cel.hav_w++] = u3a_outa(cel_w); + return; + } + } + + u3a_wfree(cel_w); +} + +/* u3a_realloc(): aligned realloc in bytes. +*/ +void* +u3a_realloc(void* lag_v, size_t len_i) +{ + if ( !lag_v ) { + return u3a_malloc(len_i); + } + + return u3a_wealloc(lag_v, (len_i + 3) >> 2); +} + +/* u3a_free(): free for aligned malloc. +*/ +void +u3a_free(void* tox_v) +{ + u3a_wfree((c3_w*)tox_v); +} + +/* _me_wash_north(): clean up mug slots after copy. +*/ +static void _me_wash_north(u3_noun dog); +static void +_me_wash_north_in(u3_noun som) +{ + if ( _(u3a_is_cat(som)) ) return; + if ( !_(u3a_north_is_junior(u3R, som)) ) return; + + _me_wash_north(som); +} +static void +_me_wash_north(u3_noun dog) +{ + u3_assert(c3y == u3a_is_dog(dog)); + // u3_assert(c3y == u3a_north_is_junior(u3R, dog)); + { + u3a_noun* dog_u = u3a_to_ptr(dog); + + if ( dog_u->mug_w == 0 ) return; + + dog_u->mug_w = 0; // power wash + // if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; } + + if ( _(u3a_is_pom(dog)) ) { + u3a_cell* god_u = (u3a_cell *)(void *)dog_u; + + _me_wash_north_in(god_u->hed); + _me_wash_north_in(god_u->tel); + } + } +} + +/* _me_wash_south(): clean up mug slots after copy. +*/ +static void _me_wash_south(u3_noun dog); +static void +_me_wash_south_in(u3_noun som) +{ + if ( _(u3a_is_cat(som)) ) return; + if ( !_(u3a_south_is_junior(u3R, som)) ) return; + + _me_wash_south(som); +} +static void +_me_wash_south(u3_noun dog) +{ + u3_assert(c3y == u3a_is_dog(dog)); + // u3_assert(c3y == u3a_south_is_junior(u3R, dog)); + { + u3a_noun* dog_u = u3a_to_ptr(dog); + + if ( dog_u->mug_w == 0 ) return; + + dog_u->mug_w = 0; // power wash + // if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; } + + if ( _(u3a_is_pom(dog)) ) { + u3a_cell* god_u = (u3a_cell *)(void *)dog_u; + + _me_wash_south_in(god_u->hed); + _me_wash_south_in(god_u->tel); + } + } +} + +/* u3a_wash(): wash all lazy mugs. RETAIN. +*/ +void +u3a_wash(u3_noun som) +{ + if ( _(u3a_is_cat(som)) ) { + return; + } + if ( _(u3a_is_north(u3R)) ) { + if ( _(u3a_north_is_junior(u3R, som)) ) { + _me_wash_north(som); + } + } + else { + if ( _(u3a_south_is_junior(u3R, som)) ) { + _me_wash_south(som); + } + } +} + +/* _me_gain_use(): increment use count. +*/ +static void +_me_gain_use(u3_noun dog) +{ + u3a_noun* box_u = u3a_to_ptr(dog); + + if ( 0x7fffffff == box_u->use_w ) { + u3l_log("fail in _me_gain_use"); + u3m_bail(c3__fail); + } + else { + if ( box_u->use_w == 0 ) { + u3m_bail(c3__foul); + } + box_u->use_w += 1; + +#ifdef U3_MEMORY_DEBUG + // enable to (maybe) help track down leaks + // + // if ( u3_Code && !box_u->cod_w ) { box_u->cod_w = u3_Code; } +#endif + } +} + +#undef VERBOSE_TAKE + +/* _ca_take_atom(): reallocate an indirect atom off the stack. +*/ +static inline u3_atom +_ca_take_atom(u3a_atom* old_u) +{ + c3_w* new_w = u3a_walloc(old_u->len_w + c3_wiseof(u3a_atom)); + u3a_atom* new_u = (u3a_atom*)(void *)new_w; + u3_noun new = u3a_to_pug(u3a_outa(new_u)); + + new_u->use_w = 1; + +#ifdef VERBOSE_TAKE + u3l_log("%s: atom %p to %p", ( c3y == u3a_is_north(u3R) ) + ? "north" + : "south", + old_u, + new_u); +#endif + + // XX use memcpy? + // + new_u->mug_w = old_u->mug_w; + new_u->len_w = old_u->len_w; + { + c3_w i_w; + + for ( i_w=0; i_w < old_u->len_w; i_w++ ) { + new_u->buf_w[i_w] = old_u->buf_w[i_w]; + } + } + + // borrow mug slot to record new destination in [old_u] + // + old_u->mug_w = new; + + return new; +} + +/* _ca_take_cell(): reallocate a cell off the stack. +*/ +static inline u3_cell +_ca_take_cell(u3a_cell* old_u, u3_noun hed, u3_noun tel) +{ + c3_w* new_w = u3a_celloc(); + u3a_cell* new_u = (u3a_cell*)(void *)new_w; + u3_cell new = u3a_to_pom(u3a_outa(new_u)); + +#ifdef VERBOSE_TAKE + u3l_log("%s: cell %p to %p", ( c3y == u3a_is_north(u3R) ) + ? "north" + : "south", + old_u, + new_u); +#endif + + new_u->use_w = 1; + new_u->mug_w = old_u->mug_w; + new_u->hed = hed; + new_u->tel = tel; + + // borrow mug slot to record new destination in [old_u] + // + old_u->mug_w = new; + + return new; +} + +/* _ca_take: stack frame for recording cell travesal +** (u3_none == hed) == head-frame +*/ +typedef struct _ca_take +{ + u3_weak hed; // taken head + u3_cell old; // old cell +} _ca_take; + +/* _ca_take_next_south: take next noun, pushing cells on stack. +*/ +static inline u3_noun +_ca_take_next_north(u3a_pile* pil_u, u3_noun veb) +{ + while ( 1 ) { + // direct atoms and senior refs are not counted. + // + if ( (c3y == u3a_is_cat(veb)) + || (c3y == u3a_north_is_senior(u3R, veb)) ) + { + return veb; + } + // not junior; normal (heap) refs on our road are counted. + // + else if ( c3n == u3a_north_is_junior(u3R, veb) ) { + _me_gain_use(veb); // bypass branches in u3k() + return veb; + } + // junior (stack) refs are copied. + // + else { + u3a_noun* veb_u = u3a_to_ptr(veb); + + // 32-bit mug_w: already copied [veb] and [mug_w] is the new ref. + // + if ( veb_u->mug_w >> 31 ) { + u3_noun nov = (u3_noun)veb_u->mug_w; + + u3_assert( c3y == u3a_north_is_normal(u3R, nov) ); + +#ifdef VERBOSE_TAKE + u3l_log("north: %p is already %p", veb_u, u3a_to_ptr(nov)); +#endif + + _me_gain_use(nov); // bypass branches in u3k() + return nov; + } + else if ( c3y == u3a_is_atom(veb) ) { + return _ca_take_atom((u3a_atom*)veb_u); + } + else { + u3a_cell* old_u = (u3a_cell*)veb_u; + _ca_take* fam_u = u3a_push(pil_u); + + fam_u->hed = u3_none; + fam_u->old = veb; + + veb = old_u->hed; + continue; + } + } + } +} + +/* _ca_take_next_south: take next noun, pushing cells on stack. +*/ +static inline u3_noun +_ca_take_next_south(u3a_pile* pil_u, u3_noun veb) +{ + while ( 1 ) { + // direct atoms and senior refs are not counted. + // + if ( (c3y == u3a_is_cat(veb)) + || (c3y == u3a_south_is_senior(u3R, veb)) ) + { + return veb; + } + // not junior; a normal pointer in our road -- refcounted + // + else if ( c3n == u3a_south_is_junior(u3R, veb) ) { + _me_gain_use(veb); // bypass branches in u3k() + return veb; + } + // junior (stack) refs are copied. + // + else { + u3a_noun* veb_u = u3a_to_ptr(veb); + + // 32-bit mug_w: already copied [veb] and [mug_w] is the new ref. + // + if ( veb_u->mug_w >> 31 ) { + u3_noun nov = (u3_noun)veb_u->mug_w; + + u3_assert( c3y == u3a_south_is_normal(u3R, nov) ); + +#ifdef VERBOSE_TAKE + u3l_log("south: %p is already %p", veb_u, u3a_to_ptr(nov)); +#endif + + _me_gain_use(nov); // bypass branches in u3k() + return nov; + } + else if ( c3y == u3a_is_atom(veb) ) { + return _ca_take_atom((u3a_atom*)veb_u); + } + else { + u3a_cell* old_u = (u3a_cell*)veb_u; + _ca_take* fam_u = u3a_push(pil_u); + + fam_u->hed = u3_none; + fam_u->old = veb; + + veb = old_u->hed; + continue; + } + } + } +} + +/* _ca_take_north(): in a north road, gain, copying juniors (from stack). +*/ +static u3_noun +_ca_take_north(u3_noun veb) +{ + u3_noun pro; + _ca_take* fam_u; + u3a_pile pil_u; + u3a_pile_prep(&pil_u, sizeof(*fam_u)); + + // commence taking + // + pro = _ca_take_next_north(&pil_u, veb); + + // process cell results + // + if ( c3n == u3a_pile_done(&pil_u) ) { + fam_u = u3a_peek(&pil_u); + + do { + // head-frame: stash copy and continue into the tail + // + if ( u3_none == fam_u->hed ) { + u3a_cell* old_u = u3a_to_ptr(fam_u->old); + fam_u->hed = pro; + pro = _ca_take_next_north(&pil_u, old_u->tel); + fam_u = u3a_peek(&pil_u); + } + // tail-frame: copy cell and pop the stack + // + else { + u3a_cell* old_u = u3a_to_ptr(fam_u->old); + pro = _ca_take_cell(old_u, fam_u->hed, pro); + fam_u = u3a_pop(&pil_u); + } + } while ( c3n == u3a_pile_done(&pil_u) ); + } + + return pro; +} +/* _ca_take_south(): in a south road, gain, copying juniors (from stack). +*/ +static u3_noun +_ca_take_south(u3_noun veb) +{ + u3_noun pro; + _ca_take* fam_u; + u3a_pile pil_u; + u3a_pile_prep(&pil_u, sizeof(*fam_u)); + + // commence taking + // + pro = _ca_take_next_south(&pil_u, veb); + + // process cell results + // + if ( c3n == u3a_pile_done(&pil_u) ) { + fam_u = u3a_peek(&pil_u); + + do { + // head-frame: stash copy and continue into the tail + // + if ( u3_none == fam_u->hed ) { + u3a_cell* old_u = u3a_to_ptr(fam_u->old); + fam_u->hed = pro; + pro = _ca_take_next_south(&pil_u, old_u->tel); + fam_u = u3a_peek(&pil_u); + } + // tail-frame: copy cell and pop the stack + // + else { + u3a_cell* old_u = u3a_to_ptr(fam_u->old); + pro = _ca_take_cell(old_u, fam_u->hed, pro); + fam_u = u3a_pop(&pil_u); + } + } while ( c3n == u3a_pile_done(&pil_u) ); + } + + return pro; +} + +/* u3a_take(): gain, copying juniors. +*/ +u3_noun +u3a_take(u3_noun veb) +{ + u3_noun pro; + u3t_on(coy_o); + + u3_assert(u3_none != veb); + + pro = ( c3y == u3a_is_north(u3R) ) + ? _ca_take_north(veb) + : _ca_take_south(veb); + + u3t_off(coy_o); + return pro; +} + +/* u3a_left(): true of junior if preserved. +*/ +c3_o +u3a_left(u3_noun som) +{ + if ( _(u3a_is_cat(som)) || + !_(u3a_is_junior(u3R, som)) ) + { + return c3y; + } + else { + u3a_noun* dog_u = u3a_to_ptr(som); + + return __(0 != (dog_u->mug_w >> 31)); + } +} + +/* _me_gain_north(): gain on a north road. +*/ +static u3_noun +_me_gain_north(u3_noun dog) +{ + if ( c3y == u3a_north_is_senior(u3R, dog) ) { + /* senior pointers are not refcounted + */ + return dog; + } + else { + /* junior nouns are disallowed + */ + u3_assert(!_(u3a_north_is_junior(u3R, dog))); + + /* normal pointers are refcounted + */ + _me_gain_use(dog); + return dog; + } +} + +/* _me_gain_south(): gain on a south road. +*/ +static u3_noun +_me_gain_south(u3_noun dog) +{ + if ( c3y == u3a_south_is_senior(u3R, dog) ) { + /* senior pointers are not refcounted + */ + return dog; + } + else { + /* junior nouns are disallowed + */ + u3_assert(!_(u3a_south_is_junior(u3R, dog))); + + /* normal nouns are refcounted + */ + _me_gain_use(dog); + return dog; + } +} + +/* _me_lose_north(): lose on a north road. +*/ +static void +_me_lose_north(u3_noun dog) +{ +top: + if ( c3y == u3a_north_is_normal(u3R, dog) ) { + u3a_noun* box_u = u3a_to_ptr(dog); + + if ( box_u->use_w > 1 ) { + box_u->use_w -= 1; + } + else { + if ( 0 == box_u->use_w ) { + u3m_bail(c3__foul); + } + else { + if ( _(u3a_is_pom(dog)) ) { + u3a_cell* dog_u = (void*)box_u; + u3_noun h_dog = dog_u->hed; + u3_noun t_dog = dog_u->tel; + + if ( !_(u3a_is_cat(h_dog)) ) { + _me_lose_north(h_dog); + } + u3a_cfree((c3_w*)dog_u); + if ( !_(u3a_is_cat(t_dog)) ) { + dog = t_dog; + goto top; + } + } + else { + u3a_wfree(box_u); + } + } + } + } +} + +/* _me_lose_south(): lose on a south road. +*/ +static void +_me_lose_south(u3_noun dog) +{ +top: + if ( c3y == u3a_south_is_normal(u3R, dog) ) { + u3a_noun* box_u = u3a_to_ptr(dog); + + if ( box_u->use_w > 1 ) { + box_u->use_w -= 1; + } + else { + if ( 0 == box_u->use_w ) { + u3m_bail(c3__foul); + } + else { + if ( _(u3a_is_pom(dog)) ) { + u3a_cell* dog_u = (void*)box_u; + u3_noun h_dog = dog_u->hed; + u3_noun t_dog = dog_u->tel; + + if ( !_(u3a_is_cat(h_dog)) ) { + _me_lose_south(h_dog); + } + u3a_cfree((c3_w*)dog_u); + if ( !_(u3a_is_cat(t_dog)) ) { + dog = t_dog; + goto top; + } + } + else { + u3a_wfree(box_u); + } + } + } + } +} + +/* u3a_gain(): gain a reference count in normal space. +*/ +u3_noun +u3a_gain(u3_noun som) +{ + u3t_on(mal_o); + u3_assert(u3_none != som); + + if ( !_(u3a_is_cat(som)) ) { + som = _(u3a_is_north(u3R)) + ? _me_gain_north(som) + : _me_gain_south(som); + } + u3t_off(mal_o); + + return som; +} + +/* u3a_lose(): lose a reference count. +*/ +void +u3a_lose(u3_noun som) +{ + u3t_on(mal_o); + if ( !_(u3a_is_cat(som)) ) { + if ( _(u3a_is_north(u3R)) ) { + _me_lose_north(som); + } else { + _me_lose_south(som); + } + } + u3t_off(mal_o); +} + +/* u3a_use(): reference count. +*/ +c3_w +u3a_use(u3_noun som) +{ + if ( _(u3a_is_cat(som)) ) { + return 1; + } + else { + u3a_noun* box_u = u3a_to_ptr(som); + return box_u->use_w; + } +} + +#define SWAP(l, r) \ + do { typeof(l) t = l; l = r; r = t; } while (0) + +/* _ca_wed_our(): unify [a] and [b] on u3R. +*/ +static inline c3_o +_ca_wed_our(u3_noun *restrict a, u3_noun *restrict b) +{ + c3_t asr_t = ( c3y == u3a_is_senior(u3R, *a) ); + c3_t bsr_t = ( c3y == u3a_is_senior(u3R, *b) ); + + if ( asr_t == bsr_t ) { + // both [a] and [b] are senior; we can't unify on u3R + // + if ( asr_t ) return c3n; + + // both are on u3R; keep the deeper address + // (and gain a reference) + // + // (N && <) || (S && >) + // XX consider keeping higher refcount instead + // + if ( (*a > *b) == (c3y == u3a_is_north(u3R)) ) SWAP(a, b); + + _me_gain_use(*a); + } + // one of [a] or [b] are senior; keep it + // + else if ( !asr_t ) SWAP(a, b); + + u3z(*b); + *b = *a; + return c3y; +} + +/* _ca_wed_you(): unify [a] and [b] on senior [rod_u]. leaks +*/ +static c3_o +_ca_wed_you(u3a_road* rod_u, u3_noun *restrict a, u3_noun *restrict b) +{ + // XX assume( rod_u != u3R ) + c3_t asr_t = ( c3y == u3a_is_senior(rod_u, *a) ); + c3_t bsr_t = ( c3y == u3a_is_senior(rod_u, *b) ); + + if ( asr_t == bsr_t ) { + // both [a] and [b] are senior; we can't unify on [rod_u] + // + if ( asr_t ) return c3n; + + // both are on [rod_u]; keep the deeper address + // (and gain a reference) + // + // (N && <) || (S && >) + // XX consider keeping higher refcount instead + // + if ( (*a > *b) == (c3y == u3a_is_north(rod_u)) ) SWAP(a, b); + + _me_gain_use(*a); + } + // one of [a] or [b] are senior; keep it + // + else if ( !asr_t ) SWAP(a, b); + + *b = *a; + return c3y; +} + +#undef SWAP + +/* u3a_wed(): unify noun references. +*/ +void +u3a_wed(u3_noun *restrict a, u3_noun *restrict b) +{ + // XX assume( *a != *b ) + u3_road* rod_u = u3R; + c3_o wed_o; + + if ( rod_u->kid_p ) return; + + wed_o = _ca_wed_our(a, b); + +#ifdef U3_MEMORY_DEBUG + return; +#else + if ( u3C.wag_w & u3o_debug_ram ) return; +#endif + + // while not at home, attempt to unify + // + // we try to unify on our road, and retry on senior roads + // until we succeed or reach the home road. + // + // we can't perform this kind of butchery on the home road, + // where asynchronous things can allocate. + // (XX anything besides u3t_samp?) + // + // when unifying on a higher road, we can't free nouns, + // because we can't track junior nouns that point into + // that road. + // + // this is just an implementation issue -- we could set use + // counts to 0 without actually freeing. but the allocator + // would have to be actually designed for this. + // (alternately, we could keep a deferred free-list) + // + // not freeing may generate spurious leaks, so we disable + // senior unification when debugging memory. this will + // cause a very slow boot process as the compiler compiles + // itself, constantly running into duplicates. + // + + while ( (c3n == wed_o) + && rod_u->par_p + && (&u3H->rod_u != (rod_u = u3to(u3_road, rod_u->par_p))) ) + { + wed_o = _ca_wed_you(rod_u, a, b); + } +} + +/* u3a_luse(): check refcount sanity. +*/ +void +u3a_luse(u3_noun som) +{ + if ( 0 == u3a_use(som) ) { + fprintf(stderr, "loom: insane %d 0x%x\r\n", som, som); + abort(); + } + if ( _(u3du(som)) ) { + u3a_luse(u3h(som)); + u3a_luse(u3t(som)); + } +} + +/* u3a_mark_ptr(): mark a pointer for gc. Produce size if first mark. +*/ +c3_w +u3a_mark_ptr(void* ptr_v) +{ + // XX restore loom-bounds check + u3_post som_p = u3a_outa(ptr_v); + c3_w siz_w = !(u3C.wag_w & u3o_debug_ram) + ? _mark_post(som_p) + : _count_post(som_p, 0); + + return siz_w; +} + +/* u3a_relocate_post(): replace post with relocation pointer (unchecked). +*/ +void +u3a_relocate_post(u3_post *som_p) +{ + *som_p = _pack_relocate(*som_p); +} + +/* u3a_mark_relocate_post(): replace post with relocation pointer (checked). +*/ +u3_post +u3a_mark_relocate_post(u3_post som_p, c3_t *fir_t) +{ + return _pack_relocate_mark(som_p, fir_t); +} + +/* u3a_relocate_noun(): replace noun with relocation reference, recursively. +*/ +void +u3a_relocate_noun(u3_noun *som) +{ + u3_post old_p, new_p; + u3_noun old; + u3a_cell* cel_u; + c3_t fir_t; + + while ( 1 ) { + old = *som; + + if ( c3y == u3a_is_cat(old) ) return; + + old_p = u3a_to_off(old); + + if ( c3n == u3a_is_cell(old) ) { + new_p = _pack_relocate(old_p); + *som = u3a_to_pug(new_p); + return; + } + + new_p = _pack_relocate_mark(old_p, &fir_t); + *som = u3a_to_pom(new_p); + + if ( !fir_t ) return; + + cel_u = u3to(u3a_cell, old_p); + u3a_relocate_noun(&(cel_u->hed)); + som = &(cel_u->tel); + } +} + +/* u3a_mark_mptr(): mark a malloc-allocated ptr for gc. +*/ +c3_w +u3a_mark_mptr(void* ptr_v) +{ + return u3a_mark_ptr(ptr_v); +} + +/* u3a_mark_rptr(): mark a refcounted, word-aligned ptr for gc. +*/ +c3_w +u3a_mark_rptr(void* ptr_v) +{ + u3_post som_p = u3a_outa(ptr_v); + c3_w siz_w = !(u3C.wag_w & u3o_debug_ram) + ? _mark_post(som_p) + : _count_post(som_p, 1); + + return siz_w; +} + +/* u3a_mark_noun(): mark a noun for gc. Produce size. +*/ +c3_w +u3a_mark_noun(u3_noun som) +{ + c3_w siz_w = 0; + + while ( 1 ) { + if ( _(u3a_is_senior(u3R, som)) ) { + return siz_w; + } + else { + c3_w* dog_w = u3a_to_ptr(som); + c3_w new_w = u3a_mark_rptr(dog_w); + + if ( 0 == new_w || 0xffffffff == new_w ) { // see u3a_mark_ptr() + return siz_w; + } + else { + siz_w += new_w; + if ( _(u3du(som)) ) { + siz_w += u3a_mark_noun(u3h(som)); + som = u3t(som); + } + else return siz_w; + } + } + } +} + +/* u3a_count_noun(): count size of pointer. +*/ +c3_w +u3a_count_ptr(void* ptr_v) +{ +#if 0 + if ( _(u3a_is_north(u3R)) ) { + if ( !((ptr_v >= u3a_into(u3R->rut_p)) && + (ptr_v < u3a_into(u3R->hat_p))) ) + { + return 0; + } + } + else { + if ( !((ptr_v >= u3a_into(u3R->hat_p)) && + (ptr_v < u3a_into(u3R->rut_p))) ) + { + return 0; + } + } + { + u3a_box* box_u = u3a_botox(ptr_v); + c3_w siz_w; + + c3_ws use_ws = (c3_ws)box_u->use_w; + + if ( use_ws == 0 ) { + fprintf(stderr, "%p is bogus\r\n", ptr_v); + siz_w = 0; + } + else { + u3_assert(use_ws != 0); + + if ( use_ws < 0 ) { + siz_w = 0; + } + else { + use_ws = -use_ws; + siz_w = box_u->siz_w; + } + box_u->use_w = (c3_w)use_ws; + } + return siz_w; + } +#endif + return 0; +} + +/* u3a_count_noun(): count size of noun. +*/ +c3_w +u3a_count_noun(u3_noun som) +{ + c3_w siz_w = 0; + + while ( 1 ) { + if ( _(u3a_is_senior(u3R, som)) ) { + return siz_w; + } + else { + c3_w* dog_w = u3a_to_ptr(som); + c3_w new_w = u3a_count_ptr(dog_w); + + if ( 0 == new_w ) { + return siz_w; + } + else { + siz_w += new_w; + if ( _(u3du(som)) ) { + siz_w += u3a_count_noun(u3h(som)); + som = u3t(som); + } + else return siz_w; + } + } + } +} + +/* u3a_discount_ptr(): clean up after counting a pointer. +*/ +c3_w +u3a_discount_ptr(void* ptr_v) +{ +#if 0 + if ( _(u3a_is_north(u3R)) ) { + if ( !((ptr_v >= u3a_into(u3R->rut_p)) && + (ptr_v < u3a_into(u3R->hat_p))) ) + { + return 0; + } + } + else { + if ( !((ptr_v >= u3a_into(u3R->hat_p)) && + (ptr_v < u3a_into(u3R->rut_p))) ) + { + return 0; + } + } + u3a_box* box_u = u3a_botox(ptr_v); + c3_w siz_w; + + c3_ws use_ws = (c3_ws)box_u->use_w; + + if ( use_ws == 0 ) { + fprintf(stderr, "%p is bogus\r\n", ptr_v); + siz_w = 0; + } + else { + u3_assert(use_ws != 0); + + if ( use_ws < 0 ) { + use_ws = -use_ws; + siz_w = box_u->siz_w; + } + else { + siz_w = 0; + } + box_u->use_w = (c3_w)use_ws; + } + + return siz_w; +#endif + return 0; +} + +/* u3a_discount_noun(): clean up after counting a noun. +*/ +c3_w +u3a_discount_noun(u3_noun som) +{ + c3_w siz_w = 0; + + while ( 1 ) { + if ( _(u3a_is_senior(u3R, som)) ) { + return siz_w; + } + else { + c3_w* dog_w = u3a_to_ptr(som); + c3_w new_w = u3a_discount_ptr(dog_w); + + if ( 0 == new_w ) { + return siz_w; + } + else { + siz_w += new_w; + if ( _(u3du(som)) ) { + siz_w += u3a_discount_noun(u3h(som)); + som = u3t(som); + } + else return siz_w; + } + } + } +} + +/* u3a_print_time: print microsecond time. +*/ +void +u3a_print_time(c3_c* str_c, c3_c* cap_c, c3_d mic_d) +{ + u3_assert( 0 != str_c ); + + c3_w sec_w = (mic_d / 1000000); + c3_w mec_w = (mic_d % 1000000) / 1000; + c3_w mic_w = (mic_d % 1000); + + if ( sec_w ) { + sprintf(str_c, "%s s/%d.%03d.%03d", cap_c, sec_w, mec_w, mic_w); + } + else if ( mec_w ) { + sprintf(str_c, "%s ms/%d.%03d", cap_c, mec_w, mic_w); + } + else { + sprintf(str_c, "%s \xc2\xb5s/%d", cap_c, mic_w); + } +} + +/* u3a_print_memory: print memory amount to file descriptor. +*/ +void +u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w) +{ + u3_assert( 0 != fil_u ); + + c3_z byt_z = ((c3_z)wor_w * 4); + c3_z gib_z = (byt_z / 1000000000); + c3_z mib_z = (byt_z % 1000000000) / 1000000; + c3_z kib_z = (byt_z % 1000000) / 1000; + c3_z bib_z = (byt_z % 1000); + + if ( byt_z ) { + if ( gib_z ) { + fprintf(fil_u, "%s: GB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, gib_z, mib_z, kib_z, bib_z); + } + else if ( mib_z ) { + fprintf(fil_u, "%s: MB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, mib_z, kib_z, bib_z); + } + else if ( kib_z ) { + fprintf(fil_u, "%s: KB/%" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, kib_z, bib_z); + } + else if ( bib_z ) { + fprintf(fil_u, "%s: B/%" PRIc3_z "\r\n", + cap_c, bib_z); + } + } +} + +/* u3a_print_memory_str: print memory amount to string. +*/ +void +u3a_print_memory_str(c3_c* str_c, c3_c* cap_c, c3_w wor_w) +{ + u3_assert( 0 != str_c ); + + c3_z byt_z = ((c3_z)wor_w * 4); + c3_z gib_z = (byt_z / 1000000000); + c3_z mib_z = (byt_z % 1000000000) / 1000000; + c3_z kib_z = (byt_z % 1000000) / 1000; + c3_z bib_z = (byt_z % 1000); + + if ( byt_z ) { + if ( gib_z ) { + sprintf(str_c, "%s: GB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, gib_z, mib_z, kib_z, bib_z); + } + else if ( mib_z ) { + sprintf(str_c, "%s: MB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, mib_z, kib_z, bib_z); + } + else if ( kib_z ) { + sprintf(str_c, "%s: KB/%" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, kib_z, bib_z); + } + else if ( bib_z ) { + sprintf(str_c, "%s: B/%" PRIc3_z "\r\n", + cap_c, bib_z); + } + } +} + +/* u3a_maid(): maybe print memory. +*/ +c3_w +u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w) +{ + if ( 0 != fil_u ) { + u3a_print_memory(fil_u, cap_c, wor_w); + } + return wor_w; +} + +/* _ca_print_memory(): un-captioned u3a_print_memory(). +*/ +static void +_ca_print_memory(FILE* fil_u, c3_w byt_w) +{ + c3_w gib_w = (byt_w / 1000000000); + c3_w mib_w = (byt_w % 1000000000) / 1000000; + c3_w kib_w = (byt_w % 1000000) / 1000; + c3_w bib_w = (byt_w % 1000); + + if ( gib_w ) { + fprintf(fil_u, "GB/%d.%03d.%03d.%03d\r\n", + gib_w, mib_w, kib_w, bib_w); + } + else if ( mib_w ) { + fprintf(fil_u, "MB/%d.%03d.%03d\r\n", mib_w, kib_w, bib_w); + } + else if ( kib_w ) { + fprintf(fil_u, "KB/%d.%03d\r\n", kib_w, bib_w); + } + else { + fprintf(fil_u, "B/%d\r\n", bib_w); + } +} + +/* u3a_quac_free: free quac memory. +*/ +void +u3a_quac_free(u3m_quac* qua_u) +{ + c3_w i_w = 0; + while ( qua_u->qua_u[i_w] != NULL ) { + u3a_quac_free(qua_u->qua_u[i_w]); + i_w++; + } + c3_free(qua_u->nam_c); + c3_free(qua_u->qua_u); + c3_free(qua_u); +} + +static c3_w +_ca_prof_mark(u3_noun som) +{ + if ( c3y == u3a_is_senior(u3R, som) ) { + return 0; + } + + // marking memory-profile entries under u3o_debug_ram + // requires special care to avoid over-incrementing the refcount, + // as the entries in the profile are not true roots: + // they either belong to arvo or the profile itself. + // we measure them here, but account for them elsewhere (subsequently) + // from a refcounting standpoint + // + u3_post som_p = u3a_to_off(som); + c3_w siz_w = !(u3C.wag_w & u3o_debug_ram) + ? _mark_post(som_p) + : _count_post(som_p, 2); + + if ( !siz_w ) { + return 0; + } + + if ( c3y == u3a_is_cell(som) ) { + siz_w += u3a_mark_noun(u3h(som)); + siz_w += u3a_mark_noun(u3t(som)); + } + + return siz_w; +} + +/* u3a_prof(): mark/measure/print memory profile. RETAIN. +*/ +u3m_quac* +u3a_prof(FILE* fil_u, u3_noun mas) +{ + u3m_quac* pro_u = c3_calloc(sizeof(*pro_u)); + u3_noun h_mas, t_mas; + + if ( c3n == u3r_cell(mas, &h_mas, &t_mas) ) { + fprintf(fil_u, "mistyped mass\r\n"); + c3_free(pro_u); + return NULL; + } + else if ( c3y == u3du(h_mas) ) { + fprintf(fil_u, "mistyped mass head\r\n"); + { + c3_c* lab_c = u3m_pretty(h_mas); + fprintf(fil_u, "h_mas: %s", lab_c); + c3_free(lab_c); + } + c3_free(pro_u); + return NULL; + } + else { + + u3_noun it_mas, tt_mas; + + if ( c3n == u3r_cell(t_mas, &it_mas, &tt_mas) ) { + fprintf(fil_u, "mistyped mass tail\r\n"); + c3_free(pro_u); + return NULL; + } + else if ( c3y == it_mas ) { + c3_w siz_w = _ca_prof_mark(tt_mas); + + pro_u->nam_c = u3r_string(h_mas); + pro_u->siz_w = siz_w*4; + pro_u->qua_u = NULL; + return pro_u; + + } + else if ( c3n == it_mas ) { + pro_u->qua_u = c3_malloc(sizeof(pro_u->qua_u)); + c3_w i_w = 0; + c3_t bad_t = 0; + while ( c3y == u3du(tt_mas) ) { + u3m_quac* new_u = u3a_prof(fil_u, u3h(tt_mas)); + if ( NULL == new_u ) { + bad_t = 1; + } else { + pro_u->qua_u = c3_realloc(pro_u->qua_u, (i_w + 2) * sizeof(pro_u->qua_u)); + pro_u->siz_w += new_u->siz_w; + pro_u->qua_u[i_w] = new_u; + } + tt_mas = u3t(tt_mas); + i_w++; + } + pro_u->qua_u[i_w] = NULL; + + if ( bad_t ) { + i_w = 0; + while ( pro_u->qua_u[i_w] != NULL ) { + u3a_quac_free(pro_u->qua_u[i_w]); + i_w++; + } + c3_free(pro_u->qua_u); + c3_free(pro_u); + return NULL; + } else { + pro_u->nam_c = u3r_string(h_mas); + return pro_u; + } + } + else { + fprintf(fil_u, "mistyped (strange) mass tail\r\n"); + c3_free(pro_u); + return NULL; + } + } +} + + +/* u3a_print_quac: print a memory report. +*/ + +void +u3a_print_quac(FILE* fil_u, c3_w den_w, u3m_quac* mas_u) +{ + u3_assert( 0 != fil_u ); + + if ( mas_u->siz_w ) { + fprintf(fil_u, "%*s%s: ", den_w, "", mas_u->nam_c); + + if ( mas_u->qua_u == NULL ) { + _ca_print_memory(fil_u, mas_u->siz_w); + } else { + fprintf(fil_u, "\r\n"); + c3_w i_w = 0; + while ( mas_u->qua_u[i_w] != NULL ) { + u3a_print_quac(fil_u, den_w+2, mas_u->qua_u[i_w]); + i_w++; + } + fprintf(fil_u, "%*s--", den_w, ""); + _ca_print_memory(fil_u, mas_u->siz_w); + } + } +} + +/* u3a_mark_road(): mark ad-hoc persistent road structures. +*/ +u3m_quac* +u3a_mark_road() +{ + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 14); + + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("namespace"); + qua_u[0]->siz_w = u3a_mark_noun(u3R->ski.gul) * 4; + + qua_u[1] = c3_calloc(sizeof(*qua_u[1])); + qua_u[1]->nam_c = strdup("trace stack"); + qua_u[1]->siz_w = u3a_mark_noun(u3R->bug.tax) * 4; + + qua_u[2] = c3_calloc(sizeof(*qua_u[2])); + qua_u[2]->nam_c = strdup("trace buffer"); + qua_u[2]->siz_w = u3a_mark_noun(u3R->bug.mer) * 4; + + qua_u[3] = c3_calloc(sizeof(*qua_u[3])); + qua_u[3]->nam_c = strdup("profile batteries"); + qua_u[3]->siz_w = u3a_mark_noun(u3R->pro.don) * 4; + + qua_u[4] = c3_calloc(sizeof(*qua_u[4])); + qua_u[4]->nam_c = strdup("profile doss"); + qua_u[4]->siz_w = u3a_mark_noun(u3R->pro.day) * 4; + + qua_u[5] = c3_calloc(sizeof(*qua_u[5])); + qua_u[5]->nam_c = strdup("new profile trace"); + qua_u[5]->siz_w = u3a_mark_noun(u3R->pro.trace) * 4; + + qua_u[6] = c3_calloc(sizeof(*qua_u[6])); + qua_u[6]->nam_c = strdup("transient memoization cache"); + qua_u[6]->siz_w = u3h_mark(u3R->cax.har_p) * 4; + + qua_u[7] = c3_calloc(sizeof(*qua_u[7])); + qua_u[7]->nam_c = strdup("persistent memoization cache"); + qua_u[7]->siz_w = u3h_mark(u3R->cax.per_p) * 4; + + qua_u[8] = c3_calloc(sizeof(*qua_u[8])); + qua_u[8]->nam_c = strdup("page directory"); + qua_u[8]->siz_w = u3a_mark_ptr(u3a_into(u3R->hep.pag_p)) * 4; + + qua_u[9] = c3_calloc(sizeof(*qua_u[9])); + qua_u[9]->nam_c = strdup("cell pool"); + + { + u3_post *cel_p; + c3_w cel_w = 0; + + if ( u3R->cel.cel_p ) { + cel_p = u3to(u3_post, u3R->cel.cel_p); + cel_w += u3a_mark_ptr(cel_p); + + for ( c3_w i_w = 0; i_w < u3R->cel.hav_w; i_w++ ) { + cel_w += u3a_mark_ptr(u3a_into(cel_p[i_w])); + } + } + + qua_u[9]->siz_w = cel_w * 4; + } + + qua_u[10] = c3_calloc(sizeof(*qua_u[10])); + qua_u[10]->nam_c = strdup("free list"); + + { + u3a_dell *fre_u = u3tn(u3a_dell, u3R->hep.fre_p); + c3_w fre_w = 0; + + while ( fre_u ) { + fre_w += u3a_mark_ptr(fre_u); + fre_u = u3tn(u3a_dell, fre_u->nex_p); + } + + if ( u3R->hep.cac_p ) { + fre_w += u3a_mark_ptr(u3a_into(u3R->hep.cac_p)); + } + + qua_u[10]->siz_w = fre_w * 4; + } + + qua_u[11] = c3_calloc(sizeof(*qua_u[11])); + qua_u[11]->nam_c = strdup("metadata"); + + { + c3_w wee_w = 0; + + for ( c3_w i_w = 0; i_w < u3a_crag_no; i_w++ ) { + wee_w += u3a_Mark.wee_w[i_w]; + } + + qua_u[11]->siz_w = wee_w * 4; + } + + qua_u[12] = NULL; + + c3_w sum_w = 0; + for (c3_w i_w = 0; qua_u[i_w]; i_w++) { + sum_w += qua_u[i_w]->siz_w; + } + + u3m_quac* tot_u = c3_malloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total road stuff"); + tot_u->siz_w = sum_w; + tot_u->qua_u = qua_u; + + return tot_u; +} + +/* u3a_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3a_reclaim(void) +{ + // clear the memoization cache + // + u3h_free(u3R->cax.har_p); + u3R->cax.har_p = u3h_new(); +} + +/* u3a_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. +*/ +void +u3a_rewrite_compact(void) +{ + // XX relocate cel_p + u3a_relocate_noun(&(u3R->ski.gul)); + u3a_relocate_noun(&(u3R->bug.tax)); + u3a_relocate_noun(&(u3R->bug.mer)); + u3a_relocate_noun(&(u3R->pro.don)); + u3a_relocate_noun(&(u3R->pro.day)); + u3a_relocate_noun(&(u3R->pro.trace)); + u3h_relocate(&(u3R->cax.har_p)); + u3h_relocate(&(u3R->cax.per_p)); +} + +/* u3a_idle(): measure free-lists in [rod_u] +*/ +c3_w +u3a_idle(u3a_road* rod_u) +{ + // XX ignores argument + c3_w pag_w = _idle_pages(); + if ( pag_w ) { + fprintf(stderr, "loom: idle %u complete pages\r\n", pag_w); + } + return (pag_w << u3a_page) + _idle_words(); +} + +void +u3a_ream(void) +{ + _poison_pages(); + _poison_words(); +} + +void +u3a_wait(void) +{ + _unpoison_words(); +} + +void +u3a_dash(void) +{ + _poison_words(); +} + +/* u3a_sweep(): sweep a fully marked road. +*/ +c3_w +u3a_sweep(void) +{ + c3_w siz_w = !(u3C.wag_w & u3o_debug_ram) + ? _sweep_directory() + : _sweep_counts(); + + return siz_w; +} + +/* u3a_pack_seek(): sweep the heap, modifying boxes to record new addresses. +*/ +void +u3a_pack_seek(u3a_road* rod_u) +{ + u3a_pack_init(); + + // XX clear cell pool on inner roads? + + // XX use road argument + _pack_seek(); + _pack_relocate_heap(); +} + +/* u3a_pack_move(): sweep the heap, moving boxes to new addresses. +*/ +void +u3a_pack_move(u3a_road* rod_u) +{ + // XX use road argument + _pack_move(); + + u3a_pack_done(); + + u3_post old_p = u3R->hat_p; + + // XX move me? + // + u3R->hat_p = u3R->rut_p + (u3R->hep.dir_ws * (c3_ws)(u3R->hep.len_w << u3a_page)); + + u3a_drop_heap(old_p, u3R->hat_p); +} + +#if 0 +/* _ca_detect(): in u3a_detect(). +*/ +static c3_d +_ca_detect(u3p(u3h_root) har_p, u3_noun fum, u3_noun som, c3_d axe_d) +{ + while ( 1 ) { + if ( som == fum ) { + return axe_d; + } + else if ( !_(u3du(fum)) || (u3_none != u3h_get(har_p, fum)) ) { + return 0; + } + else { + c3_d eax_d; + + u3h_put(har_p, fum, 0); + + if ( 0 != (eax_d = _ca_detect(har_p, u3h(fum), som, 2ULL * axe_d)) ) { + return c3y; + } + else { + fum = u3t(fum); + axe_d = (2ULL * axe_d) + 1; + } + } + } +} + +/* u3a_detect(): for debugging, check if (som) is referenced from (fum). +** +** (som) and (fum) are both RETAINED. +*/ +c3_d +u3a_detect(u3_noun fum, u3_noun som) +{ + u3p(u3h_root) har_p = u3h_new(); + c3_o ret_o; + + ret_o = _ca_detect(har_p, fum, som, 1); + u3h_free(har_p); + + return ret_o; +} +#endif + +#ifdef U3_MEMORY_DEBUG +/* u3a_lush(): leak push. +*/ +c3_w +u3a_lush(c3_w lab_w) +{ + c3_w cod_w = u3_Code; + + u3_Code = lab_w; + return cod_w; +} + +/* u3a_lop(): leak pop. +*/ +void +u3a_lop(c3_w lab_w) +{ + u3_Code = lab_w; +} +#else +/* u3a_lush(): leak push. +*/ +c3_w +u3a_lush(c3_w lab_w) +{ + return 0; +} + +/* u3a_lop(): leak pop. +*/ +void +u3a_lop(c3_w lab_w) +{ +} +#endif + +/* u3a_walk_fore(): preorder traversal, visits ever limb of a noun. +** +** cells are visited *before* their heads and tails +** and can shortcircuit traversal by returning [c3n] +*/ +void +u3a_walk_fore(u3_noun a, + void* ptr_v, + void (*pat_f)(u3_atom, void*), + c3_o (*cel_f)(u3_noun, void*)) +{ + u3_noun* top; + u3a_pile pil_u; + + // initialize stack control; push argument + // + u3a_pile_prep(&pil_u, sizeof(u3_noun)); + top = u3a_push(&pil_u); + *top = a; + + while ( c3n == u3a_pile_done(&pil_u) ) { + // visit an atom, then pop the stack + // + if ( c3y == u3a_is_atom(a) ) { + pat_f(a, ptr_v); + top = u3a_pop(&pil_u); + } + // vist a cell, if c3n, pop the stack + // + else if ( c3n == cel_f(a, ptr_v) ) { + top = u3a_pop(&pil_u); + } + // otherwise, push the tail and continue into the head + // + else { + *top = u3t(a); + top = u3a_push(&pil_u); + *top = u3h(a); + } + + a = *top; + } +} + +/* u3a_string(): `a` as an on-loom c-string. +*/ +c3_c* +u3a_string(u3_atom a) +{ + c3_w met_w = u3r_met(3, a); + c3_c* str_c = u3a_malloc(met_w + 1); + + u3r_bytes(0, met_w, (c3_y*)str_c, a); + str_c[met_w] = 0; + return str_c; +} + +/* u3a_loom_sane(): sanity checks the state of the loom for obvious corruption + */ +void +u3a_loom_sane(void) +{ +} diff --git a/vere/pkg/noun/allocate.h b/vere/pkg/noun/allocate.h new file mode 100644 index 0000000..418db1a --- /dev/null +++ b/vere/pkg/noun/allocate.h @@ -0,0 +1,854 @@ +#ifndef U3_ALLOCATE_H +#define U3_ALLOCATE_H + +#include "error.h" +#include "manage.h" + + /** Constants. + **/ + /* u3a_bits: number of bits in word-addressed pointer. 29 == 2GB. + */ +# define u3a_bits U3_OS_LoomBits /* 30 */ + + /* u3a_vits: number of virtual bits in a noun reference gained via shifting + */ +# define u3a_vits 2 + + /* u3a_walign: references into the loom are guaranteed to be word-aligned to: + */ +# define u3a_walign (1 << u3a_vits) + + /* u3a_balign: u3a_walign in bytes + */ +# define u3a_balign (sizeof(c3_w)*u3a_walign) + + /* u3a_bits_max: max loom bex + */ +# define u3a_bits_max (8 * sizeof(c3_w) + u3a_vits) + + /* u3a_page: number of bits in word-addressed page. 12 == 16K page + */ +# define u3a_page 12ULL + + /* u3a_pages: maximum number of pages in memory. + */ +# define u3a_pages (1ULL << (u3a_bits + u3a_vits - u3a_page) ) + + /* u3a_words: maximum number of words in memory. + */ +# define u3a_words ( 1ULL << (u3a_bits + u3a_vits)) + + /* u3a_bytes: maximum number of bytes in memory. + */ +# define u3a_bytes ((sizeof(c3_w) * u3a_words)) + + /* u3a_cells: number of representable cells. + */ +# define u3a_cells (( u3a_words / u3a_minimum )) + + /* u3a_maximum: maximum loom object size (largest possible atom). + */ +# define u3a_maximum (u3a_words - c3_wiseof(u3a_atom)) + + /* u3a_minimum: minimum loom object size (actual size of a cell). + */ +# define u3a_minimum ((c3_w)c3_wiseof(u3a_cell)) + + /* u3a_min_log: log2(u3a_minimum) + */ +# define u3a_min_log 2 + + /* u3a_crag_no: number of hunk (small allocation) sizes + */ +# define u3a_crag_no (u3a_page - u3a_min_log) + + /* page table constants + */ +# define u3a_free_pg (u3p(u3a_crag))0 +# define u3a_head_pg (u3p(u3a_crag))1 +# define u3a_rest_pg (u3p(u3a_crag))2 + + /** Structures. + **/ + typedef struct { + c3_w use_w; + c3_w buf_w[0]; + } u3a_rate; + /* u3a_atom, u3a_cell: logical atom and cell structures. + */ + typedef struct { + c3_w use_w; + c3_w mug_w; + } u3a_noun; + + typedef struct { + c3_w use_w; + c3_w mug_w; + c3_w len_w; + c3_w buf_w[0]; + } u3a_atom; + + typedef struct { + c3_w use_w; + c3_w mug_w; + u3_noun hed; + u3_noun tel; + } u3a_cell; + +STATIC_ASSERT( (1U << u3a_min_log) == u3a_minimum, + "log2 minimum allocation" ); +STATIC_ASSERT( u3a_vits <= u3a_min_log, + "virtual-bit alignment" ); + + /* u3a_crag: hunk-page metadata + */ + typedef struct _u3a_crag { + u3p(struct _u3a_crag) nex_p; // next + c3_w pag_w; // page index + c3_s log_s; // size log2 + c3_s fre_s; // free chunks + c3_w map_w[1]; // free-chunk bitmap + } u3a_crag; + + /* u3a_dell: page free-list entry + */ + typedef struct _u3a_dell { + u3p(struct _u3a_dell) nex_p; // next + u3p(struct _u3a_dell) pre_p; // prev + c3_w pag_w; // page index + c3_w siz_w; // number of pages + } u3a_dell; + + /* u3a_jets: jet dashboard + */ + typedef struct _u3a_jets { + u3p(u3h_root) hot_p; // hot state (home road only) + u3p(u3h_root) war_p; // warm state + u3p(u3h_root) cod_p; // cold state + u3p(u3h_root) han_p; // hank cache + u3p(u3h_root) bas_p; // battery hashes + } u3a_jets; + + /* u3a_road: contiguous allocation and execution context. + */ + typedef struct _u3a_road { + u3p(struct _u3a_road) par_p; // parent road + u3p(struct _u3a_road) kid_p; // child road list + u3p(struct _u3a_road) nex_p; // sibling road + + u3p(c3_w) cap_p; // top of transient region + u3p(c3_w) hat_p; // top of durable region + u3p(c3_w) mat_p; // bottom of transient region + u3p(c3_w) rut_p; // bottom of durable region + u3p(c3_w) ear_p; // original cap if kid is live + + c3_w off_w; // spin stack offset + c3_w fow_w; // spin stack overflow count + + c3_w fut_w[30]; // futureproof buffer + + struct { // escape buffer + union { + jmp_buf buf; + c3_w buf_w[256]; // futureproofing + }; + } esc; + + struct { // miscellaneous config + c3_w fag_w; // flag bits + } how; // + + // XX re/move + struct { // allocation pools + c3_w fre_w; // number of free words + c3_w max_w; // maximum allocated + } all; + + struct { // heap allocator + u3p(u3a_dell) fre_p; // free list entry + u3p(u3a_dell) erf_p; // free list exit + u3p(u3a_dell) cac_p; // cached pgfree struct + c3_ws dir_ws; // 1 || -1 (multiplicand for local offsets) + c3_ws off_ws; // 0 || -1 (word-offset for hat && rut) + c3_w siz_w; // directory size + c3_w len_w; // directory entries + u3p(u3a_crag*) pag_p; // directory + u3p(u3a_crag) wee_p[u3a_crag_no]; // chunk lists + } hep; + + struct { // cell pool + u3_post cel_p; // array of cells + c3_w hav_w; // length + c3_w bat_w; // batch counter + } cel; + + u3a_jets jed; // jet dashboard + + struct { // bytecode state + u3p(u3h_root) har_p; // formula->post of bytecode + } byc; + + struct { // scry namespace + u3_noun gul; // (list $+(* (unit (unit)))) now + } ski; + + struct { // trace stack + u3_noun tax; // (list ,*) + u3_noun mer; // emergency buffer to release + } bug; + + struct { // profile stack + c3_d nox_d; // nock steps + c3_d cel_d; // cell allocations + u3_noun don; // (list batt) + u3_noun trace; // (list trace) + u3_noun day; // doss, only in u3H (moveme) + } pro; + + struct { // memoization caches + u3p(u3h_root) har_p; // transient + u3p(u3h_root) per_p; // persistent + } cax; + } u3a_road; + typedef u3a_road u3_road; + + /* u3a_flag: flags for how.fag_w. All arena related. + */ + enum u3a_flag { + u3a_flag_sand = 0x1, // bump allocation (XX not impl) + }; + + /* u3a_pile: stack control, abstracted over road direction. + */ + typedef struct _u3a_pile { + c3_ws mov_ws; + c3_ws off_ws; + u3_post top_p; +#ifdef U3_MEMORY_DEBUG + u3a_road* rod_u; +#endif + } u3a_pile; + + /** Macros. Should be better commented. + **/ + /* u3a_is_cat(): yes if noun [som] is direct atom. + */ +# define u3a_is_cat(som) (((som) >> 31) ? c3n : c3y) + + /* u3a_is_dog(): yes if noun [som] is indirect noun. + */ +# define u3a_is_dog(som) (((som) >> 31) ? c3y : c3n) + + /* u3a_is_pug(): yes if noun [som] is indirect atom. + */ +# define u3a_is_pug(som) ((0b10 == ((som) >> 30)) ? c3y : c3n) + + /* u3a_is_pom(): yes if noun [som] is indirect cell. + */ +# define u3a_is_pom(som) ((0b11 == ((som) >> 30)) ? c3y : c3n) + + /* u3a_is_atom(): yes if noun [som] is direct atom or indirect atom. + */ +# define u3a_is_atom(som) c3o(u3a_is_cat(som), \ + u3a_is_pug(som)) +# define u3ud(som) u3a_is_atom(som) + + /* u3a_is_cell: yes if noun [som] is cell. + */ +# define u3a_is_cell(som) u3a_is_pom(som) +# define u3du(som) u3a_is_cell(som) + + /* u3a_h(): get head of cell [som]. Bail if [som] is not cell. + */ +# define u3a_h(som) \ + ( _(u3a_is_cell(som)) \ + ? ( ((u3a_cell *)u3a_to_ptr(som))->hed )\ + : u3m_bail(c3__exit) ) +# define u3h(som) u3a_h(som) + + /* u3a_t(): get tail of cell [som]. Bail if [som] is not cell. + */ +# define u3a_t(som) \ + ( _(u3a_is_cell(som)) \ + ? ( ((u3a_cell *)u3a_to_ptr(som))->tel )\ + : u3m_bail(c3__exit) ) +# define u3t(som) u3a_t(som) + +# define u3to(type, x) ((type *)u3a_into(x)) +# define u3tn(type, x) (x) ? (type*)u3a_into(x) : (void*)NULL + +# define u3of(type, x) (u3a_outa((type*)x)) + + /* u3a_is_north(): yes if road [r] is north road. + */ +# define u3a_is_north(r) __((r)->cap_p > (r)->hat_p) + + /* u3a_is_south(): yes if road [r] is south road. + */ +# define u3a_is_south(r) !u3a_is_north((r)) + + /* u3a_open(): words of contiguous free space in road [r] + */ +# define u3a_open(r) ( (c3y == u3a_is_north(r)) \ + ? (c3_w)((r)->cap_p - (r)->hat_p) \ + : (c3_w)((r)->hat_p - (r)->cap_p) ) + + /* u3a_full(): total words in road [r]; + ** u3a_full(r) == u3a_heap(r) + u3a_temp(r) + u3a_open(r) + */ +# define u3a_full(r) ( (c3y == u3a_is_north(r)) \ + ? (c3_w)((r)->mat_p - (r)->rut_p) \ + : (c3_w)((r)->rut_p - (r)->mat_p) ) + + /* u3a_heap(): words of heap in road [r] + */ +# define u3a_heap(r) ( (c3y == u3a_is_north(r)) \ + ? (c3_w)((r)->hat_p - (r)->rut_p) \ + : (c3_w)((r)->rut_p - (r)->hat_p) ) + + /* u3a_temp(): words of stack in road [r] + */ +# define u3a_temp(r) ( (c3y == u3a_is_north(r)) \ + ? (c3_w)((r)->mat_p - (r)->cap_p) \ + : (c3_w)((r)->cap_p - (r)->mat_p) ) + +# define u3a_north_is_senior(r, dog) \ + __((u3a_to_off(dog) < (r)->rut_p) || \ + (u3a_to_off(dog) >= (r)->mat_p)) + +# define u3a_north_is_junior(r, dog) \ + __((u3a_to_off(dog) >= (r)->cap_p) && \ + (u3a_to_off(dog) < (r)->mat_p)) + +# define u3a_north_is_normal(r, dog) \ + c3a(!(u3a_north_is_senior(r, dog)), \ + !(u3a_north_is_junior(r, dog))) + +# define u3a_south_is_senior(r, dog) \ + __((u3a_to_off(dog) < (r)->mat_p) || \ + (u3a_to_off(dog) >= (r)->rut_p)) + +# define u3a_south_is_junior(r, dog) \ + __((u3a_to_off(dog) < (r)->cap_p) && \ + (u3a_to_off(dog) >= (r)->mat_p)) + +# define u3a_south_is_normal(r, dog) \ + c3a(!(u3a_south_is_senior(r, dog)), \ + !(u3a_south_is_junior(r, dog))) + +# define u3a_is_junior(r, som) \ + ( _(u3a_is_cat(som)) \ + ? c3n \ + : _(u3a_is_north(r)) \ + ? u3a_north_is_junior(r, som) \ + : u3a_south_is_junior(r, som) ) + +# define u3a_is_senior(r, som) \ + ( _(u3a_is_cat(som)) \ + ? c3y \ + : _(u3a_is_north(r)) \ + ? u3a_north_is_senior(r, som) \ + : u3a_south_is_senior(r, som) ) + +# define u3a_is_mutable(r, som) \ + ( _(u3a_is_atom(som)) \ + ? c3n \ + : _(u3a_is_senior(r, som)) \ + ? c3n \ + : _(u3a_is_junior(r, som)) \ + ? c3n \ + : (((u3a_rate*)u3a_to_ptr(som))->use_w == 1) \ + ? c3y : c3n ) + +/* like _box_vaal but for rods. Again, probably want to prefix validation + functions at the very least. Maybe they can be defined in their own header. + + ps. while arguably cooler to have this compile to + + do {(void(0));(void(0));} while(0) + + It may be nicer to just wrap an inline function in #ifdef C3DBG guards. You + could even return the then validated road like + + u3a_road f() { + u3a_road rod_u; + ... + return _rod_vaal(rod_u); + } +*/ +# define _rod_vaal(rod_u) \ + do { \ + c3_dessert(((uintptr_t)((u3a_road*)(rod_u))->hat_p \ + & u3a_walign-1) == 0); \ + } while(0) + + +typedef struct _u3a_mark { + c3_w wee_w[u3a_crag_no]; + c3_w* bit_w; + // XX factor out? + c3_w siz_w; + c3_w len_w; + c3_w* buf_w; +} u3a_mark; + +typedef struct _u3a_gack { + c3_w *bit_w; // mark bits + c3_w *pap_w; // global page bitmap + c3_w *pum_w; // global cumulative sums + // XX factor out? + c3_w siz_w; + c3_w len_w; + c3_w *buf_w; +} u3a_gack; + +typedef struct { + c3_s log_s; // size log2 + c3_s len_s; // 1U << log_s + c3_s tot_s; // total chunks + c3_s map_s; // bitmap size + c3_s siz_s; // wiseof(crag) - 1 + map_s + c3_s hun_s; // chunks reserved + c3_s ful_s; // tot_s - hun_s +} u3a_hunk_dose; + + extern u3a_gack u3a_Gack; + + extern u3a_mark u3a_Mark; + + extern u3a_hunk_dose u3a_Hunk[u3a_crag_no]; + + /** Globals. + **/ + /// Current road (thread-local). + extern u3_road* u3a_Road; +# define u3R u3a_Road + + /* u3_Code: memory code. + */ +#ifdef U3_MEMORY_DEBUG + extern c3_w u3_Code; +#endif + +# define u3_Loom ((c3_w *)(void *)U3_OS_LoomBase) + + /* u3a_into(): convert loom offset [x] into generic pointer. + */ +# define u3a_into(x) ((void *)(u3_Loom + (x))) + + /* u3a_outa(): convert pointer [p] into word offset into loom. + */ +# define u3a_outa(p) ((c3_w *)(void *)(p) - u3_Loom) + + /* u3a_to_off(): mask off bits 30 and 31 from noun [som]. + */ +# define u3a_to_off(som) (((som) & 0x3fffffff) << u3a_vits) + + /* u3a_to_ptr(): convert noun [som] into generic pointer into loom. + */ +# define u3a_to_ptr(som) (u3a_into(u3a_to_off(som))) + + /* u3a_to_wtr(): convert noun [som] into word pointer into loom. + */ +# define u3a_to_wtr(som) ((c3_w *)u3a_to_ptr(som)) + + /** Inline functions. + **/ + /* u3a_to_pug(): set bit 31 of [off]. + */ + inline c3_w u3a_to_pug(c3_w off) { + c3_dessert((off & u3a_walign-1) == 0); + return (off >> u3a_vits) | 0x80000000; + } + + /* u3a_to_pom(): set bits 30 and 31 of [off]. + */ + inline c3_w u3a_to_pom(c3_w off) { + c3_dessert((off & u3a_walign-1) == 0); + return (off >> u3a_vits) | 0xc0000000; + } + + /** road stack. + **/ + /* u3a_drop(): drop a road stack frame per [pil_u]. + */ + inline void + u3a_drop(const u3a_pile* pil_u) + { + u3R->cap_p -= pil_u->mov_ws; + } + + /* u3a_peek(): examine the top of the road stack. + */ + inline void* + u3a_peek(const u3a_pile* pil_u) + { + return u3to(void, (u3R->cap_p + pil_u->off_ws)); + } + + /* u3a_pop(): drop a road stack frame, peek at the new top. + */ + inline void* + u3a_pop(const u3a_pile* pil_u) + { + u3a_drop(pil_u); + return u3a_peek(pil_u); + } + + /* u3a_push(): push a frame onto the road stack, per [pil_u]. + */ + inline void* + u3a_push(const u3a_pile* pil_u) + { + u3R->cap_p += pil_u->mov_ws; + +#ifndef U3_GUARD_PAGE + // !off means we're on a north road + // + if ( !pil_u->off_ws ) { + if( !(u3R->cap_p > u3R->hat_p) ) { + u3m_bail(c3__meme); + } +# ifdef U3_MEMORY_DEBUG + u3_assert( pil_u->top_p >= u3R->cap_p ); +# endif + } + else { + if( !(u3R->cap_p < u3R->hat_p) ) { + u3m_bail(c3__meme); + } +# ifdef U3_MEMORY_DEBUG + u3_assert( pil_u->top_p <= u3R->cap_p ); +# endif + } +#endif /* ifndef U3_GUARD_PAGE */ + +#ifdef U3_MEMORY_DEBUG + u3_assert( pil_u->rod_u == u3R ); +#endif + + return u3a_peek(pil_u); + } + + /* u3a_pile_done(): assert valid upon completion. + */ + inline c3_o + u3a_pile_done(const u3a_pile* pil_u) + { + return (pil_u->top_p == u3R->cap_p) ? c3y : c3n; + } + + /** Functions. + **/ + +void +u3a_init_once(void); +void +u3a_init_heap(void); +void +u3a_drop_heap(u3_post cap_p, u3_post ear_p); +void +u3a_mark_init(void); +void* +u3a_mark_alloc(c3_w len_w); +void +u3a_mark_done(void); + +void +u3a_pack_init(void); +void* +u3a_pack_alloc(c3_w len_w); +void +u3a_pack_done(void); + +void* +u3a_into_fn(u3_post); +u3_post +u3a_outa_fn(void*); +u3_post +u3a_to_off_fn(u3_noun); +u3a_noun* +u3a_to_ptr_fn(u3_noun); +u3_noun +u3a_head(u3_noun); +u3_noun +u3a_tail(u3_noun); +void +u3a_post_info(u3_post); + + /** Allocation. + **/ + /* Word-aligned allocation. + */ + /* u3a_walloc(): allocate storage measured in words. + */ + void* + u3a_walloc(c3_w len_w); + + /* u3a_celloc(): allocate a cell. Faster, sometimes. + */ + c3_w* + u3a_celloc(void); + + /* u3a_wfree(): free storage. + */ + void + u3a_wfree(void* lag_v); + + /* u3a_wtrim(): trim storage. + */ + void + u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w); + + /* u3a_wealloc(): word realloc. + */ + void* + u3a_wealloc(void* lag_v, c3_w len_w); + + /* u3a_pile_prep(): initialize stack control. + */ + void + u3a_pile_prep(u3a_pile* pil_u, c3_w len_w); + + /* C-style aligned allocation - *not* compatible with above. + */ + /* u3a_malloc(): aligned storage measured in bytes. + */ + void* + u3a_malloc(size_t len_i); + + /* u3a_calloc(): aligned storage measured in bytes. + */ + void* + u3a_calloc(size_t num_i, size_t len_i); + + /* u3a_realloc(): aligned realloc in bytes. + */ + void* + u3a_realloc(void* lag_v, size_t len_i); + + /* u3a_free(): free for aligned malloc. + */ + void + u3a_free(void* tox_v); + + /* Reference and arena control. + */ + /* u3a_gain(): gain a reference count in normal space. + */ + u3_weak + u3a_gain(u3_weak som); +# define u3k(som) u3a_gain(som) + + /* u3a_take(): gain, copying juniors. + */ + u3_noun + u3a_take(u3_noun som); + + /* u3a_left(): true of junior if preserved. + */ + c3_o + u3a_left(u3_noun som); + + /* u3a_lose(): lose a reference. + */ + void + u3a_lose(u3_weak som); +# define u3z(som) u3a_lose(som) + + /* u3a_wash(): wash all lazy mugs in subtree. RETAIN. + */ + void + u3a_wash(u3_noun som); + + /* u3a_use(): reference count. + */ + c3_w + u3a_use(u3_noun som); + + /* u3a_wed(): unify noun references. + */ + void + u3a_wed(u3_noun *restrict a, u3_noun *restrict b); + + /* u3a_luse(): check refcount sanity. + */ + void + u3a_luse(u3_noun som); + + /* u3a_mark_ptr(): mark a pointer for gc. Produce size. + */ + c3_w + u3a_mark_ptr(void* ptr_v); + + /* u3a_mark_mptr(): mark a u3_malloc-allocated ptr for gc. + */ + c3_w + u3a_mark_mptr(void* ptr_v); + + /* u3a_mark_noun(): mark a noun for gc. Produce size. + */ + c3_w + u3a_mark_noun(u3_noun som); + + /* u3a_mark_road(): mark ad-hoc persistent road structures. + */ + u3m_quac* + u3a_mark_road(); + + /* u3a_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3a_reclaim(void); + + /* u3a_relocate_post(): replace post with relocation pointer (unchecked). + */ + void + u3a_relocate_post(u3_post *som_p); + + /* u3a_mark_relocate_post(): replace post with relocation pointer (checked). + */ + u3_post + u3a_mark_relocate_post(u3_post som_p, c3_t *fir_t); + + /* u3a_relocate_noun(): replace noun with relocation reference, recursively. + */ + void + u3a_relocate_noun(u3_noun *som); + + /* u3a_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. + */ + void + u3a_rewrite_compact(void); + + /* u3a_count_noun(): count size of noun. + */ + c3_w + u3a_count_noun(u3_noun som); + + /* u3a_discount_noun(): clean up after counting a noun. + */ + c3_w + u3a_discount_noun(u3_noun som); + + /* u3a_count_ptr(): count a pointer for gc. Produce size. */ + c3_w + u3a_count_ptr(void* ptr_v); + + /* u3a_discount_ptr(): discount a pointer for gc. Produce size. */ + c3_w + u3a_discount_ptr(void* ptr_v); + + /* u3a_idle(): measure free-lists in [rod_u] + */ + c3_w + u3a_idle(u3a_road* rod_u); + + /* u3a_ream(): ream free-lists. + */ + void + u3a_ream(void); + +void +u3a_wait(void); + +void +u3a_dash(void); + + /* u3a_sweep(): sweep a fully marked road. + */ + c3_w + u3a_sweep(void); + + /* u3a_pack_seek(): sweep the heap, modifying boxes to record new addresses. + */ + void + u3a_pack_seek(u3a_road* rod_u); + + /* u3a_pack_move(): sweep the heap, moving boxes to new addresses. + */ + void + u3a_pack_move(u3a_road* rod_u); + + /* u3a_sane(): check allocator sanity. + */ + void + u3a_sane(void); + + /* u3a_lush(): leak push. + */ + c3_w + u3a_lush(c3_w lab_w); + + /* u3a_lop(): leak pop. + */ + void + u3a_lop(c3_w lab_w); + + /* u3a_print_time: print microsecond time. + */ + void + u3a_print_time(c3_c* str_c, c3_c* cap_c, c3_d mic_d); + + /* u3a_print_quac: print a quac memory report. + */ + void + u3a_print_quac(FILE* fil_u, c3_w den_w, u3m_quac* mas_u); + + /* u3a_print_memory(): print memory amount to file descriptor. + */ + void + u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w); + + /* u3a_print_memory(): print memory amount to string. + */ + void + u3a_print_memory_str(c3_c* str_c, c3_c* cap_c, c3_w wor_w); + + /* u3a_prof(): mark/measure/print memory profile. RETAIN. + */ + u3m_quac* + u3a_prof(FILE* fil_u, u3_noun mas); + + /* u3a_maid(): maybe print memory. + */ + c3_w + u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w); + + /* u3a_quac_free(): free quac memory. + */ + void + u3a_quac_free(u3m_quac* qua_u); + + /* u3a_uncap_print_memory(): un-captioned print memory amount. + */ + void + u3a_uncap_print_memory(FILE* fil_u, c3_w byt_w); + + /* u3a_deadbeef(): write 0xdeadbeef from hat to cap. + */ + void + u3a_deadbeef(void); + + /* u3a_walk_fore(): preorder traversal, visits ever limb of a noun. + ** + ** cells are visited *before* their heads and tails + ** and can shortcircuit traversal by returning [c3n] + */ + void + u3a_walk_fore(u3_noun a, + void* ptr_v, + void (*pat_f)(u3_atom, void*), + c3_o (*cel_f)(u3_noun, void*)); + + /* u3a_string(): `a` as an on-loom c-string. + */ + c3_c* + u3a_string(u3_atom a); + + /* u3a_loom_sane(): sanity checks the state of the loom for obvious corruption + */ + void + u3a_loom_sane(void); + +#endif /* ifndef U3_ALLOCATE_H */ diff --git a/vere/pkg/noun/build.zig b/vere/pkg/noun/build.zig new file mode 100644 index 0000000..2a3550f --- /dev/null +++ b/vere/pkg/noun/build.zig @@ -0,0 +1,439 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const t = target.result; + + const copts: []const []const u8 = + b.option([]const []const u8, "copt", "") orelse &.{}; + + // Parse Tracy-related compiler options from copts to determine if Tracy is enabled + var tracy_enabled = false; + var tracy_callstack = false; + var tracy_no_exit = false; + + for (copts) |opt| { + if (std.mem.eql(u8, opt, "-DTRACY_ENABLE")) { + tracy_enabled = true; + } else if (std.mem.eql(u8, opt, "-DTRACY_CALLSTACK")) { + tracy_callstack = true; + } else if (std.mem.eql(u8, opt, "-DTRACY_NO_EXIT")) { + tracy_no_exit = true; + } + } + + const pkg_noun = b.addStaticLibrary(.{ + .name = "noun", + .target = target, + .optimize = optimize, + }); + + if (target.result.os.tag.isDarwin() and !target.query.isNative()) { + const macos_sdk = b.lazyDependency("macos_sdk", .{ + .target = target, + .optimize = optimize, + }); + if (macos_sdk != null) { + pkg_noun.addSystemIncludePath(macos_sdk.?.path("usr/include")); + pkg_noun.addLibraryPath(macos_sdk.?.path("usr/lib")); + pkg_noun.addFrameworkPath(macos_sdk.?.path("System/Library/Frameworks")); + } + } + + const pkg_c3 = b.dependency("pkg_c3", .{ + .target = target, + .optimize = optimize, + .copt = copts, + }); + + const pkg_ent = b.dependency("pkg_ent", .{ + .target = target, + .optimize = optimize, + .copt = copts, + }); + + const pkg_ur = b.dependency("pkg_ur", .{ + .target = target, + .optimize = optimize, + .copt = copts, + }); + + const backtrace = b.dependency("backtrace", .{ + .target = target, + .optimize = optimize, + }); + + const gmp = b.dependency("gmp", .{ + .target = target, + .optimize = optimize, + }); + + const murmur3 = b.dependency("murmur3", .{ + .target = target, + .optimize = optimize, + }); + + const openssl = b.dependency("openssl", .{ + .target = target, + .optimize = optimize, + }); + + const pdjson = b.dependency("pdjson", .{ + .target = target, + .optimize = optimize, + }); + + const sigsegv = b.dependency("sigsegv", .{ + .target = target, + .optimize = optimize, + }); + + const softblas = b.dependency("softblas", .{ + .target = target, + .optimize = optimize, + }); + + const softfloat = b.dependency("softfloat", .{ + .target = target, + .optimize = optimize, + }); + + const unwind = b.dependency("unwind", .{ + .target = target, + .optimize = optimize, + }); + + const urcrypt = b.dependency("urcrypt", .{ + .target = target, + .optimize = optimize, + }); + + const whereami = b.dependency("whereami", .{ + .target = target, + .optimize = optimize, + }); + + const zlib = b.dependency("zlib", .{ + .target = target, + .optimize = optimize, + }); + + const wasm3 = b.dependency("wasm3", .{ + .target = target, + .optimize = optimize, + }); + + const tracy = if (tracy_enabled) b.dependency("tracy", .{ + .target = target, + .optimize = optimize, + }) else null; + + pkg_noun.linkLibC(); + + pkg_noun.linkLibrary(pkg_c3.artifact("c3")); + pkg_noun.linkLibrary(pkg_ent.artifact("ent")); + pkg_noun.linkLibrary(pkg_ur.artifact("ur")); + + pkg_noun.linkLibrary(backtrace.artifact("backtrace")); + pkg_noun.linkLibrary(gmp.artifact("gmp")); + + + + pkg_noun.linkLibrary(murmur3.artifact("murmur3")); + pkg_noun.linkLibrary(openssl.artifact("ssl")); + pkg_noun.linkLibrary(pdjson.artifact("pdjson")); + if (t.os.tag != .windows) { + pkg_noun.linkLibrary(sigsegv.artifact("sigsegv")); + } + pkg_noun.linkLibrary(softblas.artifact("softblas")); + pkg_noun.linkLibrary(softfloat.artifact("softfloat")); + if (t.os.tag == .linux) + pkg_noun.linkLibrary(unwind.artifact("unwind")); + pkg_noun.linkLibrary(urcrypt.artifact("urcrypt")); + pkg_noun.linkLibrary(whereami.artifact("whereami")); + pkg_noun.linkLibrary(zlib.artifact("z")); + pkg_noun.linkLibrary(wasm3.artifact("wasm3")); + + if (tracy_enabled) { + pkg_noun.linkLibrary(tracy.?.artifact("tracy")); + pkg_noun.addIncludePath(tracy.?.path("")); + } + + pkg_noun.addIncludePath(b.path("")); + if (t.os.tag.isDarwin()) + pkg_noun.addIncludePath(b.path("platform/darwin")); + if (t.os.tag == .linux) + pkg_noun.addIncludePath(b.path("platform/linux")); + if (t.os.tag == .windows) + pkg_noun.addIncludePath(b.path("platform/windows")); + + var flags = std.ArrayList([]const u8).init(b.allocator); + defer flags.deinit(); + try flags.appendSlice(&.{ + // "-pedantic", + "-std=gnu23", + }); + try flags.appendSlice(copts); + + pkg_noun.addCSourceFiles(.{ + .root = b.path(""), + .files = &c_source_files, + .flags = flags.items, + }); + + if (t.os.tag == .windows) { + pkg_noun.addCSourceFiles(.{ + .root = b.path("platform/windows"), + .files = &.{"veh_handler.c", "rsignal.c"}, + .flags = flags.items, + }); + } + + for (install_headers) |h| pkg_noun.installHeader(b.path(h), h); + + pkg_noun.installHeader(b.path(switch (t.os.tag) { + .macos => "platform/darwin/rsignal.h", + .linux => "platform/linux/rsignal.h", + .windows => "platform/windows/rsignal.h", + else => "", + }), "platform/rsignal.h"); + + b.installArtifact(pkg_noun); +} + +const c_source_files = [_][]const u8{ + "allocate.c", + "events.c", + "hashtable.c", + "imprison.c", + "jets.c", + "jets/a/add.c", + "jets/a/dec.c", + "jets/a/div.c", + "jets/a/gte.c", + "jets/a/gth.c", + "jets/a/lte.c", + "jets/a/lth.c", + "jets/a/max.c", + "jets/a/min.c", + "jets/a/mod.c", + "jets/a/mul.c", + "jets/a/sub.c", + "jets/b/bind.c", + "jets/b/clap.c", + "jets/b/find.c", + "jets/b/flop.c", + "jets/b/lent.c", + "jets/b/levy.c", + "jets/b/lien.c", + "jets/b/mate.c", + "jets/b/murn.c", + "jets/b/need.c", + "jets/b/reap.c", + "jets/b/reel.c", + "jets/b/roll.c", + "jets/b/scag.c", + "jets/b/skid.c", + "jets/b/skim.c", + "jets/b/skip.c", + "jets/b/slag.c", + "jets/b/snag.c", + "jets/b/sort.c", + "jets/b/turn.c", + "jets/b/weld.c", + "jets/b/zing.c", + "jets/c/aor.c", + "jets/c/bex.c", + "jets/c/c0n.c", + "jets/c/can.c", + "jets/c/cap.c", + "jets/c/cat.c", + "jets/c/clz.c", + "jets/c/ctz.c", + "jets/c/cut.c", + "jets/c/dis.c", + "jets/c/dor.c", + "jets/c/dvr.c", + "jets/c/end.c", + "jets/c/gor.c", + "jets/c/ham.c", + "jets/c/hew.c", + "jets/c/lsh.c", + "jets/c/mas.c", + "jets/c/met.c", + "jets/c/mix.c", + "jets/c/mor.c", + "jets/c/mug.c", + "jets/c/muk.c", + "jets/c/peg.c", + "jets/c/po.c", + "jets/c/pow.c", + "jets/c/rap.c", + "jets/c/rep.c", + "jets/c/rev.c", + "jets/c/rig.c", + "jets/c/rip.c", + "jets/c/rsh.c", + "jets/c/sew.c", + "jets/c/sqt.c", + "jets/c/swp.c", + "jets/c/xeb.c", + "jets/d/by_all.c", + "jets/d/by_any.c", + "jets/d/by_apt.c", + "jets/d/by_bif.c", + "jets/d/by_del.c", + "jets/d/by_dif.c", + "jets/d/by_gas.c", + "jets/d/by_get.c", + "jets/d/by_has.c", + "jets/d/by_int.c", + "jets/d/by_jab.c", + "jets/d/by_key.c", + "jets/d/by_put.c", + "jets/d/by_run.c", + "jets/d/by_uni.c", + "jets/d/by_urn.c", + "jets/d/in_apt.c", + "jets/d/in_bif.c", + "jets/d/in_del.c", + "jets/d/in_dif.c", + "jets/d/in_gas.c", + "jets/d/in_has.c", + "jets/d/in_int.c", + "jets/d/in_put.c", + "jets/d/in_rep.c", + "jets/d/in_run.c", + "jets/d/in_tap.c", + "jets/d/in_uni.c", + "jets/d/in_wyt.c", + "jets/e/adler.c", + "jets/e/aes_cbc.c", + "jets/e/aes_ecb.c", + "jets/e/aes_siv.c", + "jets/e/argon2.c", + "jets/e/base.c", + "jets/e/blake.c", + "jets/e/bytestream.c", + "jets/e/chacha.c", + "jets/e/crc.c", + "jets/e/cue.c", + "jets/e/ed_add_double_scalarmult.c", + "jets/e/ed_add_scalarmult_scalarmult_base.c", + "jets/e/ed_point_add.c", + "jets/e/ed_point_neg.c", + "jets/e/ed_scad.c", + "jets/e/ed_recs.c", + "jets/e/ed_smac.c", + "jets/e/ed_puck.c", + "jets/e/ed_luck.c", + "jets/e/ed_scalarmult.c", + "jets/e/ed_scalarmult_base.c", + "jets/e/ed_shar.c", + "jets/e/ed_sign.c", + "jets/e/ed_veri.c", + "jets/e/fein_ob.c", + "jets/e/fl.c", + "jets/e/fynd_ob.c", + "jets/e/hmac.c", + "jets/e/jam.c", + "jets/e/json_de.c", + "jets/e/json_en.c", + "jets/e/keccak.c", + "jets/e/leer.c", + "jets/e/loss.c", + "jets/e/lune.c", + "jets/e/mat.c", + "jets/e/mice.c", + "jets/e/mink.c", + "jets/e/mole.c", + "jets/e/mule.c", + "jets/e/parse.c", + "jets/e/rd.c", + "jets/e/rh.c", + "jets/e/ripe.c", + "jets/e/rq.c", + "jets/e/rs.c", + "jets/e/rub.c", + "jets/e/scot.c", + "jets/e/scow.c", + "jets/e/scr.c", + "jets/e/secp.c", + "jets/e/sha1.c", + "jets/e/shax.c", + "jets/e/slaw.c", + "jets/e/tape.c", + "jets/e/trip.c", + "jets/e/urwasm.c", + "jets/e/zlib.c", + "jets/f/cell.c", + "jets/f/comb.c", + "jets/f/cons.c", + "jets/f/core.c", + "jets/f/face.c", + "jets/f/fine.c", + "jets/f/fitz.c", + "jets/f/flan.c", + "jets/f/flip.c", + "jets/f/flor.c", + "jets/f/fork.c", + "jets/f/help.c", + "jets/f/hint.c", + "jets/f/look.c", + "jets/f/loot.c", + "jets/f/ut_crop.c", + "jets/f/ut_fish.c", + "jets/f/ut_fuse.c", + "jets/f/ut_redo.c", + "jets/f/ut_mint.c", + "jets/f/ut_mull.c", + "jets/f/ut_nest.c", + "jets/f/ut_rest.c", + "jets/g/plot.c", + "jets/i/lagoon.c", + "jets/tree.c", + "jets/137/tree.c", + "jets/136/tree.c", + "log.c", + "manage.c", + "palloc.c", + "nock.c", + "options.c", + "retrieve.c", + "ship.c", + "serial.c", + "trace.c", + "urth.c", + "vortex.c", + "xtract.c", + "zave.c", +}; + +const install_headers = [_][]const u8{ + "allocate.h", + "error.h", + "events.h", + "hashtable.h", + "imprison.h", + "jets.h", + "jets/k.h", + "jets/q.h", + "jets/w.h", + "log.h", + "manage.h", + "nock.h", + "noun.h", + "options.h", + "retrieve.h", + "serial.h", + "ship.h", + "trace.h", + "types.h", + "urth.h", + "version.h", + "vortex.h", + "xtract.h", + "zave.h", + "verstable.h", +}; diff --git a/vere/pkg/noun/build.zig.zon b/vere/pkg/noun/build.zig.zon new file mode 100644 index 0000000..a5c72a9 --- /dev/null +++ b/vere/pkg/noun/build.zig.zon @@ -0,0 +1,67 @@ +.{ + .name = .noun, + .fingerprint = 0x417412dd00c7ed8c, + .version = "0.0.1", + .dependencies = .{ + .macos_sdk = .{ + .url = "https://github.com/joseluisq/macosx-sdks/releases/download/14.5/MacOSX14.5.sdk.tar.xz", + .hash = "N-V-__8AAKtK4FMzqcFsY_ZrpMg9bGH0h7BqZDXtVyAerMtM", + .lazy = true, + }, + .pkg_c3 = .{ + .path = "../c3", + }, + .pkg_ent = .{ + .path = "../ent", + }, + .pkg_ur = .{ + .path = "../ur", + }, + .backtrace = .{ + .path = "../../ext/backtrace", + }, + .gmp = .{ + .path = "../../ext/gmp", + }, + .murmur3 = .{ + .path = "../../ext/murmur3", + }, + .openssl = .{ + .path = "../../ext/openssl", + }, + .pdjson = .{ + .path = "../../ext/pdjson", + }, + .sigsegv = .{ + .path = "../../ext/sigsegv", + }, + .softblas = .{ + .path = "../../ext/softblas", + }, + .softfloat = .{ + .path = "../../ext/softfloat", + }, + .unwind = .{ + .path = "../../ext/unwind", + }, + .urcrypt = .{ + .path = "../../ext/urcrypt", + }, + .whereami = .{ + .path = "../../ext/whereami", + }, + .zlib = .{ + .url = "https://github.com/allyourcodebase/zlib/archive/61e7df7e996ec5a5f13a653db3c419adb340d6ef.tar.gz", + .hash = "zlib-1.3.1-ZZQ7lbYMAAB1hTSOKSXAKAgHsfDcyWNH_37ojw5WSpgR", + }, + .wasm3 = .{ + .path = "../../ext/wasm3", + }, + .tracy = .{ + .path = "../../ext/tracy", + }, + }, + .paths = .{ + "", + }, +} diff --git a/vere/pkg/noun/equality_tests.c b/vere/pkg/noun/equality_tests.c new file mode 100644 index 0000000..83a5026 --- /dev/null +++ b/vere/pkg/noun/equality_tests.c @@ -0,0 +1,164 @@ +/// @file + +#include "noun.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_boot_lite(1 << 24); +} + +static c3_i +_test_unify_home(void) +{ + c3_i ret_i = 1; + + u3_noun a = u3nt(0, 0, 0); + u3_noun b = u3nt(0, 0, 0); + c3_w kep_w; + + u3_assert( u3t(a) < u3t(b) ); + kep_w = u3t(a); + + (void)u3r_sing(a, b); + + if ( u3t(a) != u3t(b) ) { + fprintf(stderr, "test: unify home: failed\r\n"); + ret_i = 0; + } + else if ( kep_w != u3t(b) ) { + fprintf(stderr, "test: unify home: deeper failed\r\n"); + ret_i = 0; + } + + u3z(a); u3z(b); + + return ret_i; +} + +static c3_i +_test_unify_inner(void) +{ + c3_i ret_i = 1; + c3_w kep_w; + u3_noun a, b; + + a = u3nt(0, 0, 0); + kep_w = u3t(a); + + u3m_hate(0); + + b = u3nt(0, 0, 0); + + (void)u3r_sing(a, b); + + if ( u3t(a) != u3t(b) ) { + fprintf(stderr, "test: unify inner 1: failed\r\n"); + ret_i = 0; + } + else if ( kep_w != u3t(b) ) { + fprintf(stderr, "test: unify inner 1: deeper failed\r\n"); + ret_i = 0; + } + + b = u3m_love(0); + + u3z(a); u3z(b); + + // -------- + + b = u3nt(0, 0, 0); + kep_w = u3t(b); + + u3m_hate(0); + + a = u3nt(0, 0, 0); + + u3m_hate(0); + + (void)u3r_sing(a, b); + + if ( u3t(a) != u3t(b) ) { + fprintf(stderr, "test: unify inner 2: failed\r\n"); + ret_i = 0; + } + else if ( kep_w != u3t(a) ) { + fprintf(stderr, "test: unify inner 2: deeper failed\r\n"); + ret_i = 0; + } + + a = u3m_love(u3m_love(0)); + + u3z(a); u3z(b); + + return ret_i; +} + +static c3_i +_test_unify_inner_home(void) +{ + c3_i ret_i = 1; + + u3_noun a = u3nt(0, 0, 0); + u3_noun b = u3nt(0, 0, 0); + + u3m_hate(0); + + (void)u3r_sing(a, b); + + if ( u3t(a) == u3t(b) ) { + fprintf(stderr, "test: unify inner-home: succeeded?\r\n"); + ret_i = 0; + } + + u3m_love(0); + + u3z(a); u3z(b); + + return ret_i; +} + +static c3_i +_test_equality(void) +{ + c3_i ret_i = 1; + + if ( !_test_unify_home() ) { + fprintf(stderr, "test: equality: unify home: failed\r\n"); + ret_i = 0; + } + + if ( !_test_unify_inner() ) { + fprintf(stderr, "test: equality: unify inner: failed\r\n"); + ret_i = 0; + } + + if ( !_test_unify_inner_home() ) { + fprintf(stderr, "test: equality: unify inner-home: failed\r\n"); + ret_i = 0; + } + + return ret_i; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_equality() ) { + fprintf(stderr, "test equality: failed\r\n"); + exit(1); + } + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "test equality: ok\r\n"); + return 0; +} diff --git a/vere/pkg/noun/error.h b/vere/pkg/noun/error.h new file mode 100644 index 0000000..57932bf --- /dev/null +++ b/vere/pkg/noun/error.h @@ -0,0 +1,38 @@ +/// @file + +#ifndef U3_ERROR_H +#define U3_ERROR_H + +#include "manage.h" + +/* Assert. Good to capture. + + TODO: determine which u3_assert calls can rather call c3_dessert, i.e. in + public releases, which calls to u3_assert should abort and which should + no-op? If the latter, is the assert useful inter-development to validate + conditions we might accidentally break or not useful at all? +*/ + +#if defined(ASAN_ENABLED) && defined(__clang__) +# define u3_assert(x) \ + do { \ + if (!(x)) { \ + u3m_bail(c3__oops); \ + abort(); \ + } \ + } while(0) +#else +# define u3_assert(x) \ + do { \ + if (!(x)) { \ + fflush(stderr); \ + fprintf(stderr, "\rAssertion '%s' " \ + "failed in %s:%d\r\n", \ + #x, __FILE__, __LINE__); \ + u3m_bail(c3__oops); \ + abort(); \ + } \ + } while(0) +#endif /* if defined(ASAN_ENABLED) && defined(__clang__) */ + +#endif /* ifndef U3_ERROR_H */ diff --git a/vere/pkg/noun/events.c b/vere/pkg/noun/events.c new file mode 100644 index 0000000..956b87d --- /dev/null +++ b/vere/pkg/noun/events.c @@ -0,0 +1,1583 @@ +//! @file events.c +//! +//! incremental, orthogonal, paginated loom snapshots +//! +//! ### components +//! +//! - page: 16KB chunk of the loom. +//! - image (u3e_image, image.bin): low contiguous loom pages, +//! (in practice, the home road heap). indexed from low to high: +//! in-order on disk. in a file-backed mapping by default. +//! - patch memory (memory.bin): new or changed pages since the last snapshot +//! - patch control (u3e_control control.bin): patch metadata, watermarks, +//! and indices/checksums for pages in patch memory. +//! +//! ### initialization (u3e_live()) +//! +//! - with the loom already mapped, all pages are marked dirty in a bitmap. +//! - if snapshot is missing or partial, empty segments are created. +//! - if a patch is present, it's applied (crash recovery). +//! - snapshot segments are mapped or copied onto the loom; +//! all included pages are marked clean and protected (read-only). +//! +//! #### page faults (u3e_fault()) +//! +//! - stores into protected pages generate faults (currently SIGSEGV, +//! handled outside this module). +//! - faults are handled by dirtying the page and switching protections to +//! read/write. +//! - a guard page is initially placed in the approximate middle of the free +//! space between the heap and stack at the time of the first page fault. +//! when a fault is detected in the guard page, the guard page is recentered +//! in the free space of the current road. if the guard page cannot be +//! recentered, then memory exhaustion has occurred. +//! +//! ### updates (u3e_save()) +//! +//! - all updates to a snapshot are made through a patch. +//! - high/low watermarks are established, +//! and dirty pages below the low mark are added to the patch. +//! - modifications have been caught by the fault handler. +//! - newly-used pages are automatically included (preemptively dirtied). +//! - unused, innermost pages are reclaimed (segments are truncated to the +//! high/low watermarks; the last page in each is always adjacent to the +//! contiguous free space). +//! - patch pages are written to memory.bin, metadata to control.bin. +//! - the patch is applied to the snapshot segments, in-place. +//! - segments are fsync'd; patch files are deleted. +//! - memory protections (and file-backed mappings) are re-established. +//! +//! ### invariants +//! +//! definitions: +//! - a clean page is PROT_READ and 0 in the bitmap +//! - a dirty page is (PROT_READ|PROT_WRITE) and 1 in the bitmap +//! - the guard page is PROT_NONE and 1 in the bitmap +//! +//! assumptions: +//! - all memory access patterns are outside-in, a page at a time +//! - ad-hoc exceptions are supported by calling u3e_ward() +//! +//! - there is a single guard page, between the segments +//! - dirty pages only become clean by being: +//! - loaded from a snapshot during initialization +//! - present in a snapshot after save +//! - clean pages only become dirty by being: +//! - modified (and caught by the fault handler) +//! - orphaned due to segment truncation (explicitly dirtied) +//! - at points of quiescence (initialization, after save) +//! - all pages of the image are clean +//! - all other pages are dirty +//! +//! ### limitations +//! +//! - loom page size is fixed (16 KB), and must be a multiple of the +//! system page size. +//! - update atomicity is crucial: +//! - patch application must either completely succeed or +//! leave on-disk segments (memory image) intact. +//! - unapplied patches can be discarded (triggering event replay), +//! but once patch application begins it must succeed. +//! - may require integration into the overall signal-handling regime. +//! - any errors are handled with assertions; error messages are poor; +//! failed/partial writes are not retried. +//! +//! ### enhancements +//! +//! - use platform specific page fault mechanism (mach rpc, userfaultfd, &c). +//! - parallelism (conflicts with demand paging) +//! + +#include "events.h" + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <stddef.h> + +#include "log.h" +#include "murmur3.h" +#include "options.h" + +/* _ce_len: byte length of pages +** _ce_len_words: word length of pages +** _ce_page: byte length of a single page +** _ce_ptr: void pointer to a page +*/ +#define _ce_len(i) ((size_t)(i) << (u3a_page + 2)) +#define _ce_len_words(i) ((size_t)(i) << u3a_page) +#define _ce_page _ce_len(1) +#define _ce_ptr(i) ((void *)((c3_c*)u3_Loom + _ce_len(i))) + +/// Snapshotting system. +u3e_pool u3e_Pool; + +static c3_w +_ce_muk_buf(c3_w len_w, void* ptr_v) +{ + c3_w haz_w; + MurmurHash3_x86_32(ptr_v, len_w, 0xcafebabeU, &haz_w); + return haz_w; +} + +static c3_w +_ce_muk_page(void* ptr_v) +{ + return _ce_muk_buf(_ce_page, ptr_v); +} + +/* _ce_flaw_mmap(): remap non-guard page after fault. +*/ +static inline c3_i +_ce_flaw_mmap(c3_w pag_w) +{ + // NB: must be static, since the stack is grown via page faults, and + // we're already in a page fault handler. + // + static c3_y con_y[_ce_page]; + + // save contents of page, to be restored after the mmap + // + memcpy(con_y, _ce_ptr(pag_w), _ce_page); + + // map the dirty page into the ephemeral file + // + if ( MAP_FAILED == mmap(_ce_ptr(pag_w), + _ce_page, + (PROT_READ | PROT_WRITE), + (MAP_FIXED | MAP_SHARED), + u3P.eph_i, _ce_len(pag_w)) ) + { + fprintf(stderr, "loom: fault mmap failed (%u): %s\r\n", + pag_w, strerror(errno)); + return 1; + } + + // restore contents of page + // + memcpy(_ce_ptr(pag_w), con_y, _ce_page); + + return 0; +} + +/* _ce_flaw_mprotect(): protect page after fault. +*/ +static inline c3_i +_ce_flaw_mprotect(c3_w pag_w) +{ + if ( 0 != mprotect(_ce_ptr(pag_w), _ce_page, (PROT_READ | PROT_WRITE)) ) { + fprintf(stderr, "loom: fault mprotect (%u): %s\r\n", + pag_w, strerror(errno)); + return 1; + } + + return 0; +} + +#ifdef U3_GUARD_PAGE +/* _ce_ward_protect(): protect the guard page. +*/ +static inline c3_i +_ce_ward_protect(void) +{ + if ( 0 != mprotect(_ce_ptr(u3P.gar_w), _ce_page, PROT_NONE) ) { + fprintf(stderr, "loom: failed to protect guard page (%u): %s\r\n", + u3P.gar_w, strerror(errno)); + return 1; + } + + return 0; +} + +/* _ce_ward_post(): set the guard page. +*/ +static inline c3_i +_ce_ward_post(c3_w nop_w, c3_w sop_w) +{ + u3P.gar_w = nop_w + ((sop_w - nop_w) / 2); + return _ce_ward_protect(); +} + +/* _ce_ward_clip(): hit the guard page. +*/ +static inline u3e_flaw +_ce_ward_clip(c3_w nop_w, c3_w sop_w) +{ + c3_w old_w = u3P.gar_w; + + if ( !u3P.gar_w || ((nop_w < u3P.gar_w) && (sop_w > u3P.gar_w)) ) { + fprintf(stderr, "loom: ward bogus (>%u %u %u<)\r\n", + nop_w, u3P.gar_w, sop_w); + return u3e_flaw_sham; + } + + if ( sop_w <= (nop_w + 1) ) { + return u3e_flaw_meme; + } + + if ( _ce_ward_post(nop_w, sop_w) ) { + return u3e_flaw_base; + } + + u3_assert( old_w != u3P.gar_w ); + + return u3e_flaw_good; +} +#endif /* ifdef U3_GUARD_PAGE */ + +/* u3e_fault(): handle a memory fault. +*/ +u3e_flaw +u3e_fault(u3_post low_p, u3_post hig_p, u3_post off_p) +{ + c3_w pag_w = off_p >> u3a_page; + c3_w blk_w = pag_w >> 5; + c3_w bit_w = pag_w & 31; + +#ifdef U3_GUARD_PAGE + c3_w gar_w = u3P.gar_w; + + if ( pag_w == gar_w ) { + u3e_flaw fal_e = _ce_ward_clip(low_p >> u3a_page, hig_p >> u3a_page); + + if ( u3e_flaw_good != fal_e ) { + return fal_e; + } + + if ( !(u3P.dit_w[blk_w] & ((c3_w)1 << bit_w)) ) { + fprintf(stderr, "loom: strange guard (%d)\r\n", pag_w); + return u3e_flaw_sham; + } + + if ( _ce_flaw_mprotect(pag_w) ) { + return u3e_flaw_base; + } + + return u3e_flaw_good; + } +#endif + + if ( u3P.dit_w[blk_w] & ((c3_w)1 << bit_w) ) { + fprintf(stderr, "loom: strange page (%d): %x\r\n", pag_w, off_p); + return u3e_flaw_sham; + } + + u3P.dit_w[blk_w] |= ((c3_w)1 << bit_w); + + if ( u3P.eph_i ) { + if ( _ce_flaw_mmap(pag_w) ) { + return u3e_flaw_base; + } + } + else if ( _ce_flaw_mprotect(pag_w) ) { + return u3e_flaw_base; + } + + return u3e_flaw_good; +} + +typedef enum { + _ce_img_good = 0, + _ce_img_fail = 1, + _ce_img_size = 2 +} _ce_img_stat; + +/* _ce_image_stat(): measure image. +*/ +static _ce_img_stat +_ce_image_stat(u3e_image* img_u, c3_w* pgs_w) +{ + struct stat buf_u; + + if ( -1 == fstat(img_u->fid_i, &buf_u) ) { + fprintf(stderr, "loom: image stat: %s\r\n", strerror(errno)); + u3_assert(0); + return _ce_img_fail; + } + else { + c3_z siz_z = buf_u.st_size; + c3_z pgs_z = (siz_z + (_ce_page - 1)) >> (u3a_page + 2); + + if ( !siz_z ) { + *pgs_w = 0; + return _ce_img_good; + } + else if ( siz_z != _ce_len(pgs_z) ) { + fprintf(stderr, "loom: image corrupt size %zu\r\n", siz_z); + return _ce_img_size; + } + else if ( pgs_z > UINT32_MAX ) { + fprintf(stderr, "loom: image overflow %zu\r\n", siz_z); + return _ce_img_fail; + } + else { + *pgs_w = (c3_w)pgs_z; + return _ce_img_good; + } + } +} + +/* _ce_ephemeral_open(): open or create ephemeral file +*/ +static c3_o +_ce_ephemeral_open(c3_i* eph_i) +{ + c3_i mod_i = O_RDWR | O_CREAT; + c3_c ful_c[8193]; + + if ( u3C.eph_c == 0 ) { + snprintf(ful_c, 8192, "%s", u3P.dir_c); + c3_mkdir(ful_c, 0700); + + snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); + c3_mkdir(ful_c, 0700); + + snprintf(ful_c, 8192, "%s/.urb/chk", u3P.dir_c); + c3_mkdir(ful_c, 0700); + + snprintf(ful_c, 8192, "%s/.urb/chk/limbo.bin", u3P.dir_c); + u3C.eph_c = strdup(ful_c); + } + + if ( -1 == (*eph_i = c3_open(u3C.eph_c, mod_i, 0666)) ) { + fprintf(stderr, "loom: ephemeral c3_open %s: %s\r\n", u3C.eph_c, + strerror(errno)); + return c3n; + } + + if ( ftruncate(*eph_i, _ce_len(u3P.pag_w)) < 0 ) { + fprintf(stderr, "loom: ephemeral ftruncate %s: %s\r\n", u3C.eph_c, + strerror(errno)); + return c3n; + } + return c3y; +} + +/* _ce_image_open(): open or create image. +*/ +static _ce_img_stat +_ce_image_open(u3e_image* img_u, c3_c* ful_c) +{ + c3_i mod_i = O_RDWR | O_CREAT; + + c3_c pax_c[8192]; + snprintf(pax_c, 8192, "%s/%s.bin", ful_c, img_u->nam_c); + if ( -1 == (img_u->fid_i = c3_open(pax_c, mod_i, 0666)) ) { + fprintf(stderr, "loom: c3_open %s: %s\r\n", pax_c, strerror(errno)); + return _ce_img_fail; + } + + return _ce_image_stat(img_u, &img_u->pgs_w); +} + +c3_i +u3e_image_open_any(c3_c* nam_c, c3_c* dir_c, c3_z* len_z) +{ + u3e_image img_u = { .nam_c = nam_c }; + + switch ( _ce_image_open(&img_u, dir_c) ) { + case _ce_img_good: { + *len_z = _ce_len(img_u.pgs_w); + return img_u.fid_i; + } break; + + case _ce_img_fail: + case _ce_img_size: { + *len_z = 0; + return -1; + } break; + } +} + +/* _ce_patch_write_control(): write control block file. +*/ +static void +_ce_patch_write_control(u3_ce_patch* pat_u) +{ + ssize_t ret_i; + c3_w len_w = sizeof(u3e_control) + + (pat_u->con_u->pgs_w * sizeof(u3e_line)); + + if ( len_w != (ret_i = write(pat_u->ctl_i, pat_u->con_u, len_w)) ) { + if ( 0 < ret_i ) { + fprintf(stderr, "loom: patch ctl partial write: %zu\r\n", (size_t)ret_i); + } + else { + fprintf(stderr, "loom: patch ctl write: %s\r\n", strerror(errno)); + } + u3_assert(0); + } +} + +/* _ce_patch_read_control(): read control block file. +*/ +static c3_o +_ce_patch_read_control(u3_ce_patch* pat_u) +{ + c3_w len_w; + + u3_assert(0 == pat_u->con_u); + { + struct stat buf_u; + + if ( -1 == fstat(pat_u->ctl_i, &buf_u) ) { + u3_assert(0); + return c3n; + } + len_w = (c3_w) buf_u.st_size; + } + + if (0 == len_w) { + return c3n; + } + + pat_u->con_u = c3_malloc(len_w); + if ( (len_w != read(pat_u->ctl_i, pat_u->con_u, len_w)) || + (len_w != sizeof(u3e_control) + + (pat_u->con_u->pgs_w * sizeof(u3e_line))) ) + { + c3_free(pat_u->con_u); + pat_u->con_u = 0; + return c3n; + } + return c3y; +} + +/* _ce_patch_create(): create patch files. +*/ +static void +_ce_patch_create(u3_ce_patch* pat_u) +{ + c3_c ful_c[8193]; + + snprintf(ful_c, 8192, "%s", u3P.dir_c); + c3_mkdir(ful_c, 0700); + + snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); + c3_mkdir(ful_c, 0700); + + snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); + if ( -1 == (pat_u->ctl_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) { + fprintf(stderr, "loom: patch c3_open control.bin: %s\r\n", strerror(errno)); + u3_assert(0); + } + + snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); + if ( -1 == (pat_u->mem_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) { + fprintf(stderr, "loom: patch c3_open memory.bin: %s\r\n", strerror(errno)); + u3_assert(0); + } +} + +/* _ce_patch_delete(): delete a patch. +*/ +static void +_ce_patch_delete(void) +{ + c3_c ful_c[8193]; + + snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); + if ( unlink(ful_c) ) { + fprintf(stderr, "loom: failed to delete control.bin: %s\r\n", + strerror(errno)); + } + + snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); + if ( unlink(ful_c) ) { + fprintf(stderr, "loom: failed to remove memory.bin: %s\r\n", + strerror(errno)); + } +} + +/* _ce_patch_verify(): check patch data checksum. +*/ +static c3_o +_ce_patch_verify(u3_ce_patch* pat_u) +{ + c3_w pag_w, has_w; + c3_y buf_y[_ce_page]; + c3_zs ret_zs; + + if ( U3P_VERLAT != pat_u->con_u->ver_w ) { + fprintf(stderr, "loom: patch version mismatch: have %"PRIc3_w", need %u\r\n", + pat_u->con_u->ver_w, + U3P_VERLAT); + return c3n; + } + + { + c3_w len_w = sizeof(u3e_control) + (pat_u->con_u->pgs_w * sizeof(u3e_line)); + c3_w off_w = offsetof(u3e_control, tot_w); + c3_y *ptr_y = (c3_y*)pat_u->con_u + off_w; + c3_w has_w = _ce_muk_buf(len_w - off_w, ptr_y); + + if ( has_w != pat_u->con_u->has_w ) { + fprintf(stderr, "loom: patch meta checksum fail: " + "have=0x%"PRIxc3_w", need=0x%"PRIxc3_w"\r\n", + has_w, pat_u->con_u->has_w); + return c3n; + } + } + + // XX check for sorted page numbers? + // + for ( c3_z i_z = 0; i_z < pat_u->con_u->pgs_w; i_z++ ) { + pag_w = pat_u->con_u->mem_u[i_z].pag_w; + has_w = pat_u->con_u->mem_u[i_z].has_w; + + if ( _ce_page != + (ret_zs = pread(pat_u->mem_i, buf_y, _ce_page, _ce_len(i_z))) ) + { + if ( 0 < ret_zs ) { + fprintf(stderr, "loom: patch partial read: %"PRIc3_zs"\r\n", ret_zs); + } + else { + fprintf(stderr, "loom: patch read: fail %s\r\n", strerror(errno)); + } + return c3n; + } + + { + c3_w nas_w = _ce_muk_page(buf_y); + + if ( has_w != nas_w ) { + fprintf(stderr, "loom: patch page (%"PRIc3_w") checksum fail: " + "have=0x%"PRIxc3_w", need=0x%"PRIxc3_w"\r\n", + pag_w, nas_w, has_w); + return c3n; + } +#if 0 + else { + u3l_log("verify: patch %"PRIc3_w"/%"PRIc3_z", %"PRIxc3_w"\r\n", pag_w, i_z, has_w); + } +#endif + } + } + + return c3y; +} + +/* _ce_patch_free(): free a patch. +*/ +static void +_ce_patch_free(u3_ce_patch* pat_u) +{ + c3_free(pat_u->con_u); + close(pat_u->ctl_i); + close(pat_u->mem_i); + c3_free(pat_u); +} + +/* _ce_patch_open(): open patch, if any. +*/ +static u3_ce_patch* +_ce_patch_open(void) +{ + u3_ce_patch* pat_u; + c3_c ful_c[8193]; + c3_i ctl_i, mem_i; + + snprintf(ful_c, 8192, "%s", u3P.dir_c); + c3_mkdir(ful_c, 0700); + + snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); + c3_mkdir(ful_c, 0700); + + snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); + if ( -1 == (ctl_i = c3_open(ful_c, O_RDWR)) ) { + return 0; + } + + snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); + if ( -1 == (mem_i = c3_open(ful_c, O_RDWR)) ) { + close(ctl_i); + + _ce_patch_delete(); + return 0; + } + pat_u = c3_malloc(sizeof(u3_ce_patch)); + pat_u->ctl_i = ctl_i; + pat_u->mem_i = mem_i; + pat_u->con_u = 0; + + if ( c3n == _ce_patch_read_control(pat_u) ) { + close(pat_u->ctl_i); + close(pat_u->mem_i); + c3_free(pat_u); + + _ce_patch_delete(); + return 0; + } + if ( c3n == _ce_patch_verify(pat_u) ) { + _ce_patch_free(pat_u); + _ce_patch_delete(); + return 0; + } + return pat_u; +} + +/* _ce_patch_write_page(): write a page of patch memory. +*/ +static void +_ce_patch_write_page(u3_ce_patch* pat_u, + c3_w pgc_w, + c3_w* mem_w) +{ + c3_zs ret_zs; + + if ( _ce_page != + (ret_zs = pwrite(pat_u->mem_i, mem_w, _ce_page, _ce_len(pgc_w))) ) + { + if ( 0 < ret_zs ) { + fprintf(stderr, "loom: patch partial write: %"PRIc3_zs"\r\n", ret_zs); + } + else { + fprintf(stderr, "loom: patch write: fail: %s\r\n", strerror(errno)); + } + fprintf(stderr, "info: you probably have insufficient disk space"); + u3_assert(0); + } +} + +/* _ce_patch_count_page(): count a page, producing new counter. +*/ +static c3_w +_ce_patch_count_page(c3_w pag_w, + c3_w off_w, + c3_w pgc_w) +{ + c3_w blk_w = (pag_w >> 5); + c3_w bit_w = (pag_w & 31); + + if ( (u3P.dit_w[blk_w] & ((c3_w)1 << bit_w)) + && ( (pag_w < off_w) + || (u3R->hep.len_w <= (pag_w - off_w)) + || (u3a_free_pg != (u3to(u3_post, u3R->hep.pag_p))[pag_w - off_w]) ) ) + { + pgc_w += 1; + } + + return pgc_w; +} + +/* _ce_patch_save_page(): save a page, producing new page counter. +*/ +static c3_w +_ce_patch_save_page(u3_ce_patch* pat_u, + c3_w pag_w, + c3_w off_w, + c3_w pgc_w) +{ + c3_w blk_w = (pag_w >> 5); + c3_w bit_w = (pag_w & 31); + + if ( u3P.dit_w[blk_w] & ((c3_w)1 << bit_w) ) { + if ( (pag_w >= off_w) + && (u3R->hep.len_w > (pag_w - off_w)) + && (u3a_free_pg == (u3to(u3_post, u3R->hep.pag_p))[pag_w - off_w]) ) + { + // fprintf(stderr, "save: skip %u\r\n", pag_w); + pat_u->sip_w++; + return pgc_w; + } + + c3_w* mem_w = _ce_ptr(pag_w); + + pat_u->con_u->mem_u[pgc_w].pag_w = pag_w; + pat_u->con_u->mem_u[pgc_w].has_w = _ce_muk_page(mem_w); + +#if 0 + fprintf(stderr, "loom: save page %d %x\r\n", + pag_w, pat_u->con_u->mem_u[pgc_w].has_w); +#endif + _ce_patch_write_page(pat_u, pgc_w, mem_w); + + pgc_w += 1; + } + return pgc_w; +} + +/* _ce_patch_compose(): make and write current patch. +*/ +static u3_ce_patch* +_ce_patch_compose(c3_w max_w) +{ + c3_w pgs_w = 0; + c3_w off_w = u3R->rut_p >> u3a_page; + + /* Count dirty pages. + */ + { + c3_w i_w; + + for ( i_w = 0; i_w < max_w; i_w++ ) { + pgs_w = _ce_patch_count_page(i_w, off_w, pgs_w); + } + } + + if ( !pgs_w ) { + return 0; + } + else { + u3_ce_patch* pat_u = c3_malloc(sizeof(u3_ce_patch)); + c3_w i_w, len_w, pgc_w; + + pat_u->sip_w = 0; + + _ce_patch_create(pat_u); + len_w = sizeof(u3e_control) + (pgs_w * sizeof(u3e_line)); + pat_u->con_u = c3_malloc(len_w); + pat_u->con_u->ver_w = U3P_VERLAT; + pgc_w = 0; + + for ( i_w = 0; i_w < max_w; i_w++ ) { + pgc_w = _ce_patch_save_page(pat_u, i_w, off_w, pgc_w); + } + + u3_assert( pgc_w == pgs_w ); + + pat_u->con_u->tot_w = max_w; + pat_u->con_u->pgs_w = pgc_w; + + { + c3_w off_w = offsetof(u3e_control, tot_w); + c3_y *ptr_y = (c3_y*)pat_u->con_u + off_w; + + pat_u->con_u->has_w = _ce_muk_buf(len_w - off_w, ptr_y); + } + + _ce_patch_write_control(pat_u); + return pat_u; + } +} + +/* _ce_patch_sync(): make sure patch is synced to disk. +*/ +static void +_ce_patch_sync(u3_ce_patch* pat_u) +{ + if ( -1 == c3_sync(pat_u->ctl_i) ) { + fprintf(stderr, "loom: control file sync failed: %s\r\n", + strerror(errno)); + u3_assert(!"loom: control sync"); + } + + if ( -1 == c3_sync(pat_u->mem_i) ) { + fprintf(stderr, "loom: patch file sync failed: %s\r\n", + strerror(errno)); + u3_assert(!"loom: patch sync"); + } +} + +/* _ce_image_sync(): make sure image is synced to disk. +*/ +static c3_o +_ce_image_sync(u3e_image* img_u) +{ + if ( -1 == c3_sync(img_u->fid_i) ) { + fprintf(stderr, "loom: image sync failed: %s\r\n", strerror(errno)); + return c3n; + } + + return c3y; +} + +/* _ce_image_resize(): resize image, truncating if it shrunk. +*/ +static void +_ce_image_resize(u3e_image* img_u, c3_w pgs_w) +{ + c3_z off_z = _ce_len(pgs_w); + off_t off_i = (off_t)off_z; + + if ( img_u->pgs_w > pgs_w ) { + if ( off_z != (size_t)off_i ) { + fprintf(stderr, "loom: image truncate: " + "offset overflow (%" PRId64 ") for page %u\r\n", + (c3_ds)off_i, pgs_w); + u3_assert(0); + } + + if ( ftruncate(img_u->fid_i, off_i) ) { + fprintf(stderr, "loom: image truncate: %s\r\n", strerror(errno)); + u3_assert(0); + } + } + + img_u->pgs_w = pgs_w; +} + +/* _ce_patch_apply(): apply patch to images. +*/ +static void +_ce_patch_apply(u3_ce_patch* pat_u) +{ + c3_zs ret_zs; + c3_w i_w; + + // resize images + // + _ce_image_resize(&u3P.img_u, pat_u->con_u->tot_w); + + // seek to begining of patch + // + if ( -1 == lseek(pat_u->mem_i, 0, SEEK_SET) ) { + fprintf(stderr, "loom: patch apply seek: %s\r\n", strerror(errno)); + u3_assert(0); + } + + c3_i fid_i = u3P.img_u.fid_i; + + // write patch pages into the appropriate image + // + for ( i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) { + c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w; + c3_y buf_y[_ce_page]; + c3_z off_z = _ce_len(pag_w); + + if ( _ce_page != (ret_zs = read(pat_u->mem_i, buf_y, _ce_page)) ) { + if ( 0 < ret_zs ) { + fprintf(stderr, "loom: patch apply partial read: %"PRIc3_zs"\r\n", + ret_zs); + } + else { + fprintf(stderr, "loom: patch apply read: %s\r\n", strerror(errno)); + } + u3_assert(0); + } + else { + if ( _ce_page != + (ret_zs = pwrite(fid_i, buf_y, _ce_page, off_z)) ) + { + if ( 0 < ret_zs ) { + fprintf(stderr, "loom: patch apply partial write: %"PRIc3_zs"\r\n", + ret_zs); + } + else { + fprintf(stderr, "loom: patch apply write: %s\r\n", strerror(errno)); + } + fprintf(stderr, "info: you probably have insufficient disk space"); + u3_assert(0); + } + } +#if 0 + u3l_log("apply: %d, %x", pag_w, _ce_muk_page(buf_y)); +#endif + } +} + +/* _ce_loom_track_sane(): quiescent page state invariants. +*/ +static c3_o +_ce_loom_track_sane(void) +{ + c3_w blk_w, bit_w, max_w, i_w = 0; + c3_o san_o = c3y; + + max_w = u3P.img_u.pgs_w; + + for ( ; i_w < max_w; i_w++ ) { + blk_w = i_w >> 5; + bit_w = i_w & 31; + + if ( u3P.dit_w[blk_w] & ((c3_w)1 << bit_w) ) { + fprintf(stderr, "loom: insane image %u\r\n", i_w); + san_o = c3n; + } + } + + max_w = u3P.pag_w; + + for ( ; i_w < max_w; i_w++ ) { + blk_w = i_w >> 5; + bit_w = i_w & 31; + + if ( !(u3P.dit_w[blk_w] & ((c3_w)1 << bit_w)) ) { + fprintf(stderr, "loom: insane open %u\r\n", i_w); + san_o = c3n; + } + } + + return san_o; +} + +/* _ce_loom_track(): [pgs_w] clean, followed by [dif_w] dirty. +*/ +void +_ce_loom_track(c3_w pgs_w, c3_w dif_w) +{ + c3_w blk_w, bit_w, i_w = 0, max_w = pgs_w; + + for ( ; i_w < max_w; i_w++ ) { + blk_w = i_w >> 5; + bit_w = i_w & 31; + u3P.dit_w[blk_w] &= ~((c3_w)1 << bit_w); + } + + max_w += dif_w; + + for ( ; i_w < max_w; i_w++ ) { + blk_w = i_w >> 5; + bit_w = i_w & 31; + u3P.dit_w[blk_w] |= ((c3_w)1 << bit_w); + } +} + +/* _ce_loom_protect(): protect/track pages from the bottom of memory. +*/ +static void +_ce_loom_protect(c3_w pgs_w, c3_w old_w) +{ + c3_w dif_w = 0; + + if ( pgs_w ) { + if ( 0 != mprotect(_ce_ptr(0), _ce_len(pgs_w), PROT_READ) ) { + fprintf(stderr, "loom: pure (%u pages): %s\r\n", + pgs_w, strerror(errno)); + u3_assert(0); + } + } + + if ( old_w > pgs_w ) { + dif_w = old_w - pgs_w; + + if ( 0 != mprotect(_ce_ptr(pgs_w), + _ce_len(dif_w), + (PROT_READ | PROT_WRITE)) ) + { + fprintf(stderr, "loom: foul (%u pages, %u old): %s\r\n", + pgs_w, old_w, strerror(errno)); + u3_assert(0); + } + +#ifdef U3_GUARD_PAGE + // protect guard page if clobbered + // + // NB: < pgs_w is precluded by assertion in u3e_save() + // + if ( u3P.gar_w < old_w ) { + fprintf(stderr, "loom: guard on reprotect\r\n"); + u3_assert( !_ce_ward_protect() ); + } +#endif + } + + _ce_loom_track(pgs_w, dif_w); +} + +/* _ce_loom_mapf_ephemeral(): map entire loom into ephemeral file +*/ +static void +_ce_loom_mapf_ephemeral(void) +{ + if ( MAP_FAILED == mmap(_ce_ptr(0), + _ce_len(u3P.pag_w), + (PROT_READ | PROT_WRITE), + (MAP_FIXED | MAP_SHARED), + u3P.eph_i, 0) ) + { + fprintf(stderr, "loom: initial ephemeral mmap failed (%u pages): %s\r\n", + u3P.pag_w, strerror(errno)); + u3_assert(0); + } +} + +/* _ce_loom_mapf(): map [pgs_w] of [fid_i] into the bottom of memory +** (and ephemeralize [old_w - pgs_w] after if needed). +*/ +static void +_ce_loom_mapf(c3_i fid_i, c3_w pgs_w, c3_w old_w) +{ + c3_w dif_w = 0; + + if ( pgs_w ) { + if ( MAP_FAILED == mmap(_ce_ptr(0), + _ce_len(pgs_w), + PROT_READ, + (MAP_FIXED | MAP_PRIVATE), + fid_i, 0) ) + { + fprintf(stderr, "loom: file-backed mmap failed (%u pages): %s\r\n", + pgs_w, strerror(errno)); + u3_assert(0); + } + } + + if ( old_w > pgs_w ) { + dif_w = old_w - pgs_w; + + if ( u3C.wag_w & u3o_swap ) { + if ( MAP_FAILED == mmap(_ce_ptr(pgs_w), + _ce_len(dif_w), + (PROT_READ | PROT_WRITE), + (MAP_FIXED | MAP_SHARED), + u3P.eph_i, _ce_len(pgs_w)) ) + { + fprintf(stderr, "loom: ephemeral mmap failed (%u pages, %u old): %s\r\n", + pgs_w, old_w, strerror(errno)); + u3_assert(0); + } + } + else { + if ( MAP_FAILED == mmap(_ce_ptr(pgs_w), + _ce_len(dif_w), + (PROT_READ | PROT_WRITE), + (MAP_ANON | MAP_FIXED | MAP_PRIVATE), + -1, 0) ) + { + fprintf(stderr, "loom: anonymous mmap failed (%u pages, %u old): %s\r\n", + pgs_w, old_w, strerror(errno)); + u3_assert(0); + } + } + +#ifdef U3_GUARD_PAGE + // protect guard page if clobbered + // + // NB: < pgs_w is precluded by assertion in u3e_save() + // + if ( u3P.gar_w < old_w ) { + fprintf(stderr, "loom: guard on remap\r\n"); + u3_assert( !_ce_ward_protect() ); + } +#endif + } + + _ce_loom_track(pgs_w, dif_w); +} + +/* _ce_loom_blit(): apply pages, in order, from the bottom of memory. +*/ +static void +_ce_loom_blit(c3_i fid_i, c3_w pgs_w) +{ + c3_w i_w; + void* ptr_v; + c3_zs ret_zs; + + for ( i_w = 0; i_w < pgs_w; i_w++ ) { + ptr_v = _ce_ptr(i_w); + + if ( _ce_page != (ret_zs = pread(fid_i, ptr_v, _ce_page, _ce_len(i_w))) ) { + if ( 0 < ret_zs ) { + fprintf(stderr, "loom: blit partial read: %"PRIc3_zs"\r\n", + ret_zs); + } + else { + fprintf(stderr, "loom: blit read %s\r\n", strerror(errno)); + } + u3_assert(0); + } + } + + _ce_loom_protect(pgs_w, 0); +} + +#ifdef U3_SNAPSHOT_VALIDATION +/* _ce_page_fine(): compare page in memory and on disk. +*/ +static c3_o +_ce_page_fine(u3e_image* img_u, c3_w pag_w, c3_z off_z) +{ + ssize_t ret_i; + c3_y buf_y[_ce_page]; + + if ( _ce_page != + (ret_i = pread(img_u->fid_i, buf_y, _ce_page, off_z)) ) + { + if ( 0 < ret_i ) { + fprintf(stderr, "loom: image fine partial read: %zu\r\n", (size_t)ret_i); + } + else { + fprintf(stderr, "loom: image fine read: %s\r\n", strerror(errno)); + } + u3_assert(0); + } + + { + c3_w mas_w = _ce_muk_page(_ce_ptr(pag_w)); + c3_w fas_w = _ce_muk_page(buf_y); + + if ( mas_w != fas_w ) { + fprintf(stderr, "loom: image checksum mismatch: " + "page %d, mem_w %x, fil_w %x\r\n", + pag_w, mas_w, fas_w); + return c3n; + } + } + + return c3y; +} + +/* _ce_loom_fine(): compare clean pages in memory and on disk. +*/ +static c3_o +_ce_loom_fine(void) +{ + c3_w off_w = u3R->rut_p >> u3a_page; + c3_w blk_w, bit_w, pag_w, i_w; + c3_o fin_o = c3y; + + for ( i_w = 0; i_w < u3P.img_u.pgs_w; i_w++ ) { + pag_w = i_w; + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + + if ( !(u3P.dit_w[blk_w] & ((c3_w)1 << bit_w)) + && ( (pag_w < off_w) + || (u3R->hep.len_w <= (pag_w - off_w)) + || (u3a_free_pg != (u3to(u3_post, u3R->hep.pag_p))[pag_w - off_w]) ) ) + { + fin_o = c3a(fin_o, _ce_page_fine(&u3P.img_u, pag_w, _ce_len(pag_w))); + } + } + + return fin_o; +} +#endif + +/* _ce_image_copy(): copy all of [fom_u] to [tou_u] +*/ +static c3_o +_ce_image_copy(u3e_image* fom_u, u3e_image* tou_u) +{ + ssize_t ret_i; + c3_w i_w; + + // resize images + // + _ce_image_resize(tou_u, fom_u->pgs_w); + + // seek to begining of patch and images + // + if ( (-1 == lseek(fom_u->fid_i, 0, SEEK_SET)) + || (-1 == lseek(tou_u->fid_i, 0, SEEK_SET)) ) + { + fprintf(stderr, "loom: image copy seek: %s\r\n", strerror(errno)); + return c3n; + } + + // copy pages into destination image + // + for ( i_w = 0; i_w < fom_u->pgs_w; i_w++ ) { + c3_y buf_y[_ce_page]; + c3_w off_w = i_w; + + if ( _ce_page != (ret_i = read(fom_u->fid_i, buf_y, _ce_page)) ) { + if ( 0 < ret_i ) { + fprintf(stderr, "loom: image copy partial read: %zu\r\n", + (size_t)ret_i); + } + else { + fprintf(stderr, "loom: image copy read: %s\r\n", + strerror(errno)); + } + return c3n; + } + else { + if ( -1 == lseek(tou_u->fid_i, _ce_len(off_w), SEEK_SET) ) { + fprintf(stderr, "loom: image copy seek: %s\r\n", strerror(errno)); + return c3n; + } + if ( _ce_page != (ret_i = write(tou_u->fid_i, buf_y, _ce_page)) ) { + if ( 0 < ret_i ) { + fprintf(stderr, "loom: image copy partial write: %zu\r\n", + (size_t)ret_i); + } + else { + fprintf(stderr, "loom: image copy write: %s\r\n", strerror(errno)); + } + fprintf(stderr, "info: you probably have insufficient disk space"); + return c3n; + } + } + } + + return c3y; +} + +/* u3e_backup(): copy snapshot from [pux_c] to [pax_c], + * overwriting optionally. note that image files must + * be named "image". +*/ +c3_o +u3e_backup(c3_c* pux_c, c3_c* pax_c, c3_o ovw_o) +{ + // source image file from [pux_c] + u3e_image nux_u = { .nam_c = "image", .pgs_w = 0 }; + + // destination image file to [pax_c] + u3e_image nax_u = { .nam_c = "image", .pgs_w = 0 }; + + c3_i mod_i = O_RDWR | O_CREAT; + + if ( !pux_c || !pax_c ) { + fprintf(stderr, "loom: image backup: bad path\r\n"); + return c3n; + } + + if ( (c3n == ovw_o) && c3_mkdir(pax_c, 0700) ) { + if ( EEXIST != errno ) { + fprintf(stderr, "loom: image backup: %s\r\n", strerror(errno)); + } + return c3n; + } + + // open source image files if they exist + // + c3_c nux_c[8193]; + snprintf(nux_c, 8192, "%s/%s.bin", pux_c, nux_u.nam_c); + if ( (0 != access(nux_c, F_OK)) + || (_ce_img_good != _ce_image_open(&nux_u, pux_c)) ) + { + fprintf(stderr, "loom: couldn't open image at %s\r\n", pux_c); + return c3n; + } + + // open destination image files + c3_c nax_c[8193]; + snprintf(nax_c, 8192, "%s/%s.bin", pax_c, nax_u.nam_c); + if ( -1 == (nax_u.fid_i = c3_open(nax_c, mod_i, 0666)) ) { + fprintf(stderr, "loom: c3_open %s: %s\r\n", nax_c, strerror(errno)); + return c3n; + } + + if ( (c3n == _ce_image_copy(&nux_u, &nax_u)) + || (c3n == _ce_image_sync(&nax_u)) ) + { + c3_unlink(nax_c); + fprintf(stderr, "loom: image backup failed\r\n"); + return c3n; + } + + close(nax_u.fid_i); + fprintf(stderr, "loom: image backup complete\r\n"); + return c3y; +} + +/* + u3e_save(): save current changes. + + If we are in dry-run mode, do nothing. + + First, call `_ce_patch_compose` to write all dirty pages to disk and + clear protection and dirty bits. If there were no dirty pages to write, + then we're done. + + - Sync the patch files to disk. + - Verify the patch (because why not?) + - Write the patch data into the image file (This is idempotent.). + - Sync the image file. + - Delete the patchfile and free it. + + Once we've written the dirty pages to disk (and have reset their dirty bits + and protection flags), we *could* handle the rest of the checkpointing + process in a separate thread, but we'd need to wait until that finishes + before we try to make another snapshot. +*/ +void +u3e_save(u3_post low_p, u3_post hig_p) +{ + u3_ce_patch* pat_u; + c3_w old_w = u3P.img_u.pgs_w; + + if ( u3C.wag_w & u3o_dryrun ) { + return; + } + + // XX discard hig_p and friends + { + c3_w nop_w = (low_p >> u3a_page); + c3_w nor_w = (low_p + (_ce_len_words(1) - 1)) >> u3a_page; + c3_w sop_w = hig_p >> u3a_page; + + u3_assert( (u3P.gar_w > nop_w) && (u3P.gar_w < sop_w) ); + + if ( !(pat_u = _ce_patch_compose(nor_w)) ) { + return; + } + } + + if ( u3C.wag_w & u3o_verbose ) { + fprintf(stderr, "sync: skipped %u free", pat_u->sip_w); + u3a_print_memory(stderr, " pages", pat_u->sip_w << u3a_page); + } + + // attempt to avoid propagating anything insane to disk + // + u3a_loom_sane(); + + if ( u3C.wag_w & u3o_verbose ) { + u3a_print_memory(stderr, "sync: save", pat_u->con_u->pgs_w << u3a_page); + } + + _ce_patch_sync(pat_u); + + if ( c3n == _ce_patch_verify(pat_u) ) { + u3_assert(!"loom: save failed"); + } + +#ifdef U3_SNAPSHOT_VALIDATION + // check that clean pages are correct + // + u3_assert( c3y == _ce_loom_fine() ); +#endif + + _ce_patch_apply(pat_u); + + u3_assert( c3y == _ce_image_sync(&u3P.img_u) ); + + _ce_patch_free(pat_u); + _ce_patch_delete(); + +#ifdef U3_SNAPSHOT_VALIDATION + { + c3_w pgs_w; + u3_assert( _ce_img_good == _ce_image_stat(&u3P.img_u, &pgs_w) ); + u3_assert( pgs_w == u3P.img_u.pgs_w ); + } + + // check that all pages in the image are clean and *fine*, + // all others are dirty + // + // since total finery requires total cleanliness, + // pages of the image are protected twice. + // + _ce_loom_protect(u3P.img_u.pgs_w, old_w); + + u3_assert( c3y == _ce_loom_track_sane() ); + u3_assert( c3y == _ce_loom_fine() ); +#endif + + if ( u3C.wag_w & u3o_no_demand ) { +#ifndef U3_SNAPSHOT_VALIDATION + _ce_loom_protect(u3P.img_u.pgs_w, old_w); +#endif + } + else { + _ce_loom_mapf(u3P.img_u.fid_i, u3P.img_u.pgs_w, old_w); + } + + u3e_toss(low_p, hig_p); +} + +/* _ce_toss_pages(): discard ephemeral pages. +*/ +static void +_ce_toss_pages(c3_w nor_w, c3_w sou_w) +{ + c3_w pgs_w = u3P.pag_w - (nor_w + sou_w); + void* ptr_v = _ce_ptr(nor_w); + + #ifndef U3_OS_windows + if ( -1 == madvise(ptr_v, _ce_len(pgs_w), MADV_DONTNEED) ) { + fprintf(stderr, "loom: madv_dontneed failed (%u pages at %u): %s\r\n", + pgs_w, nor_w, strerror(errno)); + } + #endif +} + +/* u3e_toss(): discard ephemeral pages. +*/ +void +u3e_toss(u3_post low_p, u3_post hig_p) +{ + c3_w nor_w = (low_p + (_ce_len_words(1) - 1)) >> u3a_page; + c3_w sou_w = u3P.pag_w - (hig_p >> u3a_page); + + _ce_toss_pages(nor_w, sou_w); +} + +/* u3e_live(): start the checkpointing system. +*/ +c3_o +u3e_live(c3_o nuu_o, c3_c* dir_c) +{ + // require that our page size is a multiple of the system page size. + // + { + size_t sys_i = sysconf(_SC_PAGESIZE); + + if ( _ce_page % sys_i ) { + fprintf(stderr, "loom: incompatible system page size (%zuKB)\r\n", + sys_i >> 10); + exit(1); + } + } + + u3P.dir_c = dir_c; + u3P.eph_i = 0; + u3P.img_u.nam_c = "image"; + u3P.pag_w = u3C.wor_i >> u3a_page; + + // XX review dryrun requirements, enable or remove + // +#if 0 + if ( u3C.wag_w & u3o_dryrun ) { + return c3y; + } else +#endif + { + // Open the ephemeral space file. + // + if ( u3C.wag_w & u3o_swap ) { + if ( c3n == _ce_ephemeral_open(&u3P.eph_i) ) { + fprintf(stderr, "boot: failed to load ephemeral file\r\n"); + exit(1); + } + } + + // Open image files. + // + c3_c chk_c[8193]; + snprintf(chk_c, 8193, "%s/.urb/chk", u3P.dir_c); + + _ce_img_stat sat_e = _ce_image_open(&u3P.img_u, chk_c); + + if ( _ce_img_fail == sat_e ) { + fprintf(stderr, "boot: image failed\r\n"); + exit(1); + } + else { + u3_ce_patch* pat_u; + + /* Load any patch files; apply them to images. + */ + if ( 0 != (pat_u = _ce_patch_open()) ) { + _ce_patch_apply(pat_u); + u3_assert( c3y == _ce_image_sync(&u3P.img_u) ); + _ce_patch_free(pat_u); + _ce_patch_delete(); + } + else if ( _ce_img_size == sat_e ) { + fprintf(stderr, "boot: image failed (size)\r\n"); + exit(1); + } + + // detect snapshots from a larger loom + // + if ( (u3P.img_u.pgs_w + 1) >= u3P.pag_w ) { // XX? + fprintf(stderr, "boot: snapshot too big for loom\r\n"); + exit(1); + } + + // mark all pages dirty (pages in the snapshot will be marked clean) + // + u3e_foul(); + + /* Write image files to memory; reinstate protection. + */ + { + if ( u3C.wag_w & u3o_swap ) { + _ce_loom_mapf_ephemeral(); + } + + if ( u3C.wag_w & u3o_no_demand ) { + _ce_loom_blit(u3P.img_u.fid_i, u3P.img_u.pgs_w); + } + else { + _ce_loom_mapf(u3P.img_u.fid_i, u3P.img_u.pgs_w, 0); + } + + u3l_log("boot: protected loom"); + } + + /* If the images were empty, we are logically booting. + */ + if ( !u3P.img_u.pgs_w ) { + u3l_log("live: logical boot"); + nuu_o = c3y; + } + else if ( u3C.wag_w & u3o_no_demand ) { + u3a_print_memory(stderr, "live: loaded", _ce_len_words(u3P.img_u.pgs_w)); + } + else { + u3a_print_memory(stderr, "live: mapped", _ce_len_words(u3P.img_u.pgs_w)); + } + +#ifdef U3_GUARD_PAGE + u3_assert( !_ce_ward_post(u3P.img_u.pgs_w, u3P.pag_w) ); +#endif + } + } + + return nuu_o; +} + +/* u3e_stop(): gracefully stop the persistence system. +*/ +void +u3e_stop(void) +{ + if ( u3P.eph_i ) { + _ce_toss_pages(u3P.img_u.pgs_w, u3P.pag_w); + close(u3P.eph_i); + unlink(u3C.eph_c); + } + + close(u3P.img_u.fid_i); +} + +/* u3e_yolo(): disable dirty page tracking, read/write whole loom. +*/ +c3_o +u3e_yolo(void) +{ + // NB: u3e_save() will reinstate protection flags + // + if ( 0 != mprotect(_ce_ptr(0), + _ce_len(u3P.pag_w), + (PROT_READ | PROT_WRITE)) ) + { + // XX confirm recoverable errors + // + fprintf(stderr, "loom: yolo: %s\r\n", strerror(errno)); + return c3n; + } + + u3_assert( !_ce_ward_protect() ); + + return c3y; +} + +/* u3e_foul(): dirty all the pages of the loom. +*/ +void +u3e_foul(void) +{ + memset((void*)u3P.dit_w, 0xff, sizeof(u3P.dit_w)); +} + +/* u3e_init(): initialize guard page tracking, dirty loom +*/ +void +u3e_init(void) +{ + u3P.pag_w = u3C.wor_i >> u3a_page; + + u3P.img_u.fid_i = -1; + + u3e_foul(); + +#ifdef U3_GUARD_PAGE + u3_assert( !_ce_ward_post(0, u3P.pag_w) ); +#endif +} + +/* u3e_ward(): reposition guard page if needed. +*/ +void +u3e_ward(u3_post low_p, u3_post hig_p) +{ +#ifdef U3_GUARD_PAGE + c3_w nop_w = low_p >> u3a_page; + c3_w sop_w = hig_p >> u3a_page; + c3_w pag_w = u3P.gar_w; + + if ( !((pag_w > nop_w) && (pag_w < sop_w)) ) { + u3_assert( !_ce_ward_post(nop_w, sop_w) ); + u3_assert( !_ce_flaw_mprotect(pag_w) ); + u3_assert( u3P.dit_w[pag_w >> 5] & ((c3_w)1 << (pag_w & 31)) ); + } +#endif +} diff --git a/vere/pkg/noun/events.h b/vere/pkg/noun/events.h new file mode 100644 index 0000000..d9cdb50 --- /dev/null +++ b/vere/pkg/noun/events.h @@ -0,0 +1,131 @@ +/// @file + +#ifndef U3_EVENTS_H +#define U3_EVENTS_H + +#include "c3/c3.h" +#include "allocate.h" +#include "version.h" + + /** Data structures. + **/ + /* u3e_line: control line. + */ + typedef struct _u3e_line { + c3_w pag_w; + c3_w has_w; + } u3e_line; + + /* u3e_control: memory change, control file. + */ + typedef struct _u3e_control { + u3e_version ver_w; // version number + c3_w has_w; // control checksum + c3_w tot_w; // new page count + c3_w pgs_w; // number of changed pages + u3e_line mem_u[]; // per page + } u3e_control; + + /* u3_cs_patch: memory change, top level. + */ + typedef struct _u3_cs_patch { + c3_i ctl_i; + c3_i mem_i; + c3_w sip_w; + u3e_control* con_u; + } u3_ce_patch; + + /* u3e_image: memory segment, open file. + */ + typedef struct _u3e_image { + c3_c* nam_c; // segment name + c3_i fid_i; // open file, or 0 + c3_w pgs_w; // length in pages + } u3e_image; + + /* u3e_pool: entire memory system. + */ + typedef struct _u3e_pool { + c3_c* dir_c; // path to + c3_i eph_i; // ephemeral file descriptor + c3_w dit_w[u3a_pages >> 5]; // touched since last save + c3_w pag_w; // number of pages (<= u3a_pages) + c3_w gar_w; // guard page + u3e_image img_u; // image + } u3e_pool; + + /* u3e_flaw: loom fault result. + */ + typedef enum { + u3e_flaw_sham = 0, // bogus state + u3e_flaw_base = 1, // vm fail (mprotect) + u3e_flaw_meme = 2, // bail:meme + u3e_flaw_good = 3 // handled + } u3e_flaw; + + /** Globals. + **/ + /// Snapshotting system. + extern u3e_pool u3e_Pool; +# define u3P u3e_Pool + + /** Constants. + **/ + + /** Functions. + **/ + /* u3e_backup(): copy the snapshot from [pux_c] to [pax_c], + * overwriting optional. + */ + c3_o + u3e_backup(c3_c* pux_c, c3_c* pax_c, c3_o ovw_o); + + /* u3e_fault(): handle a memory fault. + */ + u3e_flaw + u3e_fault(u3_post low_p, u3_post hig_p, u3_post off_p); + + /* u3e_save(): update the checkpoint. + */ + void + u3e_save(u3_post low_p, u3_post hig_p); + + /* u3e_toss(): discard ephemeral pages. + */ + void + u3e_toss(u3_post low_p, u3_post hig_p); + + /* u3e_live(): start the persistence system. Return c3y if no image. + */ + c3_o + u3e_live(c3_o nuu_o, c3_c* dir_c); + + /* u3e_stop(): gracefully stop the persistence system. + */ + void + u3e_stop(void); + + /* u3e_yolo(): disable dirty page tracking, read/write whole loom. + */ + c3_o + u3e_yolo(void); + + /* u3e_foul(): dirty all the pages of the loom. + */ + void + u3e_foul(void); + + /* u3e_init(): initialize guard page tracking. + */ + void + u3e_init(void); + + /* u3e_ward(): reposition guard page if needed. + */ + void + u3e_ward(u3_post low_p, u3_post hig_p); + + c3_i + u3e_image_open_any(c3_c* nam_c, c3_c* dir_c, c3_z* len_z); + +#endif /* ifndef U3_EVENTS_H */ diff --git a/vere/pkg/noun/hashtable.c b/vere/pkg/noun/hashtable.c new file mode 100644 index 0000000..6b1fb39 --- /dev/null +++ b/vere/pkg/noun/hashtable.c @@ -0,0 +1,1408 @@ +/// @file + +#include "hashtable.h" + +#include "allocate.h" +#include "imprison.h" +#include "retrieve.h" +#include "xtract.h" + +/* CUT_END(): extract [b_w] low bits from [a_w] +*/ +#define CUT_END(a_w, b_w) ((a_w) & (((c3_w)1 << (b_w)) - 1)) + +/* BIT_SET(): [1] if bit [b_w] is set in [a_w] +*/ +#define BIT_SET(a_w, b_w) ((a_w) & ((c3_w)1 << (b_w))) + +static u3_weak +_ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w); + +static u3_weak +_ch_trim_root(u3h_root* har_u); + +c3_w +_ch_skip_slot(c3_w mug_w, c3_w lef_w); + +/* u3h_new_cache(): create hashtable with bounded size. +*/ +u3p(u3h_root) +u3h_new_cache(c3_w max_w) +{ + u3h_root* har_u = u3a_walloc(c3_wiseof(u3h_root)); + u3p(u3h_root) har_p = u3of(u3h_root, har_u); + c3_w i_w; + + har_u->max_w = max_w; + har_u->use_w = 0; + har_u->arm_u.mug_w = 0; + har_u->arm_u.inx_w = 0; + + for ( i_w = 0; i_w < 64; i_w++ ) { + har_u->sot_w[i_w] = 0; + } + return har_p; +} + +/* u3h_new(): create hashtable. +*/ +u3p(u3h_root) +u3h_new(void) +{ + return u3h_new_cache(0); +} + +/* _ch_popcount(): number of bits set in word. A standard intrinsic. +*/ +static c3_w +_ch_popcount(c3_w num_w) +{ + return c3_pc_w(num_w); +} + +/* _ch_buck_new(): create new bucket. +*/ +static u3h_buck* +_ch_buck_new(c3_w len_w) +{ + u3h_buck* hab_u = u3a_walloc(c3_wiseof(u3h_buck) + + (len_w * c3_wiseof(u3h_slot))); + hab_u->len_w = len_w; + return hab_u; +} + +/* _ch_node_new(): create new node. +*/ +static u3h_node* +_ch_node_new(c3_w len_w) +{ + u3h_node* han_u = u3a_walloc(c3_wiseof(u3h_node) + + (len_w * c3_wiseof(u3h_slot))); + han_u->map_w = 0; + return han_u; +} + +static void _ch_slot_put(u3h_slot*, u3_noun, c3_w, c3_w, c3_w*); + +/* _ch_node_add(): add to node. +*/ +static u3h_node* +_ch_node_add(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) +{ + c3_w bit_w, inx_w, map_w, i_w; + + lef_w -= 5; + bit_w = (rem_w >> lef_w); + rem_w = CUT_END(rem_w, lef_w); + map_w = han_u->map_w; + inx_w = _ch_popcount(CUT_END(map_w, bit_w)); + + if ( BIT_SET(map_w, bit_w) ) { + _ch_slot_put(&(han_u->sot_w[inx_w]), kev, lef_w, rem_w, use_w); + return han_u; + } + else { + // nothing was at this slot. + // Optimize: use u3a_wealloc. + // + c3_w len_w = _ch_popcount(map_w); + u3h_node* nah_u = _ch_node_new(1 + len_w); + nah_u->map_w = han_u->map_w | ((c3_w)1 << bit_w); + + for ( i_w = 0; i_w < inx_w; i_w++ ) { + nah_u->sot_w[i_w] = han_u->sot_w[i_w]; + } + nah_u->sot_w[inx_w] = u3h_noun_be_warm(u3h_noun_to_slot(kev)); + for ( i_w = inx_w; i_w < len_w; i_w++ ) { + nah_u->sot_w[i_w + 1] = han_u->sot_w[i_w]; + } + + u3a_wfree(han_u); + *use_w += 1; + return nah_u; + } +} + +/* ch_buck_add(): add to bucket. +*/ +static u3h_buck* +_ch_buck_add(u3h_buck* hab_u, u3_noun kev, c3_w *use_w) +{ + c3_w i_w; + + // if our key is equal to any of the existing keys in the bucket, + // then replace that key-value pair with kev. + // + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3_noun kov = u3h_slot_to_noun(hab_u->sot_w[i_w]); + if ( c3y == u3r_sing(u3h(kev), u3h(kov)) ) { + hab_u->sot_w[i_w] = u3h_noun_to_slot(kev); + u3z(kov); + return hab_u; + } + } + + // create mutant bucket with added key-value pair. + // Optimize: use u3a_wealloc(). + { + u3h_buck* bah_u = _ch_buck_new(1 + hab_u->len_w); + bah_u->sot_w[0] = u3h_noun_be_warm(u3h_noun_to_slot(kev)); + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + bah_u->sot_w[i_w + 1] = hab_u->sot_w[i_w]; + } + + u3a_wfree(hab_u); + *use_w += 1; + return bah_u; + } +} + +/* _ch_some_add(): add to node or bucket. +*/ +static void* +_ch_some_add(void* han_v, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) +{ + if ( 0 == lef_w ) { + return _ch_buck_add((u3h_buck*)han_v, kev, use_w); + } + else return _ch_node_add((u3h_node*)han_v, lef_w, rem_w, kev, use_w); +} + +/* _ch_two(): create a new node with two leaves underneath +*/ +u3h_slot +_ch_two(u3h_slot had_w, u3h_slot add_w, c3_w lef_w, c3_w ham_w, c3_w mad_w) +{ + void* ret; + + if ( 0 == lef_w ) { + u3h_buck* hab_u = _ch_buck_new(2); + ret = hab_u; + hab_u->sot_w[0] = had_w; + hab_u->sot_w[1] = add_w; + } + else { + c3_w hop_w, tad_w; + lef_w -= 5; + hop_w = ham_w >> lef_w; + tad_w = mad_w >> lef_w; + if ( hop_w == tad_w ) { + // fragments collide: store in a child node. + u3h_node* han_u = _ch_node_new(1); + ret = han_u; + han_u->map_w = (c3_w)1 << hop_w; + ham_w = CUT_END(ham_w, lef_w); + mad_w = CUT_END(mad_w, lef_w); + han_u->sot_w[0] = _ch_two(had_w, add_w, lef_w, ham_w, mad_w); + } + else { + u3h_node* han_u = _ch_node_new(2); + ret = han_u; + han_u->map_w = ((c3_w)1 << hop_w) | ((c3_w)1 << tad_w); + // smaller mug fragments go in earlier slots + if ( hop_w < tad_w ) { + han_u->sot_w[0] = had_w; + han_u->sot_w[1] = add_w; + } + else { + han_u->sot_w[0] = add_w; + han_u->sot_w[1] = had_w; + } + } + } + + return u3h_node_to_slot(ret); +} + +/* _ch_slot_put(): store a key-value pair in a non-null slot +*/ +static void +_ch_slot_put(u3h_slot* sot_w, u3_noun kev, c3_w lef_w, c3_w rem_w, c3_w* use_w) +{ + if ( c3n == u3h_slot_is_noun(*sot_w) ) { + void* hav_v = _ch_some_add(u3h_slot_to_node(*sot_w), + lef_w, + rem_w, + kev, + use_w); + + u3_assert( c3y == u3h_slot_is_node(*sot_w) ); + *sot_w = u3h_node_to_slot(hav_v); + } + else { + u3_noun kov = u3h_slot_to_noun(*sot_w); + u3h_slot add_w = u3h_noun_be_warm(u3h_noun_to_slot(kev)); + if ( c3y == u3r_sing(u3h(kev), u3h(kov)) ) { + // replace old value + u3z(kov); + *sot_w = add_w; + } + else { + c3_w ham_w = CUT_END(u3r_mug(u3h(kov)), lef_w); + *sot_w = _ch_two(*sot_w, add_w, lef_w, ham_w, rem_w); + *use_w += 1; + } + } +} + +/* u3h_put_get(): insert in caching hashtable, returning deleted key-value pair +** +** `key` is RETAINED; `val` is transferred. +*/ +u3_weak +u3h_put_get(u3p(u3h_root) har_p, u3_noun key, u3_noun val) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + u3_noun kev = u3nc(u3k(key), val); + c3_w mug_w = u3r_mug(key); + c3_w inx_w = (mug_w >> 25); // 6 bits + c3_w rem_w = CUT_END(mug_w, 25); + u3h_slot* sot_w = &(har_u->sot_w[inx_w]); + + if ( c3y == u3h_slot_is_null(*sot_w) ) { + *sot_w = u3h_noun_be_warm(u3h_noun_to_slot(kev)); + har_u->use_w += 1; + } + else { + _ch_slot_put(sot_w, kev, 25, rem_w, &(har_u->use_w)); + } + + { + u3_weak ret = u3_none; + + if ( har_u->max_w && (har_u->use_w > har_u->max_w) ) { + do { + ret = _ch_trim_root(har_u); + } + while ( u3_none == ret ); + har_u->use_w -= 1; + } + + return ret; + } +} + +/* u3h_put(): insert in hashtable. +** +** `key` is RETAINED; `val` is transferred. +*/ +void +u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val) +{ + u3_weak del = u3h_put_get(har_p, key, val); + if ( u3_none != del ) { + u3z(del); + } +} + +/* _ch_buck_del(): delete from bucket +*/ +static c3_o +_ch_buck_del(u3h_slot* sot_w, u3_noun key) +{ + u3h_buck* hab_u = u3h_slot_to_node(*sot_w); + c3_w fin_w = hab_u->len_w; + c3_w i_w; + // + // find index of key to be deleted + // + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3_noun kov = u3h_slot_to_noun(hab_u->sot_w[i_w]); + if ( c3y == u3r_sing(key, u3h(kov)) ) { + fin_w = i_w; + u3z(kov); + break; + } + } + + // no key found, no-op + if ( fin_w == hab_u->len_w ) { + return c3n; + } + + { + hab_u->len_w--; + // u3_assert(c3y == u3h_slot_is_noun(hab_u->sot_w[fin_w])); + for ( i_w = fin_w; i_w < hab_u->len_w; i_w++ ) { + hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1]; + } + + return c3y; + } +} + +static c3_o _ch_some_del(u3h_slot*, u3_noun, c3_w, c3_w); + +/* _ch_slot_del(): delete from slot +*/ +static c3_o +_ch_slot_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w) +{ + if ( c3y == u3h_slot_is_noun(*sot_w) ) { + u3_noun kev = u3h_slot_to_noun(*sot_w); + *sot_w = 0; + u3z(kev); + return c3y; + } + else { + return _ch_some_del(sot_w, key, lef_w, rem_w); + } +} + +/* _ch_slot_del(): delete from node +*/ +static c3_o +_ch_node_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w) +{ + u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w); + u3h_slot* tos_w; + + c3_w bit_w, inx_w, map_w, i_w; + + lef_w -= 5; + bit_w = (rem_w >> lef_w); + rem_w = CUT_END(rem_w, lef_w); + map_w = han_u->map_w; + inx_w = _ch_popcount(CUT_END(map_w, bit_w)); + + tos_w = &(han_u->sot_w[inx_w]); + + // nothing at slot, no-op + if ( !BIT_SET(map_w, bit_w) ) { + return c3n; + } + + if ( c3n == _ch_slot_del(tos_w, key, lef_w, rem_w) ) { + // nothing deleted + return c3n; + } + else if ( 0 != *tos_w ) { + // something deleted, but slot still has value + return c3y; + } + else { + // shrink! + c3_w i_w, ken_w, len_w = _ch_popcount(map_w); + u3h_slot kes_w; + + if ( 2 == len_w && ((ken_w = (0 == inx_w) ? 1 : 0), + (kes_w = han_u->sot_w[ken_w]), + (c3y == u3h_slot_is_noun(kes_w))) ) + { + // only one side left, and the other is a noun. debucketize. + *sot_w = kes_w; + u3a_wfree(han_u); + } + else { + // shrink node in place; don't reallocate, we could be low on memory + // + han_u->map_w &= ~(1 << bit_w); + --len_w; + + for ( i_w = inx_w; i_w < len_w; i_w++ ) { + han_u->sot_w[i_w] = han_u->sot_w[i_w + 1]; + } + } + return c3y; + } +} + +/* _ch_some_del(): delete from node or buck +*/ +static c3_o +_ch_some_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w) +{ + if ( 0 == lef_w ) { + return _ch_buck_del(sot_w, key); + } + + return _ch_node_del(sot_w, key, lef_w, rem_w); +} + +/* u3h_del(); delete from hashtable. +*/ +void +u3h_del(u3p(u3h_root) har_p, u3_noun key) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w mug_w = u3r_mug(key); + c3_w inx_w = (mug_w >> 25); + c3_w rem_w = CUT_END(mug_w, 25); + u3h_slot* sot_w = &(har_u->sot_w[inx_w]); + + if ( (c3n == u3h_slot_is_null(*sot_w)) + && (c3y == _ch_slot_del(sot_w, key, 25, rem_w)) ) + { + har_u->use_w--; + } +} + +/* _ch_uni_with(): key/value callback, put into [*wit] +*/ +static void +_ch_uni_with(u3_noun kev, void* wit) +{ + u3p(u3h_root) har_p = *(u3p(u3h_root)*)wit; + u3_noun key, val; + u3x_cell(kev, &key, &val); + + u3h_put(har_p, key, u3k(val)); +} + +/* u3h_uni(): unify hashtables, copying [rah_p] into [har_p] +*/ +void +u3h_uni(u3p(u3h_root) har_p, u3p(u3h_root) rah_p) +{ + u3h_walk_with(rah_p, _ch_uni_with, &har_p); +} + +/* _ch_trim_node(): trim one entry from a node slot or its children +*/ +static u3_weak +_ch_trim_node(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w) +{ + c3_w bit_w, map_w, inx_w; + u3h_slot* tos_w; + u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w); + + lef_w -= 5; + bit_w = (rem_w >> lef_w); + map_w = han_u->map_w; + + if ( !BIT_SET(map_w, bit_w) ) { + har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w); + return c3n; + } + + rem_w = CUT_END(rem_w, lef_w); + inx_w = _ch_popcount(CUT_END(map_w, bit_w)); + tos_w = &(han_u->sot_w[inx_w]); + + u3_weak ret = _ch_trim_slot(har_u, tos_w, lef_w, rem_w); + if ( (u3_none != ret) && (0 == *tos_w) ) { + // shrink! + c3_w i_w, ken_w, len_w = _ch_popcount(map_w); + u3h_slot kes_w; + + if ( 2 == len_w && ((ken_w = (0 == inx_w) ? 1 : 0), + (kes_w = han_u->sot_w[ken_w]), + (c3y == u3h_slot_is_noun(kes_w))) ) { + // only one side left, and the other is a noun. debucketize. + *sot_w = kes_w; + u3a_wfree(han_u); + } + else { + // shrink node in place; don't reallocate, we could be low on memory + // + han_u->map_w &= ~(1 << bit_w); + --len_w; + + for ( i_w = inx_w; i_w < len_w; i_w++ ) { + han_u->sot_w[i_w] = han_u->sot_w[i_w + 1]; + } + } + } + return ret; +} + +/* _ch_trim_kev(): trim a single entry slot +*/ +static u3_weak +_ch_trim_kev(u3h_slot *sot_w) +{ + if ( _(u3h_slot_is_warm(*sot_w)) ) { + *sot_w = u3h_noun_be_cold(*sot_w); + return u3_none; + } + else { + u3_noun kev = u3h_slot_to_noun(*sot_w); + *sot_w = 0; + return kev; + } +} + +/* _ch_trim_node(): trim one entry from a bucket slot +*/ +static u3_weak +_ch_trim_buck(u3h_root* har_u, u3h_slot* sot_w) +{ + c3_w i_w, len_w; + u3h_buck* hab_u = u3h_slot_to_node(*sot_w); + + for ( len_w = hab_u->len_w; + har_u->arm_u.inx_w < len_w; + har_u->arm_u.inx_w += 1 ) + { + u3_weak ret = _ch_trim_kev(&(hab_u->sot_w[har_u->arm_u.inx_w])); + if ( u3_none != ret ) { + if ( 2 == len_w ) { + // 2 things in bucket: debucketize to key-value pair, the next + // run will point at this pair (same mug_w, no longer in bucket) + *sot_w = hab_u->sot_w[ (0 == har_u->arm_u.inx_w) ? 1 : 0 ]; + u3a_wfree(hab_u); + har_u->arm_u.inx_w = 0; + } + else { + // shrink bucket in place; don't reallocate, we could be low on memory + hab_u->len_w = --len_w; + + for ( i_w = har_u->arm_u.inx_w; i_w < len_w; ++i_w ) { + hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1]; + } + // leave the arm pointing at the next index in the bucket + ++(har_u->arm_u.inx_w); + } + return ret; + } + } + + har_u->arm_u.mug_w = (har_u->arm_u.mug_w + 1) & 0x7FFFFFFF; // modulo 2^31 + har_u->arm_u.inx_w = 0; + return u3_none; +} + +/* _ch_trim_some(): trim one entry from a bucket or node slot +*/ +static u3_weak +_ch_trim_some(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w) +{ + if ( 0 == lef_w ) { + return _ch_trim_buck(har_u, sot_w); + } + else { + return _ch_trim_node(har_u, sot_w, lef_w, rem_w); + } +} + +/* _ch_skip_slot(): increment arm over hash prefix. +*/ +c3_w +_ch_skip_slot(c3_w mug_w, c3_w lef_w) +{ + c3_w hig_w = mug_w >> lef_w; + c3_w new_w = CUT_END(hig_w + 1, (31 - lef_w)); // modulo 2^(31 - lef_w) + return new_w << lef_w; +} + +/* _ch_trim_slot(): trim one entry from a non-bucket slot +*/ +static u3_weak +_ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w) +{ + if ( c3y == u3h_slot_is_noun(*sot_w) ) { + har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w); + return _ch_trim_kev(sot_w); + } + else { + return _ch_trim_some(har_u, sot_w, lef_w, rem_w); + } +} + +/* _ch_trim_root(): trim one entry from a hashtable +*/ +static u3_weak +_ch_trim_root(u3h_root* har_u) +{ + c3_w mug_w = har_u->arm_u.mug_w; + c3_w inx_w = mug_w >> 25; // 6 bits + u3h_slot* sot_w = &(har_u->sot_w[inx_w]); + + if ( c3y == u3h_slot_is_null(*sot_w) ) { + har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, 25); + return u3_none; + } + + return _ch_trim_slot(har_u, sot_w, 25, CUT_END(mug_w, 25)); +} + +/* u3h_trim_to(): trim to n key-value pairs +*/ +void +u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w) +{ + u3h_trim_with(har_p, n_w, u3a_lose); +} + +/* u3h_trim_to(): trim to n key-value pairs +*/ +void +u3h_trim_with(u3p(u3h_root) har_p, c3_w n_w, void (*del_cb)(u3_noun)) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + + while ( har_u->use_w > n_w ) { + u3_weak del = _ch_trim_root(har_u); + if ( u3_none != del ) { + har_u->use_w -= 1; + del_cb(del); + } + } +} + +/* _ch_buck_hum(): read in bucket. +*/ +static c3_o +_ch_buck_hum(u3h_buck* hab_u, c3_w mug_w) +{ + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + if ( mug_w == u3r_mug(u3h(u3h_slot_to_noun(hab_u->sot_w[i_w]))) ) { + return c3y; + } + } + return c3n; +} + +/* _ch_node_hum(): read in node. +*/ +static c3_o +_ch_node_hum(u3h_node* han_u, c3_w lef_w, c3_w rem_w, c3_w mug_w) +{ + c3_w bit_w, map_w; + + lef_w -= 5; + bit_w = (rem_w >> lef_w); + rem_w = CUT_END(rem_w, lef_w); + map_w = han_u->map_w; + + if ( !BIT_SET(map_w, bit_w) ) { + return c3n; + } + else { + c3_w inx_w = _ch_popcount(CUT_END(map_w, bit_w)); + c3_w sot_w = han_u->sot_w[inx_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + if ( mug_w == u3r_mug(u3h(kev)) ) { + return c3y; + } + else { + return c3n; + } + } + else { + void* hav_v = u3h_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + return _ch_buck_hum(hav_v, mug_w); + } + else return _ch_node_hum(hav_v, lef_w, rem_w, mug_w); + } + } +} + +/* u3h_hum(): check presence in hashtable. +** +** `key` is RETAINED. +*/ +c3_o +u3h_hum(u3p(u3h_root) har_p, c3_w mug_w) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w inx_w = (mug_w >> 25); + c3_w rem_w = CUT_END(mug_w, 25); + c3_w sot_w = har_u->sot_w[inx_w]; + + if ( _(u3h_slot_is_null(sot_w)) ) { + return c3n; + } + else if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + if ( mug_w == u3r_mug(u3h(kev)) ) { + return c3y; + } + else { + return c3n; + } + } + else { + u3h_node* han_u = u3h_slot_to_node(sot_w); + + return _ch_node_hum(han_u, 25, rem_w, mug_w); + } +} + +/* _ch_buck_git(): read in bucket. +*/ +static u3_weak +_ch_buck_git(u3h_buck* hab_u, u3_noun key) +{ + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3_noun kev = u3h_slot_to_noun(hab_u->sot_w[i_w]); + if ( _(u3r_sing(key, u3h(kev))) ) { + return u3t(kev); + } + } + return u3_none; +} + +/* _ch_node_git(): read in node. +*/ +static u3_weak +_ch_node_git(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun key) +{ + c3_w bit_w, map_w; + + lef_w -= 5; + bit_w = (rem_w >> lef_w); + rem_w = CUT_END(rem_w, lef_w); + map_w = han_u->map_w; + + if ( !BIT_SET(map_w, bit_w) ) { + return u3_none; + } + else { + c3_w inx_w = _ch_popcount(CUT_END(map_w, bit_w)); + c3_w sot_w = han_u->sot_w[inx_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + if ( _(u3r_sing(key, u3h(kev))) ) { + return u3t(kev); + } + else { + return u3_none; + } + } + else { + void* hav_v = u3h_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + return _ch_buck_git(hav_v, key); + } + else return _ch_node_git(hav_v, lef_w, rem_w, key); + } + } +} + +/* u3h_git(): read from hashtable. +** +** `key` is RETAINED; result is RETAINED. +*/ +u3_weak +u3h_git(u3p(u3h_root) har_p, u3_noun key) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w mug_w = u3r_mug(key); + c3_w inx_w = (mug_w >> 25); + c3_w rem_w = CUT_END(mug_w, 25); + c3_w sot_w = har_u->sot_w[inx_w]; + + if ( _(u3h_slot_is_null(sot_w)) ) { + return u3_none; + } + else if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + if ( _(u3r_sing(key, u3h(kev))) ) { + har_u->sot_w[inx_w] = u3h_noun_be_warm(sot_w); + return u3t(kev); + } + else { + return u3_none; + } + } + else { + u3h_node* han_u = u3h_slot_to_node(sot_w); + + return _ch_node_git(han_u, 25, rem_w, key); + } +} + +/* u3h_get(): read from hashtable, incrementing refcount. +** +** `key` is RETAINED; result is PRODUCED. +*/ +u3_weak +u3h_get(u3p(u3h_root) har_p, u3_noun key) +{ + u3_noun pro = u3h_git(har_p, key); + + if ( u3_none != pro ) { + u3k(pro); + } + return pro; +} + +/* _ch_free_buck(): free bucket +*/ +static void +_ch_free_buck(u3h_buck* hab_u) +{ + //fprintf(stderr, "free buck\r\n"); + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3z(u3h_slot_to_noun(hab_u->sot_w[i_w])); + } + u3a_wfree(hab_u); +} + +/* _ch_free_node(): free node. +*/ +static void +_ch_free_node(u3h_node* han_u, c3_w lef_w, c3_o pin_o) +{ + c3_w len_w = _ch_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + if ( _(u3h_slot_is_null(sot_w))) { + } else if ( _(u3h_slot_is_noun(sot_w)) ) { + u3z(u3h_slot_to_noun(sot_w)); + } else { + void* hav_v = u3h_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + _ch_free_buck(hav_v); + } else { + _ch_free_node(hav_v, lef_w, pin_o); + } + } + } + u3a_wfree(han_u); +} + +/* u3h_free(): free hashtable. +*/ +void +u3h_free(u3p(u3h_root) har_p) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w i_w; + + for ( i_w = 0; i_w < 64; i_w++ ) { + c3_w sot_w = har_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3z(u3h_slot_to_noun(sot_w)); + } + else if ( _(u3h_slot_is_node(sot_w)) ) { + u3h_node* han_u = u3h_slot_to_node(sot_w); + + _ch_free_node(han_u, 25, i_w == 57); + } + } + u3a_wfree(har_u); +} + +/* _ch_walk_buck(): walk bucket for gc. +*/ +static void +_ch_walk_buck(u3h_buck* hab_u, void (*fun_f)(u3_noun, void*), void* wit) +{ + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + fun_f(u3h_slot_to_noun(hab_u->sot_w[i_w]), wit); + } +} + +/* _ch_walk_node(): walk node for gc. +*/ +static void +_ch_walk_node(u3h_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), void* wit) +{ + c3_w len_w = _ch_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + fun_f(kev, wit); + } + else { + void* hav_v = u3h_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + _ch_walk_buck(hav_v, fun_f, wit); + } else { + _ch_walk_node(hav_v, lef_w, fun_f, wit); + } + } + } +} + +/* u3h_walk_with(): traverse hashtable with key, value fn and data + * argument; RETAINS. +*/ +void +u3h_walk_with(u3p(u3h_root) har_p, + void (*fun_f)(u3_noun, void*), + void* wit) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w i_w; + + for ( i_w = 0; i_w < 64; i_w++ ) { + c3_w sot_w = har_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + fun_f(kev, wit); + } + else if ( _(u3h_slot_is_node(sot_w)) ) { + u3h_node* han_u = u3h_slot_to_node(sot_w); + + _ch_walk_node(han_u, 25, fun_f, wit); + } + } +} + +/* _ch_walk_plain(): use plain u3_noun fun_f for each node + */ +static void +_ch_walk_plain(u3_noun kev, void* wit) +{ + void (*fun_f)(u3_noun) = (void (*)(u3_noun))wit; + fun_f(kev); +} + +/* u3h_walk(): u3h_walk_with, but with no data argument +*/ +void +u3h_walk(u3p(u3h_root) har_p, void (*fun_f)(u3_noun)) +{ + u3h_walk_with(har_p, _ch_walk_plain, (void *)fun_f); +} + +/* _ch_take_noun(): take key and call [fun_f] on val. +*/ +static u3h_slot +_ch_take_noun(u3h_slot sot_w, u3_funk fun_f) +{ + u3_noun kov = u3h_slot_to_noun(sot_w); + u3_noun kev = u3nc(u3a_take(u3h(kov)), + fun_f(u3t(kov))); + + return u3h_noun_to_slot(kev); +} + +/* _ch_take_buck(): take bucket and contents +*/ +static u3h_slot +_ch_take_buck(u3h_slot sot_w, u3_funk fun_f) +{ + u3h_buck* hab_u = u3h_slot_to_node(sot_w); + u3h_buck* bah_u = _ch_buck_new(hab_u->len_w); + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + bah_u->sot_w[i_w] = _ch_take_noun(hab_u->sot_w[i_w], fun_f); + } + + return u3h_node_to_slot(bah_u); +} + +/* _ch_take_node(): take node and contents +*/ +static u3h_slot +_ch_take_node(u3h_slot sot_w, c3_w lef_w, u3_funk fun_f) +{ + u3h_node* han_u = u3h_slot_to_node(sot_w); + c3_w len_w = _ch_popcount(han_u->map_w); + u3h_node* nah_u = _ch_node_new(len_w); + c3_w i_w; + + nah_u->map_w = han_u->map_w; + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w tos_w = han_u->sot_w[i_w]; + nah_u->sot_w[i_w] = ( c3y == u3h_slot_is_noun(tos_w) ) + ? _ch_take_noun(tos_w, fun_f) + : ( 0 == lef_w ) + ? _ch_take_buck(tos_w, fun_f) + : _ch_take_node(tos_w, lef_w, fun_f); + } + + return u3h_node_to_slot(nah_u); +} + +/* u3h_take_with(): gain hashtable, copying junior keys +** and calling [fun_f] on values +*/ +u3p(u3h_root) +u3h_take_with(u3p(u3h_root) har_p, u3_funk fun_f) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + u3p(u3h_root) rah_p = u3h_new_cache(har_u->max_w); + u3h_root* rah_u = u3to(u3h_root, rah_p); + c3_w sot_w, i_w; + + rah_u->use_w = har_u->use_w; + rah_u->arm_u = har_u->arm_u; + + for ( i_w = 0; i_w < 64; i_w++ ) { + sot_w = har_u->sot_w[i_w]; + if ( c3n == u3h_slot_is_null(sot_w) ) { + rah_u->sot_w[i_w] = ( c3y == u3h_slot_is_noun(sot_w) ) + ? _ch_take_noun(sot_w, fun_f) + : _ch_take_node(sot_w, 25, fun_f); + } + } + + return rah_p; +} + +/* u3h_take(): gain hashtable, copying junior nouns +*/ +u3p(u3h_root) +u3h_take(u3p(u3h_root) har_p) +{ + return u3h_take_with(har_p, u3a_take); +} + +/* _ch_mark_buck(): mark bucket for gc. +*/ +c3_w +_ch_mark_buck(u3h_buck* hab_u) +{ + c3_w tot_w = 0; + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + tot_w += u3a_mark_noun(u3h_slot_to_noun(hab_u->sot_w[i_w])); + } + tot_w += u3a_mark_ptr(hab_u); + + return tot_w; +} + +/* _ch_mark_node(): mark node for gc. +*/ +c3_w +_ch_mark_node(u3h_node* han_u, c3_w lef_w) +{ + c3_w tot_w = 0; + c3_w len_w = _ch_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + tot_w += u3a_mark_noun(kev); + } + else { + void* hav_v = u3h_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + tot_w += _ch_mark_buck(hav_v); + } else { + tot_w += _ch_mark_node(hav_v, lef_w); + } + } + } + + tot_w += u3a_mark_ptr(han_u); + + return tot_w; +} + +/* u3h_mark(): mark hashtable for gc. +*/ +c3_w +u3h_mark(u3p(u3h_root) har_p) +{ + c3_w tot_w = 0; + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w i_w; + + for ( i_w = 0; i_w < 64; i_w++ ) { + c3_w sot_w = har_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + tot_w += u3a_mark_noun(kev); + } + else if ( _(u3h_slot_is_node(sot_w)) ) { + u3h_node* han_u = u3h_slot_to_node(sot_w); + + tot_w += _ch_mark_node(han_u, 25); + } + } + + tot_w += u3a_mark_ptr(har_u); + + return tot_w; +} + +static void +_ch_relocate_noun(u3h_slot *sot_w) +{ + u3_noun kev = u3h_slot_to_noun(*sot_w); + u3a_relocate_noun(&kev); + *sot_w = u3h_noun_to_slot(kev); +} + +static void +_ch_relocate_buck(u3h_slot *sot_w) +{ + u3h_buck *hab_u = u3h_slot_to_node(*sot_w); + u3_post new_p, sot_p = u3a_outa(hab_u); + c3_t fir_t; + + new_p = u3a_mark_relocate_post(sot_p, &fir_t); + *sot_w = u3h_node_to_slot(u3a_into(new_p)); + + if ( !fir_t ) return; + + for ( c3_w i_w = 0; i_w < hab_u->len_w; i_w++ ) { + _ch_relocate_noun(&(hab_u->sot_w[i_w])); + } +} + +static void +_ch_relocate_slot(u3h_slot *sot_w, c3_w lef_w); + +static void +_ch_relocate_node(u3h_slot *sot_w, c3_w lef_w) +{ + u3h_node* han_u = u3h_slot_to_node(*sot_w); + u3_post new_p, sot_p = u3a_outa(han_u); + c3_w len_w; + c3_t fir_t; + + new_p = u3a_mark_relocate_post(sot_p, &fir_t); + *sot_w = u3h_node_to_slot(u3a_into(new_p)); + + if ( !fir_t ) return; + + len_w = _ch_popcount(han_u->map_w); + lef_w -= 5; + + for ( c3_w i_w = 0; i_w < len_w; i_w++ ) { + _ch_relocate_slot(&(han_u->sot_w[i_w]), lef_w); + } +} + +static void +_ch_relocate_slot(u3h_slot *sot_w, c3_w lef_w) +{ + if ( c3y == u3h_slot_is_noun(*sot_w) ) { + _ch_relocate_noun(sot_w); + } + else if ( !lef_w ) { + _ch_relocate_buck(sot_w); + } + else { + _ch_relocate_node(sot_w, lef_w); + } +} + +/* u3h_relocate(): relocate hashtable for compaction. +*/ +void +u3h_relocate(u3p(u3h_root) *har_p) +{ + u3_post new_p, old_p = *har_p; + u3h_root* har_u = u3to(u3h_root, old_p); + c3_w sot_w, i_w; + c3_t fir_t; + + new_p = u3a_mark_relocate_post(old_p, &fir_t); + *har_p = new_p; + + if ( !fir_t ) return; + + for ( i_w = 0; i_w < 64; i_w++ ) { + sot_w = har_u->sot_w[i_w]; + + if ( c3n == u3h_slot_is_null(sot_w) ) { + _ch_relocate_slot(&(har_u->sot_w[i_w]), 25); + } + } +} + +/* _ch_count_buck(): count bucket for gc. +*/ +c3_w +_ch_count_buck(u3h_buck* hab_u) +{ + c3_w tot_w = 0; + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + tot_w += u3a_count_noun(u3h_slot_to_noun(hab_u->sot_w[i_w])); + } + tot_w += u3a_count_ptr(hab_u); + + return tot_w; +} + +/* _ch_count_node(): count node for gc. +*/ +c3_w +_ch_count_node(u3h_node* han_u, c3_w lef_w) +{ + c3_w tot_w = 0; + c3_w len_w = _ch_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + tot_w += u3a_count_noun(kev); + } + else { + void* hav_v = u3h_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + tot_w += _ch_count_buck(hav_v); + } else { + tot_w += _ch_count_node(hav_v, lef_w); + } + } + } + + tot_w += u3a_count_ptr(han_u); + + return tot_w; +} + +/* u3h_count(): count hashtable for gc. +*/ +c3_w +u3h_count(u3p(u3h_root) har_p) +{ + c3_w tot_w = 0; + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w i_w; + + for ( i_w = 0; i_w < 64; i_w++ ) { + c3_w sot_w = har_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + tot_w += u3a_count_noun(kev); + } + else if ( _(u3h_slot_is_node(sot_w)) ) { + u3h_node* han_u = u3h_slot_to_node(sot_w); + + tot_w += _ch_count_node(han_u, 25); + } + } + + tot_w += u3a_count_ptr(har_u); + + return tot_w; +} + +/* _ch_discount_buck(): discount bucket for gc. +*/ +c3_w +_ch_discount_buck(u3h_buck* hab_u) +{ + c3_w tot_w = 0; + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + tot_w += u3a_discount_noun(u3h_slot_to_noun(hab_u->sot_w[i_w])); + } + tot_w += u3a_discount_ptr(hab_u); + + return tot_w; +} + +/* _ch_discount_node(): discount node for gc. +*/ +c3_w +_ch_discount_node(u3h_node* han_u, c3_w lef_w) +{ + c3_w tot_w = 0; + c3_w len_w = _ch_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + tot_w += u3a_discount_noun(kev); + } + else { + void* hav_v = u3h_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + tot_w += _ch_discount_buck(hav_v); + } else { + tot_w += _ch_discount_node(hav_v, lef_w); + } + } + } + + tot_w += u3a_discount_ptr(han_u); + + return tot_w; +} + +/* u3h_discount(): discount hashtable for gc. +*/ +c3_w +u3h_discount(u3p(u3h_root) har_p) +{ + c3_w tot_w = 0; + u3h_root* har_u = u3to(u3h_root, har_p); + c3_w i_w; + + for ( i_w = 0; i_w < 64; i_w++ ) { + c3_w sot_w = har_u->sot_w[i_w]; + + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + + tot_w += u3a_discount_noun(kev); + } + else if ( _(u3h_slot_is_node(sot_w)) ) { + u3h_node* han_u = u3h_slot_to_node(sot_w); + + tot_w += _ch_discount_node(han_u, 25); + } + } + + tot_w += u3a_discount_ptr(har_u); + + return tot_w; +} + +/* u3h_wyt(): number of entries +*/ +c3_w +u3h_wyt(u3p(u3h_root) har_p) +{ + u3h_root* har_u = u3to(u3h_root, har_p); + return har_u->use_w; +} diff --git a/vere/pkg/noun/hashtable.h b/vere/pkg/noun/hashtable.h new file mode 100644 index 0000000..f263dd8 --- /dev/null +++ b/vere/pkg/noun/hashtable.h @@ -0,0 +1,206 @@ +#ifndef U3_HASHTABLE_H +#define U3_HASHTABLE_H + +#include "c3/c3.h" +#include "types.h" + + /** Data structures. + **/ + /** Straightforward implementation of the classic Bagwell + *** HAMT (hash array mapped trie), using a mug hash. + *** + *** Because a mug is 31 bits, the root table has 64 slots. + *** The 31 bits of a mug are divided into the first lookup, + *** which is 6 bits (corresponding to the 64 entries in the + *** root table), followed by 5 more branchings of 5 bits each, + *** corresponding to the 32-slot nodes for everything under + *** the root node. + *** + *** We store an extra "freshly warm" bit and use it for a simple + *** clock-algorithm reclamation policy. + **/ + /* u3h_slot: map slot. + ** + ** Either a key-value cell or a loom offset, decoded as a pointer + ** to a u3h_node, or a u3h_buck at the bottom. Matches the u3_noun + ** format - coordinate with allocate.h. The top two bits are: + ** + ** 00 - empty (in the root table only) + ** 01 - table (node or buck) + ** 02 - entry, stale + ** 03 - entry, fresh + */ + typedef c3_w u3h_slot; + + /* u3h_node: map node. + */ + typedef struct { + c3_w map_w; // bitmap for [sot_w] + u3h_slot sot_w[]; // filled slots + } u3h_node; + + /* u3h_root: hash root table + */ + typedef struct { + c3_w max_w; // number of cache lines (0 for no trimming) + c3_w use_w; // number of lines currently filled + struct { + c3_w mug_w; // current hash + c3_w inx_w; // index into current hash bucket + c3_o buc_o; // XX remove + } arm_u; // clock arm + u3h_slot sot_w[64]; // slots + } u3h_root; + + /* u3h_buck: bottom bucket. + */ + typedef struct { + c3_w len_w; // length of [sot_w] + u3h_slot sot_w[]; // filled slots + } u3h_buck; + + /** HAMT macros. + *** + *** Coordinate with u3_noun definition! + **/ + /* u3h_slot_is_null(): yes iff slot is empty + ** u3h_slot_is_noun(): yes iff slot contains a key/value cell + ** u3h_slot_is_node(): yes iff slot contains a subtable/bucket + ** u3h_slot_is_warm(): yes iff fresh bit is set + ** u3h_slot_to_node(): slot to node pointer + ** u3h_node_to_slot(): node pointer to slot + ** u3h_slot_to_noun(): slot to cell + ** u3h_noun_to_slot(): cell to slot + ** u3h_noun_be_warm(): warm mutant + ** u3h_noun_be_cold(): cold mutant + */ +# define u3h_slot_is_null(sot) ((0 == ((sot) >> 30)) ? c3y : c3n) +# define u3h_slot_is_node(sot) ((1 == ((sot) >> 30)) ? c3y : c3n) +# define u3h_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? c3y : c3n) +# define u3h_slot_is_warm(sot) (((sot) & 0x40000000) ? c3y : c3n) +# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3a_vits)) +# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3a_vits) | 0x40000000) +# define u3h_noun_be_warm(sot) ((sot) | 0x40000000) +# define u3h_noun_be_cold(sot) ((sot) & ~0x40000000) +# define u3h_slot_to_noun(sot) (0x40000000 | (sot)) +# define u3h_noun_to_slot(som) (u3h_noun_be_warm(som)) + + /** Functions. + *** + *** Needs: delete and merge functions; clock reclamation function. + **/ + /* u3h_new_cache(): create hashtable with bounded size. + */ + u3p(u3h_root) + u3h_new_cache(c3_w clk_w); + + /* u3h_new(): create hashtable. + */ + u3p(u3h_root) + u3h_new(void); + + /* u3h_put(): insert in hashtable. + ** + ** `key` is RETAINED; `val` is transferred. + */ + void + u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val); + + /* u3h_put_get(): insert in caching hashtable, returning deleted entry + ** + ** `key` is RETAINED; `val` is transferred. + */ + u3_weak + u3h_put_get(u3p(u3h_root) har_p, u3_noun key, u3_noun val); + + /* u3h_uni(): unify hashtables, copying [rah_p] into [har_p] + */ + void + u3h_uni(u3p(u3h_root) har_p, u3p(u3h_root) rah_p); + + /* u3h_get(): read from hashtable. + ** + ** `key` is RETAINED; result is PRODUCED. + */ + u3_weak + u3h_get(u3p(u3h_root) har_p, u3_noun key); + + /* u3h_git(): read from hashtable, retaining result. + ** + ** `key` is RETAINED; result is RETAINED. + */ + u3_weak + u3h_git(u3p(u3h_root) har_p, u3_noun key); + + /* u3h_del(); delete from hashtable. + ** + ** `key` is RETAINED + */ + void + u3h_del(u3p(u3h_root) har_p, u3_noun key); + + /* u3h_trim_to(): trim to n key-value pairs + */ + void + u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w); + + /* u3h_trim_with(): trim to n key-value pairs, with deletion callback + */ + void + u3h_trim_with(u3p(u3h_root) har_p, c3_w n_w, void (*del_cb)(u3_noun)); + + /* u3h_free(): free hashtable. + */ + void + u3h_free(u3p(u3h_root) har_p); + + /* u3h_mark(): mark hashtable for gc. + */ + c3_w + u3h_mark(u3p(u3h_root) har_p); + + /* u3h_relocate(): relocate hashtable for compaction. + */ + void + u3h_relocate(u3p(u3h_root) *har_p); + + /* u3h_count(): count hashtable for gc. + */ + c3_w + u3h_count(u3p(u3h_root) har_p); + + /* u3h_discount(): discount hashtable for gc. + */ + c3_w + u3h_discount(u3p(u3h_root) har_p); + + /* u3h_walk_with(): traverse hashtable with key, value fn and data + * argument; RETAINS. + */ + void + u3h_walk_with(u3p(u3h_root) har_p, + void (*fun_f)(u3_noun, void*), + void* wit); + + /* u3h_walk(): u3h_walk_with, but with no data argument + */ + void + u3h_walk(u3p(u3h_root) har_p, void (*fun_f)(u3_noun)); + + /* u3h_take_with(): gain hashtable, copying junior keys + ** and calling [fun_f] on values + */ + u3p(u3h_root) + u3h_take_with(u3p(u3h_root) har_p, u3_funk fun_f); + + /* u3h_take(): gain hashtable, copying junior nouns + */ + u3p(u3h_root) + u3h_take(u3p(u3h_root) har_p); + + /* u3h_wyt(): number of entries + */ + c3_w + u3h_wyt(u3p(u3h_root) har_p); + +#endif /* ifndef U3_HASHTABLE_H */ diff --git a/vere/pkg/noun/hashtable_tests.c b/vere/pkg/noun/hashtable_tests.c new file mode 100644 index 0000000..9a5a3f8 --- /dev/null +++ b/vere/pkg/noun/hashtable_tests.c @@ -0,0 +1,301 @@ +/// @file + +#include "noun.h" +#define TEST_SIZE 100000 + +// defined in noun/hashtable.c +c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w); + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_init(1 << 27); + u3m_pave(c3y); +} + +/* _test_put_del(): +*/ +static c3_i +_test_put_del() +{ + u3p(u3h_root) har_p = u3h_new(); + c3_i ret_i = 1; + + c3_w i_w; + for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) { + u3_noun key = u3i_word(i_w); + u3_noun val = u3nc(u3_nul, u3k(key)); + u3h_put(har_p, key, val); + u3z(key); + } + // fprintf(stderr, "inserted\r\n"); + + for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) { + u3_noun key = u3i_word(i_w); + u3_weak val = u3h_get(har_p, key); + if ( val == u3_none ) { + fprintf(stderr, "failed insert\r\n"); + ret_i = 0; + } + u3z(key); + u3z(val); + } + // fprintf(stderr, "presence\r\n"); + c3_w del_w[4] = {30, 82, 4921, 535}; + + for ( i_w = 0; i_w < 4; i_w++ ) { + u3_noun key = u3i_word(del_w[i_w]); + u3h_del(har_p, key); + u3z(key); + } + // fprintf(stderr, "deleted\r\n"); + + for ( i_w = 0; i_w < 4; i_w++ ) { + u3_noun key = u3i_word(del_w[i_w]); + u3_weak val = u3h_get(har_p, key); + if ( u3_none != val ) { + fprintf(stderr, "failed delete\r\n"); + ret_i = 0; + break; + } + } + // fprintf(stderr, "presence two\r\n"); + u3h_free(har_p); + // fprintf(stderr, "freed\r\n"); + + return ret_i; +} + +/* _test_bit_manipulation(): +*/ +static c3_i +_test_bit_manipulation() +{ + c3_i ret_i = 1; + + if ( sizeof(u3_noun) != sizeof(u3h_slot) ) { + fprintf(stderr, "bit manipulation: wrong size\r\n"); + ret_i = 0; + } + + u3h_slot a = 0; + + if (u3h_slot_is_null(a) != c3y) { + fprintf(stderr, "bit manipulation: nullity\r\n"); + ret_i = 0; + } + + a = u3h_noun_be_warm(a); + if (u3h_slot_is_warm(a) != c3y) { + fprintf(stderr, "bit manipulation: warmth\r\n"); + ret_i = 0; + } + + if (u3h_slot_is_null(a) != c3n) { + fprintf(stderr, "bit manipulation: nullity 2\r\n"); + ret_i = 0; + } + + a = u3h_noun_be_cold(a); + if (u3h_slot_is_warm(a) != c3n) { + fprintf(stderr, "bit manipulation: coldness\r\n"); + ret_i = 0; + } + + return ret_i; +} + +/* _test_no_cache(): test a hashtable without caching. +*/ +static c3_i +_test_no_cache(void) +{ + c3_i ret_i = 1; + c3_w max_w = 1000; + c3_w i_w; + + u3p(u3h_root) har_p = u3h_new(); + + for ( i_w = 0; i_w < max_w; i_w++ ) { + u3h_put(har_p, i_w, i_w + max_w); + } + + for ( i_w = 0; i_w < max_w; i_w++ ) { + if ( (i_w + max_w) != u3h_get(har_p, i_w) ) { + fprintf(stderr, "bit test_no_cache: get failed\r\n"); + ret_i = 0; + } + } + + u3h_free(har_p); + return ret_i; +} + +/* _test_skip_slot(): +*/ +static c3_i +_test_skip_slot(void) +{ + c3_i ret_i = 1; + + // root table + { + c3_w mug_w = 0x17 << 25; + c3_w res_w = _ch_skip_slot(mug_w, 25); + + if ( (0x18 << 25) != res_w ) { + fprintf(stderr, "bit skip_slot (a): failed\r\n"); + ret_i = 0; + } + } + + { + c3_w mug_w = 63 << 25; // 6 bits, all ones + c3_w res_w = _ch_skip_slot(mug_w, 25); + + if ( 0 != res_w ) { + fprintf(stderr, "bit skip_slot (b): failed\r\n"); + ret_i = 0; + } + } + + // child nodes + { + c3_w mug_w = 17 << 20; + c3_w res_w = _ch_skip_slot(mug_w, 20); + + if ( (18 << 20) != res_w ) { + fprintf(stderr, "bit skip_slot (c): failed\r\n"); + ret_i = 0; + } + } + + { + c3_w mug_w = 31 << 20; // 5 bits, all ones + c3_w res_w = _ch_skip_slot(mug_w, 20); + u3_assert((1 << 25) == res_w); + + if ( (1 << 25) != res_w ) { + fprintf(stderr, "bit skip_slot (d): failed\r\n"); + ret_i = 0; + } + } + + return ret_i; +} + +/* _test_cache_trimming(): ensure a caching hashtable removes stale items. +*/ +static c3_i +_test_cache_trimming(void) +{ + c3_i ret_i = 1; + c3_w max_w = 2000000; // big number + //c3_w max_w = 348000; // caused a leak before + c3_w i_w, fil_w = max_w / 10; + + u3p(u3h_root) har_p = u3h_new_cache(fil_w); + u3h_root* har_u = u3to(u3h_root, har_p); + + for ( i_w = 0; i_w < max_w; i_w++ ) { + u3_noun cel = u3nc(i_w, i_w); + u3h_put(har_p, cel, cel); + } + + { + // last thing we put in is still there + c3_w las_w = max_w - 1; + u3_noun key = u3nc(las_w, las_w); + u3_noun val = u3h_get(har_p, key); + u3z(key); + + if ( las_w != u3t(val) ) { + fprintf(stderr, "cache_trimming (a): fail\r\n"); + ret_i = 0; + } + + if ( fil_w != har_u->use_w ) { + fprintf(stderr, "cache_trimming (b): fail %d != %d\r\n", + fil_w, har_u->use_w ); + ret_i = 0; + } + + u3z(val); + } + + u3h_free(har_p); + return ret_i; +} + +/* _test_cache_replace_value(): +*/ +static c3_i +_test_cache_replace_value(void) +{ + c3_i ret_i = 1; + c3_w max_w = 100; + c3_w i_w; + + u3p(u3h_root) har_p = u3h_new_cache(max_w); + u3h_root* har_u = u3to(u3h_root, har_p); + + for ( i_w = 0; i_w < max_w; i_w++ ) { + u3h_put(har_p, i_w, i_w + max_w); + } + + for ( i_w = 0; i_w < max_w; i_w++ ) { + u3h_put(har_p, i_w, i_w + max_w + 1); + } + + if ( (2 * max_w) != u3h_get(har_p, max_w - 1) ) { + fprintf(stderr, "cache_replace (a): fail\r\n"); + ret_i = 0; + } + if ( max_w != har_u->use_w ) { + fprintf(stderr, "cache_replace (b): fail\r\n"); + fprintf(stderr, "cache_replace (b): fail %d %d\r\n", + max_w, har_u->use_w ); + ret_i = 0; + } + + u3h_free(har_p); + return ret_i; +} + +static c3_i +_test_hashtable(void) +{ + c3_i ret_i = 1; + + ret_i &= _test_bit_manipulation(); + ret_i &= _test_no_cache(); + ret_i &= _test_skip_slot(); + ret_i &= _test_cache_trimming(); + ret_i &= _test_cache_replace_value(); + ret_i &= _test_put_del(); + + return ret_i; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_hashtable() ) { + fprintf(stderr, "test_hashtable: failed\r\n"); + exit(1); + } + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "test_hashtable: ok\r\n"); + + return 0; +} diff --git a/vere/pkg/noun/imprison.c b/vere/pkg/noun/imprison.c new file mode 100644 index 0000000..c182d95 --- /dev/null +++ b/vere/pkg/noun/imprison.c @@ -0,0 +1,772 @@ +/// @file + +#include "imprison.h" + +#include "jets/k.h" +#include "jets/q.h" +#include "manage.h" +#include "retrieve.h" +#include "trace.h" +#include "xtract.h" + +/* _ci_slab_size(): calculate slab bloq-size, checking for overflow. +*/ +static c3_w +_ci_slab_size(c3_g met_g, c3_d len_d) +{ + c3_d bit_d = len_d << met_g; + c3_d wor_d = (bit_d + 0x1f) >> 5; + c3_w wor_w = (c3_w)wor_d; + + if ( (wor_w != wor_d) + || (len_d != (bit_d >> met_g)) ) + { + return (c3_w)u3m_bail(c3__fail); + } + + return wor_w; +} + +/* _ci_slab_init(): initialize slab with heap allocation. +** NB: callers must ensure [len_w] >0 +*/ +static void +_ci_slab_init(u3i_slab* sab_u, c3_w len_w) +{ + c3_w* nov_w = u3a_walloc(len_w + c3_wiseof(u3a_atom)); + u3a_atom* vat_u = (void *)nov_w; + + vat_u->use_w = 1; + vat_u->mug_w = 0; + vat_u->len_w = len_w; + +#ifdef U3_MEMORY_DEBUG + u3_assert( len_w ); +#endif + + sab_u->_._vat_u = vat_u; + sab_u->buf_w = vat_u->buf_w; + sab_u->len_w = len_w; +} + +/* _ci_slab_grow(): update slab with heap reallocation. +*/ +static void +_ci_slab_grow(u3i_slab* sab_u, c3_w len_w) +{ + c3_w* old_w = (void*)sab_u->_._vat_u; + // XX implement a more efficient u3a_wealloc() + // + c3_w* nov_w = u3a_wealloc(old_w, len_w + c3_wiseof(u3a_atom)); + u3a_atom* vat_u = (void *)nov_w; + + vat_u->len_w = len_w; + + sab_u->_._vat_u = vat_u; + sab_u->buf_w = vat_u->buf_w; + sab_u->len_w = len_w; +} + +/* _ci_atom_mint(): finalize a heap-allocated atom at specified length. +*/ +static u3_atom +_ci_atom_mint(u3a_atom* vat_u, c3_w len_w) +{ + c3_w* nov_w = (void*)vat_u; + + if ( 0 == len_w ) { + u3a_wfree(nov_w); + return (u3_atom)0; + } + else if ( 1 == len_w ) { + c3_w dat_w = *vat_u->buf_w; + + if ( c3y == u3a_is_cat(dat_w) ) { + u3a_wfree(nov_w); + return (u3_atom)dat_w; + } + } + + // try to strip a block off the end + // + { + c3_w old_w = vat_u->len_w; + + if ( old_w > len_w ) { + c3_y wiz_y = c3_wiseof(u3a_atom); + u3a_wtrim(nov_w, old_w + wiz_y, len_w + wiz_y); + } + } + + vat_u->len_w = len_w; + + return u3a_to_pug(u3a_outa(nov_w)); +} + +/* u3i_slab_init(): configure bloq-length slab, zero-initialize. +*/ +void +u3i_slab_init(u3i_slab* sab_u, c3_g met_g, c3_d len_d) +{ + u3i_slab_bare(sab_u, met_g, len_d); + + u3t_on(mal_o); + memset(sab_u->buf_y, 0, (size_t)sab_u->len_w * 4); + u3t_off(mal_o); +} + +/* u3i_slab_bare(): configure bloq-length slab, uninitialized. +*/ +void +u3i_slab_bare(u3i_slab* sab_u, c3_g met_g, c3_d len_d) +{ + u3t_on(mal_o); + { + c3_w wor_w = _ci_slab_size(met_g, len_d); + + // if we only need one word, use the static storage in [sab_u] + // + if ( (0 == wor_w) || (1 == wor_w) ) { + sab_u->_._vat_u = 0; + sab_u->buf_w = &sab_u->_._sat_w; + sab_u->len_w = 1; + } + // allocate an indirect atom + // + else { + _ci_slab_init(sab_u, wor_w); + } + } + u3t_off(mal_o); +} + +/* u3i_slab_from(): configure bloq-length slab, initialize with [a]. +*/ +void +u3i_slab_from(u3i_slab* sab_u, u3_atom a, c3_g met_g, c3_d len_d) +{ + u3i_slab_bare(sab_u, met_g, len_d); + + // copies [a], zero-initializes any additional space + // + u3r_words(0, sab_u->len_w, sab_u->buf_w, a); + + // if necessary, mask off extra most-significant bits + // from most-significant word + // + if ( (5 > met_g) && (u3r_met(5, a) >= sab_u->len_w) ) { + // NB: overflow already checked in _ci_slab_size() + // + c3_d bit_d = len_d << met_g; + c3_w wor_w = bit_d >> 5; + c3_w bit_w = bit_d & 0x1f; + + if ( bit_w ) { + sab_u->buf_w[wor_w] &= ((c3_w)1 << bit_w) - 1; + } + } +} + +/* u3i_slab_grow(): resize slab, zero-initializing new space. +*/ +void +u3i_slab_grow(u3i_slab* sab_u, c3_g met_g, c3_d len_d) +{ + c3_w old_w = sab_u->len_w; + + u3t_on(mal_o); + { + c3_w wor_w = _ci_slab_size(met_g, len_d); + + // XX actually shrink? + // + if ( wor_w <= old_w ) { + sab_u->len_w = wor_w; + } + else { + // upgrade from static storage + // + if ( 1 == old_w ) { + c3_w dat_w = *sab_u->buf_w; + + _ci_slab_init(sab_u, wor_w); + sab_u->buf_w[0] = dat_w; + } + // reallocate + // + else { + _ci_slab_grow(sab_u, wor_w); + } + + { + c3_y* buf_y = (void*)(sab_u->buf_w + old_w); + size_t dif_i = wor_w - old_w; + memset(buf_y, 0, dif_i * 4); + } + } + } + u3t_off(mal_o); +} + +/* u3i_slab_free(): dispose memory backing slab. +*/ +void +u3i_slab_free(u3i_slab* sab_u) +{ + c3_w len_w = sab_u->len_w; + u3a_atom* vat_u = sab_u->_._vat_u; + + u3t_on(mal_o); + + if ( 1 == len_w ) { + u3_assert( !vat_u ); + } + else { + c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom)); + u3_assert( tav_w == (c3_w*)vat_u ); + u3a_wfree(vat_u); + } + + u3t_off(mal_o); +} + +/* u3i_slab_mint(): produce atom from slab, trimming. +*/ +u3_atom +u3i_slab_mint(u3i_slab* sab_u) +{ + c3_w len_w = sab_u->len_w; + u3a_atom* vat_u = sab_u->_._vat_u; + u3_atom pro; + + u3t_on(mal_o); + + if ( 1 == len_w ) { + c3_w dat_w = *sab_u->buf_w; + + u3_assert( !vat_u ); + + u3t_off(mal_o); + pro = u3i_word(dat_w); + u3t_on(mal_o); + } + else { + u3a_atom* vat_u = sab_u->_._vat_u; + c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom)); + u3_assert( tav_w == (c3_w*)vat_u ); + + // trim trailing zeros + // + while ( len_w && !(sab_u->buf_w[len_w - 1]) ) { + len_w--; + } + + pro = _ci_atom_mint(vat_u, len_w); + } + + u3t_off(mal_o); + + return pro; +} + +/* u3i_slab_moot(): produce atom from slab, no trimming. +*/ +u3_atom +u3i_slab_moot(u3i_slab* sab_u) +{ + c3_w len_w = sab_u->len_w; + u3_atom pro; + + u3t_on(mal_o); + + if ( 1 == len_w) { + c3_w dat_w = *sab_u->buf_w; + + u3_assert( !sab_u->_._vat_u ); + + u3t_off(mal_o); + pro = u3i_word(dat_w); + u3t_on(mal_o); + } + else { + u3a_atom* vat_u = sab_u->_._vat_u; + c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom)); + u3_assert( tav_w == (c3_w*)vat_u ); + + pro = _ci_atom_mint(vat_u, len_w); + } + + u3t_off(mal_o); + + return pro; +} + +/* u3i_word(): construct u3_atom from c3_w. +*/ +u3_atom +u3i_word(c3_w dat_w) +{ + u3_atom pro; + + u3t_on(mal_o); + + if ( c3y == u3a_is_cat(dat_w) ) { + pro = (u3_atom)dat_w; + } + else { + c3_w* nov_w = u3a_walloc(1 + c3_wiseof(u3a_atom)); + u3a_atom* vat_u = (void *)nov_w; + + vat_u->use_w = 1; + vat_u->mug_w = 0; + vat_u->len_w = 1; + vat_u->buf_w[0] = dat_w; + + pro = u3a_to_pug(u3a_outa(nov_w)); + } + + u3t_off(mal_o); + + return pro; +} + +/* u3i_chub(): construct u3_atom from c3_d. +*/ +u3_atom +u3i_chub(c3_d dat_d) +{ + if ( c3y == u3a_is_cat(dat_d) ) { + return (u3_atom)dat_d; + } + else { + c3_w dat_w[2] = { + dat_d & 0xffffffffULL, + dat_d >> 32 + }; + + return u3i_words(2, dat_w); + } +} + +/* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom. +*/ +u3_atom +u3i_bytes(c3_w a_w, + const c3_y* b_y) +{ + // strip trailing zeroes. + // + while ( a_w && !b_y[a_w - 1] ) { + a_w--; + } + + if ( !a_w ) { + return (u3_atom)0; + } + else { + u3i_slab sab_u; + + u3i_slab_bare(&sab_u, 3, a_w); + + u3t_on(mal_o); + { + // zero-initialize last word + // + sab_u.buf_w[sab_u.len_w - 1] = 0; + memcpy(sab_u.buf_y, b_y, a_w); + } + u3t_off(mal_o); + + return u3i_slab_moot_bytes(&sab_u); + } +} + +/* u3i_words(): Copy [a] words from [b] into an atom. +*/ +u3_atom +u3i_words(c3_w a_w, + const c3_w* b_w) +{ + // strip trailing zeroes. + // + while ( a_w && !b_w[a_w - 1] ) { + a_w--; + } + + if ( !a_w ) { + return (u3_atom)0; + } + else { + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 5, a_w); + + u3t_on(mal_o); + memcpy(sab_u.buf_w, b_w, (size_t)4 * a_w); + u3t_off(mal_o); + + return u3i_slab_moot(&sab_u); + } +} + +/* u3i_chubs(): Copy [a] chubs from [b] into an atom. +*/ +u3_atom +u3i_chubs(c3_w a_w, + const c3_d* b_d) +{ + // strip trailing zeroes. + // + while ( a_w && !b_d[a_w - 1] ) { + a_w--; + } + + if ( !a_w ) { + return (u3_atom)0; + } + else if ( 1 == a_w ) { + return u3i_chub(b_d[0]); + } + else { + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 6, a_w); + + u3t_on(mal_o); + { + c3_w* buf_w = sab_u.buf_w; + c3_w i_w; + c3_d i_d; + + for ( i_w = 0; i_w < a_w; i_w++ ) { + i_d = b_d[i_w]; + *buf_w++ = i_d & 0xffffffffULL; + *buf_w++ = i_d >> 32; + } + } + u3t_off(mal_o); + + return u3i_slab_mint(&sab_u); + } +} + +/* u3i_mp(): Copy the GMP integer [a] into an atom, and clear it. +*/ +u3_atom +u3i_mp(mpz_t a_mp) +{ + size_t siz_i = mpz_sizeinbase(a_mp, 2); + u3i_slab sab_u; + u3i_slab_init(&sab_u, 0, siz_i); + + mpz_export(sab_u.buf_w, 0, -1, sizeof(c3_w), 0, 0, a_mp); + mpz_clear(a_mp); + + // per the mpz_export() docs: + // + // > If op is non-zero then the most significant word produced + // > will be non-zero. + // + return u3i_slab_moot(&sab_u); +} + +/* u3i_vint(): increment [a]. +*/ +u3_atom +u3i_vint(u3_noun a) +{ + u3_assert(u3_none != a); + + if ( _(u3a_is_cat(a)) ) { + return ( a == 0x7fffffff ) ? u3i_word(a + 1) : (a + 1); + } + else if ( _(u3a_is_cell(a)) ) { + return u3m_bail(c3__exit); + } + else { + mpz_t a_mp; + + u3r_mp(a_mp, a); + u3z(a); + + mpz_add_ui(a_mp, a_mp, 1); + return u3i_mp(a_mp); + } +} + +/* u3i_defcons(): allocate cell for deferred construction. +** NB: [hed] and [tel] pointers MUST be filled. +*/ +u3_cell +u3i_defcons(u3_noun** hed, u3_noun** tel) +{ + u3_noun pro; + + u3t_on(mal_o); + { + c3_w* nov_w = u3a_celloc(); + u3a_cell* nov_u = (void *)nov_w; + + nov_u->use_w = 1; + nov_u->mug_w = 0; + +#ifdef U3_MEMORY_DEBUG + nov_u->hed = u3_none; + nov_u->tel = u3_none; +#endif + + *hed = &nov_u->hed; + *tel = &nov_u->tel; + + pro = u3a_to_pom(u3a_outa(nov_w)); + } + u3t_off(mal_o); + + return pro; +} + +/* u3i_cell(): Produce the cell `[a b]`. +*/ +u3_noun +u3i_cell(u3_noun a, u3_noun b) +{ + u3_noun pro; + + u3t_on(mal_o); + { + c3_w* nov_w = u3a_celloc(); + u3a_cell* nov_u = (void *)nov_w; + + nov_u->use_w = 1; + nov_u->mug_w = 0; + nov_u->hed = a; + nov_u->tel = b; + + pro = u3a_to_pom(u3a_outa(nov_w)); + } + u3t_off(mal_o); + + return pro; +} + +/* u3i_trel(): Produce the triple `[a b c]`. +*/ +u3_noun +u3i_trel(u3_noun a, u3_noun b, u3_noun c) +{ + return u3i_cell(a, u3i_cell(b, c)); +} + +/* u3i_qual(): Produce the cell `[a b c d]`. +*/ +u3_noun +u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d) +{ + return u3i_cell(a, u3i_trel(b, c, d)); +} + +/* u3i_string(): Produce an LSB-first atom from the C string [a]. +*/ +u3_atom +u3i_string(const c3_c* a_c) +{ + return u3i_bytes(strlen(a_c), (c3_y *)a_c); +} + +/* u3i_tape(): from a C string, to a list of bytes. +*/ +u3_noun +u3i_tape(const c3_c* txt_c) +{ + if ( !*txt_c ) { + return u3_nul; + } else return u3i_cell(*txt_c, u3i_tape(txt_c + 1)); +} + +/* u3i_list(): list from `u3_none`-terminated varargs. +*/ +u3_noun +u3i_list(u3_weak som, ...) +{ + u3_noun lit = u3_nul; + va_list ap; + + if ( u3_none == som ) { + return lit; + } + else { + lit = u3nc(som, lit); + } + + { + u3_noun tem; + + va_start(ap, som); + while ( 1 ) { + if ( u3_none == (tem = va_arg(ap, u3_weak)) ) { + break; + } + else { + lit = u3nc(tem, lit); + } + } + va_end(ap); + } + + return u3kb_flop(lit); +} + +/* u3i_edit(): +** +** Mutate `big` at axis `axe` with new value `som`. +** `axe` is RETAINED. +*/ +u3_noun +u3i_edit(u3_noun big, u3_noun axe, u3_noun som) +{ + u3_noun pro; + u3_noun* out = &pro; + + switch ( axe ) { + case 0: return u3m_bail(c3__exit); + case 1: break; + + default: { + c3_w dep_w = u3r_met(0, u3x_atom(axe)) - 2; + const c3_w* axe_w = ( c3y == u3a_is_cat(axe) ) + ? &axe + : ((u3a_atom*)u3a_to_ptr(axe))->buf_w; + + do { + u3a_cell* big_u = u3a_to_ptr(big); + u3_noun* old = (u3_noun*)&(big_u->hed); + const c3_y bit_y = 1 & (axe_w[dep_w >> 5] >> (dep_w & 31)); + + if ( c3n == u3a_is_cell(big) ) { + return u3m_bail(c3__exit); + } + else if ( c3y == u3a_is_mutable(u3R, big) ) { + *out = big; + out = &(old[bit_y]); + big = *out; + big_u->mug_w = 0; + } + else { + u3_noun luz = big; + u3_noun* new[2]; + + *out = u3i_defcons(&new[0], &new[1]); + out = new[bit_y]; + big = u3k(old[bit_y]); + *(new[!bit_y]) = u3k(old[!bit_y]); + + u3z(luz); + } + } + while ( dep_w-- ); + } + } + + u3z(big); + *out = som; + return pro; +} + +/* u3i_molt(): +** +** Mutate `som` with a 0-terminated list of axis, noun pairs. +** Axes must be cats (31 bit). +*/ + struct _molt_pair { + c3_w axe_w; + u3_noun som; + }; + + static c3_w + _molt_cut(c3_w len_w, + struct _molt_pair* pms_m) + { + c3_w i_w, cut_t, cut_w; + + cut_t = 0; + cut_w = 0; + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w axe_w = pms_m[i_w].axe_w; + + if ( (cut_t == 0) && (3 == u3x_cap(axe_w)) ) { + cut_t = 1; + cut_w = i_w; + } + pms_m[i_w].axe_w = u3x_mas(axe_w); + } + return cut_t ? cut_w : i_w; + } + + static u3_noun // transfer + _molt_apply(u3_noun som, // retain + c3_w len_w, + struct _molt_pair* pms_m) // transfer + { + if ( len_w == 0 ) { + return u3k(som); + } + else if ( (len_w == 1) && (1 == pms_m[0].axe_w) ) { + return pms_m[0].som; + } + else { + c3_w cut_w = _molt_cut(len_w, pms_m); + + if ( c3n == u3a_is_cell(som) ) { + return u3m_bail(c3__exit); + } + else { + return u3i_cell + (_molt_apply(u3a_h(som), cut_w, pms_m), + _molt_apply(u3a_t(som), (len_w - cut_w), (pms_m + cut_w))); + } + } + } + +u3_noun +u3i_molt(u3_noun som, ...) +{ + va_list ap; + c3_w len_w; + struct _molt_pair* pms_m; + u3_noun pro; + + // Count. + // + len_w = 0; + { + va_start(ap, som); + while ( 1 ) { + if ( 0 == va_arg(ap, c3_w) ) { + break; + } + va_arg(ap, u3_weak*); + len_w++; + } + va_end(ap); + } + + u3_assert( 0 != len_w ); + pms_m = alloca(len_w * sizeof(struct _molt_pair)); + + // Install. + // + { + c3_w i_w; + + va_start(ap, som); + for ( i_w = 0; i_w < len_w; i_w++ ) { + pms_m[i_w].axe_w = va_arg(ap, c3_w); + pms_m[i_w].som = va_arg(ap, u3_noun); + } + va_end(ap); + } + + // Apply. + // + pro = _molt_apply(som, len_w, pms_m); + u3z(som); + return pro; +} diff --git a/vere/pkg/noun/imprison.h b/vere/pkg/noun/imprison.h new file mode 100644 index 0000000..6d2dcb1 --- /dev/null +++ b/vere/pkg/noun/imprison.h @@ -0,0 +1,170 @@ +/// @file + +#ifndef U3_IMPRISON_H +#define U3_IMPRISON_H + +#include "allocate.h" +#include "c3/c3.h" +#include "gmp.h" +#include "types.h" + + /** Structures. + **/ + /* u3i_slab: atom builder. + */ + typedef struct _u3i_slab { + struct { // internals + u3a_atom* _vat_u; // heap atom (nullable) + c3_w _sat_w; // static storage + } _; // + union { // + c3_y* buf_y; // bytes + c3_w* buf_w; // words + }; // + c3_w len_w; // word length + } u3i_slab; + + /* staged atom-building api + */ + /* u3i_slab_init(): configure bloq-length slab, zero-initialize. + */ + void + u3i_slab_init(u3i_slab* sab_u, c3_g met_g, c3_d len_d); + + /* u3i_slab_bare(): configure bloq-length slab, uninitialized. + */ + void + u3i_slab_bare(u3i_slab* sab_u, c3_g met_g, c3_d len_d); + + /* u3i_slab_from(): configure bloq-length slab, initialize with [a]. + */ + void + u3i_slab_from(u3i_slab* sab_u, u3_atom a, c3_g met_g, c3_d len_d); + + /* u3i_slab_grow(): resize slab, zero-initializing new space. + */ + void + u3i_slab_grow(u3i_slab* sab_u, c3_g met_g, c3_d len_d); + + /* u3i_slab_free(): dispose memory backing slab. + */ + void + u3i_slab_free(u3i_slab* sab_u); + + /* u3i_slab_mint(): produce atom from slab, trimming. + */ + u3_atom + u3i_slab_mint(u3i_slab* sab_u); + + /* u3i_slab_moot(): produce atom from slab, no trimming. + */ + u3_atom + u3i_slab_moot(u3i_slab* sab_u); + + /* u3i_slab_mint_bytes(): produce atom from byte-slab, trimming. + ** XX assumes little-endian, implement swap to support big-endian + */ +# define u3i_slab_mint_bytes u3i_slab_mint + + /* u3i_slab_moot_bytes(): produce atom from byte-slab, no trimming. + ** XX assumes little-endian, implement swap to support big-endian + */ +# define u3i_slab_moot_bytes u3i_slab_moot + + /* General constructors. + */ + /* u3i_word(): construct u3_atom from c3_w. + */ + u3_atom + u3i_word(c3_w dat_w); + + /* u3i_chub(): construct u3_atom from c3_d. + */ + u3_atom + u3i_chub(c3_d dat_d); + + /* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom. + */ + u3_atom + u3i_bytes(c3_w a_w, + const c3_y* b_y); + + /* u3i_words(): Copy [a] words from [b] into an atom. + */ + u3_atom + u3i_words(c3_w a_w, + const c3_w* b_w); + + /* u3i_chubs(): Copy [a] chubs from [b] into an atom. + */ + u3_atom + u3i_chubs(c3_w a_w, + const c3_d* b_d); + + /* u3i_mp(): Copy the GMP integer [a] into an atom, and clear it. + */ + u3_atom + u3i_mp(mpz_t a_mp); + + /* u3i_vint(): increment [a]. + */ + u3_atom + u3i_vint(u3_noun a); + + /* u3i_cell(): Produce the cell `[a b]`. + */ + u3_noun + u3i_cell(u3_noun a, u3_noun b); +# define u3nc(a, b) u3i_cell(a, b) + + /* u3i_defcons(): allocate cell for deferred construction. + ** NB: [hed] and [tel] pointers MUST be filled. + */ + u3_cell + u3i_defcons(u3_noun** hed, u3_noun** tel); + + /* u3i_trel(): Produce the triple `[a b c]`. + */ + u3_noun + u3i_trel(u3_noun a, u3_noun b, u3_noun c); +# define u3nt(a, b, c) u3i_trel(a, b, c) + + /* u3i_qual(): Produce the cell `[a b c d]`. + */ + u3_noun + u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d); +# define u3nq(a, b, c, d) u3i_qual(a, b, c, d) + + /* u3i_string(): Produce an LSB-first atom from the C string [a]. + */ + u3_atom + u3i_string(const c3_c* a_c); + + /* u3i_tape(): from a C string, to a list of bytes. + */ + u3_noun + u3i_tape(const c3_c* txt_c); + + /* u3i_list(): list from `u3_none`-terminated varargs. + */ + u3_noun + u3i_list(u3_weak som, ...); +# define u3nl u3i_list + + /* u3i_edit(): + ** + ** Mutate `big` at axis `axe` with new value `som` + ** `axe` is RETAINED. + */ + u3_noun + u3i_edit(u3_noun big, u3_noun axe, u3_noun som); + + /* u3i_molt(): + ** + ** Mutate `som` with a 0-terminated list of axis, noun pairs. + ** Axes must be cats (31 bit). + */ + u3_noun + u3i_molt(u3_noun som, ...); + +#endif /* ifndef U3_IMPRISON_H */ diff --git a/vere/pkg/noun/jets.c b/vere/pkg/noun/jets.c new file mode 100644 index 0000000..3598364 --- /dev/null +++ b/vere/pkg/noun/jets.c @@ -0,0 +1,2445 @@ +/// @file + +#include "jets.h" + +#include "allocate.h" +#include "hashtable.h" +#include "imprison.h" +#include "jets/k.h" +#include "jets/q.h" +#include "log.h" +#include "manage.h" +#include "nock.h" +#include "options.h" +#include "retrieve.h" +#include "serial.h" +#include "trace.h" +#include "urcrypt.h" +#include "vortex.h" +#include "xtract.h" + + +/** Functions. +**/ + +/* _cj_count(): count and link dashboard entries. +*/ +static c3_w +_cj_count(u3j_core* par_u, u3j_core* dev_u) +{ + c3_w len_l = 0; + c3_w i_w; + + if ( dev_u ) { + for ( i_w = 0; 0 != dev_u[i_w].cos_c; i_w++ ) { + u3j_core* kid_u = &dev_u[i_w]; + + if ( par_u ) { + kid_u->par_u = par_u; + } + len_l += _cj_count(kid_u, kid_u->dev_u); + } + } + return 1 + len_l; +} + +/* _cj_core_loc(): location noun from u3j_core. + */ +static u3_noun +_cj_core_loc(u3_noun pel, u3j_core* cop_u) +{ + c3_w i_w; + u3_noun nam = u3i_string(cop_u->cos_c), + huc = u3_nul, + pat; + + if ( cop_u->huc_u ) { + for ( i_w = 0; 0 != cop_u->huc_u[i_w].nam_c; ++i_w ) { + u3j_hood* huc_u = &(cop_u->huc_u[i_w]); + u3_noun fol = ( c3n == huc_u->kic_o ) + ? u3nc(0, huc_u->axe_l) + : u3nt(9, huc_u->axe_l, u3nc(0, + (0 == huc_u->sax_l) ? 1 : huc_u->sax_l)); + huc = u3kdb_put(huc, u3i_string(huc_u->nam_c), fol); + } + } + + pat = ( 0 == cop_u->axe_l ) + ? u3nt(c3y, c3y, pel) + : ( (3 == cop_u->axe_l) && (c3y == u3h(u3h(pel))) ) + ? u3nt(c3y, c3n, pel) + : u3nt(c3n, cop_u->axe_l, pel); + + return u3nt(pat, nam, huc); +} + +/* _cj_hash(): noun from pasted-in battery hash + */ +static u3_noun +_cj_hash(c3_c* has_c) +{ + c3_w i_w, len_w = strlen(has_c); + if ( 64 != len_w ) { + u3l_log("bash not 64 characters: %s", has_c); + u3_assert(0); + } + u3_assert( 64 == len_w ); + c3_y dig_y[32]; + for ( i_w = 0; i_w < 64; ) { + c3_y hi_y = has_c[i_w++], + lo_y = has_c[i_w++], + hid_y = hi_y >= 'a' ? (hi_y - 'a') + 10 : hi_y - '0', + lod_y = lo_y >= 'a' ? (lo_y - 'a') + 10 : lo_y - '0'; + dig_y[32-(i_w>>1)] = hid_y << 4 | lod_y; + } + u3_noun pro = u3i_bytes(32, dig_y); + return pro; +} + +// in the jam jet file +c3_w* u3qe_jam_buf(u3_noun, c3_w* bit_w); + +/* _cj_bash(): battery hash. RETAIN. + */ +static u3_noun +_cj_bash(u3_noun bat) +{ + if ( u3C.wag_w & u3o_hashless ) { + return u3_nul; + } + + u3_weak pro; + u3a_road* rod_u = u3R; + while ( 1 ) { + pro = u3h_get(rod_u->jed.bas_p, bat); + + if ( u3_none != pro ) { + break; + } + + if ( rod_u->par_p ) { + rod_u = u3to(u3_road, rod_u->par_p); + } + else { + u3i_slab sab_u; + c3_w bit_w = u3s_jam_fib(&sab_u, bat); + c3_w met_w = (bit_w + 0x7) >> 3; + // XX assumes little-endian + // + c3_y* fat_y = sab_u.buf_y; + c3_y dig_y[32]; + urcrypt_shay(fat_y, met_w, dig_y); + + pro = u3i_bytes(32, dig_y); + u3h_put(u3R->jed.bas_p, bat, u3k(pro)); + u3i_slab_free(&sab_u); + break; + } + } + return pro; +} + +/* _cj_mine_par_old(): register hooks and parent location within existing + * axis in ancestor list or u3_none. + */ +static u3_weak +_cj_mine_par_old(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) +{ + u3_noun par; + u3_weak pro; + + if ( u3_nul == lan ) { + pro = u3_none; + u3z(axe); u3z(pel); u3z(loc); + } + else if ( c3y == u3r_sing(axe, u3h(par = u3h(lan))) ) { + u3_noun lol = u3kdb_put(u3k(u3t(par)), pel, loc), + rap = u3nc(axe, lol); + pro = u3nc(rap, u3k(u3t(lan))); + } + else { + u3_weak nex = _cj_mine_par_old(u3k(u3t(lan)), axe, pel, loc); + if ( u3_none == nex ) { + pro = u3_none; + } + else { + pro = u3nc(u3k(par), nex); + } + } + + u3z(lan); + return pro; +} + +/* _cj_mine_par_new(): insert ancestor within lan at sorted index. + */ +static u3_noun +_cj_mine_par_new(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) +{ + u3_weak pro; + + if ( (u3_nul == lan) || (c3y == u3qa_lth(axe, u3h(u3h(lan)))) ) { + u3_noun par = u3nc(axe, u3kdb_put(u3_nul, pel, loc)); + pro = u3nc(par, lan); + } + else { + pro = u3nc(u3k(u3h(lan)), + _cj_mine_par_new(u3k(u3t(lan)), axe, pel, loc)); + u3z(lan); + } + + return pro; +} + +/* _cj_mine_par(): register a location as an ancestor + * in a list of ancestors. + */ +static u3_noun +_cj_mine_par(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) +{ + u3_weak old = _cj_mine_par_old(u3k(lan), u3k(axe), u3k(pel), u3k(loc)); + if ( u3_none != old ) { + u3z(lan); u3z(axe); u3z(pel); u3z(loc); + return old; + } + else { + return _cj_mine_par_new(lan, axe, pel, loc); + } +} + + +/* _cj_gust(): add location to registry. +*/ +static u3_noun +_cj_gust(u3_weak reg, u3_noun axe, u3_noun pel, u3_noun loc) +{ + u3_noun ger; + if ( u3_none == reg ) { + reg = u3nc(u3_nul, u3_nul); + } + + ger = ( 0 == axe ) + ? u3nc(u3kdb_put(u3k(u3h(reg)), pel, loc), u3k(u3t(reg))) + : u3nc(u3k(u3h(reg)), _cj_mine_par(u3k(u3t(reg)), axe, pel, loc)); + + u3z(reg); + return ger; +} + +/* _cj_axis(): axis from formula, or 0. `fol` is RETAINED. +*/ +static c3_l +_cj_axis(u3_noun fol) +{ + u3_noun p_fol, q_fol, r_fol; + + while ( _(u3du(fol)) && (11 == u3h(fol)) ) + { fol = u3t(u3t(fol)); } + + if ( !_(u3r_trel(fol, &p_fol, &q_fol, &r_fol)) ) { + if ( !_(u3r_cell(fol, &p_fol, &q_fol)) || + (0 != p_fol) || + (!_(u3a_is_cat(q_fol))) ) + { + u3l_log("axis: bad a"); + return 0; + } + return q_fol; + } + else { + if ( 9 != p_fol ) + { u3l_log("axis: bad b"); return 0; } + if ( !_(u3a_is_cat(q_fol)) ) + { u3l_log("axis: bad c"); return 0; } + if ( !_(u3du(r_fol)) || (0 != u3h(r_fol)) || (1 != u3t(r_fol)) ) + { u3l_log("axis: bad d"); return 0; } + + return q_fol; + } +} + +/* _cj_warm_hump(): generate axis-to-arm map. RETAIN. +*/ +static u3_noun +_cj_warm_hump(c3_l jax_l, u3_noun huc) +{ + u3_noun hap = u3_nul; + u3j_core* cop_u; + + /* Compute axes of all correctly declared arms. + */ + if ( jax_l && (cop_u = &u3D.ray_u[jax_l])->arm_u ) { + u3j_harm* jet_u; + c3_l i_l; + + for ( i_l = 0; (jet_u = &cop_u->arm_u[i_l])->fcs_c; i_l++ ) { + c3_l axe_l = 0; + + if ( '.' == *(jet_u->fcs_c) ) { + c3_d axe_d = 0; + + if ( (1 != sscanf(jet_u->fcs_c+1, "%" SCNu64, &axe_d)) || + axe_d >> 32ULL || + (((c3_w)1 << 31) & (axe_l = (c3_w)axe_d)) || + (axe_l < 2) ) + { + u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c); + } + } + else { + u3_noun nam = u3i_string(jet_u->fcs_c); + u3_noun fol = u3kdb_get(u3k(huc), nam); + + if ( u3_none == fol ) { + u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c); + } + else { + axe_l = _cj_axis(fol); + u3z(fol); + } + } + if ( 0 != axe_l ) { + hap = u3kdb_put(hap, axe_l, i_l); + } + } + } + return hap; +} + +/* _cj_install(): install dashboard entries. +*/ +static c3_w +_cj_install(u3j_core* ray_u, c3_w jax_l, u3_noun pel, u3_noun lab, u3j_core* dev_u) +{ + c3_w i_w; + u3_assert(u3R == &(u3H->rod_u)); + + if ( dev_u ) { + for ( i_w = 0; 0 != dev_u[i_w].cos_c; i_w++ ) { + u3j_core* kid_u = &dev_u[i_w]; + u3_noun loc = _cj_core_loc(u3k(pel), kid_u), + bal = u3nc(u3k(u3h(u3t(loc))), u3k(lab)); + + kid_u->jax_l = jax_l; + ray_u[jax_l] = *kid_u; + + if ( kid_u->bas_u ) { + c3_w j_w; + for ( j_w = 0; 0 != kid_u->bas_u[j_w]; j_w++ ) { + u3_noun key = _cj_hash(kid_u->bas_u[j_w]), + hot = u3h_git(u3R->jed.hot_p, key), + old = ( u3_none == hot ) ? u3_none : u3k(u3h(hot)), + reg = _cj_gust(old, kid_u->axe_l, u3k(pel), u3k(loc)), + huc = u3t(u3t(loc)), + hap = _cj_warm_hump(jax_l, huc), + toh = u3nq(reg, jax_l, hap, u3k(bal)); + + u3h_put(u3R->jed.hot_p, key, toh); + u3z(key); + } + } + + jax_l = _cj_install(ray_u, ++jax_l, loc, bal, kid_u->dev_u); + } + } + u3z(pel); + u3z(lab); + return jax_l; +} + +#if 0 +/* _cj_by_gut(): (~(get by a) b), unifying; RETAINS a, b, AND result. +*/ +static u3_weak +_cj_by_gut(u3_noun a, u3_noun b) +{ + if ( u3_nul == a ) { + return u3_none; + } + else { + u3_noun l_a, n_a, r_a; + u3_noun pn_a, qn_a; + + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_cell(n_a, &pn_a, &qn_a); + { + if ( (c3y == u3r_sing(b, pn_a)) ) { + return qn_a; + } + else { + if ( c3y == u3qc_gor(b, pn_a) ) { + return _cj_by_gut(l_a, b); + } + else return _cj_by_gut(r_a, b); + } + } + } +} +#endif + +/* _cj_chum(): decode chum as string. +*/ +static c3_c* +_cj_chum(u3_noun chu) +{ + if ( _(u3ud(chu)) ) { + return u3r_string(chu); + } + else { + u3_noun h_chu = u3h(chu); + u3_noun t_chu = u3t(chu); + + if ( !_(u3a_is_cat(t_chu)) ) { + return 0; + } else { + c3_c* h_chu_c = u3r_string(h_chu); + c3_c buf[33]; + + memset(buf, 0, 33); + snprintf(buf, 32, "%s%d", h_chu_c, t_chu); + + c3_free(h_chu_c); + return strdup(buf); + } + } +} + +/* _cj_je_fsck: fsck:je, or none. +*/ +static u3_noun +_cj_je_fsck(u3_noun clu) +{ + u3_noun p_clu, q_clu, r_clu; + u3_noun huk; + c3_c* nam_c; + c3_l axe_l; + + if ( c3n == u3r_trel(clu, &p_clu, &q_clu, &r_clu) ) { + u3z(clu); return u3_none; + } + if ( 0 == (nam_c = _cj_chum(p_clu)) ) { + u3z(clu); return u3_none; + } + while ( _(u3du(q_clu)) && (11 == u3h(q_clu)) ) { + q_clu = u3t(u3t(q_clu)); + } + if ( !_(u3du(q_clu)) ) { + u3z(clu); c3_free(nam_c); return u3_none; + } + + if ( (1 == u3h(q_clu)) && (0 == u3t(q_clu)) ) { + axe_l = 0; + } + else { + if ( (0 != u3h(q_clu)) || !_(u3a_is_cat(axe_l = u3t(q_clu))) ) { + u3z(clu); c3_free(nam_c); return u3_none; + } + } + + { + huk = 0; + + while ( _(u3du(r_clu)) ) { + u3_noun ir_clu, tr_clu, pir_clu, qir_clu; + + if ( (c3n == u3r_cell(r_clu, &ir_clu, &tr_clu)) || + (c3n == u3r_cell(ir_clu, &pir_clu, &qir_clu)) || + (c3n == u3ud(pir_clu)) ) + { + u3z(huk); u3z(clu); c3_free(nam_c); return u3_none; + } + huk = u3kdb_put(huk, u3k(pir_clu), u3k(qir_clu)); + r_clu = tr_clu; + } + } + u3z(clu); + + { + u3_noun pro = u3nt(u3i_string(nam_c), axe_l, huk); + c3_free(nam_c); + return pro; + } +} + +/* _cj_find_cold(): search cold state for `bat`s [bash registry]. + * RETAIN. + */ +static u3_weak +_cj_find_cold(u3_noun bat) +{ + u3a_road* rod_u = u3R; + + while ( 1 ) { + u3_weak bar = u3h_get(rod_u->jed.cod_p, bat); + + if ( u3_none != bar ) { + return bar; + } + + if ( rod_u->par_p ) { + rod_u = u3to(u3_road, rod_u->par_p); + } + else return u3_none; + } +} + +/* _cj_find_warm(): search warm state for `loc`s activation. + * RETAIN. + */ +static u3_weak +_cj_find_warm(u3_noun loc) +{ + u3a_road* rod_u = u3R; + + while ( 1 ) { + u3_weak ank = u3h_get(rod_u->jed.war_p, loc); + + if ( u3_none != ank ) { + return ank; + } + + if ( rod_u->par_p ) { + rod_u = u3to(u3_road, rod_u->par_p); + } + else return u3_none; + } +} + +static u3_weak _cj_spot(u3_noun cor, u3_weak* bas); + +/* _cj_reg_find(): locate core within registry. RETAIN. + */ +static u3_weak +_cj_reg_find(u3_noun reg, u3_noun cor) +{ + u3_noun rut = u3h(reg), + pas = u3t(reg), + rum = u3qdb_get(rut, u3t(cor)); + if ( u3_nul != rum ) { + u3_noun loc = u3k(u3t(rum)); + u3z(rum); + return loc; + } + else { + while ( u3_nul != pas ) { + u3_noun pap = u3h(pas), + axe = u3h(pap), + lol = u3t(pap); + u3_weak par = u3r_at(axe, cor), + pel; + if ( u3_none != par ) { + pel = _cj_spot(par, NULL); + if ( u3_none != pel ) { + u3_noun nit = u3qdb_get(lol, pel); + u3z(pel); + if ( u3_nul != nit ) { + u3_noun loc = u3k(u3t(nit)); + u3z(nit); + return loc; + } + } + } + pas = u3t(pas); + } + return u3_none; + } +} + +/* _cj_jit(): generate arbitrary warm jet-associated data. RETAIN. +*/ +static u3_noun +_cj_jit(c3_l jax_l, u3_noun bat) +{ + return u3_nul; +} + +/* _cj_loc_axe(): axis-within-core from location (0 for root). RETAIN. + */ +static u3_noun +_cj_loc_axe(u3_noun loc) +{ + u3_noun pat = u3h(loc); + return ( c3n == u3h(pat) ) + ? u3k(u3h(u3t(pat))) + : (c3y == u3h(u3t(pat))) ? 0 : 3; +} + +/* _cj_loc_pel(): parent location (or root noun, if root) of loc. RETAIN. + */ +static u3_noun +_cj_loc_pel(u3_noun loc) +{ + return u3k(u3t(u3t(u3h(loc)))); +} + +/* _cj_spot_cold(): spot, cold dashboard only. *bar is set to + * the [bash registry] found for battery. RETAIN. + */ +static u3_weak +_cj_spot_cold(u3_noun cor, u3_weak* bar) +{ + *bar = _cj_find_cold(u3h(cor)); + if ( u3_none == *bar ) { + return u3_none; + } + else { + return _cj_reg_find(u3t(*bar), cor); + } +} + +/* _cj_spot_hot(): try to locate core by hot dashboard. if found, + * the activation (warm state) is returned and the + * location is produced at *loc. RETAIN. + */ +static u3_weak +_cj_spot_hot(u3_noun cor, u3_noun bas, u3_noun* loc) +{ + u3_noun bat = u3h(cor); + u3_weak act = u3_none, + hot = u3h_get(u3H->rod_u.jed.hot_p, bas); + if ( u3_none != hot ) { + u3_noun reg, jax, hap, bal; + c3_l jax_l; + u3x_qual(hot, ®, &jax, &hap, &bal); + jax_l = (c3_l) jax; + if ( u3_none != (*loc = _cj_reg_find(reg, cor)) ) { + act = u3nq(jax_l, u3k(hap), u3k(bal), _cj_jit(jax_l, bat)); + } + u3z(hot); + } + return act; +} + +/* _cj_spot(): find location of cor. expensive. RETAIN. + * bas is complicated to make it easy to cache bashes. + * you can safely ignore it by passing NULL. Otherwise, + * if it points to u3_none, and no location is found, + * a bash will be PRODUCED there. if it contains a bash, + * that will be used instead of calling _cj_bash. + */ +static u3_weak +_cj_spot(u3_noun cor, u3_weak* bas) +{ + u3_weak bak = u3_none, + bar = u3_none, + reg = u3_none, + loc = _cj_spot_cold(cor, &bar); + + if ( NULL == bas ) { + bas = &bak; + } + + if ( u3_none != bar ) { + if ( (u3_none == *bas) ) { + *bas = u3k(u3h(bar)); + } + reg = u3k(u3t(bar)); + u3z(bar); + } + + if ( u3_none == loc ) { + if ( u3_none == *bas ) { + *bas = _cj_bash(u3h(cor)); + } + + if ( !(u3C.wag_w & u3o_hashless) ) { + u3_weak act = _cj_spot_hot(cor, *bas, &loc); + if ( u3_none != act ) { + reg = _cj_gust(reg, _cj_loc_axe(loc), _cj_loc_pel(loc), u3k(loc)); + u3h_put(u3R->jed.cod_p, u3h(cor), u3nc(u3k(*bas), u3k(reg))); + /* caution: could overwrites old value, debug batteries etc. + ** old value contains old _cj_jit (from different + ** battery). if we change jit to (map battery *), + ** will need to merge with that map here. + */ + u3h_put(u3R->jed.war_p, loc, act); + } + } + } + if ( u3_none != bak ) { + u3z(bak); + } + if ( u3_none != reg ) { + u3z(reg); + } + return loc; +} + +/* _cj_cast(): create a u3j_fink that can be used to efficiently verify + * that another core is located where this one is. RETAIN. + */ +static u3p(u3j_fink) +_cj_cast(u3_noun cor, u3_noun loc) +{ + c3_w i_w = 0; + u3_noun j, par, bat, dyn, pax, + rev = u3_nul, + pat = u3h(loc); + u3j_fink* fin_u; + + while ( c3n == u3h(pat) ) { + bat = u3h(cor); + dyn = u3t(pat); + pax = u3h(dyn); + loc = u3t(dyn); + pat = u3h(loc); + rev = u3nc(u3nc(u3k(bat), u3k(pax)), rev); + // pax already known-valid + cor = u3r_at(pax, cor); + ++i_w; + } + + fin_u = u3a_walloc(c3_wiseof(u3j_fink) + + (i_w * c3_wiseof(u3j_fist))); + fin_u->len_w = i_w; + fin_u->sat = u3k(cor); + for ( j = rev; i_w-- > 0; j = u3t(j) ) { + u3j_fist* fis_u = &(fin_u->fis_u[i_w]); + par = u3h(j); + fis_u->bat = u3k(u3h(par)); + fis_u->pax = u3k(u3t(par)); + } + u3z(rev); + u3_assert( u3_nul == j ); + + return u3of(u3j_fink, fin_u); +} + +/* _cj_fine(): check that a core matches a u3j_fink. RETAIN. + */ +static c3_o +_cj_fine(u3_noun cor, u3p(u3j_fink) fin_p) +{ + u3j_fink* fin_u = u3to(u3j_fink, fin_p); + c3_w i_w; + for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { + u3j_fist* fis_u = &(fin_u->fis_u[i_w]); + if ( c3n == u3r_sing(fis_u->bat, u3h(cor)) ) { + return c3n; + } + else { + cor = u3r_at(fis_u->pax, cor); + } + } + return u3r_sing(fin_u->sat, cor); +} + +/* _cj_nail(): resolve hot state for arm at axis within cores located + * at loc. a label will be PRODUCED at *lab, unconditionally. + * Arguments are RETAINED. Return value is yes if a jet driver + * is present. + */ +static c3_o +_cj_nail(u3_noun loc, u3_noun axe, + u3_noun* lab, u3j_core** cop_u, u3j_harm** ham_u) +{ + c3_o ret_o; + u3_noun jax, hap, bal, jit; + u3_weak act; + act = _cj_find_warm(loc); + u3_assert(u3_none != act); + u3x_qual(act, &jax, &hap, &bal, &jit); + + *lab = u3k(bal); + if ( 0 == jax ) { + ret_o = c3n; + } + else { + u3_weak inx = u3kdb_get(u3k(hap), u3k(axe)); + if ( u3_none == inx ) { + ret_o = c3n; + } + else { + c3_l jax_l = jax, + inx_l = inx; + *cop_u = &(u3D.ray_u[jax_l]); + *ham_u = &((*cop_u)->arm_u[inx_l]); + ret_o = c3y; + } + } + + u3z(act); + return ret_o; +} + +/* _cj_hot_mean(): in parent, declare a core. RETAINS. +*/ +static c3_l +_cj_hot_mean(c3_l par_l, u3_noun nam) +{ + u3j_core* par_u; + u3j_core* dev_u; + + if ( 0 != par_l ) { + par_u = &u3D.ray_u[par_l]; + dev_u = par_u->dev_u; + } + else { + par_u = 0; + dev_u = u3D.dev_u; + } + + { + c3_w i_l = 0; + u3j_core* cop_u; + + while ( (cop_u = &dev_u[i_l])->cos_c ) { + if ( _(u3r_sing_c(cop_u->cos_c, nam)) ) { +#if 0 + u3l_log("hot: bound jet %d/%s/%s/", + cop_u->jax_l, + cop_u->cos_c, + par_u ? par_u->cos_c : "~"); +#endif + return cop_u->jax_l; + } + i_l++; + } + } + return 0; +} + +/* u3j_boot(): initialize jet system. +*/ +c3_w +u3j_boot(c3_o nuu_o) +{ + u3_assert(u3R == &(u3H->rod_u)); + + u3D.len_l = _cj_count(0, u3D.dev_u); + u3D.all_l = (2 * u3D.len_l) + 1024; // horrid heuristic + + u3D.ray_u = c3_malloc(u3D.all_l * sizeof(u3j_core)); + memset(u3D.ray_u, 0, (u3D.all_l * sizeof(u3j_core))); + + if ( c3n == nuu_o ) { + u3h_free(u3R->jed.hot_p); + } + u3R->jed.hot_p = u3h_new(); + + return _cj_install(u3D.ray_u, 1, + (c3_l) (long long) u3D.dev_u[0].par_u, + u3_nul, + u3D.dev_u); +} + +/* _cj_soft(): kick softly by arm axis. +*/ +static u3_noun +_cj_soft(u3_noun cor, u3_noun axe) +{ + u3_noun arm = u3x_at(axe, cor); + + return u3n_nock_on(cor, u3k(arm)); +} + + void + find_error(u3_noun cor, + u3_noun old, + u3_noun new); + +/* _cj_kick_z(): try to kick by jet. If no kick, produce u3_none. +** +** `cor` is RETAINED iff there is no kick, TRANSFERRED if one. +** `axe` is RETAINED. +*/ +static u3_weak +_cj_kick_z(u3_noun cor, u3j_core* cop_u, u3j_harm* ham_u, u3_atom axe) +{ + if ( 0 == ham_u->fun_f ) { + return u3_none; + } + + if ( !_(ham_u->liv) ) { + return u3_none; + } + else { +#ifdef U3_MEMORY_DEBUG + c3_w cod_w; + + { + char soc_c[5]; + + memset(soc_c, 0, 5); + strncpy(soc_c, cop_u->cos_c, 4); + soc_c[4] = 0; + cod_w = u3i_string(soc_c); + cod_w = u3a_lush(cod_w); + } +#endif + + if ( _(ham_u->ice) ) { + u3_weak pro = ham_u->fun_f(cor); + +#ifdef U3_MEMORY_DEBUG + u3a_lop(cod_w); +#endif + if ( u3_none != pro ) { + u3z(cor); + return pro; + } + } + else { + u3_weak pro, ame; + + ham_u->ice = c3y; + pro = ham_u->fun_f(cor); + ham_u->ice = c3n; + +#ifdef U3_MEMORY_DEBUG + u3a_lop(cod_w); +#endif + if ( u3_none == pro ) { + u3z(cor); + return pro; + } + ham_u->liv = c3n; + ame = _cj_soft(cor, axe); + ham_u->liv = c3y; + + if ( c3n == u3r_sing(ame, pro) ) { + u3l_log("test: %s %s: mismatch: good %x, bad %x", + cop_u->cos_c, + (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c, + u3r_mug(ame), + u3r_mug(pro)); + ham_u->liv = c3n; + + return u3m_bail(c3__fail); + } + else { + +#if 0 + u3l_log("test: %s %s", + cop_u->cos_c, + (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c); +#endif + u3z(ame); + return pro; + } + } + return u3_none; + } +} + +/* _cj_hook_in(): execute hook from core, or fail. +*/ +static u3_noun +_cj_hook_in(u3_noun cor, + const c3_c* tam_c, + c3_o jet_o) +{ + u3_weak loc, col; + u3_noun roc, tem, got, pat, nam, huc; + + if ( c3n == u3du(cor) ) { + u3l_log("_cj_hook_in failure: c3n == u3du(cor)"); + return u3m_bail(c3__fail); + } + + loc = _cj_spot(cor, NULL); + if ( u3_none == loc ) { + u3l_log("_cj_hook_in failure: u3_none == loc"); + return u3m_bail(c3__fail); + } + + tem = u3i_string(tam_c); + while ( 1 ) { + u3x_trel(loc, &pat, &nam, &huc); + got = u3qdb_get(huc, tem); + if ( u3_nul != got ) { + c3_l axe_l; + u3_noun pro, fol; + u3j_core* cop_u; + + u3z(tem); + fol = u3k(u3t(got)); + u3z(got); + axe_l = _cj_axis(fol); + if ( 0 == axe_l ) { + u3t_off(glu_o); + pro = u3n_nock_on(cor, fol); + u3t_on(glu_o); + } + else { + c3_l jax_l, inx_l; + u3_noun hap, act; + + u3z(fol); + act = _cj_find_warm(loc); + jax_l = u3h(act); + hap = u3h(u3t(act)); + cop_u = &u3D.ray_u[jax_l]; + + // Tricky: the above case would work here too, but would + // disable jet_o and create some infinite recursions. + // + u3t_off(glu_o); + if ( (c3n == jet_o) || + (u3_none == (inx_l = u3kdb_get(u3k(hap), axe_l))) || + (u3_none == (pro = _cj_kick_z(cor, + cop_u, + &cop_u->arm_u[inx_l], + axe_l))) ) { + pro = u3n_nock_on(cor, u3k(u3x_at(axe_l, cor))); + } + u3t_on(glu_o); + u3z(act); + } + u3z(loc); + return pro; + } + else if ( c3n == u3h(pat) ) { + u3_noun dyn = u3t(pat), + axe = u3h(dyn), + pel = u3t(dyn); + // axe already known-valid + roc = u3k(u3r_at(axe, cor)); + u3z(cor); + cor = roc; + col = u3k(pel); + u3z(loc); + loc = col; + } + else { + u3_noun sat = u3t(pat); + if ( c3y == u3h(sat) ) { + u3l_log("_cj_hook_in failure: c3y == u3h(sat)"); + return u3m_bail(c3__fail); + } + else { + col = u3k(u3t(sat)); + u3z(loc); + loc = col; + roc = u3k(u3t(cor)); + u3z(cor); + cor = roc; + } + } + } +} + +/* u3j_soft(): execute soft hook. +*/ +u3_noun +u3j_soft(u3_noun cor, + const c3_c* tam_c) +{ + u3_noun pro; + u3t_on(glu_o); + pro = _cj_hook_in(cor, tam_c, c3n); + u3t_off(glu_o); + return pro; +} + +/* u3j_hook(): execute hook from core, or fail. +*/ +u3_noun +u3j_hook(u3_noun cor, + const c3_c* tam_c) +{ + u3_noun pro; + u3t_on(glu_o); + pro = _cj_hook_in(cor, tam_c, c3y); + u3t_off(glu_o); + return pro; +} + +/* _cj_prog(): stop tracing glu and find a nock program + */ +static u3p(u3n_prog) +_cj_prog(u3_weak loc, u3_noun fol) +{ + u3p(u3n_prog) pog_p; + u3t_off(glu_o); + pog_p = u3n_find((loc == u3_none ? u3_nul : loc), fol); + u3t_on(glu_o); + return pog_p; +} + +static inline c3_w +_cj_of_hank(u3j_hank *han_u) +{ + u3_post han_p = u3of(u3j_hank, han_u); + return han_p >> u3a_vits; +} + +static inline u3j_hank* +_cj_to_hank(c3_w han_w) +{ + u3_post han_p = han_w << u3a_vits; + return u3to(u3j_hank, han_p); +} + +/* cj_hank_find(): find cached hook information, keyed by arbitrary + * prefix and term cords. RETAIN. + */ +static u3j_hank* +_cj_hank_find(u3_noun pre, u3_noun tam) +{ + u3_noun key = u3nc(u3k(pre), u3k(tam)); + u3_noun got = u3h_git(u3R->jed.han_p, key); + + if ( u3_none != got ) { + u3z(key); + return _cj_to_hank(got); + } + else { + u3j_hank* new_u = u3a_walloc(c3_wiseof(u3j_hank)); + u3a_road* rod_u = u3R; + + while ( rod_u->par_p && u3_none == got ) { + rod_u = u3to(u3a_road, rod_u->par_p); + got = u3h_git(rod_u->jed.han_p, key); + } + + if ( u3_none == got ) { + new_u->hax = u3_none; + } + else { + u3j_hank* old_u = _cj_to_hank(got); + if ( u3_none != (new_u->hax = old_u->hax) ) { + // it's unusual but safe to "take" here, because + // u3a_take will no-op on senior nouns (just as u3k would) + // + u3j_site_take(&(new_u->sit_u), &(old_u->sit_u)); + } + } + + u3h_put(u3R->jed.han_p, key, _cj_of_hank(new_u)); + u3z(key); + return new_u; + } +} + +/* _cj_hank_fine(): check that cached hook information is valid + * for given core. *inn will point to the hooked + * core on return if valid. RETAIN. + */ +static c3_o +_cj_hank_fine(u3j_hank* han_u, u3_noun cor, u3_noun *inn) +{ + u3_noun hax = han_u->hax; + if ( u3_none == hax ) { + return c3n; + } + else { + *inn = u3r_at(hax, cor); + if ( u3_none == *inn ) { + return c3n; + } + else { + u3j_site* sit_u = &(han_u->sit_u); + u3_assert(u3_none != sit_u->loc); + return _cj_fine(*inn, sit_u->fin_p); + } + } +} + +/* _cj_hank_lose(): release memory maintained in a hook cache. +*/ +static void +_cj_hank_lose(u3j_hank* han_u) +{ + if ( u3_none != han_u->hax ) { + u3z(han_u->hax); + u3j_site_lose(&(han_u->sit_u)); + } +} + +/* _cj_hank_fill(): slow path, populate han_u. + */ +static u3_noun +_cj_hank_fill(u3j_hank* han_u, u3_noun tam, u3_noun cor) +{ + u3_weak loc, col; + u3_noun got, pat, nam, huc; + u3_noun hax = 1; + u3j_site* sit_u = &(han_u->sit_u); + + if ( c3n == u3du(cor) ) { + u3l_log("fail in _cj_hank_fill (c3n == u3du(cor))"); + return u3m_bail(c3__fail); + } + + sit_u->bas = u3_none; + if ( u3_none == (col = loc = _cj_spot(cor, NULL)) ) { + u3l_log("fail in _cj_hank_fill (_cj_spot(cor, NULL))"); + return u3m_bail(c3__fail); + } + + while ( 1 ) { + u3x_trel(loc, &pat, &nam, &huc); + got = u3qdb_get(huc, tam); + if ( u3_nul != got ) { + u3_noun fol = u3k(u3t(got)); + u3z(got); + sit_u->bat = u3k(u3h(cor)); + sit_u->loc = u3k(loc); + sit_u->fin_p = _cj_cast(cor, loc); + sit_u->fon_o = c3y; + if ( 0 == (sit_u->axe = _cj_axis(fol)) ) { + sit_u->jet_o = c3n; + sit_u->pog_p = _cj_prog(loc, fol); + } + else { + // loc already known-valid + han_u->sit_u.pog_p = _cj_prog(loc, u3r_at(sit_u->axe, cor)); + han_u->sit_u.jet_o = _cj_nail(loc, sit_u->axe, + &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); + } + u3z(fol); + u3z(col); + han_u->hax = hax; + return cor; + } + else if ( c3n == u3h(pat) ) { + u3_noun dyn = u3t(pat), + axe = u3h(dyn), + xah; + // axe already known-valid + cor = u3r_at(axe, cor); + loc = u3t(dyn); + xah = u3qc_peg(axe, hax); + u3z(hax); + hax = xah; + } + else { + u3_noun sat = u3t(pat); + if ( c3y == u3h(sat) ) { + u3l_log("fail in _cj_hank_fill (c3y == u3h(sat))"); + return u3m_bail(c3__fail); + } + else { + u3_noun xah; + cor = u3t(cor); + loc = u3t(sat); + xah = u3qc_peg(3, hax); + u3z(hax); + hax = xah; + } + } + } +} + +/* _cj_sink(): kick by nock. + */ +static u3_noun +_cj_sink(u3_noun cor, u3_noun axe) +{ + u3_noun fol = u3x_at(axe, cor); + u3z(axe); + return u3n_nock_on(cor, u3k(fol)); +} + +/* u3j_kick(): new kick. +** +** `axe` is RETAINED by the caller; `cor` is RETAINED iff there +** is no kick, TRANSFERRED if one. +*/ +u3_weak +u3j_kick(u3_noun cor, u3_noun axe) +{ + u3t_on(glu_o); + u3_weak loc = _cj_spot(cor, NULL); + if ( u3_none == loc ) { + u3t_off(glu_o); + return u3_none; + } + else { + u3_weak act = _cj_find_warm(loc); + u3z(loc); + if ( u3_none == act ) { + u3t_off(glu_o); + return u3_none; + } + else { + c3_l jax_l; + u3_noun hap, bal, jit, inx; + + u3x_qual(act, &jax_l, &hap, &bal, &jit); + + if ( u3_none == (inx = u3kdb_get(u3k(hap), u3k(axe))) ) { + u3t_off(glu_o); + { + c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); + c3_o trc_o = __(u3C.wag_w & u3o_trace); + + if ( _(pof_o) ) { + pof_o = u3t_come(bal); + } + if ( _(trc_o) ) { + trc_o = u3t_nock_trace_push(bal); + } + u3z(act); + if ( _(pof_o) || _(trc_o) ) { + u3_noun pro = _cj_sink(cor, u3k(axe)); + + if (_(pof_o)) { + u3t_flee(); + } + if ( _(trc_o) ) { + u3t_nock_trace_pop(); + } + return pro; + } + else { + return u3_none; + } + } + } + else { + u3j_core* cop_u = &u3D.ray_u[jax_l]; + c3_l inx_l = inx; + u3j_harm* ham_u = &cop_u->arm_u[inx_l]; + c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); + c3_o trc_o = __(u3C.wag_w & u3o_trace); + u3_noun pro; + + if ( _(pof_o) ) { + pof_o = u3t_come(bal); + } + if ( _(trc_o) ) { + trc_o = u3t_nock_trace_push(bal); + } + u3z(act); + u3t_off(glu_o); + pro = _cj_kick_z(cor, cop_u, ham_u, axe); + + if ( u3_none == pro ) { + if ( _(pof_o) || _(trc_o) ) { + pro = _cj_sink(cor, u3k(axe)); + + if (_(pof_o)) { + u3t_flee(); + } + if ( _(trc_o) ) { + u3t_nock_trace_pop(); + } + } + return pro; + } + else { + if ( _(pof_o) ) { + u3t_flee(); + } + if ( _(trc_o) ) { + u3t_nock_trace_pop(); + } + return pro; + } + } + } + } +} + +/* _cj_fink_take(): copy u3j_fink from junior road. +*/ +static u3j_fink* +_cj_fink_take(u3j_fink* jun_u) +{ + c3_w i_w, len_w = jun_u->len_w; + u3j_fink* fin_u = u3a_walloc(c3_wiseof(u3j_fink) + + (len_w * c3_wiseof(u3j_fist))); + + fin_u->len_w = len_w; + fin_u->sat = u3a_take(jun_u->sat); + for ( i_w = 0; i_w < len_w; ++i_w ) { + u3j_fist* fis_u = &(fin_u->fis_u[i_w]); + u3j_fist* sif_u = &(jun_u->fis_u[i_w]); + fis_u->bat = u3a_take(sif_u->bat); + fis_u->pax = u3a_take(sif_u->pax); + } + return fin_u; +} + +/* _cj_fink_free(): lose and free everything in a u3j_fink. +*/ +static void +_cj_fink_free(u3p(u3j_fink) fin_p) +{ + c3_w i_w; + u3j_fink* fin_u = u3to(u3j_fink, fin_p); + u3z(fin_u->sat); + for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { + u3j_fist* fis_u = &(fin_u->fis_u[i_w]); + u3z(fis_u->bat); + u3z(fis_u->pax); + } + u3a_wfree(fin_u); +} + +/* u3j_rite_take(): copy junior rite references. [dst_u] is uninitialized +*/ +void +u3j_rite_take(u3j_rite* dst_u, u3j_rite* src_u) +{ + if ( u3_none == src_u->clu ) { + dst_u->clu = u3_none; + dst_u->fin_p = 0; + dst_u->own_o = c3n; + } + else { + dst_u->clu = u3a_take(src_u->clu); + dst_u->own_o = src_u->own_o; + dst_u->fin_p = ( c3n == src_u->own_o ) + ? src_u->fin_p + : u3of(u3j_fink, _cj_fink_take(u3to(u3j_fink, src_u->fin_p))); + } +} + +/* u3j_rite_merge(): copy rite references from src_u to dst_u, +** losing old references +*/ +void +u3j_rite_merge(u3j_rite* dst_u, u3j_rite* src_u) +{ + if ( u3_none != src_u->clu ) { + if ( u3_none != dst_u->clu ) { + u3z(dst_u->clu); + } + + dst_u->clu = src_u->clu; + + if ( dst_u->fin_p != src_u->fin_p ) { + if ( c3y == dst_u->own_o ) { + _cj_fink_free(dst_u->fin_p); + } + + dst_u->fin_p = src_u->fin_p; + dst_u->own_o = src_u->own_o; + } + } +} + +/* u3j_site_take(): copy junior site references. [dst_u] is uninitialized +*/ +void +u3j_site_take(u3j_site* dst_u, u3j_site* src_u) +{ + dst_u->axe = u3a_take(src_u->axe); + dst_u->bat = u3_none; + dst_u->bas = u3_none; + dst_u->pog_p = 0; + + if ( u3_none == src_u->loc ) { + dst_u->loc = u3_none; + dst_u->lab = u3_none; + dst_u->jet_o = c3n; + dst_u->cop_u = NULL; + dst_u->ham_u = NULL; + dst_u->fin_p = 0; + dst_u->fon_o = c3n; + } + else { + dst_u->loc = u3a_take(src_u->loc); + dst_u->lab = u3a_take(src_u->lab); + dst_u->jet_o = src_u->jet_o; + dst_u->cop_u = src_u->cop_u; + dst_u->ham_u = src_u->ham_u; + + if ( c3y == src_u->fon_o ) { + dst_u->fin_p = u3of(u3j_fink, _cj_fink_take(u3to(u3j_fink, src_u->fin_p))); + dst_u->fon_o = c3y; + } + else { + dst_u->fin_p = src_u->fin_p; + dst_u->fon_o = c3n; + } + } +} + +/* u3j_site_merge(): copy site references from src_u to dst_u, +** losing old references +*/ +void +u3j_site_merge(u3j_site* dst_u, u3j_site* src_u) +{ + u3z(dst_u->axe); + dst_u->axe = src_u->axe; + + if ( u3_none != src_u->loc ) { + u3z(dst_u->loc); // XX these may be u3_none + u3z(dst_u->lab); + dst_u->loc = src_u->loc; + dst_u->lab = src_u->lab; + dst_u->cop_u = src_u->cop_u; + dst_u->ham_u = src_u->ham_u; + dst_u->jet_o = src_u->jet_o; + + if ( dst_u->fin_p != src_u->fin_p ) { + if ( c3y == dst_u->fon_o ) { + _cj_fink_free(dst_u->fin_p); + } + + dst_u->fin_p = src_u->fin_p; + dst_u->fon_o = src_u->fon_o; + } + } +} + +/* u3j_site_ream(): refresh u3j_site after restoring from checkpoint +*/ +void +u3j_site_ream(u3j_site* sit_u) +{ + if ( u3_none != sit_u->loc ) { + u3z(sit_u->lab); + sit_u->jet_o = _cj_nail(sit_u->loc, sit_u->axe, + &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); + } +} + +/* _cj_site_lock(): ensure site has a valid program pointer + */ +static void +_cj_site_lock(u3_noun loc, u3_noun cor, u3j_site* sit_u) +{ + if ( (u3_none != sit_u->bat) && + (c3y == u3r_sing(sit_u->bat, u3h(cor))) ) { + return; + } + sit_u->pog_p = _cj_prog(loc, u3x_at(sit_u->axe, cor)); + if ( u3_none != sit_u->bat ) { + u3z(sit_u->bat); + } + sit_u->bat = u3k(u3h(cor)); +} + +/* _cj_burn(): stop tracing glu and call a nock program + */ +static u3_noun +_cj_burn(u3p(u3n_prog) pog_p, u3_noun cor) +{ + u3_noun pro; + u3t_off(glu_o); + pro = u3n_burn(pog_p, cor); + u3t_on(glu_o); + return pro; +} + +/* _cj_site_kick_hot(): execute site's kick on located core +** (no validity checks). +*/ +static u3_weak +_cj_site_kick_hot(u3_noun loc, u3_noun cor, u3j_site* sit_u, c3_o lok_o) +{ + u3_weak pro = u3_none; + c3_o jet_o = sit_u->jet_o; + c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); + c3_o trc_o = __(u3C.wag_w & u3o_trace); + + if ( c3n == pof_o && c3n == trc_o ) { + if ( c3y == jet_o ) { + u3t_off(glu_o); + pro = _cj_kick_z(cor, sit_u->cop_u, sit_u->ham_u, sit_u->axe); + u3t_on(glu_o); + } + if ( u3_none == pro ) { + if ( c3y == lok_o ) { + _cj_site_lock(loc, cor, sit_u); + } + } + } + else { + if ( _(pof_o) ) { + pof_o = u3t_come(sit_u->lab); + } + if ( _(trc_o) ) { + trc_o = u3t_nock_trace_push(sit_u->lab); + } + + if ( c3y == jet_o ) { + u3t_off(glu_o); + pro = _cj_kick_z(cor, sit_u->cop_u, sit_u->ham_u, sit_u->axe); + u3t_on(glu_o); + } + if ( u3_none == pro ) { + if ( c3y == lok_o ) { + _cj_site_lock(loc, cor, sit_u); + } + pro = _cj_burn(sit_u->pog_p, cor); + } + + if ( c3y == pof_o ) { + u3t_flee(); + } + if ( c3y == trc_o ) { + u3t_nock_trace_pop(); + } + } + + return pro; +} + +/* _cj_site_kick(): execute site's kick on core. + */ +static u3_weak +_cj_site_kick(u3_noun cor, u3j_site* sit_u) +{ + u3_weak loc, pro; + + loc = pro = u3_none; + + if ( u3_none != sit_u->loc ) { + if ( c3y == _cj_fine(cor, sit_u->fin_p) ) { + loc = sit_u->loc; + pro = _cj_site_kick_hot(loc, cor, sit_u, c3y); + } + } + + if ( u3_none == loc ) { + loc = _cj_spot(cor, &(sit_u->bas)); + if ( u3_none != loc ) { + u3p(u3j_fink) fon_p = 0; + u3_weak lod = u3_none; + u3_weak lob = u3_none; + + if ( u3_none != sit_u->loc ) { + lod = sit_u->loc; + lob = sit_u->lab; + if ( c3y == sit_u->fon_o ) { + fon_p = sit_u->fin_p; + } + } + + sit_u->loc = loc; + sit_u->fin_p = _cj_cast(cor, loc); + sit_u->fon_o = c3y; + sit_u->jet_o = _cj_nail(loc, sit_u->axe, + &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); + pro = _cj_site_kick_hot(loc, cor, sit_u, c3y); + + if ( u3_none != lod ) { + u3z(lod); + u3z(lob); + if ( 0 != fon_p ) { + _cj_fink_free(fon_p); + } + } + } + } + + if ( u3_none == pro ) { + _cj_site_lock(loc, cor, sit_u); + } + + return pro; +} + +/* u3j_site_kick(): kick a core with a u3j_site cache. + */ +u3_weak +u3j_site_kick(u3_noun cor, u3j_site* sit_u) +{ + u3_weak pro; + u3t_on(glu_o); + pro = _cj_site_kick(cor, sit_u); + u3t_off(glu_o); + return pro; +} + +/* u3j_cook(): Execute hook from core, call site cached by arbitrary c string +*/ +u3_noun +u3j_cook(const c3_c* key_c, + u3_noun cor, + const c3_c* tam_c) +{ + u3_noun pro, key, tam, inn; + u3j_hank* han_u; + + u3t_on(glu_o); + key = u3i_string(key_c); + tam = u3i_string(tam_c); + han_u = _cj_hank_find(key, tam); + if ( c3n == _cj_hank_fine(han_u, cor, &inn) ) { + _cj_hank_lose(han_u); + inn = _cj_hank_fill(han_u, tam, cor); + } + pro = _cj_site_kick(u3k(inn), &(han_u->sit_u)); + if ( u3_none == pro ) { + pro = _cj_burn(han_u->sit_u.pog_p, inn); + } + u3z(cor); + + u3z(key); + u3z(tam); + u3t_off(glu_o); + return pro; +} + +/* u3j_kink(): kick either by jet or by nock. +*/ +u3_noun +u3j_kink(u3_noun cor, u3_noun axe) +{ + u3_weak pro = u3j_kick(cor, axe); + + if ( u3_none != pro ) { + return pro; + } + else { + return _cj_sink(cor, axe); + } +} + +/* u3j_gate_prep(): prepare a locally cached gate to call repeatedly. + * core is TRANSFERRED. + */ +void +u3j_gate_prep(u3j_site* sit_u, u3_noun cor) +{ + u3_noun loc; + u3t_on(glu_o); + if ( c3n == u3du(cor) || c3n == u3du(u3t(cor)) ) { + u3m_bail(c3__exit); + return; + } + sit_u->bas = u3_none; + sit_u->axe = 2; + sit_u->bat = cor; // a lie, this isn't really the battery! + sit_u->loc = loc = _cj_spot(cor, &(sit_u->bas)); + sit_u->pog_p = _cj_prog(loc, u3h(cor)); + if ( u3_none != loc ) { + u3_noun pax = _cj_loc_axe(loc), + pay = u3qc_cap(pax), + pam = u3qc_mas(pax); + if ( 3 != pay || 2 == pam || (3 != pam && 3 != u3qc_cap(pam)) ) { + u3l_log("u3j_gate_prep(): parent axis includes sample"); + u3m_p("axis", pax); + u3_weak act = _cj_find_warm(loc); + u3_assert( u3_none != act ); + sit_u->jet_o = c3n; + sit_u->lab = u3k(u3h(u3t(u3t(act)))); + u3z(act); + } + else { + sit_u->jet_o = _cj_nail(loc, 2, + &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); + } + u3z(pam); u3z(pax); + } + u3t_off(glu_o); +} + +/* u3j_gate_slam(): slam a site prepared by u3j_gate_find() with sample. + * sam is TRANSFERRED. + */ +u3_noun +u3j_gate_slam(u3j_site* sit_u, u3_noun sam) +{ + u3_weak pro; + u3_noun cor; + + u3t_on(glu_o); + pro = u3_none; + cor = u3nt(u3k(u3h(sit_u->bat)), + sam, + u3k(u3t(u3t(sit_u->bat)))); + if ( u3_none != sit_u->loc ) { + pro = _cj_site_kick_hot(sit_u->loc, cor, sit_u, c3n); + } + if ( u3_none == pro ) { + pro = _cj_burn(sit_u->pog_p, cor); + } + u3t_off(glu_o); + return pro; +} + +/* u3j_gate_lose(): clean up site prepared by u3j_gate_find(). + */ +void +u3j_gate_lose(u3j_site* sit_u) +{ + u3z(sit_u->bat); + u3z(sit_u->bas); + if ( u3_none != sit_u->loc ) { + u3z(sit_u->loc); + u3z(sit_u->lab); + } +} + +/* _cj_minx(): produce location of core from fsck'd clue. RETAIN. + */ +static u3_weak +_cj_minx(u3_noun cey, u3_noun cor) +{ + u3_noun nam, axe, huc; + u3x_trel(cey, &nam, &axe, &huc); + + if ( 0 == axe ) { + return u3nt(u3nt(c3y, c3y, u3k(u3t(cor))), u3k(nam), u3k(huc)); + } + else { + u3_weak par, pel; + u3_noun pat; + + par = u3r_at(axe, cor); + if ( u3_none == par || c3n == u3du(par) ) { + u3l_log("fund: %s is bogus", u3r_string(nam)); + return u3_none; + } + pel = _cj_spot(par, NULL); + if ( u3_none == pel ) { + u3l_log("fund: in %s, parent %x not found at %d", + u3r_string(nam), + u3r_mug(u3h(par)), + axe); + return u3_none; + } + pat = ( ( 3 == axe ) && (c3y == u3h(u3h(pel))) ) + ? u3nt(c3y, c3n, pel) + : u3nt(c3n, u3k(axe), pel); + return u3nt(pat, u3k(nam), u3k(huc)); + } +} + +static void +_cj_print_tas(u3_noun tas) +{ + c3_w met_w = u3r_met(3, tas); + c3_c* str_c = alloca(met_w + 1); + u3r_bytes(0, met_w, (c3_y*)str_c, tas); + str_c[met_w] = 0; + u3l_log("/%s", str_c); +} + +/* _cj_mine(): declare a core and produce location. RETAIN. +*/ +static u3_weak +_cj_mine(u3_noun cey, u3_noun cor, u3_noun bas) +{ + u3_weak loc = _cj_minx(cey, cor); + if ( u3_none != loc ) { + c3_l par_l, jax_l; + u3_noun pel = _cj_loc_pel(loc), + axe = _cj_loc_axe(loc), + bat = u3h(cor), + nam = u3h(u3t(loc)), + bar = _cj_find_cold(bat), + reg, hap, bal, act; + if ( u3_none == bar ) { + reg = u3_none; + } + else { + reg = u3k(u3t(bar)); + u3z(bar); + } + reg = _cj_gust(reg, u3k(axe), u3k(pel), u3k(loc)); + if ( 0 == axe ) { + par_l = 0; + bal = u3nc(u3k(nam), u3_nul); + } + else { + u3_weak pac = _cj_find_warm(pel); + u3_assert(u3_none != pac); + par_l = u3h(pac); + bal = u3nc(u3k(nam), u3k(u3h(u3t(u3t(pac))))); + u3z(pac); + } + jax_l = _cj_hot_mean(par_l, nam); +#if 0 + u3m_p("new jet", bal); + u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); +#endif + + if ( !(u3C.wag_w & u3o_hashless) ) { + if ( jax_l ) { + c3_y dig_y[32]; + c3_w i_w; + u3_noun i = bal; + u3l_log("hot jet: "); + while ( i != u3_nul ) { + _cj_print_tas(u3h(i)); + i = u3t(i); + } + u3l_log("\r\n axe %d, jax %d,\r\n bash ", axe, jax_l); + u3r_bytes(0, 32, dig_y, bas); + for ( i_w = 32; i_w > 0; ) { + u3l_log("%02x", dig_y[--i_w]); + } + u3l_log(""); + } + } + + hap = _cj_warm_hump(jax_l, u3t(u3t(loc))); + act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); + u3h_put(u3R->jed.cod_p, bat, u3nc(u3k(bas), reg)); + u3h_put(u3R->jed.war_p, loc, act); // see note in _cj_spot + u3z(pel); u3z(axe); + } + + return loc; +#if 0 + { + u3_noun bas = _cj_bash(bat), + hot = u3h_get(u3D.hot_p, bas); + c3_o hav_o = c3n; + + if ( u3_none != hot ) { + u3_noun her = u3h(hot), + hol = _cj_reg_find(her, cor); + if ( hol != u3_none ) { + hav_o = c3y; + u3z(hol); + } + u3z(hot); + } + + if ( c3n == hav_o ) { + u3m_p("unregistered battery", bal); + u3l_log("hash: %x", bas); + } + u3z(bas); + } +#endif +} + +static void +_cj_audit(u3_noun loc, u3_noun cey, u3_noun cor) +{ + u3_noun pat, nam, huc, cax, can, cuc, pax; + + u3x_trel(loc, &pat, &nam, &huc); + u3x_trel(cey, &can, &cax, &cuc); + + pax = _cj_loc_axe(loc); + + if ( (c3n == u3r_sing(nam, can)) || + (c3n == u3r_sing(pax, cax)) || + (c3n == u3r_sing(huc, cuc)) ) { + u3_noun mix = _cj_minx(cey, cor); + u3m_p("bad audit", loc); + u3m_p("hint says", mix); + u3z(mix); + } + + u3z(pax); +} + +/* _cj_mile(): register core for jets, returning location. +*/ +static u3_weak +_cj_mile(u3_noun clu, u3_noun cor) +{ + u3_weak loc = u3_none; + if ( c3n == u3du(cor) ) { + u3z(clu); + u3z(cor); + } + else { + u3_weak cey = _cj_je_fsck(clu); + if ( u3_none != cey ) { + u3_weak bas = u3_none; + loc = _cj_spot(cor, &bas); + if ( u3_none == loc ) { + loc = _cj_mine(cey, cor, bas); + } + else { + _cj_audit(loc, cey, cor); + } + u3z(cey); + if ( u3_none != bas ) { + u3z(bas); + } + } + u3z(cor); + } + return loc; +} + +/* u3j_mine(): register core for jets. +*/ +void +u3j_mine(u3_noun clu, u3_noun cor) +{ + u3_weak loc; + u3t_on(glu_o); + loc = _cj_mile(clu, cor); + u3z(loc); + u3t_off(glu_o); +} + +/* u3j_rite_mine(): mine cor with clue, using u3j_rite for caching +*/ +void +u3j_rite_mine(u3j_rite* rit_u, u3_noun clu, u3_noun cor) +{ + c3_t non_t; + u3t_on(glu_o); + + non_t = (u3_none == rit_u->clu); + + if ( non_t || + c3n == u3r_sing(rit_u->clu, clu) || + c3n == _cj_fine(cor, rit_u->fin_p) ) { + u3_weak loc = _cj_mile(u3k(clu), u3k(cor)); + if ( u3_none != loc ) { + u3p(u3j_fink) fon_p = rit_u->fin_p; + u3_noun old = rit_u->clu; + c3_o own_o = rit_u->own_o; + rit_u->own_o = c3y; + rit_u->clu = u3k(clu); + rit_u->fin_p = _cj_cast(cor, loc); + u3z(loc); + + if ( !non_t && (c3y == own_o) ) { + u3z(old); + _cj_fink_free(fon_p); + } + } + } + u3z(clu); + u3z(cor); + u3t_off(glu_o); +} + +/* _cj_take_hank_cb(): u3h_take_with cb for taking hanks +*/ +static c3_w +_cj_take_hank_cb(c3_w nah_w) +{ + u3j_hank* nah_u = _cj_to_hank(nah_w); + u3j_hank* han_u = u3a_walloc(c3_wiseof(u3j_hank)); + + if ( u3_none == nah_u->hax ) { + han_u->hax = u3_none; + // han_u->sit_u left uninitialized, will be ignored + } + else { + han_u->hax = u3a_take(nah_u->hax); + u3j_site_take(&(han_u->sit_u), &(nah_u->sit_u)); + } + + return _cj_of_hank(han_u); +} + +/* u3j_take(): copy junior jet state. +*/ +u3a_jets +u3j_take(u3a_jets jed_u) +{ + jed_u.war_p = u3h_take(jed_u.war_p); + jed_u.cod_p = u3h_take(jed_u.cod_p); + jed_u.han_p = u3h_take_with(jed_u.han_p, _cj_take_hank_cb); + jed_u.bas_p = u3h_take(jed_u.bas_p); + return jed_u; +} + +/* _cj_merge_hank_cb(): u3h_uni_with cb for integrating taken hanks +** NB "transfers" or frees hanks in jed_u.han_p +*/ +static void +_cj_merge_hank_cb(u3_noun kev, void* wit) +{ + u3p(u3h_root) han_p = *(u3p(u3h_root)*)wit; + u3j_hank* nah_u; + u3_noun key; + c3_w nah_w; + u3x_cell(kev, &key, &nah_w); + + nah_u = _cj_to_hank(nah_w); + + if ( u3_none == nah_u->hax ) { + u3a_wfree(nah_u); + } + else { + u3j_hank* han_u; + u3_weak got = u3h_git(u3R->jed.han_p, key); + + if ( u3_none == got ) { + han_u = nah_u; + } + else { + han_u = _cj_to_hank(got); + + if ( u3_none != han_u->hax ) { + u3z(han_u->hax); + } + han_u->hax = nah_u->hax; + + u3j_site_merge(&(han_u->sit_u), &(nah_u->sit_u)); + u3a_wfree(nah_u); + } + + u3h_put(han_p, key, _cj_of_hank(han_u)); + } +} + +/* u3j_reap(): promote jet state. +*/ +void +u3j_reap(u3a_jets jed_u) +{ + u3h_uni(u3R->jed.war_p, jed_u.war_p); + u3h_free(jed_u.war_p); + + u3h_uni(u3R->jed.cod_p, jed_u.cod_p); + u3h_free(jed_u.cod_p); + + u3h_walk_with(jed_u.han_p, _cj_merge_hank_cb, &u3R->jed.han_p); + u3h_free(jed_u.han_p); + + u3h_uni(u3R->jed.bas_p, jed_u.bas_p); + u3h_free(jed_u.bas_p); +} + +/* _cj_ream(): ream list of battery [bash registry] pairs. RETAIN. + */ +static void +_cj_ream(u3_noun all) +{ + c3_l par_l, jax_l; + u3_noun i, j, k, rul, loc, bal, act, lop, kev, rut, hap, + pat, reg, pol, rem, rec, bat, pel, nam, huc; + u3_weak pac; + + for ( i = all, lop = u3_nul; i != u3_nul; i = u3t(i) ) { + kev = u3h(i); + bat = u3h(kev); + reg = u3t(u3t(kev)); + rut = u3h(reg); + + // register roots + rul = u3qdb_tap(rut); + for ( j = rul; j != u3_nul; j = u3t(j) ) { + loc = u3t(u3h(j)); + u3x_trel(loc, &pat, &nam, &huc); + bal = u3nc(u3k(nam), u3_nul); + jax_l = _cj_hot_mean(0, nam); + hap = _cj_warm_hump(jax_l, huc); + act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); +#if 0 + u3m_p("old jet", bal); + u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); +#endif + u3h_put(u3R->jed.war_p, loc, act); + } + u3z(rul); + + // put ancestors in lop (list [battery=^ parent=location this=location]) + for ( j = u3t(reg); j != u3_nul; j = u3t(j) ) { + pol = lop; + lop = u3qdb_tap(u3t(u3h(j))); + for ( k = lop; u3_nul != k; k = u3t(k) ) { + pol = u3nc(u3nc(u3k(bat), u3k(u3h(k))), pol); + } + u3z(lop); + lop = pol; + } + } + + // ordering is random so we need to push onto rem when parent + // isn't yet present in the warm state + while ( u3_nul != lop ) { + rem = u3_nul; + for ( i = lop; u3_nul != i; i = u3t(i) ) { + rec = u3h(i); + u3x_trel(rec, &bat, &pel, &loc); + pac = _cj_find_warm(pel); + if ( u3_none == pac ) { + rem = u3nc(u3k(rec), rem); + } + else { + u3x_trel(loc, &pat, &nam, &huc); + par_l = u3h(pac); + jax_l = _cj_hot_mean(par_l, nam); + bal = u3nc(u3k(nam), u3k(u3h(u3t(u3t(pac))))); + hap = _cj_warm_hump(jax_l, huc), + u3z(pac); + act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); +#if 0 + u3m_p("old jet", bal); + u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); +#endif + u3h_put(u3R->jed.war_p, loc, act); + } + } + u3z(lop); + lop = rem; + } +} + +/* _cj_warm_tap(): tap war_p to rel +*/ +static void +_cj_warm_tap(u3_noun kev, void* wit) +{ + u3_noun* rel = wit; + *rel = u3nc(u3k(kev), *rel); +} + +/* _cj_ream_hank(): clear hot state out of hook sites. +*/ +static void +_cj_ream_hank(u3_noun kev) +{ + u3j_site_ream(&(_cj_to_hank(u3t(kev))->sit_u)); +} + +/* u3j_ream(): rebuild warm state +*/ +void +u3j_ream(void) +{ + u3_noun rel = u3_nul; + u3_assert(u3R == &(u3H->rod_u)); + u3h_free(u3R->jed.war_p); + u3R->jed.war_p = u3h_new(); + u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel); + _cj_ream(rel); + u3z(rel); + + u3h_walk(u3R->jed.han_p, _cj_ream_hank); +} + +/* u3j_stay(): extract cold state +*/ +u3_noun +u3j_stay(void) +{ + u3_noun rel = u3_nul; + u3_assert(u3R == &(u3H->rod_u)); + u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel); + return rel; +} + +/* u3j_load(): inject cold state +*/ +void +u3j_load(u3_noun rel) +{ + u3_noun ler = rel; + u3_noun lor; + + while ( u3_nul != ler ) { + u3x_cell(ler, &lor, &ler); + u3h_put(u3R->jed.cod_p, u3h(lor), u3k(u3t(lor))); + } + + u3z(rel); +} + +/* _cj_fink_mark(): mark a u3j_fink for gc. +*/ +static c3_w +_cj_fink_mark(u3j_fink* fin_u) +{ + c3_w i_w, tot_w = u3a_mark_noun(fin_u->sat); + for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { + u3j_fist* fis_u = &(fin_u->fis_u[i_w]); + tot_w += u3a_mark_noun(fis_u->bat); + tot_w += u3a_mark_noun(fis_u->pax); + } + tot_w += u3a_mark_ptr(fin_u); + return tot_w; +} + +/* u3j_site_lose(): lose references of u3j_site (but do not free). + */ +void +u3j_site_lose(u3j_site* sit_u) +{ + u3z(sit_u->axe); + if ( u3_none != sit_u->bat ) { + u3z(sit_u->bat); + } + if ( u3_none != sit_u->bas ) { + u3z(sit_u->bas); + } + if ( u3_none != sit_u->loc ) { + u3z(sit_u->loc); + u3z(sit_u->lab); + if ( c3y == sit_u->fon_o ) { + _cj_fink_free(sit_u->fin_p); + } + } +} + +/* u3j_rite_lose(): lose references of u3j_rite (but do not free). + */ +void +u3j_rite_lose(u3j_rite* rit_u) +{ + if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) { + u3z(rit_u->clu); + _cj_fink_free(rit_u->fin_p); + } +} + +/* u3j_rite_mark(): mark u3j_rite for gc. +*/ +c3_w +u3j_rite_mark(u3j_rite* rit_u) +{ + c3_w tot_w = 0; + if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) { + tot_w += u3a_mark_noun(rit_u->clu); + tot_w += _cj_fink_mark(u3to(u3j_fink, rit_u->fin_p)); + } + return tot_w; +} + +/* u3j_site_mark(): mark u3j_site for gc. +*/ +c3_w +u3j_site_mark(u3j_site* sit_u) +{ + c3_w tot_w = u3a_mark_noun(sit_u->axe); + if ( u3_none != sit_u->bat ) { + tot_w += u3a_mark_noun(sit_u->bat); + } + if ( u3_none != sit_u->bas ) { + tot_w += u3a_mark_noun(sit_u->bas); + } + if ( u3_none != sit_u->loc ) { + tot_w += u3a_mark_noun(sit_u->loc); + tot_w += u3a_mark_noun(sit_u->lab); + if ( c3y == sit_u->fon_o ) { + tot_w += _cj_fink_mark(u3to(u3j_fink, sit_u->fin_p)); + } + } + return tot_w; +} + +/* _cj_mark_hank(): mark hank cache for gc. +*/ +static void +_cj_mark_hank(u3_noun kev, void* dat) +{ + c3_w* tot_w = (c3_w*) dat; + u3j_hank* han_u = _cj_to_hank(u3t(kev)); + *tot_w += u3a_mark_ptr(han_u); + if ( u3_none != han_u->hax ) { + *tot_w += u3a_mark_noun(han_u->hax); + *tot_w += u3j_site_mark(&(han_u->sit_u)); + } +} + +/* u3j_mark(): mark jet state for gc. +*/ +u3m_quac* +u3j_mark() +{ + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 7); + + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("warm jet state"); + qua_u[0]->siz_w = u3h_mark(u3R->jed.war_p) * 4; + + qua_u[1] = c3_calloc(sizeof(*qua_u[1])); + qua_u[1]->nam_c = strdup("cold jet state"); + qua_u[1]->siz_w = u3h_mark(u3R->jed.cod_p) * 4; + + qua_u[2] = c3_calloc(sizeof(*qua_u[2])); + qua_u[2]->nam_c = strdup("hank cache"); + qua_u[2]->siz_w = u3h_mark(u3R->jed.han_p) * 4; + + qua_u[3] = c3_calloc(sizeof(*qua_u[3])); + qua_u[3]->nam_c = strdup("battery hash cache"); + qua_u[3]->siz_w = u3h_mark(u3R->jed.bas_p) * 4; + + qua_u[4] = c3_calloc(sizeof(*qua_u[4])); + qua_u[4]->nam_c = strdup("call site cache"); + u3h_walk_with(u3R->jed.han_p, _cj_mark_hank, &qua_u[4]->siz_w); + qua_u[4]->siz_w *= 4; + + c3_w sum_w = 0; + for ( c3_w i_w = 0; i_w < 5; i_w++ ) { + sum_w += qua_u[i_w]->siz_w; + } + + u3m_quac* tot_u = c3_calloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total jet stuff"); + + if ( u3R == &(u3H->rod_u) ) { + qua_u[5] = c3_calloc(sizeof(*qua_u[5])); + qua_u[5]->nam_c = strdup("hot jet state"); + qua_u[5]->siz_w = u3h_mark(u3R->jed.hot_p) * 4; + + sum_w += qua_u[5]->siz_w; + + qua_u[6] = NULL; + + tot_u->siz_w = sum_w; + tot_u->qua_u = qua_u; + + return tot_u; + } else { + qua_u[5] = NULL; + + tot_u->siz_w = sum_w; + tot_u->qua_u = qua_u; + + return tot_u; + } +} + +/* u3j_free_hank(): free an entry from the hank cache. +*/ +void +u3j_free_hank(u3_noun kev) +{ + u3j_hank* han_u = _cj_to_hank(u3t(kev)); + if ( u3_none != han_u->hax ) { + u3z(han_u->hax); + u3j_site_lose(&(han_u->sit_u)); + } + u3a_wfree(han_u); +} + +/* u3j_free(): free jet state. +*/ +void +u3j_free(void) +{ + u3h_walk(u3R->jed.han_p, u3j_free_hank); + u3h_free(u3R->jed.war_p); + u3h_free(u3R->jed.cod_p); + u3h_free(u3R->jed.han_p); + u3h_free(u3R->jed.bas_p); + if ( u3R == &(u3H->rod_u) ) { + u3h_free(u3R->jed.hot_p); + } +} + +/* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3j_reclaim(void) +{ + // re-establish the warm jet state + // + // XX might this reduce fragmentation? + // + // if ( &(u3H->rod_u) == u3R ) { + // u3j_ream(); + // } + // clear the jet hank cache + // + u3h_walk(u3R->jed.han_p, u3j_free_hank); + u3h_free(u3R->jed.han_p); + u3R->jed.han_p = u3h_new(); +} + +/* u3j_rewrite_compact(): rewrite jet state for compaction. + * + * NB: u3R->jed.han_p *must* be cleared (currently via u3j_reclaim above) + * since it contains hanks which are not nouns but have loom pointers. + * Alternately, rewrite the entries with u3h_walk, using u3j_mark as a + * template for how to walk. There's an untested attempt at this in git + * history at e8a307a. +*/ +void +u3j_rewrite_compact(void) +{ + u3h_relocate(&(u3R->jed.war_p)); + u3h_relocate(&(u3R->jed.cod_p)); + u3h_relocate(&(u3R->jed.han_p)); + u3h_relocate(&(u3R->jed.bas_p)); + + if ( u3R == &(u3H->rod_u) ) { + u3h_relocate(&(u3R->jed.hot_p)); + } +} diff --git a/vere/pkg/noun/jets.h b/vere/pkg/noun/jets.h new file mode 100644 index 0000000..c81ab18 --- /dev/null +++ b/vere/pkg/noun/jets.h @@ -0,0 +1,322 @@ +/// @file + +#ifndef U3_JETS_H +#define U3_JETS_H + +#include "allocate.h" +#include "c3/c3.h" +#include "types.h" + + /** Noun semantics. + **/ +#if 0 ++= location $: pattern=(each static dynamic) + name=term + hooks=(map term axis) + == ++= static (each payload=* parent=location) ++= dynamic [where=axis parent=location] +:: ++= registry [roots=(map * location) parents=(list parent)] ++= parent (pair axis (map location location)) +:: ++= activation $: hot-index=@ud + drivers=(map axis @ud) + label=path + jit=* :: FIXME: should probably be (map battery *) + :: since there can be multiple batteries per location + == ++= hot-info $: reg=registry + hot-index=@ud + drivers=(map axis @ud) + label=path + == ++= bash @ :: battery hash (sha-256 based) +:: ++= hot (map bash hot-info) ++= cold (map battery=^ (pair bash registry)) ++= warm (map location activation) +#endif + + /** Data structures. + *** + *** All of these are transient structures allocated with malloc. + **/ + /* u3j_harm: jet arm. + */ + typedef struct _u3j_harm { + c3_c* fcs_c; // `.axe` or name + u3_noun (*fun_f)(u3_noun); // compute or 0 / semitransfer + // c3_o (*val_f)(u3_noun); // validate or 0 / retain + c3_o ice; // perfect (don't test) + c3_o tot; // total (never punts) + c3_o liv; // live (enabled) + c3_l axe_l; // computed/discovered axis + struct _u3j_core* cop_u; // containing core + } u3j_harm; + + /* u3j_hood: hook description. + */ + typedef struct _u3j_hood { + c3_c* nam_c; // hook name + c3_l axe_l; // hook axis (XX: direct) + c3_o kic_o; // hook is kick (vs. fragment) + c3_l sax_l; // hook subject axis (XX: direct) + } u3j_hood; + + /* u3j_core: driver definition. + */ + typedef struct _u3j_core { + c3_c* cos_c; // control string + c3_l axe_l; // axis to parent + struct _u3j_harm* arm_u; // blank-terminated static list + struct _u3j_core* dev_u; // blank-terminated static list + c3_c** bas_u; // blank-terminated static list + struct _u3j_hood* huc_u; // blank-terminated static list + struct _u3j_core* par_u; // dynamic parent pointer + c3_l jax_l; // index in global dashboard + } u3j_core; + + /* u3j_dash, u3_Dash, u3D: jet dashboard singleton + */ + typedef struct _u3j_dash { + u3j_core* dev_u; // null-terminated static list + c3_l len_l; // dynamic array length + c3_l all_l; // allocated length + u3j_core* ray_u; // dynamic array by axis + } u3j_dash; + + /* u3j_fist: a single step in a fine check. + */ + typedef struct { + u3_noun bat; // battery + u3_noun pax; // parent axis + } u3j_fist; + + /* u3j_fink: (fine check) enough data to verify a located core. + */ + typedef struct { + c3_w len_w; // number of fists + u3_noun sat; // static noun at end of check + u3j_fist fis_u[]; // fists + } u3j_fink; + + /* u3j_rite: site of a %fast, used to skip re-mining. + */ + typedef struct { + c3_o own_o; // rite owns fink? + u3_weak clu; // cached product of clue formula + u3p(u3j_fink) fin_p; // fine check + } u3j_rite; + + /* u3j_site: site of a kick (nock 9), used to cache call target. + */ + struct _u3n_prog; + typedef struct { + u3p(struct _u3n_prog) pog_p; // program for formula + u3_noun axe; // axis + u3_weak bat; // battery (for verification) + u3_weak bas; // hash of battery (for hot find) + u3_weak loc; // location (for reaming) + c3_o jet_o; // have jet driver? + c3_o fon_o; // site owns fink? + u3_weak lab; // label (for tracing) + u3j_core* cop_u; // jet core + u3j_harm* ham_u; // jet arm + u3p(u3j_fink) fin_p; // fine check + } u3j_site; + + /* u3j_hank: cached hook information. + */ + typedef struct { + u3_weak hax; // axis of hooked inner core + u3j_site sit_u; // call-site data + } u3j_hank; + + /** Globals. + **/ + /* u3_Dash: jet dashboard. + */ + extern u3j_dash u3j_Dash; +# define u3D u3j_Dash + + /** Functions. + **/ + /* u3j_boot(): initialize jet system. + */ + c3_w + u3j_boot(c3_o nuu_o); + + /* u3j_clear(): clear jet table to re-register. + */ + void + u3j_clear(void); + + /* u3j_cook(): + ** + ** Execute hook from core, call site cached by arbitrary c string + */ + u3_noun + u3j_cook(const c3_c* key_c, + u3_noun cor, + const c3_c* tam_c); + + /* u3j_hook(): + ** + ** Execute hook from core. + */ + u3_noun + u3j_hook(u3_noun cor, + const c3_c* tam_c); + + /* u3j_soft(): + ** + ** Execute hook from core, without jet. + */ + u3_noun + u3j_soft(u3_noun cor, + const c3_c* tam_c); + + /* u3j_kick(): try to kick by jet. If no kick, produce u3_none. + ** + ** `axe` is RETAINED by the caller; `cor` is RETAINED iff there + ** is no kick, TRANSFERRED if one. + */ + u3_weak + u3j_kick(u3_noun cor, u3_noun axe); + + /* u3j_kink(): kick either by jet or by nock. + */ + u3_noun + u3j_kink(u3_noun cor, + u3_noun axe); + + /* u3j_mine(): register core for jets. + */ + void + u3j_mine(u3_noun clu, + u3_noun cor); + + /* u3j_ream(): refresh after restoring from checkpoint. + */ + void + u3j_ream(void); + + /* u3j_stay(): extract cold state + */ + u3_noun + u3j_stay(void); + + /* u3j_load(): inject cold state + */ + void + u3j_load(u3_noun rel); + + /* u3j_reap(): promote jet state. + */ + void + u3j_reap(u3a_jets jed_u); + + /* u3j_take(): copy junior jet state. + */ + u3a_jets + u3j_take(u3a_jets jed_u); + + /* u3j_rite_mine(): mine cor with clu, using u3j_rite for caching + */ + void + u3j_rite_mine(u3j_rite* rit_u, u3_noun clu, u3_noun cor); + + /* u3j_rite_take(): copy junior rite references from src_u to dst_u. + */ + void + u3j_rite_take(u3j_rite* dst_u, u3j_rite* src_u); + + /* u3j_rite_merge(): copy rite references from src_u to dst_u, + ** losing old references + */ + void + u3j_rite_merge(u3j_rite* dst_u, u3j_rite* src_u); + + /* u3j_site_take(): copy junior site references. + */ + void + u3j_site_take(u3j_site* dst_u, u3j_site* src_u); + + /* u3j_site_merge(): copy site references from src_u to dst_u, + ** losing old references + */ + void + u3j_site_merge(u3j_site* dst_u, u3j_site* src_u); + + /* u3j_site_ream(): refresh u3j_site after restoring from checkpoint + */ + void + u3j_site_ream(u3j_site* sit_u); + + /* u3j_site_kick(): kick a core with a u3j_site cache. + */ + u3_weak + u3j_site_kick(u3_noun cor, u3j_site* sit_u); + + /* u3j_gate_prep(): prepare a locally cached gate to call repeatedly. + */ + void + u3j_gate_prep(u3j_site* sit_u, u3_noun cor); + + /* u3j_gate_slam(): slam a site prepared by u3j_gate_find() with sample. + */ + u3_noun + u3j_gate_slam(u3j_site* sit_u, u3_noun sam); + + /* u3j_gate_lose(): clean up site prepared by u3j_gate_find(). + */ + void + u3j_gate_lose(u3j_site* sit_u); + + /* u3j_rite_mark(): mark u3j_rite for gc. + */ + c3_w + u3j_rite_mark(u3j_rite* rit_u); + + /* u3j_rite_lose(): lose references of u3j_rite (but do not free). + */ + void + u3j_rite_lose(u3j_rite* rit_u); + + /* u3j_site_lose(): lose references of u3j_site (but do not free). + */ + void + u3j_site_lose(u3j_site* sit_u); + + /* u3j_site_mark(): mark u3j_site for gc. + */ + c3_w + u3j_site_mark(u3j_site* sit_u); + + /* u3j_mark(): mark jet state for gc. + */ + u3m_quac* + u3j_mark(); + + /* u3j_free(): free jet state. + */ + void + u3j_free(void); + + /* u3j_free_hank(): free an entry from the hank cache. + */ + void + u3j_free_hank(u3_noun kev); + + /* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3j_reclaim(void); + + /* u3j_rewrite_compact(): rewrite jet state for compaction. + */ + void + u3j_rewrite_compact(void); + +#endif /* ifndef U3_JETS_H */ diff --git a/vere/pkg/noun/jets/136/tree.c b/vere/pkg/noun/jets/136/tree.c new file mode 100644 index 0000000..345fe3a --- /dev/null +++ b/vere/pkg/noun/jets/136/tree.c @@ -0,0 +1,1268 @@ +#include "c3/c3.h" +#include "jets.h" +#include "jets/w.h" + + +static c3_c* no_hashes[] = { 0 }; + +static u3j_harm _136_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}}; +static u3j_harm _136_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}}; +static u3j_core _136_hex_mimes_base16_d[] = + { { "en", 7, _136_hex_mimes_base16_en_a, 0, no_hashes }, + { "de", 7, _136_hex_mimes_base16_de_a, 0, no_hashes }, + {} + }; +static u3j_core _136_hex_mimes_d[] = + { { "base16", 3, 0, _136_hex_mimes_base16_d, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}}; +static u3j_harm _136_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}}; +static u3j_core _136_hex_aes_ecba_d[] = + { { "en", 7, _136_hex_aes_ecba_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_ecba_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}}; +static u3j_harm _136_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}}; +static u3j_core _136_hex_aes_ecbb_d[] = + { { "en", 7, _136_hex_aes_ecbb_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_ecbb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}}; +static u3j_harm _136_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}}; +static u3j_core _136_hex_aes_ecbc_d[] = + { { "en", 7, _136_hex_aes_ecbc_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_ecbc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}}; +static u3j_harm _136_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}}; +static u3j_core _136_hex_aes_cbca_d[] = + { { "en", 7, _136_hex_aes_cbca_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_cbca_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}}; +static u3j_harm _136_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}}; +static u3j_core _136_hex_aes_cbcb_d[] = + { { "en", 7, _136_hex_aes_cbcb_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_cbcb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}}; +static u3j_harm _136_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}}; +static u3j_core _136_hex_aes_cbcc_d[] = + { { "en", 7, _136_hex_aes_cbcc_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_cbcc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}}; +static u3j_harm _136_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}}; +static u3j_core _136_hex_aes_siva_d[] = + { { "en", 7, _136_hex_aes_siva_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_siva_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}}; +static u3j_harm _136_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}}; +static u3j_core _136_hex_aes_sivb_d[] = + { { "en", 7, _136_hex_aes_sivb_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_sivb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}}; +static u3j_harm _136_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}}; +static u3j_core _136_hex_aes_sivc_d[] = + { { "en", 7, _136_hex_aes_sivc_en_a, 0, no_hashes }, + { "de", 7, _136_hex_aes_sivc_de_a, 0, no_hashes }, + {} + }; +static u3j_core _136_hex_aes_d[] = + { { "ecba", 7, 0, _136_hex_aes_ecba_d, no_hashes }, + { "ecbb", 7, 0, _136_hex_aes_ecbb_d, no_hashes }, + { "ecbc", 7, 0, _136_hex_aes_ecbc_d, no_hashes }, + { "cbca", 7, 0, _136_hex_aes_cbca_d, no_hashes }, + { "cbcb", 7, 0, _136_hex_aes_cbcb_d, no_hashes }, + { "cbcc", 7, 0, _136_hex_aes_cbcc_d, no_hashes }, + { "siva", 7, 0, _136_hex_aes_siva_d, no_hashes }, + { "sivb", 7, 0, _136_hex_aes_sivb_d, no_hashes }, + { "sivc", 7, 0, _136_hex_aes_sivc_d, no_hashes }, + {} + }; + +static u3j_harm _136_hex_leer_a[] = {{".2", u3we_leer}, {}}; +static u3j_harm _136_hex_lore_a[] = {{".2", u3we_lore}, {}}; +static u3j_harm _136_hex_loss_a[] = {{".2", u3we_loss}, {}}; +static u3j_harm _136_hex_lune_a[] = {{".2", u3we_lune}, {}}; + + +static u3j_harm _136_hex__adler32_a[] = {{".2", u3we_adler32, c3y}, {}}; +static u3j_core _136_hex__adler_d[] = + { { "adler32", 7, _136_hex__adler32_a, 0, no_hashes }, + {} + }; +static u3j_harm _136_hex__crc32_a[] = {{".2", u3we_crc32}, {}}; +static u3j_core _136_hex__crc_d[] = + { {"crc32", 7, _136_hex__crc32_a, 0, no_hashes }, + {} + }; + +static u3j_core _136_hex_checksum_d[] = + { { "adler", 3, 0, _136_hex__adler_d, no_hashes }, + { "crc", 3, 0, _136_hex__crc_d, no_hashes}, + {} + }; + + +static u3j_harm _136_hex__decompress_zlib_a[] = {{".2", u3we_decompress_zlib}, {}}; +static u3j_harm _136_hex__decompress_gzip_a[] = {{".2", u3we_decompress_gzip}, {}}; +static u3j_core _136_hex__zlib_d[] = { + {"decompress-zlib", 7, _136_hex__decompress_zlib_a, 0, no_hashes }, + {"decompress-gzip", 7, _136_hex__decompress_gzip_a, 0, no_hashes }, + {}}; + + +static u3j_harm _136_hex_coed__ed_scad_a[] = {{".2", u3wee_scad}, {}}; +static u3j_harm _136_hex_coed__ed_scas_a[] = {{".2", u3wee_scas}, {}}; +static u3j_harm _136_hex_coed__ed_scap_a[] = {{".2", u3wee_scap}, {}}; + +static u3j_harm _136_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}}; +static u3j_harm _136_hex_coed__ed_luck_a[] = {{".2", u3wee_luck}, {}}; +static u3j_harm _136_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}}; +static u3j_harm _136_hex_coed__ed_sign_raw_a[] = {{".2", u3wee_sign_raw}, {}}; +static u3j_harm _136_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}}; +static u3j_harm _136_hex_coed__ed_sign_octs_raw_a[] = {{".2", u3wee_sign_octs_raw}, {}}; +static u3j_harm _136_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}}; +static u3j_harm _136_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}}; +static u3j_harm _136_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}}; +static u3j_harm _136_hex_coed__ed_slar_a[] = {{".2", u3wee_slar}, {}}; + +static u3j_harm _136_hex_coed__ed_smac_a[] = + {{".2", u3wee_smac}, {}}; + +static u3j_harm _136_hex_coed__ed_recs_a[] = + {{".2", u3wee_recs}, {}}; + +static u3j_harm _136_hex_coed__ed_point_neg_a[] = + {{".2", u3wee_point_neg}, {}}; + +static u3j_harm _136_hex_coed__ed_point_add_a[] = + {{".2", u3wee_point_add}, {}}; + +static u3j_harm _136_hex_coed__ed_scalarmult_a[] = + {{".2", u3wee_scalarmult}, {}}; + +static u3j_harm _136_hex_coed__ed_scalarmult_base_a[] = + {{".2", u3wee_scalarmult_base}, {}}; + +static u3j_harm _136_hex_coed__ed_add_scalarmult_scalarmult_base_a[] = + {{".2", u3wee_add_scalarmult_scalarmult_base}, {}}; + +static u3j_harm _136_hex_coed__ed_add_double_scalarmult_a[] = + {{".2", u3wee_add_double_scalarmult}, {}}; + +static u3j_core _136_hex_coed__ed_d[] = + { { "sign", 7, _136_hex_coed__ed_sign_a, 0, no_hashes }, + { "sign-raw", 7, _136_hex_coed__ed_sign_raw_a, 0, no_hashes }, + { "sign-octs", 7, _136_hex_coed__ed_sign_octs_a, 0, no_hashes }, + { "sign-octs-raw", 7, _136_hex_coed__ed_sign_octs_raw_a, 0, no_hashes }, + { "puck", 7, _136_hex_coed__ed_puck_a, 0, no_hashes }, + { "luck", 7, _136_hex_coed__ed_luck_a, 0, no_hashes }, + { "scad", 7, _136_hex_coed__ed_scad_a, 0, no_hashes }, + { "scas", 7, _136_hex_coed__ed_scas_a, 0, no_hashes }, + { "scap", 7, _136_hex_coed__ed_scap_a, 0, no_hashes }, + { "veri-octs", 7, _136_hex_coed__ed_veri_octs_a, 0, no_hashes }, + { "veri", 7, _136_hex_coed__ed_veri_a, 0, no_hashes }, + { "shar", 7, _136_hex_coed__ed_shar_a, 0, no_hashes }, + { "slar", 7, _136_hex_coed__ed_slar_a, 0, no_hashes }, + { "point-add", 7, _136_hex_coed__ed_point_add_a, 0, 0 }, + { "point-neg", 7, _136_hex_coed__ed_point_neg_a, 0, 0 }, + { "recs", 7, _136_hex_coed__ed_recs_a, 0, 0 }, + { "smac", 7, _136_hex_coed__ed_smac_a, 0, 0 }, + { "scalarmult", 7, _136_hex_coed__ed_scalarmult_a, 0, + no_hashes }, + { "scalarmult-base", 7, _136_hex_coed__ed_scalarmult_base_a, 0, + no_hashes }, + { "add-scalarmult-scalarmult-base", 7, + _136_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0, + no_hashes }, + { "add-double-scalarmult", 7, + _136_hex_coed__ed_add_double_scalarmult_a, 0, + no_hashes }, + {} + }; + +static u3j_core _136_hex_coed_d[] = + { { "ed", 3, 0, _136_hex_coed__ed_d, no_hashes }, + {} + }; + +static u3j_harm _136_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}}; +static u3j_core _136_hex_hmac_d[] = + { { "hmac", 7, _136_hex_hmac_hmac_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_argon2_a[] = {{".2", u3we_argon2}, {}}; +static u3j_core _136_hex_argon_d[] = + { { "argon2", 511, _136_hex_argon2_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}}; +static u3j_harm _136_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}}; +static u3j_harm _136_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}}; +static u3j_harm _136_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}}; +static u3j_core _136_hex_scr_d[] = + { { "pbk", 7, _136_hex_scr_pbk_a, 0, no_hashes }, + { "pbl", 7, _136_hex_scr_pbl_a, 0, no_hashes }, + { "hsh", 7, _136_hex_scr_hsh_a, 0, no_hashes }, + { "hsl", 7, _136_hex_scr_hsl_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}}; +static u3j_harm _136_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}}; +static u3j_harm _136_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}}; + +static u3j_harm _136_hex_secp_secp256k1_schnorr_sosi_a[] = + {{".2", u3we_sosi}, {}}; +static u3j_harm _136_hex_secp_secp256k1_schnorr_sove_a[] = + {{".2", u3we_sove}, {}}; +static u3j_core _136_hex_secp_secp256k1_schnorr_d[] = + { { "sosi", 7, + _136_hex_secp_secp256k1_schnorr_sosi_a, 0, + no_hashes }, + { "sove", 7, + _136_hex_secp_secp256k1_schnorr_sove_a, 0, + no_hashes }, + {} + }; + +static u3j_core _136_hex_secp_secp256k1_d[] = + { { "make", 7, _136_hex_secp_secp256k1_make_a, 0, no_hashes }, + { "sign", 7, _136_hex_secp_secp256k1_sign_a, 0, no_hashes }, + { "reco", 7, _136_hex_secp_secp256k1_reco_a, 0, no_hashes }, + { "schnorr", 7, 0, + _136_hex_secp_secp256k1_schnorr_d, + no_hashes }, + {} + }; +static u3j_core _136_hex_secp_d[] = + { { "secp256k1", 3, 0, _136_hex_secp_secp256k1_d, no_hashes }, + {} + }; + + +static u3j_harm _136_hex_kecc_k224_a[] = + {{".2", u3we_kecc224, c3y, c3y, c3y}, {}}; +static u3j_harm _136_hex_kecc_k256_a[] = + {{".2", u3we_kecc256, c3y, c3y, c3y}, {}}; +static u3j_harm _136_hex_kecc_k384_a[] = + {{".2", u3we_kecc384, c3y, c3y, c3y}, {}}; +static u3j_harm _136_hex_kecc_k512_a[] = + {{".2", u3we_kecc512, c3y, c3y, c3y}, {}}; +static u3j_core _136_hex_kecc_d[] = + { { "k224", 7, _136_hex_kecc_k224_a, 0, no_hashes }, + { "k256", 7, _136_hex_kecc_k256_a, 0, no_hashes }, + { "k384", 7, _136_hex_kecc_k384_a, 0, no_hashes }, + { "k512", 7, _136_hex_kecc_k512_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}}; +static u3j_core _136_hex_ripe_d[] = + { { "ripemd160", 7, _136_hex_ripemd_160_a, 0, no_hashes }, + {} + }; + + + +/* layer five + */ +static u3j_harm _136_pen_cell_a[] = {{".2", u3wf_cell}, {}}; +static u3j_harm _136_pen_comb_a[] = {{".2", u3wf_comb}, {}}; +static u3j_harm _136_pen_cons_a[] = {{".2", u3wf_cons}, {}}; +static u3j_harm _136_pen_core_a[] = {{".2", u3wf_core}, {}}; +static u3j_harm _136_pen_face_a[] = {{".2", u3wf_face}, {}}; +static u3j_harm _136_pen_fitz_a[] = {{".2", u3wf_fitz}, {}}; +static u3j_harm _136_pen_fork_a[] = {{".2", u3wf_fork}, {}}; + +static u3j_harm _136_pen_look_a[] = {{".2", u3wf_look}, {}}; +static u3j_harm _136_pen_loot_a[] = {{".2", u3wf_loot}, {}}; + +static u3j_harm _136_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}}; +static u3j_harm _136_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}}; +static u3j_harm _136_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}}; +static u3j_harm _136_pen__ut_redo_a[] = {{".2", u3wfu_redo}, {}}; +static u3j_harm _136_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}}; +static u3j_harm _136_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}}; + +static u3j_harm _136_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}}; +static u3j_core _136_pen__ut_nest_in_d[] = + { + { "nest-dext", 3, _136_pen__ut_nest_dext_a, 0, no_hashes }, + {} + }; +static u3j_core _136_pen__ut_nest_d[] = + { + { "nest-in", 7, 0, _136_pen__ut_nest_in_d, no_hashes }, + {} + }; + +static u3j_harm _136_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}}; + +static u3j_core _136_pen__ut_d[] = + { + { "crop", 7, _136_pen__ut_crop_a, 0, no_hashes }, + { "fish", 7, _136_pen__ut_fish_a, 0, no_hashes }, + { "fuse", 7, _136_pen__ut_fuse_a, 0, no_hashes }, + { "redo", 7, _136_pen__ut_redo_a, 0, no_hashes }, + { "mint", 7, _136_pen__ut_mint_a, 0, no_hashes }, + { "mull", 7, _136_pen__ut_mull_a, 0, no_hashes }, + { "nest", 7, 0, _136_pen__ut_nest_d, no_hashes }, + { "rest", 7, _136_pen__ut_rest_a, 0, no_hashes }, + {} + }; + +static u3j_hood _136_pen__ut_ho[] = + { { "ar", 12282 }, + { "fan", 28, c3n }, + { "rib", 58, c3n }, + { "vet", 59, c3n }, + + { "blow", 6015 }, + { "burp", 342 }, + { "busk", 1363 }, + { "buss", 374 }, + { "crop", 1494 }, + { "duck", 1524 }, + { "dune", 2991 }, + { "dunk", 3066 }, + { "epla", 12206 }, + { "emin", 1534 }, + { "emul", 6134 }, + { "feel", 1502 }, + { "felt", 94 }, + { "fine", 49086 }, + { "fire", 4 }, + { "fish", 6006 }, + { "fond", 12283 }, + { "fund", 6014 }, + // XX +funk is not part of +ut, and this hook appears to be unused + // remove from here and the +ut hint + // + { "funk", 0xbefafa, c3y, 31 }, + { "fuse", 24021 }, + { "gain", 380 }, + { "lose", 0x2fefe }, + { "mile", 382 }, + { "mine", 372 }, + { "mint", 49083 }, + { "moot", 0x2feff }, + { "mull", 24020 }, + { "nest", 92 }, + { "peel", 1526 }, + { "play", 3006 }, + { "peek", 1532 }, + { "repo", 22 }, + { "rest", 6102 }, + { "tack", 6007 }, + { "toss", 24540 }, + { "wrap", 6136 }, + {}, + }; + + +static u3j_hood _136_pen_ho[] = { + { "ap", 22 }, + { "ut", 86 }, + {}, +}; + + +/* layer four + */ +static u3j_harm _136_qua_trip_a[] = {{".2", u3we_trip}, {}}; + +static u3j_harm _136_qua_slaw_a[] = {{".2", u3we_slaw}, {}}; +static u3j_harm _136_qua_scot_a[] = {{".2", u3we_scot}, {}}; +static u3j_harm _136_qua_scow_a[] = {{".2", u3we_scow}, {}}; + +static u3j_harm _136_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}}; +static u3j_harm _136_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}}; +static u3j_harm _136_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}}; +static u3j_harm _136_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}}; +static u3j_core _136_qua__po_d[] = + { { "ind", 7, _136_qua__po_ind_a, 0, no_hashes }, + { "ins", 7, _136_qua__po_ins_a, 0, no_hashes }, + { "tod", 7, _136_qua__po_tod_a, 0, no_hashes }, + { "tos", 7, _136_qua__po_tos_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}}; +static u3j_core _136_qua__bend_d[] = + { { "fun", 7, _136_qua__bend_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}}; +static u3j_core _136_qua__cold_d[] = + { { "fun", 7, _136_qua__cold_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}}; +static u3j_core _136_qua__cook_d[] = + { { "fun", 7, _136_qua__cook_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}}; +static u3j_core _136_qua__comp_d[] = + { { "fun", 7, _136_qua__comp_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}}; +static u3j_core _136_qua__easy_d[] = + { { "fun", 7, _136_qua__easy_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}}; +static u3j_core _136_qua__glue_d[] = + { { "fun", 7, _136_qua__glue_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}}; +static u3j_core _136_qua__here_d[] = + { { "fun", 7, _136_qua__here_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}}; +static u3j_core _136_qua__just_d[] = + { { "fun", 7, _136_qua__just_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}}; +static u3j_core _136_qua__mask_d[] = + { { "fun", 7, _136_qua__mask_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}}; +static u3j_core _136_qua__shim_d[] = + { { "fun", 7, _136_qua__shim_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}}; +static u3j_core _136_qua__stag_d[] = + { { "fun", 7, _136_qua__stag_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}}; +static u3j_core _136_qua__stew_d[] = + { { "fun", 31, _136_qua__stew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}}; +static u3j_core _136_qua__stir_d[] = + { { "fun", 7, _136_qua__stir_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_qua_pfix_a[] = {{".2", u3we_pfix}, {}}; + +static u3j_harm _136_qua_plug_a[] = {{".2", u3we_plug}, {}}; +static u3j_harm _136_qua_pose_a[] = {{".2", u3we_pose}, {}}; + +static u3j_harm _136_qua_sfix_a[] = {{".2", u3we_sfix}, {}}; + +static u3j_harm _136_qua_mink_a[] = {{".2", u3we_mink}, {}}; +static u3j_harm _136_qua_mole_a[] = {{".2", u3we_mole}, {}}; +static u3j_harm _136_qua_mule_a[] = {{".2", u3we_mule}, {}}; + + +static u3j_hood _136_qua_ho[] = { + { "show", 188 }, + {}, +}; + + +/* layer three + */ +static u3j_harm _136_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}}; +static u3j_harm _136_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}}; +static u3j_core _136_tri__cofl_d[] = + { { "drg", 7, _136_tri__cofl__drg_a, 0, no_hashes }, + { "lug", 7, _136_tri__cofl__lug_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_tri__rd_add_a[] = {{".2", u3wer_add}, {}}; +static u3j_harm _136_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}}; +static u3j_harm _136_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}}; +static u3j_harm _136_tri__rd_div_a[] = {{".2", u3wer_div}, {}}; +static u3j_harm _136_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}}; +static u3j_harm _136_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}}; +static u3j_harm _136_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}}; +static u3j_harm _136_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}}; +static u3j_harm _136_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}}; +static u3j_harm _136_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}}; +static u3j_harm _136_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}}; +static u3j_core _136_tri__rd_d[] = + { { "add", 7, _136_tri__rd_add_a, 0, no_hashes }, + { "sub", 7, _136_tri__rd_sub_a, 0, no_hashes }, + { "mul", 7, _136_tri__rd_mul_a, 0, no_hashes }, + { "div", 7, _136_tri__rd_div_a, 0, no_hashes }, + { "sqt", 7, _136_tri__rd_sqt_a, 0, no_hashes }, + { "fma", 7, _136_tri__rd_fma_a, 0, no_hashes }, + { "lth", 7, _136_tri__rd_lth_a, 0, no_hashes }, + { "lte", 7, _136_tri__rd_lte_a, 0, no_hashes }, + { "equ", 7, _136_tri__rd_equ_a, 0, no_hashes }, + { "gte", 7, _136_tri__rd_gte_a, 0, no_hashes }, + { "gth", 7, _136_tri__rd_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_tri__rs_add_a[] = {{".2", u3wet_add}, {}}; +static u3j_harm _136_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}}; +static u3j_harm _136_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}}; +static u3j_harm _136_tri__rs_div_a[] = {{".2", u3wet_div}, {}}; +static u3j_harm _136_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}}; +static u3j_harm _136_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}}; +static u3j_harm _136_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}}; +static u3j_harm _136_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}}; +static u3j_harm _136_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}}; +static u3j_harm _136_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}}; +static u3j_harm _136_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}}; +static u3j_core _136_tri__rs_d[] = + { { "add", 7, _136_tri__rs_add_a, 0, no_hashes }, + { "sub", 7, _136_tri__rs_sub_a, 0, no_hashes }, + { "mul", 7, _136_tri__rs_mul_a, 0, no_hashes }, + { "div", 7, _136_tri__rs_div_a, 0, no_hashes }, + { "sqt", 7, _136_tri__rs_sqt_a, 0, no_hashes }, + { "fma", 7, _136_tri__rs_fma_a, 0, no_hashes }, + { "lth", 7, _136_tri__rs_lth_a, 0, no_hashes }, + { "lte", 7, _136_tri__rs_lte_a, 0, no_hashes }, + { "equ", 7, _136_tri__rs_equ_a, 0, no_hashes }, + { "gte", 7, _136_tri__rs_gte_a, 0, no_hashes }, + { "gth", 7, _136_tri__rs_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_tri__rq_add_a[] = {{".2", u3weq_add}, {}}; +static u3j_harm _136_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}}; +static u3j_harm _136_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}}; +static u3j_harm _136_tri__rq_div_a[] = {{".2", u3weq_div}, {}}; +static u3j_harm _136_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}}; +static u3j_harm _136_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}}; +static u3j_harm _136_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}}; +static u3j_harm _136_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}}; +static u3j_harm _136_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}}; +static u3j_harm _136_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}}; +static u3j_harm _136_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}}; +static u3j_core _136_tri__rq_d[] = + { { "add", 7, _136_tri__rq_add_a, 0, no_hashes }, + { "sub", 7, _136_tri__rq_sub_a, 0, no_hashes }, + { "mul", 7, _136_tri__rq_mul_a, 0, no_hashes }, + { "div", 7, _136_tri__rq_div_a, 0, no_hashes }, + { "sqt", 7, _136_tri__rq_sqt_a, 0, no_hashes }, + { "fma", 7, _136_tri__rq_fma_a, 0, no_hashes }, + { "lth", 7, _136_tri__rq_lth_a, 0, no_hashes }, + { "lte", 7, _136_tri__rq_lte_a, 0, no_hashes }, + { "equ", 7, _136_tri__rq_equ_a, 0, no_hashes }, + { "gte", 7, _136_tri__rq_gte_a, 0, no_hashes }, + { "gth", 7, _136_tri__rq_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_tri__rh_add_a[] = {{".2", u3wes_add}, {}}; +static u3j_harm _136_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}}; +static u3j_harm _136_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}}; +static u3j_harm _136_tri__rh_div_a[] = {{".2", u3wes_div}, {}}; +static u3j_harm _136_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}}; +static u3j_harm _136_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}}; +static u3j_harm _136_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}}; +static u3j_harm _136_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}}; +static u3j_harm _136_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}}; +static u3j_harm _136_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}}; +static u3j_harm _136_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}}; +static u3j_core _136_tri__rh_d[] = + { { "add", 7, _136_tri__rh_add_a, 0, no_hashes }, + { "sub", 7, _136_tri__rh_sub_a, 0, no_hashes }, + { "mul", 7, _136_tri__rh_mul_a, 0, no_hashes }, + { "div", 7, _136_tri__rh_div_a, 0, no_hashes }, + { "sqt", 7, _136_tri__rh_sqt_a, 0, no_hashes }, + { "fma", 7, _136_tri__rh_fma_a, 0, no_hashes }, + { "lth", 7, _136_tri__rh_lth_a, 0, no_hashes }, + { "lte", 7, _136_tri__rh_lte_a, 0, no_hashes }, + { "equ", 7, _136_tri__rh_equ_a, 0, no_hashes }, + { "gte", 7, _136_tri__rh_gte_a, 0, no_hashes }, + { "gth", 7, _136_tri__rh_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_tri__og_raw_a[] = {{".2", u3weo_raw}, {}}; +static u3j_core _136_tri__og_d[] = + { { "raw", 7, _136_tri__og_raw_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}}; +static u3j_core _136_tri__sha_d[] = + { { "sha1", 7, _136_tri__sha_sha1_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_tri_shax_a[] = {{".2", u3we_shax}, {}}; +static u3j_harm _136_tri_shay_a[] = {{".2", u3we_shay}, {}}; +static u3j_harm _136_tri_shas_a[] = {{".2", u3we_shas}, {}}; +static u3j_harm _136_tri_shal_a[] = {{".2", u3we_shal}, {}}; + +static u3j_harm _136_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}}; +static u3j_harm _136_ob_fein_a[] = {{".2", u3we_fein_ob}, {}}; +static u3j_core _136_ob_d[] = { + { "fein", 7, _136_ob_fein_a, 0, no_hashes }, + { "fynd", 7, _136_ob_fynd_a, 0, no_hashes }, + {} +}; +static u3j_hood _136_ob_ho[] = { + { "fein", 42 }, + { "fynd", 20 }, + {}, +}; + + +static u3j_hood _136_tri_ho[] = { + { "ob", 20 }, + { "yore", 5462 }, + { "year", 44975 }, + {}, +}; + + +/* layer two + */ +static u3j_harm _136_two_find_a[] = {{".2", u3wb_find, c3y}, {}}; +static u3j_harm _136_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}}; +static u3j_harm _136_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}}; +static u3j_harm _136_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}}; +static u3j_harm _136_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}}; +static u3j_harm _136_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}}; +static u3j_harm _136_two_need_a[] = {{".2", u3wb_need, c3y}, {}}; +static u3j_harm _136_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}}; +static u3j_harm _136_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}}; +static u3j_harm _136_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}}; +static u3j_harm _136_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}}; +static u3j_harm _136_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}}; +static u3j_harm _136_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}}; +static u3j_harm _136_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}}; +static u3j_harm _136_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}}; +static u3j_harm _136_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}}; +static u3j_harm _136_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}}; +static u3j_harm _136_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}}; +static u3j_harm _136_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}}; +static u3j_harm _136_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}}; +static u3j_harm _136_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}}; + +static u3j_harm _136_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}}; +static u3j_harm _136_two_can_a[] = {{".2", u3wc_can, c3y}, {}}; +static u3j_harm _136_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}}; +static u3j_harm _136_two_con_a[] = {{".2", u3wc_con, c3y}, {}}; +static u3j_harm _136_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}}; +static u3j_harm _136_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}}; +static u3j_harm _136_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}}; +static u3j_harm _136_two_end_a[] = {{".2", u3wc_end, c3y}, {}}; +static u3j_harm _136_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}}; +static u3j_harm _136_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}}; +static u3j_harm _136_two_met_a[] = {{".2", u3wc_met, c3y}, {}}; +static u3j_harm _136_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}}; +static u3j_harm _136_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}}; +static u3j_harm _136_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}}; +static u3j_harm _136_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}}; +static u3j_harm _136_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}}; +static u3j_harm _136_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}}; +static u3j_harm _136_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}}; +static u3j_harm _136_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}}; +static u3j_harm _136_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}}; +static u3j_harm _136_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}}; +static u3j_harm _136_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}}; +static u3j_harm _136_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}}; +static u3j_harm _136_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}}; + +static u3j_harm _136_two__in_bif_a[] = {{".2", u3wdi_bif}, {}}; +static u3j_harm _136_two__in_del_a[] = {{".2", u3wdi_del}, {}}; +static u3j_harm _136_two__in_dif_a[] = {{".2", u3wdi_dif}, {}}; +static u3j_harm _136_two__in_gas_a[] = {{".2", u3wdi_gas}, {}}; +static u3j_harm _136_two__in_has_a[] = {{".2", u3wdi_has}, {}}; +static u3j_harm _136_two__in_int_a[] = {{".2", u3wdi_int}, {}}; +static u3j_harm _136_two__in_put_a[] = {{".2", u3wdi_put}, {}}; +static u3j_harm _136_two__in_rep_a[] = {{".2", u3wdi_rep}, {}}; +static u3j_harm _136_two__in_run_a[] = {{".2", u3wdi_run}, {}}; +static u3j_harm _136_two__in_tap_a[] = {{".2", u3wdi_tap}, {}}; +static u3j_harm _136_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}}; +static u3j_harm _136_two__in_uni_a[] = {{".2", u3wdi_uni}, {}}; + +static u3j_harm _136_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}}; +static u3j_harm _136_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}}; +static u3j_harm _136_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}}; + +static u3j_harm _136_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}}; +static u3j_harm _136_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}}; +static u3j_harm _136_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}}; +static u3j_harm _136_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}}; +static u3j_harm _136_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}}; +static u3j_harm _136_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}}; +static u3j_harm _136_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}}; +static u3j_harm _136_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}}; +static u3j_harm _136_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}}; +static u3j_harm _136_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}}; +static u3j_harm _136_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}}; +static u3j_harm _136_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}}; +static u3j_harm _136_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}}; +static u3j_harm _136_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}}; +static u3j_harm _136_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}}; + +static u3j_harm _136_two_cue_a[] = {{".2", u3we_cue}, {}}; +static u3j_harm _136_two_jam_a[] = {{".2", u3we_jam}, {}}; +static u3j_harm _136_two_mat_a[] = {{".2", u3we_mat}, {}}; +static u3j_harm _136_two_rub_a[] = {{".2", u3we_rub}, {}}; + + + +/* layer one + */ +static u3j_harm _136_one_add_a[] = {{".2", u3wa_add, c3y}, {}}; +static u3j_harm _136_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}}; +static u3j_harm _136_one_div_a[] = {{".2", u3wa_div, c3y}, {}}; +static u3j_harm _136_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}}; +static u3j_harm _136_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}}; +static u3j_harm _136_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}}; +static u3j_harm _136_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}}; +static u3j_harm _136_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}}; +static u3j_harm _136_one_max_a[] = {{".2", u3wa_max, c3y}, {}}; +static u3j_harm _136_one_min_a[] = {{".2", u3wa_min, c3y}, {}}; +static u3j_harm _136_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}}; +static u3j_harm _136_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}}; +static u3j_harm _136_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}}; + +static u3j_harm _136_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}}; +static u3j_harm _136_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}}; +static u3j_harm _136_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}}; + +static u3j_harm _136_lull_plot_fax_a[] = {{".2", u3wg_plot_fax, c3y}, {}}; +static u3j_harm _136_lull_plot_met_a[] = {{".2", u3wg_plot_met, c3y}, {}}; + +static u3j_core _136_lull_plot_d[] = + { { "fax", 7, _136_lull_plot_fax_a, 0, no_hashes }, + { "met", 7, _136_lull_plot_met_a, 0, no_hashes }, + {} + }; + +static u3j_core _136_lull_d[] = + { { "plot", 31, 0, _136_lull_plot_d, no_hashes }, + {} + }; + +static u3j_harm _136_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}}; +static u3j_harm _136_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}}; +static u3j_harm _136_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}}; + +static u3j_core _136_hex_blake3_d[] = + { { "hash", 7, _136_hex_blake3_hash_a, 0, no_hashes }, + { "chunk-output", 7, _136_hex_blake3_chunk_output_a, 0, no_hashes }, + {} + }; + + +static u3j_core _136_hex_blake3_impl_d[] = + { { "compress", 7, _136_hex_blake3_compress_a, 0, no_hashes }, + { "blake3", 7, 0, _136_hex_blake3_d, no_hashes }, + {} + }; + +static u3j_harm _136_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}}; + +static u3j_core _136_hex_blake_d[] = + { { "blake2b", 7, _136_hex_blake2b_a, 0, no_hashes }, + { "blake3-impl", 7, 0, _136_hex_blake3_impl_d, no_hashes }, + {} + }; + + +static u3j_harm _136_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}}; +static u3j_harm _136_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}}; +static u3j_core _136_hex_chacha_d[] = + { { "crypt", 7, _136_hex_chacha_crypt_a, 0, no_hashes }, + { "xchacha", 7, _136_hex_chacha_xchacha_a, 0, no_hashes }, + {} + }; + + +//+| %utilities +static u3j_harm _136_hex_bytestream_rip_octs_a[] = {{".2", u3we_bytestream_rip_octs, c3y}, {}}; +static u3j_harm _136_hex_bytestream_cat_octs_a[] = {{".2", u3we_bytestream_cat_octs, c3y}, {}}; +static u3j_harm _136_hex_bytestream_can_octs_a[] = {{".2", u3we_bytestream_can_octs, c3y}, {}}; +//+| %read-byte +static u3j_harm _136_hex_bytestream_read_byte_a[] = {{".2", u3we_bytestream_read_byte, c3y}, {}}; +//+| %read-octs +static u3j_harm _136_hex_bytestream_read_octs_a[] = {{".2", u3we_bytestream_read_octs, c3y}, {}}; +//+| %navigation +static u3j_harm _136_hex_bytestream_skip_line_a[] = {{".2", u3we_bytestream_skip_line, c3y}, {}}; +static u3j_harm _136_hex_bytestream_find_byte_a[] = {{".2", u3we_bytestream_find_byte, c3y}, {}}; +static u3j_harm _136_hex_bytestream_seek_byte_a[] = {{".2", u3we_bytestream_seek_byte, c3y}, {}}; +//+| %transformation +static u3j_harm _136_hex_bytestream_chunk_a[] = {{".2", u3we_bytestream_chunk}, {}}; +static u3j_harm _136_hex_bytestream_extract_a[] = {{".2", u3we_bytestream_extract}, {}}; +static u3j_harm _136_hex_bytestream_fuse_extract_a[] = {{".2", u3we_bytestream_fuse_extract}, {}}; +//+| %bitstream +static u3j_harm _136_hex_bytestream_need_bits_a[] = {{".2", u3we_bytestream_need_bits}, {}}; +static u3j_harm _136_hex_bytestream_drop_bits_a[] = {{".2", u3we_bytestream_drop_bits}, {}}; +// static u3j_harm _136_hex_bytestream_skip_bits_a[] = {{".2", u3we_bytestream_skip_bits}, {}}; +static u3j_harm _136_hex_bytestream_peek_bits_a[] = {{".2", u3we_bytestream_peek_bits}, {}}; +static u3j_harm _136_hex_bytestream_read_bits_a[] = {{".2", u3we_bytestream_read_bits}, {}}; +// static u3j_harm _136_hex_bytestream_read_need_bits_a[] = {{".2", u3we_bytestream_read_need_bits}, {}}; +static u3j_harm _136_hex_bytestream_byte_bits_a[] = {{".2", u3we_bytestream_byte_bits}, {}}; + +static u3j_core _136_hex_bytestream_d[] = + { //+| %utilities + {"rip-octs", 7, _136_hex_bytestream_rip_octs_a, 0, no_hashes }, + {"cat-octs", 7, _136_hex_bytestream_cat_octs_a, 0, no_hashes }, + {"can-octs", 7, _136_hex_bytestream_can_octs_a, 0, no_hashes }, + //+| %navigation + {"skip-line", 7, _136_hex_bytestream_skip_line_a, 0, no_hashes }, + {"find-byte", 7, _136_hex_bytestream_find_byte_a, 0, no_hashes }, + {"seek-byte", 7, _136_hex_bytestream_seek_byte_a, 0, no_hashes }, + //+| %read-byte + {"read-byte", 7, _136_hex_bytestream_read_byte_a, 0, no_hashes }, + //+| %read-octs + {"read-octs", 7, _136_hex_bytestream_read_octs_a, 0, no_hashes }, + //+| %transformation + {"chunk", 7, _136_hex_bytestream_chunk_a, 0, no_hashes }, + {"extract", 7, _136_hex_bytestream_extract_a, 0, no_hashes }, + {"fuse-extract", 7, _136_hex_bytestream_fuse_extract_a, 0, no_hashes }, + //+| %bitstream + {"need-bits", 7, _136_hex_bytestream_need_bits_a, 0, no_hashes }, + {"drop-bits", 7, _136_hex_bytestream_drop_bits_a, 0, no_hashes }, + // {"skip-bits", 7, _136_hex_bytestream_skip_bits_a, 0, no_hashes }, + {"peek-bits", 7, _136_hex_bytestream_peek_bits_a, 0, no_hashes }, + {"read-bits", 7, _136_hex_bytestream_read_bits_a, 0, no_hashes }, + // {"read-need-bits", 7, _136_hex_bytestream_read_need_bits_a, 0, no_hashes }, + {"byte-bits", 7, _136_hex_bytestream_byte_bits_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_hex_json_de_a[] = {{".2", u3we_json_de}, {}}; +static u3j_harm _136_hex_json_en_a[] = {{".2", u3we_json_en}, {}}; +static u3j_core _136_hex_json_d[] = + { { "de", 15, _136_hex_json_de_a, 0, no_hashes }, + { "en", 15, _136_hex_json_en_a, 0, no_hashes }, + {} + }; + +/* /lib jets in non core +*/ +static u3j_harm _136_non__lagoon_add_a[] = {{".2", u3wi_la_add}, {}}; +static u3j_harm _136_non__lagoon_sub_a[] = {{".2", u3wi_la_sub}, {}}; +static u3j_harm _136_non__lagoon_mul_a[] = {{".2", u3wi_la_mul}, {}}; +static u3j_harm _136_non__lagoon_div_a[] = {{".2", u3wi_la_div}, {}}; +static u3j_harm _136_non__lagoon_mod_a[] = {{".2", u3wi_la_mod}, {}}; +static u3j_harm _136_non__lagoon_adds_a[] = {{".2", u3wi_la_adds}, {}}; +static u3j_harm _136_non__lagoon_subs_a[] = {{".2", u3wi_la_subs}, {}}; +static u3j_harm _136_non__lagoon_muls_a[] = {{".2", u3wi_la_muls}, {}}; +static u3j_harm _136_non__lagoon_divs_a[] = {{".2", u3wi_la_divs}, {}}; +static u3j_harm _136_non__lagoon_mods_a[] = {{".2", u3wi_la_mods}, {}}; +static u3j_harm _136_non__lagoon_dot_a[] = {{".2", u3wi_la_dot}, {}}; +static u3j_harm _136_non__lagoon_trans_a[] ={{".2", u3wi_la_transpose}, {}}; +static u3j_harm _136_non__lagoon_cumsum_a[]={{".2", u3wi_la_cumsum}, {}}; +static u3j_harm _136_non__lagoon_argmin_a[]={{".2", u3wi_la_argmin}, {}}; +static u3j_harm _136_non__lagoon_argmax_a[]={{".2", u3wi_la_argmax}, {}}; +static u3j_harm _136_non__lagoon_ravel_a[]={{".2", u3wi_la_ravel}, {}}; +static u3j_harm _136_non__lagoon_min_a[] = {{".2", u3wi_la_min}, {}}; +static u3j_harm _136_non__lagoon_max_a[] = {{".2", u3wi_la_max}, {}}; +static u3j_harm _136_non__lagoon_linspace_a[]={{".2", u3wi_la_linspace}, {}}; +static u3j_harm _136_non__lagoon_range_a[]= {{".2", u3wi_la_range}, {}}; +static u3j_harm _136_non__lagoon_abs_a[] = {{".2", u3wi_la_abs}, {}}; +static u3j_harm _136_non__lagoon_gth_a[] = {{".2", u3wi_la_gth}, {}}; +static u3j_harm _136_non__lagoon_gte_a[] = {{".2", u3wi_la_gte}, {}}; +static u3j_harm _136_non__lagoon_lth_a[] = {{".2", u3wi_la_lth}, {}}; +static u3j_harm _136_non__lagoon_lte_a[] = {{".2", u3wi_la_lte}, {}}; +static u3j_harm _136_non__lagoon_diag_a[] = {{".2", u3wi_la_diag}, {}}; +static u3j_harm _136_non__lagoon_trace_a[]= {{".2", u3wi_la_trace}, {}}; +static u3j_harm _136_non__lagoon_mmul_a[] = {{".2", u3wi_la_mmul}, {}}; +static u3j_harm _136_non__mice_a[] = {{".2", u3we_mice}, {}}; + +static u3j_core _136_non__la_core_d[] = + { { "add-rays", 7, _136_non__lagoon_add_a, 0, no_hashes }, + { "sub-rays", 7, _136_non__lagoon_sub_a, 0, no_hashes }, + { "mul-rays", 7, _136_non__lagoon_mul_a, 0, no_hashes }, + { "div-rays", 7, _136_non__lagoon_div_a, 0, no_hashes }, + { "mod-rays", 7, _136_non__lagoon_mod_a, 0, no_hashes }, + { "add-scal", 7, _136_non__lagoon_adds_a, 0, no_hashes }, + { "sub-scal", 7, _136_non__lagoon_subs_a, 0, no_hashes }, + { "mul-scal", 7, _136_non__lagoon_muls_a, 0, no_hashes }, + { "div-scal", 7, _136_non__lagoon_divs_a, 0, no_hashes }, + { "mod-scal", 7, _136_non__lagoon_mods_a, 0, no_hashes }, + { "dot", 7, _136_non__lagoon_dot_a, 0, no_hashes }, + { "transpose",7, _136_non__lagoon_trans_a, 0, no_hashes }, + { "cumsum", 7, _136_non__lagoon_cumsum_a, 0, no_hashes }, + { "argmin", 7, _136_non__lagoon_argmin_a, 0, no_hashes }, + { "argmax", 7, _136_non__lagoon_argmax_a, 0, no_hashes }, + { "ravel", 7, _136_non__lagoon_ravel_a, 0, no_hashes }, + { "min", 7, _136_non__lagoon_min_a, 0, no_hashes }, + { "max", 7, _136_non__lagoon_max_a, 0, no_hashes }, + { "linspace", 7, _136_non__lagoon_linspace_a, 0, no_hashes }, + { "range", 7, _136_non__lagoon_range_a, 0, no_hashes }, + { "abs", 7, _136_non__lagoon_abs_a, 0, no_hashes }, + { "gth", 7, _136_non__lagoon_gth_a, 0, no_hashes }, + { "gte", 7, _136_non__lagoon_gte_a, 0, no_hashes }, + { "lth", 7, _136_non__lagoon_lth_a, 0, no_hashes }, + { "lte", 7, _136_non__lagoon_lte_a, 0, no_hashes }, + { "diag", 7, _136_non__lagoon_diag_a, 0, no_hashes }, + { "trace", 7, _136_non__lagoon_trace_a,0, no_hashes }, + { "mmul", 7, _136_non__lagoon_mmul_a, 0, no_hashes }, + {} + }; + +static u3j_core _136_non_d[] = + { { "lagoon", 7, 0, _136_non__la_core_d, no_hashes }, + { "mice", 7, _136_non__mice_a, 0, no_hashes }, + {} + }; + + +static u3j_harm _136_hex_lia_run_v1_a[] = {{".2", u3we_lia_run_v1, c3y}, {}}; + +static u3j_harm _136_hex_lia_run_once_inner_a[] = {{".2", u3we_lia_run_once, c3y}, {}}; + +static u3j_core _136_hex_lia_run_once_d[] = { + { "run-once-inner-v0", 15, _136_hex_lia_run_once_inner_a, 0, no_hashes }, + {} +}; + +static u3j_core _136_hex_lia_monad_d[] = { + { "run-v1", 7, _136_hex_lia_run_v1_a, 0, no_hashes }, + { "run-once-v0", 7, 0, _136_hex_lia_run_once_d, no_hashes }, + {} +}; + +static u3j_core _136_hex_wasm_engine_d[] = { + { "monad-v0", 3, 0, _136_hex_lia_monad_d, no_hashes }, + {} +}; + +static u3j_core _136_hex_wasm_op_def_d[] = { + { "wasm-engine-v0", 3, 0, _136_hex_wasm_engine_d, no_hashes }, + {} +}; + +static u3j_core _136_hex_wasm_validator_d[] = { + { "wasm-op-def-v0", 3, 0, _136_hex_wasm_op_def_d, no_hashes }, + {} +}; + +static u3j_core _136_hex_wasm_parser_d[] = { + { "validator-v0", 3, 0, _136_hex_wasm_validator_d, no_hashes }, + {} +}; + +static u3j_core _136_hex_lia_sur_d[] = { + { "wasm-parser-v0", 3, 0, _136_hex_wasm_parser_d, no_hashes }, + {} +}; + +static u3j_core _136_hex_wasm_engine_sur_d[] = { + { "monad-sur-v1", 3, 0, _136_hex_lia_sur_d, no_hashes }, + {} +}; + +static u3j_core _136_hex_wasm_sur_d[] = { + { "engine-sur-v0", 3, 0, _136_hex_wasm_engine_sur_d, no_hashes }, + {} +}; + +static u3j_core _136_hex_d[] = + { { "non", 7, 0, _136_non_d, no_hashes }, + + { "lull", 3, 0, _136_lull_d, no_hashes }, + + { "lore", 63, _136_hex_lore_a, 0, no_hashes }, + + { "leer", 63, _136_hex_leer_a, 0, no_hashes }, + { "loss", 63, _136_hex_loss_a, 0, no_hashes }, + { "lune", 127, _136_hex_lune_a, 0, no_hashes }, + + { "crc", 31, 0, _136_hex__crc_d, no_hashes }, + + { "coed", 63, 0, _136_hex_coed_d, no_hashes }, + { "aes", 31, 0, _136_hex_aes_d, no_hashes }, + + { "hmac", 63, 0, _136_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _136_hex_argon_d, no_hashes }, + { "blake", 31, 0, _136_hex_blake_d, no_hashes }, + { "chacha", 31, 0, _136_hex_chacha_d, no_hashes }, + { "kecc", 31, 0, _136_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _136_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _136_hex_scr_d, no_hashes }, + { "secp", 6, 0, _136_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _136_hex_mimes_d, no_hashes }, + { "json", 31, 0, _136_hex_json_d, no_hashes }, + { "checksum", 15, 0, _136_hex_checksum_d, no_hashes}, + { "wasm-sur-v0", 3, 0, _136_hex_wasm_sur_d, no_hashes }, + { "bytestream-v0", 31, 0, _136_hex_bytestream_d, no_hashes}, + { "zlib-v0", 31, 0, _136_hex__zlib_d, no_hashes }, + {} + }; + +static u3j_core _136_pen_d[] = + { { "hex", 7, 0, _136_hex_d, no_hashes }, + + { "cell", 7, _136_pen_cell_a, 0, no_hashes }, + { "comb", 7, _136_pen_comb_a, 0, no_hashes }, + { "cons", 7, _136_pen_cons_a, 0, no_hashes }, + { "core", 7, _136_pen_core_a, 0, no_hashes }, + { "face", 7, _136_pen_face_a, 0, no_hashes }, + { "fitz", 7, _136_pen_fitz_a, 0, no_hashes }, + { "fork", 7, _136_pen_fork_a, 0, no_hashes }, + { "look", 7, _136_pen_look_a, 0, no_hashes }, + { "loot", 7, _136_pen_loot_a, 0, no_hashes }, + { "ut", 15, 0, _136_pen__ut_d, no_hashes, _136_pen__ut_ho }, + {} + }; + +static u3j_core _136_qua__vi_d[] = + { + { "mole", 7, _136_qua_mole_a, 0, no_hashes }, + { "mule", 7, _136_qua_mule_a, 0, no_hashes }, + {} + }; + +static u3j_core _136_qua_d[] = + { { "pen", 3, 0, _136_pen_d, no_hashes, _136_pen_ho }, + + { "po", 7, 0, _136_qua__po_d, no_hashes }, + + { "trip", 7, _136_qua_trip_a, 0, no_hashes }, + + { "bend", 7, 0, _136_qua__bend_d, no_hashes }, + { "cold", 7, 0, _136_qua__cold_d, no_hashes }, + { "comp", 7, 0, _136_qua__comp_d, no_hashes }, + { "cook", 7, 0, _136_qua__cook_d, no_hashes }, + { "easy", 7, 0, _136_qua__easy_d, no_hashes }, + { "glue", 7, 0, _136_qua__glue_d, no_hashes }, + { "here", 7, 0, _136_qua__here_d, no_hashes }, + { "just", 7, 0, _136_qua__just_d, no_hashes }, + { "mask", 7, 0, _136_qua__mask_d, no_hashes }, + { "shim", 7, 0, _136_qua__shim_d, no_hashes }, + { "stag", 7, 0, _136_qua__stag_d, no_hashes }, + { "stew", 7, 0, _136_qua__stew_d, no_hashes }, + { "stir", 7, 0, _136_qua__stir_d, no_hashes }, + + { "pfix", 7, _136_qua_pfix_a, 0, no_hashes }, + { "plug", 7, _136_qua_plug_a, 0, no_hashes }, + { "pose", 7, _136_qua_pose_a, 0, no_hashes }, + { "sfix", 7, _136_qua_sfix_a, 0, no_hashes }, + + { "mink", 7, _136_qua_mink_a, 0, no_hashes }, + { "vi", 7, 0, _136_qua__vi_d, no_hashes }, + + { "scot", 7, _136_qua_scot_a, 0, no_hashes }, + { "scow", 7, _136_qua_scow_a, 0, no_hashes }, + { "slaw", 7, _136_qua_slaw_a, 0, no_hashes }, + {} + }; + +static u3j_core _136_tri_d[] = + { { "qua", 3, 0, _136_qua_d, no_hashes, _136_qua_ho }, + + { "cofl", 7, 0, _136_tri__cofl_d, no_hashes }, + { "rd", 7, 0, _136_tri__rd_d, no_hashes }, + { "rs", 7, 0, _136_tri__rs_d, no_hashes }, + { "rq", 7, 0, _136_tri__rq_d, no_hashes }, + { "rh", 7, 0, _136_tri__rh_d, no_hashes }, + { "og", 7, 0, _136_tri__og_d, no_hashes }, + + { "sha", 7, 0, _136_tri__sha_d, no_hashes }, + { "shax", 7, _136_tri_shax_a, 0, no_hashes }, + { "shay", 7, _136_tri_shay_a, 0, no_hashes }, + { "shas", 7, _136_tri_shas_a, 0, no_hashes }, + { "shal", 7, _136_tri_shal_a, 0, no_hashes }, + + { "ob", 3, 0, _136_ob_d, no_hashes, _136_ob_ho }, + {} + }; + +static u3j_harm _136_two_clz_a[] = {{".2", u3wc_clz, c3n}, {}}; +static u3j_harm _136_two_ctz_a[] = {{".2", u3wc_ctz, c3n}, {}}; +static u3j_harm _136_two_ham_a[] = {{".2", u3wc_ham, c3n}, {}}; + +static u3j_harm _136_two__hew_fun_a[] = {{".2", u3wc_hew, c3n}, {}}; +static u3j_core _136_two__hew_d[] = + { { "fun", 15, _136_two__hew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}}; + +static u3j_core _136_two__by_d[] = + { { "all", 7, _136_two__by_all_a, 0, no_hashes }, + { "any", 7, _136_two__by_any_a, 0, no_hashes }, + { "apt", 7, _136_two__by_apt_a, 0, no_hashes }, + { "bif", 7, _136_two__by_bif_a, 0, no_hashes }, + { "del", 7, _136_two__by_del_a, 0, no_hashes }, + { "dif", 7, _136_two__by_dif_a, 0, no_hashes }, + { "gas", 7, _136_two__by_gas_a, 0, no_hashes }, + { "get", 7, _136_two__by_get_a, 0, no_hashes }, + { "has", 7, _136_two__by_has_a, 0, no_hashes }, + { "int", 7, _136_two__by_int_a, 0, no_hashes }, + { "jab", 7, _136_two__by_jab_a, 0, no_hashes }, + { "key", 7, _136_two__by_key_a, 0, no_hashes }, + { "put", 7, _136_two__by_put_a, 0, no_hashes }, + { "rep", 7, _136_two__by_rep_a, 0, no_hashes }, + { "run", 7, _136_two__by_run_a, 0, no_hashes }, + { "tap", 7, _136_two__by_tap_a, 0, no_hashes }, + { "uni", 7, _136_two__by_uni_a, 0, no_hashes }, + { "urn", 7, _136_two__by_urn_a, 0, no_hashes }, + { "wyt", 3, _136_two__by_wyt_a, 0, no_hashes }, + {} + }; + + +static u3j_harm _136_two__in_apt_a[] = {{".2", u3wdi_apt}, {}}; + +static u3j_core _136_two__in_d[] = + { { "apt", 7, _136_two__in_apt_a, 0, no_hashes }, + { "bif", 7, _136_two__in_bif_a, 0, no_hashes }, + { "del", 7, _136_two__in_del_a, 0, no_hashes }, + { "dif", 7, _136_two__in_dif_a, 0, no_hashes }, + { "gas", 7, _136_two__in_gas_a, 0, no_hashes }, + { "has", 7, _136_two__in_has_a, 0, no_hashes }, + { "int", 7, _136_two__in_int_a, 0, no_hashes }, + { "put", 7, _136_two__in_put_a, 0, no_hashes }, + { "rep", 7, _136_two__in_rep_a, 0, no_hashes }, + { "run", 7, _136_two__in_run_a, 0, no_hashes }, + { "tap", 7, _136_two__in_tap_a, 0, no_hashes }, + { "uni", 7, _136_two__in_uni_a, 0, no_hashes }, + { "wyt", 3, _136_two__in_wyt_a, 0, no_hashes }, + {} + }; + +static u3j_harm _136_two_rig_a[] = {{".2", u3wc_rig, c3n}, {}}; + +static u3j_harm _136_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}}; +static u3j_harm _136_two_sew_a[] = {{".2", u3wc_sew, c3y}, {}}; + +static u3j_core _136_two_d[] = + { { "tri", 3, 0, _136_tri_d, no_hashes, _136_tri_ho }, + + { "find", 7, _136_two_find_a, 0, no_hashes }, + { "flop", 7, _136_two_flop_a, 0, no_hashes }, + { "lent", 7, _136_two_lent_a, 0, no_hashes }, + { "levy", 7, _136_two_levy_a, 0, no_hashes }, + { "lien", 7, _136_two_lien_a, 0, no_hashes }, + { "murn", 7, _136_two_murn_a, 0, no_hashes }, + { "need", 7, _136_two_need_a, 0, no_hashes }, + { "mate", 7, _136_two_mate_a, 0, no_hashes }, + { "reap", 7, _136_two_reap_a, 0, no_hashes }, + { "reel", 7, _136_two_reel_a, 0, no_hashes }, + { "roll", 7, _136_two_roll_a, 0, no_hashes }, + { "skid", 7, _136_two_skid_a, 0, no_hashes }, + { "skim", 7, _136_two_skim_a, 0, no_hashes }, + { "skip", 7, _136_two_skip_a, 0, no_hashes }, + { "scag", 7, _136_two_scag_a, 0, no_hashes }, + { "slag", 7, _136_two_slag_a, 0, no_hashes }, + { "snag", 7, _136_two_snag_a, 0, no_hashes }, + { "sort", 7, _136_two_sort_a, 0, no_hashes }, + { "turn", 7, _136_two_turn_a, 0, no_hashes }, + { "weld", 7, _136_two_weld_a, 0, no_hashes }, + { "welp", 7, _136_two_welp_a, 0, no_hashes }, + { "zing", 7, _136_two_zing_a, 0, no_hashes }, + + { "bex", 7, _136_two_bex_a, 0, no_hashes }, + { "cat", 7, _136_two_cat_a, 0, no_hashes }, + { "can", 7, _136_two_can_a, 0, no_hashes }, + { "clz", 7, _136_two_clz_a, 0, no_hashes }, + { "con", 7, _136_two_con_a, 0, no_hashes }, + { "ctz", 7, _136_two_ctz_a, 0, no_hashes }, + { "cue", 7, _136_two_cue_a, 0, no_hashes }, + { "cut", 7, _136_two_cut_a, 0, no_hashes }, + { "dis", 7, _136_two_dis_a, 0, no_hashes }, + { "dor", 7, _136_two_dor_a, 0, no_hashes }, + { "end", 7, _136_two_end_a, 0, no_hashes }, + { "gor", 7, _136_two_gor_a, 0, no_hashes }, + { "ham", 7, _136_two_ham_a, 0, no_hashes }, + { "hew", 7, 0, _136_two__hew_d, no_hashes }, + { "jam", 7, _136_two_jam_a, 0, no_hashes }, + { "lsh", 7, _136_two_lsh_a, 0, no_hashes }, + { "mat", 7, _136_two_mat_a, 0, no_hashes }, + { "met", 7, _136_two_met_a, 0, no_hashes }, + { "mix", 7, _136_two_mix_a, 0, no_hashes }, + { "mor", 7, _136_two_mor_a, 0, no_hashes }, + { "mug", 7, _136_two_mug_a, 0, no_hashes }, + { "muk", 7, _136_two_muk_a, 0, no_hashes }, + { "rap", 7, _136_two_rap_a, 0, no_hashes }, + { "rep", 7, _136_two_rep_a, 0, no_hashes }, + { "rev", 7, _136_two_rev_a, 0, no_hashes }, + { "rig", 7, _136_two_rig_a, 0, no_hashes }, + { "rip", 7, _136_two_rip_a, 0, no_hashes }, + { "rsh", 7, _136_two_rsh_a, 0, no_hashes }, + { "swp", 7, _136_two_swp_a, 0, no_hashes }, + { "rub", 7, _136_two_rub_a, 0, no_hashes }, + { "pow", 7, _136_two_pow_a, 0, no_hashes }, + { "sew", 7, _136_two_sew_a, 0, no_hashes }, + { "sqt", 7, _136_two_sqt_a, 0, no_hashes }, + { "xeb", 7, _136_two_xeb_a, 0, no_hashes }, + + { "by", 7, 0, _136_two__by_d, no_hashes }, + { "in", 7, 0, _136_two__in_d, no_hashes }, + {} + }; + +static u3j_core _136_one_d[] = + { { "two", 3, 0, _136_two_d, no_hashes }, + + { "add", 7, _136_one_add_a, 0, no_hashes }, + { "dec", 7, _136_one_dec_a, 0, no_hashes }, + { "div", 7, _136_one_div_a, 0, no_hashes }, + { "dvr", 7, _136_one_dvr_a, 0, no_hashes }, + { "gte", 7, _136_one_gte_a, 0, no_hashes }, + { "gth", 7, _136_one_gth_a, 0, no_hashes }, + { "lte", 7, _136_one_lte_a, 0, no_hashes }, + { "lth", 7, _136_one_lth_a, 0, no_hashes }, + { "max", 7, _136_one_max_a, 0, no_hashes }, + { "min", 7, _136_one_min_a, 0, no_hashes }, + { "mod", 7, _136_one_mod_a, 0, no_hashes }, + { "mul", 7, _136_one_mul_a, 0, no_hashes }, + { "sub", 7, _136_one_sub_a, 0, no_hashes }, + + { "cap", 7, _136_one_cap_a, 0, no_hashes }, + { "mas", 7, _136_one_mas_a, 0, no_hashes }, + { "peg", 7, _136_one_peg_a, 0, no_hashes }, + {} + }; + +u3j_core _k136_d[] = + { { "one", 3, 0, _136_one_d, no_hashes }, + {} + }; + diff --git a/vere/pkg/noun/jets/137/tree.c b/vere/pkg/noun/jets/137/tree.c new file mode 100644 index 0000000..9564135 --- /dev/null +++ b/vere/pkg/noun/jets/137/tree.c @@ -0,0 +1,1184 @@ +#include "c3/c3.h" +#include "jets.h" +#include "jets/w.h" + + +static c3_c* no_hashes[] = { 0 }; + +static u3j_harm _137_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}}; +static u3j_harm _137_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}}; +static u3j_core _137_hex_mimes_base16_d[] = + { { "en", 7, _137_hex_mimes_base16_en_a, 0, no_hashes }, + { "de", 7, _137_hex_mimes_base16_de_a, 0, no_hashes }, + {} + }; +static u3j_core _137_hex_mimes_d[] = + { { "base16", 3, 0, _137_hex_mimes_base16_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}}; +static u3j_harm _137_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}}; +static u3j_core _137_hex_aes_ecba_d[] = + { { "en", 7, _137_hex_aes_ecba_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_ecba_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}}; +static u3j_harm _137_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}}; +static u3j_core _137_hex_aes_ecbb_d[] = + { { "en", 7, _137_hex_aes_ecbb_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_ecbb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}}; +static u3j_harm _137_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}}; +static u3j_core _137_hex_aes_ecbc_d[] = + { { "en", 7, _137_hex_aes_ecbc_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_ecbc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}}; +static u3j_harm _137_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}}; +static u3j_core _137_hex_aes_cbca_d[] = + { { "en", 7, _137_hex_aes_cbca_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_cbca_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}}; +static u3j_harm _137_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}}; +static u3j_core _137_hex_aes_cbcb_d[] = + { { "en", 7, _137_hex_aes_cbcb_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_cbcb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}}; +static u3j_harm _137_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}}; +static u3j_core _137_hex_aes_cbcc_d[] = + { { "en", 7, _137_hex_aes_cbcc_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_cbcc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}}; +static u3j_harm _137_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}}; +static u3j_core _137_hex_aes_siva_d[] = + { { "en", 7, _137_hex_aes_siva_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_siva_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}}; +static u3j_harm _137_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}}; +static u3j_core _137_hex_aes_sivb_d[] = + { { "en", 7, _137_hex_aes_sivb_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_sivb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}}; +static u3j_harm _137_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}}; +static u3j_core _137_hex_aes_sivc_d[] = + { { "en", 7, _137_hex_aes_sivc_en_a, 0, no_hashes }, + { "de", 7, _137_hex_aes_sivc_de_a, 0, no_hashes }, + {} + }; +static u3j_core _137_hex_aes_d[] = + { { "ecba", 7, 0, _137_hex_aes_ecba_d, no_hashes }, + { "ecbb", 7, 0, _137_hex_aes_ecbb_d, no_hashes }, + { "ecbc", 7, 0, _137_hex_aes_ecbc_d, no_hashes }, + { "cbca", 7, 0, _137_hex_aes_cbca_d, no_hashes }, + { "cbcb", 7, 0, _137_hex_aes_cbcb_d, no_hashes }, + { "cbcc", 7, 0, _137_hex_aes_cbcc_d, no_hashes }, + { "siva", 7, 0, _137_hex_aes_siva_d, no_hashes }, + { "sivb", 7, 0, _137_hex_aes_sivb_d, no_hashes }, + { "sivc", 7, 0, _137_hex_aes_sivc_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_leer_a[] = {{".2", u3we_leer}, {}}; +static u3j_harm _137_hex_lore_a[] = {{".2", u3we_lore}, {}}; +static u3j_harm _137_hex_loss_a[] = {{".2", u3we_loss}, {}}; +static u3j_harm _137_hex_lune_a[] = {{".2", u3we_lune}, {}}; + + +static u3j_harm _137_hex__crc32_a[] = {{".2", u3we_crc32}, {}}; + +static u3j_core _137_hex__crc_d[] = {{"crc32", 7, _137_hex__crc32_a, 0, no_hashes }, {}}; + + +static u3j_harm _137_hex_coed__ed_scad_a[] = {{".2", u3wee_scad}, {}}; +static u3j_harm _137_hex_coed__ed_scas_a[] = {{".2", u3wee_scas}, {}}; +static u3j_harm _137_hex_coed__ed_scap_a[] = {{".2", u3wee_scap}, {}}; + +static u3j_harm _137_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}}; +static u3j_harm _137_hex_coed__ed_luck_a[] = {{".2", u3wee_luck}, {}}; +static u3j_harm _137_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}}; +static u3j_harm _137_hex_coed__ed_sign_raw_a[] = {{".2", u3wee_sign_raw}, {}}; +static u3j_harm _137_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}}; +static u3j_harm _137_hex_coed__ed_sign_octs_raw_a[] = {{".2", u3wee_sign_octs_raw}, {}}; +static u3j_harm _137_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}}; +static u3j_harm _137_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}}; +static u3j_harm _137_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}}; +static u3j_harm _137_hex_coed__ed_slar_a[] = {{".2", u3wee_slar}, {}}; + +static u3j_harm _137_hex_coed__ed_smac_a[] = + {{".2", u3wee_smac}, {}}; + +static u3j_harm _137_hex_coed__ed_recs_a[] = + {{".2", u3wee_recs}, {}}; + +static u3j_harm _137_hex_coed__ed_point_neg_a[] = + {{".2", u3wee_point_neg}, {}}; + +static u3j_harm _137_hex_coed__ed_point_add_a[] = + {{".2", u3wee_point_add}, {}}; + +static u3j_harm _137_hex_coed__ed_scalarmult_a[] = + {{".2", u3wee_scalarmult}, {}}; + +static u3j_harm _137_hex_coed__ed_scalarmult_base_a[] = + {{".2", u3wee_scalarmult_base}, {}}; + +static u3j_harm _137_hex_coed__ed_add_scalarmult_scalarmult_base_a[] = + {{".2", u3wee_add_scalarmult_scalarmult_base}, {}}; + +static u3j_harm _137_hex_coed__ed_add_double_scalarmult_a[] = + {{".2", u3wee_add_double_scalarmult}, {}}; + +static u3j_core _137_hex_coed__ed_d[] = + { { "sign", 7, _137_hex_coed__ed_sign_a, 0, no_hashes }, + { "sign-raw", 7, _137_hex_coed__ed_sign_raw_a, 0, no_hashes }, + { "sign-octs", 7, _137_hex_coed__ed_sign_octs_a, 0, no_hashes }, + { "sign-octs-raw", 7, _137_hex_coed__ed_sign_octs_raw_a, 0, no_hashes }, + { "puck", 7, _137_hex_coed__ed_puck_a, 0, no_hashes }, + { "luck", 7, _137_hex_coed__ed_luck_a, 0, no_hashes }, + { "scad", 7, _137_hex_coed__ed_scad_a, 0, no_hashes }, + { "scas", 7, _137_hex_coed__ed_scas_a, 0, no_hashes }, + { "scap", 7, _137_hex_coed__ed_scap_a, 0, no_hashes }, + { "veri-octs", 7, _137_hex_coed__ed_veri_octs_a, 0, no_hashes }, + { "veri", 7, _137_hex_coed__ed_veri_a, 0, no_hashes }, + { "shar", 7, _137_hex_coed__ed_shar_a, 0, no_hashes }, + { "slar", 7, _137_hex_coed__ed_slar_a, 0, no_hashes }, + { "point-add", 7, _137_hex_coed__ed_point_add_a, 0, 0 }, + { "point-neg", 7, _137_hex_coed__ed_point_neg_a, 0, 0 }, + { "recs", 7, _137_hex_coed__ed_recs_a, 0, 0 }, + { "smac", 7, _137_hex_coed__ed_smac_a, 0, 0 }, + { "scalarmult", 7, _137_hex_coed__ed_scalarmult_a, 0, + no_hashes }, + { "scalarmult-base", 7, _137_hex_coed__ed_scalarmult_base_a, 0, + no_hashes }, + { "add-scalarmult-scalarmult-base", 7, + _137_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0, + no_hashes }, + { "add-double-scalarmult", 7, + _137_hex_coed__ed_add_double_scalarmult_a, 0, + no_hashes }, + {} + }; + +static u3j_core _137_hex_coed_d[] = + { { "ed", 3, 0, _137_hex_coed__ed_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}}; +static u3j_core _137_hex_hmac_d[] = + { { "hmac", 7, _137_hex_hmac_hmac_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_argon2_a[] = {{".2", u3we_argon2}, {}}; +static u3j_core _137_hex_argon_d[] = + { { "argon2", 511, _137_hex_argon2_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}}; +static u3j_harm _137_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}}; +static u3j_harm _137_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}}; +static u3j_harm _137_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}}; +static u3j_core _137_hex_scr_d[] = + { { "pbk", 7, _137_hex_scr_pbk_a, 0, no_hashes }, + { "pbl", 7, _137_hex_scr_pbl_a, 0, no_hashes }, + { "hsh", 7, _137_hex_scr_hsh_a, 0, no_hashes }, + { "hsl", 7, _137_hex_scr_hsl_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}}; +static u3j_harm _137_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}}; +static u3j_harm _137_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}}; + +static u3j_harm _137_hex_secp_secp256k1_schnorr_sosi_a[] = + {{".2", u3we_sosi}, {}}; +static u3j_harm _137_hex_secp_secp256k1_schnorr_sove_a[] = + {{".2", u3we_sove}, {}}; +static u3j_core _137_hex_secp_secp256k1_schnorr_d[] = + { { "sosi", 7, + _137_hex_secp_secp256k1_schnorr_sosi_a, 0, + no_hashes }, + { "sove", 7, + _137_hex_secp_secp256k1_schnorr_sove_a, 0, + no_hashes }, + {} + }; + +static u3j_core _137_hex_secp_secp256k1_d[] = + { { "make", 7, _137_hex_secp_secp256k1_make_a, 0, no_hashes }, + { "sign", 7, _137_hex_secp_secp256k1_sign_a, 0, no_hashes }, + { "reco", 7, _137_hex_secp_secp256k1_reco_a, 0, no_hashes }, + { "schnorr", 7, 0, + _137_hex_secp_secp256k1_schnorr_d, + no_hashes }, + {} + }; +static u3j_core _137_hex_secp_d[] = + { { "secp256k1", 3, 0, _137_hex_secp_secp256k1_d, no_hashes }, + {} + }; + + +static u3j_harm _137_hex_kecc_k224_a[] = + {{".2", u3we_kecc224, c3y, c3y, c3y}, {}}; +static u3j_harm _137_hex_kecc_k256_a[] = + {{".2", u3we_kecc256, c3y, c3y, c3y}, {}}; +static u3j_harm _137_hex_kecc_k384_a[] = + {{".2", u3we_kecc384, c3y, c3y, c3y}, {}}; +static u3j_harm _137_hex_kecc_k512_a[] = + {{".2", u3we_kecc512, c3y, c3y, c3y}, {}}; +static u3j_core _137_hex_kecc_d[] = + { { "k224", 7, _137_hex_kecc_k224_a, 0, no_hashes }, + { "k256", 7, _137_hex_kecc_k256_a, 0, no_hashes }, + { "k384", 7, _137_hex_kecc_k384_a, 0, no_hashes }, + { "k512", 7, _137_hex_kecc_k512_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}}; +static u3j_core _137_hex_ripe_d[] = + { { "ripemd160", 7, _137_hex_ripemd_160_a, 0, no_hashes }, + {} + }; + + + +/* layer five + */ +static u3j_harm _137_pen_cell_a[] = {{".2", u3wf_cell}, {}}; +static u3j_harm _137_pen_comb_a[] = {{".2", u3wf_comb}, {}}; +static u3j_harm _137_pen_cons_a[] = {{".2", u3wf_cons}, {}}; +static u3j_harm _137_pen_core_a[] = {{".2", u3wf_core}, {}}; +static u3j_harm _137_pen_face_a[] = {{".2", u3wf_face}, {}}; +static u3j_harm _137_pen_fitz_a[] = {{".2", u3wf_fitz}, {}}; +static u3j_harm _137_pen_fork_a[] = {{".2", u3wf_fork}, {}}; + +static u3j_harm _137_pen_look_a[] = {{".2", u3wf_look}, {}}; +static u3j_harm _137_pen_loot_a[] = {{".2", u3wf_loot}, {}}; + +static u3j_harm _137_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}}; +static u3j_harm _137_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}}; +static u3j_harm _137_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}}; +static u3j_harm _137_pen__ut_redo_a[] = {{".2", u3wfu_redo}, {}}; +static u3j_harm _137_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}}; +static u3j_harm _137_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}}; + +static u3j_harm _137_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}}; +static u3j_core _137_pen__ut_nest_in_d[] = + { + { "nest-dext", 3, _137_pen__ut_nest_dext_a, 0, no_hashes }, + {} + }; +static u3j_core _137_pen__ut_nest_d[] = + { + { "nest-in", 7, 0, _137_pen__ut_nest_in_d, no_hashes }, + {} + }; + +static u3j_harm _137_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}}; + +static u3j_core _137_pen__ut_d[] = + { + { "crop", 7, _137_pen__ut_crop_a, 0, no_hashes }, + { "fish", 7, _137_pen__ut_fish_a, 0, no_hashes }, + { "fuse", 7, _137_pen__ut_fuse_a, 0, no_hashes }, + { "redo", 7, _137_pen__ut_redo_a, 0, no_hashes }, + { "mint", 7, _137_pen__ut_mint_a, 0, no_hashes }, + { "mull", 7, _137_pen__ut_mull_a, 0, no_hashes }, + { "nest", 7, 0, _137_pen__ut_nest_d, no_hashes }, + { "rest", 7, _137_pen__ut_rest_a, 0, no_hashes }, + {} + }; + +static u3j_hood _137_pen__ut_ho[] = + { { "ar", 12282 }, + { "fan", 28, c3n }, + { "rib", 58, c3n }, + { "vet", 59, c3n }, + + { "blow", 6015 }, + { "burp", 342 }, + { "busk", 1373 }, + { "buss", 374 }, + { "crop", 1494 }, + { "duck", 1524 }, + { "dune", 2991 }, + { "dunk", 3066 }, + { "epla", 12206 }, + { "emin", 1534 }, + { "emul", 6134 }, + { "feel", 1502 }, + { "felt", 94 }, + { "fine", 49086 }, + { "fire", 4 }, + { "fish", 6006 }, + { "fond", 12283 }, + { "fund", 6014 }, + // XX +funk is not part of +ut, and this hook appears to be unused + // remove from here and the +ut hint + // + { "funk", 0xbefafa, c3y, 31 }, + { "fuse", 24021 }, + { "gain", 380 }, + { "lose", 0x2fefe }, + { "mile", 382 }, + { "mine", 372 }, + { "mint", 49083 }, + { "moot", 0x2feff }, + { "mull", 24020 }, + { "nest", 92 }, + { "peel", 1526 }, + { "play", 3006 }, + { "peek", 1532 }, + { "repo", 22 }, + { "rest", 6102 }, + { "tack", 6007 }, + { "toss", 24540 }, + { "wrap", 6137 }, + {}, + }; + + +static u3j_hood _137_pen_ho[] = { + { "ap", 22 }, + { "ut", 86 }, + {}, +}; + + +/* layer four + */ +static u3j_harm _137_qua_trip_a[] = {{".2", u3we_trip}, {}}; + +static u3j_harm _137_qua_slaw_a[] = {{".2", u3we_slaw}, {}}; +static u3j_harm _137_qua_scot_a[] = {{".2", u3we_scot}, {}}; +static u3j_harm _137_qua_scow_a[] = {{".2", u3we_scow}, {}}; + +static u3j_harm _137_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}}; +static u3j_harm _137_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}}; +static u3j_harm _137_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}}; +static u3j_harm _137_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}}; +static u3j_core _137_qua__po_d[] = + { { "ind", 7, _137_qua__po_ind_a, 0, no_hashes }, + { "ins", 7, _137_qua__po_ins_a, 0, no_hashes }, + { "tod", 7, _137_qua__po_tod_a, 0, no_hashes }, + { "tos", 7, _137_qua__po_tos_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}}; +static u3j_core _137_qua__bend_d[] = + { { "fun", 7, _137_qua__bend_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}}; +static u3j_core _137_qua__cold_d[] = + { { "fun", 7, _137_qua__cold_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}}; +static u3j_core _137_qua__cook_d[] = + { { "fun", 7, _137_qua__cook_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}}; +static u3j_core _137_qua__comp_d[] = + { { "fun", 7, _137_qua__comp_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}}; +static u3j_core _137_qua__easy_d[] = + { { "fun", 7, _137_qua__easy_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}}; +static u3j_core _137_qua__glue_d[] = + { { "fun", 7, _137_qua__glue_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}}; +static u3j_core _137_qua__here_d[] = + { { "fun", 7, _137_qua__here_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}}; +static u3j_core _137_qua__just_d[] = + { { "fun", 7, _137_qua__just_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}}; +static u3j_core _137_qua__mask_d[] = + { { "fun", 7, _137_qua__mask_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}}; +static u3j_core _137_qua__shim_d[] = + { { "fun", 7, _137_qua__shim_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}}; +static u3j_core _137_qua__stag_d[] = + { { "fun", 7, _137_qua__stag_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}}; +static u3j_core _137_qua__stew_d[] = + { { "fun", 31, _137_qua__stew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}}; +static u3j_core _137_qua__stir_d[] = + { { "fun", 7, _137_qua__stir_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_qua_pfix_a[] = {{".2", u3we_pfix}, {}}; + +static u3j_harm _137_qua_plug_a[] = {{".2", u3we_plug}, {}}; +static u3j_harm _137_qua_pose_a[] = {{".2", u3we_pose}, {}}; + +static u3j_harm _137_qua_sfix_a[] = {{".2", u3we_sfix}, {}}; + +static u3j_harm _137_qua_mink_a[] = {{".2", u3we_mink}, {}}; +static u3j_harm _137_qua_mole_a[] = {{".2", u3we_mole}, {}}; +static u3j_harm _137_qua_mule_a[] = {{".2", u3we_mule}, {}}; + + +static u3j_hood _137_qua_ho[] = { + { "mute", 0x2fbabe }, + { "show", 24406 }, + { "mure", 1374 }, + {}, +}; + + +/* layer three + */ +static u3j_harm _137_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}}; +static u3j_harm _137_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}}; +static u3j_core _137_tri__cofl_d[] = + { { "drg", 7, _137_tri__cofl__drg_a, 0, no_hashes }, + { "lug", 7, _137_tri__cofl__lug_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__rd_add_a[] = {{".2", u3wer_add}, {}}; +static u3j_harm _137_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}}; +static u3j_harm _137_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}}; +static u3j_harm _137_tri__rd_div_a[] = {{".2", u3wer_div}, {}}; +static u3j_harm _137_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}}; +static u3j_harm _137_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}}; +static u3j_harm _137_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}}; +static u3j_harm _137_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}}; +static u3j_harm _137_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}}; +static u3j_harm _137_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}}; +static u3j_harm _137_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}}; +static u3j_core _137_tri__rd_d[] = + { { "add", 7, _137_tri__rd_add_a, 0, no_hashes }, + { "sub", 7, _137_tri__rd_sub_a, 0, no_hashes }, + { "mul", 7, _137_tri__rd_mul_a, 0, no_hashes }, + { "div", 7, _137_tri__rd_div_a, 0, no_hashes }, + { "sqt", 7, _137_tri__rd_sqt_a, 0, no_hashes }, + { "fma", 7, _137_tri__rd_fma_a, 0, no_hashes }, + { "lth", 7, _137_tri__rd_lth_a, 0, no_hashes }, + { "lte", 7, _137_tri__rd_lte_a, 0, no_hashes }, + { "equ", 7, _137_tri__rd_equ_a, 0, no_hashes }, + { "gte", 7, _137_tri__rd_gte_a, 0, no_hashes }, + { "gth", 7, _137_tri__rd_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__rs_add_a[] = {{".2", u3wet_add}, {}}; +static u3j_harm _137_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}}; +static u3j_harm _137_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}}; +static u3j_harm _137_tri__rs_div_a[] = {{".2", u3wet_div}, {}}; +static u3j_harm _137_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}}; +static u3j_harm _137_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}}; +static u3j_harm _137_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}}; +static u3j_harm _137_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}}; +static u3j_harm _137_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}}; +static u3j_harm _137_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}}; +static u3j_harm _137_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}}; +static u3j_core _137_tri__rs_d[] = + { { "add", 7, _137_tri__rs_add_a, 0, no_hashes }, + { "sub", 7, _137_tri__rs_sub_a, 0, no_hashes }, + { "mul", 7, _137_tri__rs_mul_a, 0, no_hashes }, + { "div", 7, _137_tri__rs_div_a, 0, no_hashes }, + { "sqt", 7, _137_tri__rs_sqt_a, 0, no_hashes }, + { "fma", 7, _137_tri__rs_fma_a, 0, no_hashes }, + { "lth", 7, _137_tri__rs_lth_a, 0, no_hashes }, + { "lte", 7, _137_tri__rs_lte_a, 0, no_hashes }, + { "equ", 7, _137_tri__rs_equ_a, 0, no_hashes }, + { "gte", 7, _137_tri__rs_gte_a, 0, no_hashes }, + { "gth", 7, _137_tri__rs_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__rq_add_a[] = {{".2", u3weq_add}, {}}; +static u3j_harm _137_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}}; +static u3j_harm _137_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}}; +static u3j_harm _137_tri__rq_div_a[] = {{".2", u3weq_div}, {}}; +static u3j_harm _137_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}}; +static u3j_harm _137_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}}; +static u3j_harm _137_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}}; +static u3j_harm _137_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}}; +static u3j_harm _137_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}}; +static u3j_harm _137_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}}; +static u3j_harm _137_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}}; +static u3j_core _137_tri__rq_d[] = + { { "add", 7, _137_tri__rq_add_a, 0, no_hashes }, + { "sub", 7, _137_tri__rq_sub_a, 0, no_hashes }, + { "mul", 7, _137_tri__rq_mul_a, 0, no_hashes }, + { "div", 7, _137_tri__rq_div_a, 0, no_hashes }, + { "sqt", 7, _137_tri__rq_sqt_a, 0, no_hashes }, + { "fma", 7, _137_tri__rq_fma_a, 0, no_hashes }, + { "lth", 7, _137_tri__rq_lth_a, 0, no_hashes }, + { "lte", 7, _137_tri__rq_lte_a, 0, no_hashes }, + { "equ", 7, _137_tri__rq_equ_a, 0, no_hashes }, + { "gte", 7, _137_tri__rq_gte_a, 0, no_hashes }, + { "gth", 7, _137_tri__rq_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__rh_add_a[] = {{".2", u3wes_add}, {}}; +static u3j_harm _137_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}}; +static u3j_harm _137_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}}; +static u3j_harm _137_tri__rh_div_a[] = {{".2", u3wes_div}, {}}; +static u3j_harm _137_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}}; +static u3j_harm _137_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}}; +static u3j_harm _137_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}}; +static u3j_harm _137_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}}; +static u3j_harm _137_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}}; +static u3j_harm _137_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}}; +static u3j_harm _137_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}}; +static u3j_core _137_tri__rh_d[] = + { { "add", 7, _137_tri__rh_add_a, 0, no_hashes }, + { "sub", 7, _137_tri__rh_sub_a, 0, no_hashes }, + { "mul", 7, _137_tri__rh_mul_a, 0, no_hashes }, + { "div", 7, _137_tri__rh_div_a, 0, no_hashes }, + { "sqt", 7, _137_tri__rh_sqt_a, 0, no_hashes }, + { "fma", 7, _137_tri__rh_fma_a, 0, no_hashes }, + { "lth", 7, _137_tri__rh_lth_a, 0, no_hashes }, + { "lte", 7, _137_tri__rh_lte_a, 0, no_hashes }, + { "equ", 7, _137_tri__rh_equ_a, 0, no_hashes }, + { "gte", 7, _137_tri__rh_gte_a, 0, no_hashes }, + { "gth", 7, _137_tri__rh_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__og_raw_a[] = {{".2", u3weo_raw}, {}}; +static u3j_core _137_tri__og_d[] = + { { "raw", 7, _137_tri__og_raw_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}}; +static u3j_core _137_tri__sha_d[] = + { { "sha1", 7, _137_tri__sha_sha1_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_tri_shax_a[] = {{".2", u3we_shax}, {}}; +static u3j_harm _137_tri_shay_a[] = {{".2", u3we_shay}, {}}; +static u3j_harm _137_tri_shas_a[] = {{".2", u3we_shas}, {}}; +static u3j_harm _137_tri_shal_a[] = {{".2", u3we_shal}, {}}; + +static u3j_harm _137_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}}; +static u3j_harm _137_ob_fein_a[] = {{".2", u3we_fein_ob}, {}}; +static u3j_core _137_ob_d[] = { + { "fein", 7, _137_ob_fein_a, 0, no_hashes }, + { "fynd", 7, _137_ob_fynd_a, 0, no_hashes }, + {} +}; +static u3j_hood _137_ob_ho[] = { + { "fein", 42 }, + { "fynd", 20 }, + {}, +}; + + +static u3j_hood _137_tri_ho[] = { + { "ob", 20 }, + { "yore", 5462 }, + { "year", 44975 }, + {}, +}; + + +/* layer two + */ +static u3j_harm _137_two_find_a[] = {{".2", u3wb_find, c3y}, {}}; +static u3j_harm _137_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}}; +static u3j_harm _137_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}}; +static u3j_harm _137_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}}; +static u3j_harm _137_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}}; +static u3j_harm _137_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}}; +static u3j_harm _137_two_need_a[] = {{".2", u3wb_need, c3y}, {}}; +static u3j_harm _137_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}}; +static u3j_harm _137_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}}; +static u3j_harm _137_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}}; +static u3j_harm _137_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}}; +static u3j_harm _137_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}}; +static u3j_harm _137_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}}; +static u3j_harm _137_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}}; +static u3j_harm _137_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}}; +static u3j_harm _137_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}}; +static u3j_harm _137_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}}; +static u3j_harm _137_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}}; +static u3j_harm _137_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}}; +static u3j_harm _137_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}}; +static u3j_harm _137_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}}; + +static u3j_harm _137_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}}; +static u3j_harm _137_two_can_a[] = {{".2", u3wc_can, c3y}, {}}; +static u3j_harm _137_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}}; +static u3j_harm _137_two_con_a[] = {{".2", u3wc_con, c3y}, {}}; +static u3j_harm _137_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}}; +static u3j_harm _137_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}}; +static u3j_harm _137_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}}; +static u3j_harm _137_two_end_a[] = {{".2", u3wc_end, c3y}, {}}; +static u3j_harm _137_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}}; +static u3j_harm _137_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}}; +static u3j_harm _137_two_met_a[] = {{".2", u3wc_met, c3y}, {}}; +static u3j_harm _137_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}}; +static u3j_harm _137_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}}; +static u3j_harm _137_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}}; +static u3j_harm _137_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}}; +static u3j_harm _137_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}}; +static u3j_harm _137_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}}; +static u3j_harm _137_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}}; +static u3j_harm _137_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}}; +static u3j_harm _137_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}}; +static u3j_harm _137_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}}; +static u3j_harm _137_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}}; +static u3j_harm _137_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}}; +static u3j_harm _137_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}}; + +static u3j_harm _137_two__in_bif_a[] = {{".2", u3wdi_bif}, {}}; +static u3j_harm _137_two__in_del_a[] = {{".2", u3wdi_del}, {}}; +static u3j_harm _137_two__in_dif_a[] = {{".2", u3wdi_dif}, {}}; +static u3j_harm _137_two__in_gas_a[] = {{".2", u3wdi_gas}, {}}; +static u3j_harm _137_two__in_has_a[] = {{".2", u3wdi_has}, {}}; +static u3j_harm _137_two__in_int_a[] = {{".2", u3wdi_int}, {}}; +static u3j_harm _137_two__in_put_a[] = {{".2", u3wdi_put}, {}}; +static u3j_harm _137_two__in_rep_a[] = {{".2", u3wdi_rep}, {}}; +static u3j_harm _137_two__in_run_a[] = {{".2", u3wdi_run}, {}}; +static u3j_harm _137_two__in_tap_a[] = {{".2", u3wdi_tap}, {}}; +static u3j_harm _137_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}}; +static u3j_harm _137_two__in_uni_a[] = {{".2", u3wdi_uni}, {}}; + +static u3j_harm _137_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}}; +static u3j_harm _137_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}}; +static u3j_harm _137_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}}; + +static u3j_harm _137_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}}; +static u3j_harm _137_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}}; +static u3j_harm _137_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}}; +static u3j_harm _137_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}}; +static u3j_harm _137_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}}; +static u3j_harm _137_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}}; +static u3j_harm _137_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}}; +static u3j_harm _137_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}}; +static u3j_harm _137_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}}; +static u3j_harm _137_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}}; +static u3j_harm _137_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}}; +static u3j_harm _137_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}}; +static u3j_harm _137_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}}; +static u3j_harm _137_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}}; +static u3j_harm _137_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}}; + +static u3j_harm _137_two_cue_a[] = {{".2", u3we_cue}, {}}; +static u3j_harm _137_two_jam_a[] = {{".2", u3we_jam}, {}}; +static u3j_harm _137_two_mat_a[] = {{".2", u3we_mat}, {}}; +static u3j_harm _137_two_rub_a[] = {{".2", u3we_rub}, {}}; + + + +/* layer one + */ +static u3j_harm _137_one_add_a[] = {{".2", u3wa_add, c3y}, {}}; +static u3j_harm _137_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}}; +static u3j_harm _137_one_div_a[] = {{".2", u3wa_div, c3y}, {}}; +static u3j_harm _137_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}}; +static u3j_harm _137_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}}; +static u3j_harm _137_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}}; +static u3j_harm _137_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}}; +static u3j_harm _137_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}}; +static u3j_harm _137_one_max_a[] = {{".2", u3wa_max, c3y}, {}}; +static u3j_harm _137_one_min_a[] = {{".2", u3wa_min, c3y}, {}}; +static u3j_harm _137_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}}; +static u3j_harm _137_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}}; +static u3j_harm _137_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}}; + +static u3j_harm _137_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}}; +static u3j_harm _137_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}}; +static u3j_harm _137_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}}; + +static u3j_harm _137_lull_plot_fax_a[] = {{".2", u3wg_plot_fax, c3y}, {}}; +static u3j_harm _137_lull_plot_met_a[] = {{".2", u3wg_plot_met, c3y}, {}}; + +static u3j_core _137_lull_plot_d[] = + { { "fax", 7, _137_lull_plot_fax_a, 0, no_hashes }, + { "met", 7, _137_lull_plot_met_a, 0, no_hashes }, + {} + }; + +static u3j_core _137_lull_d[] = + { { "plot", 31, 0, _137_lull_plot_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}}; +static u3j_harm _137_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}}; +static u3j_harm _137_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}}; + +static u3j_core _137_hex_blake3_d[] = + { { "hash", 7, _137_hex_blake3_hash_a, 0, no_hashes }, + { "chunk-output", 7, _137_hex_blake3_chunk_output_a, 0, no_hashes }, + {} + }; + + +static u3j_core _137_hex_blake3_impl_d[] = + { { "compress", 7, _137_hex_blake3_compress_a, 0, no_hashes }, + { "blake3", 7, 0, _137_hex_blake3_d, no_hashes }, + {} + }; + +static u3j_harm _137_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}}; + +static u3j_core _137_hex_blake_d[] = + { { "blake2b", 7, _137_hex_blake2b_a, 0, no_hashes }, + { "blake3-impl", 7, 0, _137_hex_blake3_impl_d, no_hashes }, + {} + }; + + +static u3j_harm _137_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}}; +static u3j_harm _137_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}}; +static u3j_core _137_hex_chacha_d[] = + { { "crypt", 7, _137_hex_chacha_crypt_a, 0, no_hashes }, + { "xchacha", 7, _137_hex_chacha_xchacha_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_hex_json_de_a[] = {{".2", u3we_json_de}, {}}; +static u3j_harm _137_hex_json_en_a[] = {{".2", u3we_json_en}, {}}; +static u3j_core _137_hex_json_d[] = + { { "de", 15, _137_hex_json_de_a, 0, no_hashes }, + { "en", 15, _137_hex_json_en_a, 0, no_hashes }, + {} + }; + +/* /lib jets in non core +*/ +static u3j_harm _137_non__lagoon_add_a[] = {{".2", u3wi_la_add}, {}}; +static u3j_harm _137_non__lagoon_sub_a[] = {{".2", u3wi_la_sub}, {}}; +static u3j_harm _137_non__lagoon_mul_a[] = {{".2", u3wi_la_mul}, {}}; +static u3j_harm _137_non__lagoon_div_a[] = {{".2", u3wi_la_div}, {}}; +static u3j_harm _137_non__lagoon_mod_a[] = {{".2", u3wi_la_mod}, {}}; +static u3j_harm _137_non__lagoon_adds_a[] = {{".2", u3wi_la_adds}, {}}; +static u3j_harm _137_non__lagoon_subs_a[] = {{".2", u3wi_la_subs}, {}}; +static u3j_harm _137_non__lagoon_muls_a[] = {{".2", u3wi_la_muls}, {}}; +static u3j_harm _137_non__lagoon_divs_a[] = {{".2", u3wi_la_divs}, {}}; +static u3j_harm _137_non__lagoon_mods_a[] = {{".2", u3wi_la_mods}, {}}; +static u3j_harm _137_non__lagoon_dot_a[] = {{".2", u3wi_la_dot}, {}}; +static u3j_harm _137_non__lagoon_trans_a[] ={{".2", u3wi_la_transpose}, {}}; +static u3j_harm _137_non__lagoon_cumsum_a[]={{".2", u3wi_la_cumsum}, {}}; +static u3j_harm _137_non__lagoon_argmin_a[]={{".2", u3wi_la_argmin}, {}}; +static u3j_harm _137_non__lagoon_argmax_a[]={{".2", u3wi_la_argmax}, {}}; +static u3j_harm _137_non__lagoon_ravel_a[]={{".2", u3wi_la_ravel}, {}}; +static u3j_harm _137_non__lagoon_min_a[] = {{".2", u3wi_la_min}, {}}; +static u3j_harm _137_non__lagoon_max_a[] = {{".2", u3wi_la_max}, {}}; +static u3j_harm _137_non__lagoon_linspace_a[]={{".2", u3wi_la_linspace}, {}}; +static u3j_harm _137_non__lagoon_range_a[]= {{".2", u3wi_la_range}, {}}; +static u3j_harm _137_non__lagoon_abs_a[] = {{".2", u3wi_la_abs}, {}}; +static u3j_harm _137_non__lagoon_gth_a[] = {{".2", u3wi_la_gth}, {}}; +static u3j_harm _137_non__lagoon_gte_a[] = {{".2", u3wi_la_gte}, {}}; +static u3j_harm _137_non__lagoon_lth_a[] = {{".2", u3wi_la_lth}, {}}; +static u3j_harm _137_non__lagoon_lte_a[] = {{".2", u3wi_la_lte}, {}}; +static u3j_harm _137_non__lagoon_diag_a[] = {{".2", u3wi_la_diag}, {}}; +static u3j_harm _137_non__lagoon_trace_a[]= {{".2", u3wi_la_trace}, {}}; +static u3j_harm _137_non__lagoon_mmul_a[] = {{".2", u3wi_la_mmul}, {}}; + +static u3j_core _137_non__la_core_d[] = + { { "add-rays", 7, _137_non__lagoon_add_a, 0, no_hashes }, + { "sub-rays", 7, _137_non__lagoon_sub_a, 0, no_hashes }, + { "mul-rays", 7, _137_non__lagoon_mul_a, 0, no_hashes }, + { "div-rays", 7, _137_non__lagoon_div_a, 0, no_hashes }, + { "mod-rays", 7, _137_non__lagoon_mod_a, 0, no_hashes }, + { "add-scal", 7, _137_non__lagoon_adds_a, 0, no_hashes }, + { "sub-scal", 7, _137_non__lagoon_subs_a, 0, no_hashes }, + { "mul-scal", 7, _137_non__lagoon_muls_a, 0, no_hashes }, + { "div-scal", 7, _137_non__lagoon_divs_a, 0, no_hashes }, + { "mod-scal", 7, _137_non__lagoon_mods_a, 0, no_hashes }, + { "dot", 7, _137_non__lagoon_dot_a, 0, no_hashes }, + { "transpose",7, _137_non__lagoon_trans_a, 0, no_hashes }, + { "cumsum", 7, _137_non__lagoon_cumsum_a, 0, no_hashes }, + { "argmin", 7, _137_non__lagoon_argmin_a, 0, no_hashes }, + { "argmax", 7, _137_non__lagoon_argmax_a, 0, no_hashes }, + { "ravel", 7, _137_non__lagoon_ravel_a, 0, no_hashes }, + { "min", 7, _137_non__lagoon_min_a, 0, no_hashes }, + { "max", 7, _137_non__lagoon_max_a, 0, no_hashes }, + { "linspace", 7, _137_non__lagoon_linspace_a, 0, no_hashes }, + { "range", 7, _137_non__lagoon_range_a, 0, no_hashes }, + { "abs", 7, _137_non__lagoon_abs_a, 0, no_hashes }, + { "gth", 7, _137_non__lagoon_gth_a, 0, no_hashes }, + { "gte", 7, _137_non__lagoon_gte_a, 0, no_hashes }, + { "lth", 7, _137_non__lagoon_lth_a, 0, no_hashes }, + { "lte", 7, _137_non__lagoon_lte_a, 0, no_hashes }, + { "diag", 7, _137_non__lagoon_diag_a, 0, no_hashes }, + { "trace", 7, _137_non__lagoon_trace_a,0, no_hashes }, + { "mmul", 7, _137_non__lagoon_mmul_a, 0, no_hashes }, + {} + }; + +static u3j_core _137_non_d[] = + { { "lagoon", 7, 0, _137_non__la_core_d, no_hashes }, + {} + }; + + +static u3j_harm _137_hex_lia_run_v1_a[] = {{".2", u3we_lia_run_v1, c3y}, {}}; + +static u3j_harm _137_hex_lia_run_once_inner_a[] = {{".2", u3we_lia_run_once, c3y}, {}}; + +static u3j_core _137_hex_lia_run_once_d[] = { + { "run-once-inner-v0", 15, _137_hex_lia_run_once_inner_a, 0, no_hashes }, + {} +}; + +static u3j_core _137_hex_lia_monad_d[] = { + { "run-v1", 7, _137_hex_lia_run_v1_a, 0, no_hashes }, + { "run-once-v0", 7, 0, _137_hex_lia_run_once_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_engine_d[] = { + { "monad-v0", 3, 0, _137_hex_lia_monad_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_op_def_d[] = { + { "wasm-engine-v0", 3, 0, _137_hex_wasm_engine_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_validator_d[] = { + { "wasm-op-def-v0", 3, 0, _137_hex_wasm_op_def_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_parser_d[] = { + { "validator-v0", 3, 0, _137_hex_wasm_validator_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_lia_sur_d[] = { + { "wasm-parser-v0", 3, 0, _137_hex_wasm_parser_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_engine_sur_d[] = { + { "monad-sur-v1", 3, 0, _137_hex_lia_sur_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_sur_d[] = { + { "engine-sur-v0", 3, 0, _137_hex_wasm_engine_sur_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_d[] = + { { "non", 7, 0, _137_non_d, no_hashes }, + + { "lull", 3, 0, _137_lull_d, no_hashes }, + + { "lore", 63, _137_hex_lore_a, 0, no_hashes }, + + { "leer", 63, _137_hex_leer_a, 0, no_hashes }, + { "loss", 63, _137_hex_loss_a, 0, no_hashes }, + { "lune", 127, _137_hex_lune_a, 0, no_hashes }, + + { "crc", 31, 0, _137_hex__crc_d, no_hashes }, + + { "coed", 63, 0, _137_hex_coed_d, no_hashes }, + { "aes", 31, 0, _137_hex_aes_d, no_hashes }, + + { "hmac", 63, 0, _137_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _137_hex_argon_d, no_hashes }, + { "blake", 31, 0, _137_hex_blake_d, no_hashes }, + { "chacha", 31, 0, _137_hex_chacha_d, no_hashes }, + { "kecc", 31, 0, _137_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _137_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _137_hex_scr_d, no_hashes }, + { "secp", 6, 0, _137_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _137_hex_mimes_d, no_hashes }, + { "json", 31, 0, _137_hex_json_d, no_hashes }, + { "wasm-sur-v0", 3, 0, _137_hex_wasm_sur_d, no_hashes }, + {} + }; + +static u3j_core _137_pen_d[] = + { { "hex", 7, 0, _137_hex_d, no_hashes }, + + { "cell", 7, _137_pen_cell_a, 0, no_hashes }, + { "comb", 7, _137_pen_comb_a, 0, no_hashes }, + { "cons", 7, _137_pen_cons_a, 0, no_hashes }, + { "core", 7, _137_pen_core_a, 0, no_hashes }, + { "face", 7, _137_pen_face_a, 0, no_hashes }, + { "fitz", 7, _137_pen_fitz_a, 0, no_hashes }, + { "fork", 7, _137_pen_fork_a, 0, no_hashes }, + { "look", 7, _137_pen_look_a, 0, no_hashes }, + { "loot", 7, _137_pen_loot_a, 0, no_hashes }, + { "ut", 15, 0, _137_pen__ut_d, no_hashes, _137_pen__ut_ho }, + {} + }; + +static u3j_core _137_qua_d[] = + { { "pen", 3, 0, _137_pen_d, no_hashes, _137_pen_ho }, + + { "po", 7, 0, _137_qua__po_d, no_hashes }, + + { "trip", 7, _137_qua_trip_a, 0, no_hashes }, + + { "bend", 7, 0, _137_qua__bend_d, no_hashes }, + { "cold", 7, 0, _137_qua__cold_d, no_hashes }, + { "comp", 7, 0, _137_qua__comp_d, no_hashes }, + { "cook", 7, 0, _137_qua__cook_d, no_hashes }, + { "easy", 7, 0, _137_qua__easy_d, no_hashes }, + { "glue", 7, 0, _137_qua__glue_d, no_hashes }, + { "here", 7, 0, _137_qua__here_d, no_hashes }, + { "just", 7, 0, _137_qua__just_d, no_hashes }, + { "mask", 7, 0, _137_qua__mask_d, no_hashes }, + { "shim", 7, 0, _137_qua__shim_d, no_hashes }, + { "stag", 7, 0, _137_qua__stag_d, no_hashes }, + { "stew", 7, 0, _137_qua__stew_d, no_hashes }, + { "stir", 7, 0, _137_qua__stir_d, no_hashes }, + + { "pfix", 7, _137_qua_pfix_a, 0, no_hashes }, + { "plug", 7, _137_qua_plug_a, 0, no_hashes }, + { "pose", 7, _137_qua_pose_a, 0, no_hashes }, + { "sfix", 7, _137_qua_sfix_a, 0, no_hashes }, + + { "mink", 7, _137_qua_mink_a, 0, no_hashes }, + { "mole", 7, _137_qua_mole_a, 0, no_hashes }, + { "mule", 7, _137_qua_mule_a, 0, no_hashes }, + + { "scot", 7, _137_qua_scot_a, 0, no_hashes }, + { "scow", 7, _137_qua_scow_a, 0, no_hashes }, + { "slaw", 7, _137_qua_slaw_a, 0, no_hashes }, + {} + }; + +static u3j_core _137_tri_d[] = + { { "qua", 3, 0, _137_qua_d, no_hashes, _137_qua_ho }, + + { "cofl", 7, 0, _137_tri__cofl_d, no_hashes }, + { "rd", 7, 0, _137_tri__rd_d, no_hashes }, + { "rs", 7, 0, _137_tri__rs_d, no_hashes }, + { "rq", 7, 0, _137_tri__rq_d, no_hashes }, + { "rh", 7, 0, _137_tri__rh_d, no_hashes }, + { "og", 7, 0, _137_tri__og_d, no_hashes }, + + { "sha", 7, 0, _137_tri__sha_d, no_hashes }, + { "shax", 7, _137_tri_shax_a, 0, no_hashes }, + { "shay", 7, _137_tri_shay_a, 0, no_hashes }, + { "shas", 7, _137_tri_shas_a, 0, no_hashes }, + { "shal", 7, _137_tri_shal_a, 0, no_hashes }, + + { "ob", 3, 0, _137_ob_d, no_hashes, _137_ob_ho }, + {} + }; + +static u3j_harm _137_two_clz_a[] = {{".2", u3wc_clz, c3n}, {}}; +static u3j_harm _137_two_ctz_a[] = {{".2", u3wc_ctz, c3n}, {}}; +static u3j_harm _137_two_ham_a[] = {{".2", u3wc_ham, c3n}, {}}; + +static u3j_harm _137_two__hew_fun_a[] = {{".2", u3wc_hew, c3n}, {}}; +static u3j_core _137_two__hew_d[] = + { { "fun", 15, _137_two__hew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}}; + +static u3j_core _137_two__by_d[] = + { { "all", 7, _137_two__by_all_a, 0, no_hashes }, + { "any", 7, _137_two__by_any_a, 0, no_hashes }, + { "apt", 7, _137_two__by_apt_a, 0, no_hashes }, + { "bif", 7, _137_two__by_bif_a, 0, no_hashes }, + { "del", 7, _137_two__by_del_a, 0, no_hashes }, + { "dif", 7, _137_two__by_dif_a, 0, no_hashes }, + { "gas", 7, _137_two__by_gas_a, 0, no_hashes }, + { "get", 7, _137_two__by_get_a, 0, no_hashes }, + { "has", 7, _137_two__by_has_a, 0, no_hashes }, + { "int", 7, _137_two__by_int_a, 0, no_hashes }, + { "jab", 7, _137_two__by_jab_a, 0, no_hashes }, + { "key", 7, _137_two__by_key_a, 0, no_hashes }, + { "put", 7, _137_two__by_put_a, 0, no_hashes }, + { "rep", 7, _137_two__by_rep_a, 0, no_hashes }, + { "run", 7, _137_two__by_run_a, 0, no_hashes }, + { "tap", 7, _137_two__by_tap_a, 0, no_hashes }, + { "uni", 7, _137_two__by_uni_a, 0, no_hashes }, + { "urn", 7, _137_two__by_urn_a, 0, no_hashes }, + { "wyt", 3, _137_two__by_wyt_a, 0, no_hashes }, + {} + }; + + +static u3j_harm _137_two__in_apt_a[] = {{".2", u3wdi_apt}, {}}; + +static u3j_core _137_two__in_d[] = + { { "apt", 7, _137_two__in_apt_a, 0, no_hashes }, + { "bif", 7, _137_two__in_bif_a, 0, no_hashes }, + { "del", 7, _137_two__in_del_a, 0, no_hashes }, + { "dif", 7, _137_two__in_dif_a, 0, no_hashes }, + { "gas", 7, _137_two__in_gas_a, 0, no_hashes }, + { "has", 7, _137_two__in_has_a, 0, no_hashes }, + { "int", 7, _137_two__in_int_a, 0, no_hashes }, + { "put", 7, _137_two__in_put_a, 0, no_hashes }, + { "rep", 7, _137_two__in_rep_a, 0, no_hashes }, + { "run", 7, _137_two__in_run_a, 0, no_hashes }, + { "tap", 7, _137_two__in_tap_a, 0, no_hashes }, + { "uni", 7, _137_two__in_uni_a, 0, no_hashes }, + { "wyt", 3, _137_two__in_wyt_a, 0, no_hashes }, + {} + }; + +static u3j_harm _137_two_rig_a[] = {{".2", u3wc_rig, c3n}, {}}; + +static u3j_harm _137_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}}; +static u3j_harm _137_two_sew_a[] = {{".2", u3wc_sew, c3y}, {}}; + +static u3j_core _137_two_d[] = + { { "tri", 3, 0, _137_tri_d, no_hashes, _137_tri_ho }, + + { "find", 7, _137_two_find_a, 0, no_hashes }, + { "flop", 7, _137_two_flop_a, 0, no_hashes }, + { "lent", 7, _137_two_lent_a, 0, no_hashes }, + { "levy", 7, _137_two_levy_a, 0, no_hashes }, + { "lien", 7, _137_two_lien_a, 0, no_hashes }, + { "murn", 7, _137_two_murn_a, 0, no_hashes }, + { "need", 7, _137_two_need_a, 0, no_hashes }, + { "mate", 7, _137_two_mate_a, 0, no_hashes }, + { "reap", 7, _137_two_reap_a, 0, no_hashes }, + { "reel", 7, _137_two_reel_a, 0, no_hashes }, + { "roll", 7, _137_two_roll_a, 0, no_hashes }, + { "skid", 7, _137_two_skid_a, 0, no_hashes }, + { "skim", 7, _137_two_skim_a, 0, no_hashes }, + { "skip", 7, _137_two_skip_a, 0, no_hashes }, + { "scag", 7, _137_two_scag_a, 0, no_hashes }, + { "slag", 7, _137_two_slag_a, 0, no_hashes }, + { "snag", 7, _137_two_snag_a, 0, no_hashes }, + { "sort", 7, _137_two_sort_a, 0, no_hashes }, + { "turn", 7, _137_two_turn_a, 0, no_hashes }, + { "weld", 7, _137_two_weld_a, 0, no_hashes }, + { "welp", 7, _137_two_welp_a, 0, no_hashes }, + { "zing", 7, _137_two_zing_a, 0, no_hashes }, + + { "bex", 7, _137_two_bex_a, 0, no_hashes }, + { "cat", 7, _137_two_cat_a, 0, no_hashes }, + { "can", 7, _137_two_can_a, 0, no_hashes }, + { "clz", 7, _137_two_clz_a, 0, no_hashes }, + { "con", 7, _137_two_con_a, 0, no_hashes }, + { "ctz", 7, _137_two_ctz_a, 0, no_hashes }, + { "cue", 7, _137_two_cue_a, 0, no_hashes }, + { "cut", 7, _137_two_cut_a, 0, no_hashes }, + { "dis", 7, _137_two_dis_a, 0, no_hashes }, + { "dor", 7, _137_two_dor_a, 0, no_hashes }, + { "end", 7, _137_two_end_a, 0, no_hashes }, + { "gor", 7, _137_two_gor_a, 0, no_hashes }, + { "ham", 7, _137_two_ham_a, 0, no_hashes }, + { "hew", 7, 0, _137_two__hew_d, no_hashes }, + { "jam", 7, _137_two_jam_a, 0, no_hashes }, + { "lsh", 7, _137_two_lsh_a, 0, no_hashes }, + { "mat", 7, _137_two_mat_a, 0, no_hashes }, + { "met", 7, _137_two_met_a, 0, no_hashes }, + { "mix", 7, _137_two_mix_a, 0, no_hashes }, + { "mor", 7, _137_two_mor_a, 0, no_hashes }, + { "mug", 7, _137_two_mug_a, 0, no_hashes }, + { "muk", 59, _137_two_muk_a, 0, no_hashes }, + { "rap", 7, _137_two_rap_a, 0, no_hashes }, + { "rep", 7, _137_two_rep_a, 0, no_hashes }, + { "rev", 7, _137_two_rev_a, 0, no_hashes }, + { "rig", 7, _137_two_rig_a, 0, no_hashes }, + { "rip", 7, _137_two_rip_a, 0, no_hashes }, + { "rsh", 7, _137_two_rsh_a, 0, no_hashes }, + { "swp", 7, _137_two_swp_a, 0, no_hashes }, + { "rub", 7, _137_two_rub_a, 0, no_hashes }, + { "pow", 7, _137_two_pow_a, 0, no_hashes }, + { "sew", 7, _137_two_sew_a, 0, no_hashes }, + { "sqt", 7, _137_two_sqt_a, 0, no_hashes }, + { "xeb", 7, _137_two_xeb_a, 0, no_hashes }, + + { "by", 7, 0, _137_two__by_d, no_hashes }, + { "in", 7, 0, _137_two__in_d, no_hashes }, + {} + }; + +static u3j_core _137_one_d[] = + { { "two", 3, 0, _137_two_d, no_hashes }, + + { "add", 7, _137_one_add_a, 0, no_hashes }, + { "dec", 7, _137_one_dec_a, 0, no_hashes }, + { "div", 7, _137_one_div_a, 0, no_hashes }, + { "dvr", 7, _137_one_dvr_a, 0, no_hashes }, + { "gte", 7, _137_one_gte_a, 0, no_hashes }, + { "gth", 7, _137_one_gth_a, 0, no_hashes }, + { "lte", 7, _137_one_lte_a, 0, no_hashes }, + { "lth", 7, _137_one_lth_a, 0, no_hashes }, + { "max", 7, _137_one_max_a, 0, no_hashes }, + { "min", 7, _137_one_min_a, 0, no_hashes }, + { "mod", 7, _137_one_mod_a, 0, no_hashes }, + { "mul", 7, _137_one_mul_a, 0, no_hashes }, + { "sub", 7, _137_one_sub_a, 0, no_hashes }, + + { "cap", 7, _137_one_cap_a, 0, no_hashes }, + { "mas", 7, _137_one_mas_a, 0, no_hashes }, + { "peg", 7, _137_one_peg_a, 0, no_hashes }, + {} + }; + +u3j_core _k137_d[] = + { { "one", 3, 0, _137_one_d, no_hashes }, + {} + }; + diff --git a/vere/pkg/noun/jets/a/add.c b/vere/pkg/noun/jets/a/add.c new file mode 100644 index 0000000..308d143 --- /dev/null +++ b/vere/pkg/noun/jets/a/add.c @@ -0,0 +1,61 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_add(u3_atom a, + u3_atom b) +{ + if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { + c3_w c = a + b; + + return u3i_word(c); + } + else if ( 0 == a ) { + return u3k(b); + } + else if ( 0 == b ) { + return u3k(a); + } + else { + mpz_t a_mp, b_mp; + + u3r_mp(a_mp, a); + u3r_mp(b_mp, b); + + mpz_add(a_mp, a_mp, b_mp); + mpz_clear(b_mp); + + return u3i_mp(a_mp); + } +} + +u3_noun +u3wa_add(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_add(a, b); + } +} + +u3_noun +u3ka_add(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qa_add(a, b); + + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/a/dec.c b/vere/pkg/noun/jets/a/dec.c new file mode 100644 index 0000000..02a8ba1 --- /dev/null +++ b/vere/pkg/noun/jets/a/dec.c @@ -0,0 +1,57 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_inc(u3_atom a) +{ + return u3i_vint(u3k(a)); +} + +u3_noun +u3qa_dec(u3_atom a) +{ + if ( 0 == a ) { + return u3m_error("decrement-underflow"); + } + else { + if ( _(u3a_is_cat(a)) ) { + return a - 1; + } + else { + mpz_t a_mp; + + u3r_mp(a_mp, a); + mpz_sub_ui(a_mp, a_mp, 1); + + return u3i_mp(a_mp); + } + } +} + +u3_noun +u3wa_dec(u3_noun cor) +{ + u3_noun a; + + if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_dec(a); + } +} + +u3_noun +u3ka_dec(u3_atom a) +{ + u3_noun b = u3qa_dec(a); + u3z(a); + return b; +} diff --git a/vere/pkg/noun/jets/a/div.c b/vere/pkg/noun/jets/a/div.c new file mode 100644 index 0000000..74b33dd --- /dev/null +++ b/vere/pkg/noun/jets/a/div.c @@ -0,0 +1,57 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_div(u3_atom a, + u3_atom b) +{ + if ( 0 == b ) { + return u3m_error("divide-by-zero"); + } + else { + if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { + return a / b; + } + else { + mpz_t a_mp, b_mp; + + u3r_mp(a_mp, a); + u3r_mp(b_mp, b); + + mpz_tdiv_q(a_mp, a_mp, b_mp); + mpz_clear(b_mp); + + return u3i_mp(a_mp); + } + } +} + +u3_noun +u3wa_div(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_div(a, b); + } +} + +u3_noun +u3ka_div(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qa_div(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/a/gte.c b/vere/pkg/noun/jets/a/gte.c new file mode 100644 index 0000000..371727d --- /dev/null +++ b/vere/pkg/noun/jets/a/gte.c @@ -0,0 +1,51 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_gte(u3_atom a, u3_atom b) +{ + if (c3y == u3a_is_cat(a) || c3y == u3a_is_cat(b)) + { + return __( a >= b ); + } + + if (a == b) return c3y; + + u3a_atom* a_u = u3a_to_ptr(a); + u3a_atom* b_u = u3a_to_ptr(b); + + if (a_u->len_w != b_u->len_w) + { + return __( a_u->len_w > b_u->len_w ); + } + + c3_w* a_w = a_u->buf_w; + c3_w* b_w = b_u->buf_w; + for (c3_w i_w = a_u->len_w; i_w--;) + { + if (a_w[i_w] > b_w[i_w]) return c3y; + if (a_w[i_w] < b_w[i_w]) return c3n; + } + + return c3y; +} + +u3_noun +u3wa_gte(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) + || (c3n == u3ud(b)) + || (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_gte(a, b); + } +} diff --git a/vere/pkg/noun/jets/a/gth.c b/vere/pkg/noun/jets/a/gth.c new file mode 100644 index 0000000..3863b94 --- /dev/null +++ b/vere/pkg/noun/jets/a/gth.c @@ -0,0 +1,60 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_gth(u3_atom a, u3_atom b) +{ + if (c3y == u3a_is_cat(a) || c3y == u3a_is_cat(b)) + { + return __( a > b ); + } + + if (a == b) return c3n; + + u3a_atom* a_u = u3a_to_ptr(a); + u3a_atom* b_u = u3a_to_ptr(b); + + if (a_u->len_w != b_u->len_w) + { + return __( a_u->len_w > b_u->len_w ); + } + + c3_w* a_w = a_u->buf_w; + c3_w* b_w = b_u->buf_w; + for (c3_w i_w = a_u->len_w; i_w--;) + { + if (a_w[i_w] > b_w[i_w]) return c3y; + if (a_w[i_w] < b_w[i_w]) return c3n; + } + + return c3n; +} + +u3_noun +u3wa_gth(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) + || (c3n == u3ud(b)) + || (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_gth(a, b); + } +} + +u3_noun +u3ka_gth(u3_noun a, u3_noun b) +{ + u3_noun c = u3qa_gth(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/a/lte.c b/vere/pkg/noun/jets/a/lte.c new file mode 100644 index 0000000..0565212 --- /dev/null +++ b/vere/pkg/noun/jets/a/lte.c @@ -0,0 +1,60 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_lte(u3_atom a, u3_atom b) +{ + if (c3y == u3a_is_cat(a) || c3y == u3a_is_cat(b)) + { + return __( a <= b ); + } + + if (a == b) return c3y; + + u3a_atom* a_u = u3a_to_ptr(a); + u3a_atom* b_u = u3a_to_ptr(b); + + if (a_u->len_w != b_u->len_w) + { + return __( a_u->len_w < b_u->len_w ); + } + + c3_w* a_w = a_u->buf_w; + c3_w* b_w = b_u->buf_w; + for (c3_w i_w = a_u->len_w; i_w--;) + { + if (a_w[i_w] < b_w[i_w]) return c3y; + if (a_w[i_w] > b_w[i_w]) return c3n; + } + + return c3y; +} + +u3_noun +u3wa_lte(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) + || (c3n == u3ud(b)) + || (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_lte(a, b); + } +} + +u3_noun +u3ka_lte(u3_noun a, u3_noun b) +{ + u3_noun c = u3qa_lte(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/a/lth.c b/vere/pkg/noun/jets/a/lth.c new file mode 100644 index 0000000..edf95b3 --- /dev/null +++ b/vere/pkg/noun/jets/a/lth.c @@ -0,0 +1,51 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_lth(u3_atom a, u3_atom b) +{ + if (c3y == u3a_is_cat(a) || c3y == u3a_is_cat(b)) + { + return __( a < b ); + } + + if (a == b) return c3n; + + u3a_atom* a_u = u3a_to_ptr(a); + u3a_atom* b_u = u3a_to_ptr(b); + + if (a_u->len_w != b_u->len_w) + { + return __( a_u->len_w < b_u->len_w ); + } + + c3_w* a_w = a_u->buf_w; + c3_w* b_w = b_u->buf_w; + for (c3_w i_w = a_u->len_w; i_w--;) + { + if (a_w[i_w] < b_w[i_w]) return c3y; + if (a_w[i_w] > b_w[i_w]) return c3n; + } + + return c3n; +} + +u3_noun +u3wa_lth(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) + || (c3n == u3ud(b)) + || (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_lth(a, b); + } +} diff --git a/vere/pkg/noun/jets/a/max.c b/vere/pkg/noun/jets/a/max.c new file mode 100644 index 0000000..2646ec7 --- /dev/null +++ b/vere/pkg/noun/jets/a/max.c @@ -0,0 +1,60 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_max(u3_atom a, u3_atom b) +{ + if ( _(u3a_is_cat(a)) || _(u3a_is_cat(b)) ) + { + return u3k(c3_max(a, b)); + } + + if (a == b) return u3k(a); + + u3a_atom* a_u = u3a_to_ptr(a); + u3a_atom* b_u = u3a_to_ptr(b); + + if (a_u->len_w != b_u->len_w) + { + return (a_u->len_w > b_u->len_w) ? u3k(a) : u3k(b); + } + + c3_w* a_w = a_u->buf_w; + c3_w* b_w = b_u->buf_w; + for (c3_w i_w = a_u->len_w; i_w--;) + { + if (a_w[i_w] > b_w[i_w]) return u3k(a); + if (a_w[i_w] < b_w[i_w]) return u3k(b); + } + + return u3k(a); +} + +u3_noun +u3wa_max(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) + || (c3n == u3ud(b)) + || (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_max(a, b); + } +} + +u3_noun +u3ka_max(u3_noun a, u3_noun b) +{ + u3_noun c = u3qa_max(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/a/min.c b/vere/pkg/noun/jets/a/min.c new file mode 100644 index 0000000..00a75e6 --- /dev/null +++ b/vere/pkg/noun/jets/a/min.c @@ -0,0 +1,62 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_min(u3_atom a, u3_atom b) +{ + if ( _(u3a_is_cat(a)) || _(u3a_is_cat(b)) ) + { + // this will always return a direct atom, no refcount gain necessary + // + return c3_min(a, b); + } + + if (a == b) return u3k(a); + + u3a_atom* a_u = u3a_to_ptr(a); + u3a_atom* b_u = u3a_to_ptr(b); + + if (a_u->len_w != b_u->len_w) + { + return (a_u->len_w < b_u->len_w) ? u3k(a) : u3k(b); + } + + c3_w* a_w = a_u->buf_w; + c3_w* b_w = b_u->buf_w; + for (c3_w i_w = a_u->len_w; i_w--;) + { + if (a_w[i_w] < b_w[i_w]) return u3k(a); + if (a_w[i_w] > b_w[i_w]) return u3k(b); + } + + return u3k(a); +} + +u3_noun +u3wa_min(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) + || (c3n == u3ud(b)) + || (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_min(a, b); + } +} + +u3_noun +u3ka_min(u3_noun a, u3_noun b) +{ + u3_noun c = u3qa_min(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/a/mod.c b/vere/pkg/noun/jets/a/mod.c new file mode 100644 index 0000000..1eb9aab --- /dev/null +++ b/vere/pkg/noun/jets/a/mod.c @@ -0,0 +1,55 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_mod(u3_atom a, + u3_atom b) +{ + if ( 0 == b ) { + return u3m_error("divide-by-zero"); + } + else if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { + return a % b; + } + else { + mpz_t a_mp, b_mp; + + u3r_mp(a_mp, a); + u3r_mp(b_mp, b); + + mpz_tdiv_r(a_mp, a_mp, b_mp); + mpz_clear(b_mp); + + return u3i_mp(a_mp); + } +} + +u3_noun +u3wa_mod(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_mod(a, b); + } +} + +u3_noun +u3ka_mod(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qa_mod(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/a/mul.c b/vere/pkg/noun/jets/a/mul.c new file mode 100644 index 0000000..aaba68c --- /dev/null +++ b/vere/pkg/noun/jets/a/mul.c @@ -0,0 +1,58 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_mul(u3_atom a, + u3_atom b) +{ + if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { + c3_d c = ((c3_d) a) * ((c3_d) b); + + return u3i_chubs(1, &c); + } + else if ( 0 == a ) { + return 0; + } + else { + mpz_t a_mp, b_mp; + + u3r_mp(a_mp, a); + u3r_mp(b_mp, b); + + mpz_mul(a_mp, a_mp, b_mp); + mpz_clear(b_mp); + + return u3i_mp(a_mp); + } +} + +u3_noun +u3wa_mul(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_mul(a, b); + } +} + +u3_noun +u3ka_mul(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qa_mul(a, b); + + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/a/sub.c b/vere/pkg/noun/jets/a/sub.c new file mode 100644 index 0000000..321ba77 --- /dev/null +++ b/vere/pkg/noun/jets/a/sub.c @@ -0,0 +1,67 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qa_sub(u3_atom a, + u3_atom b) +{ + if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { + if ( a < b ) { + return u3m_error("subtract-underflow"); + } + else { + return (a - b); + } + } + else if ( 0 == b ) { + return u3k(a); + } + else { + mpz_t a_mp, b_mp; + + u3r_mp(a_mp, a); + u3r_mp(b_mp, b); + + if ( mpz_cmp(a_mp, b_mp) < 0 ) { + mpz_clear(a_mp); + mpz_clear(b_mp); + + return u3m_error("subtract-underflow"); + } + mpz_sub(a_mp, a_mp, b_mp); + mpz_clear(b_mp); + + return u3i_mp(a_mp); + } +} + +u3_noun +u3wa_sub(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(b)) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } + else { + return u3qa_sub(a, b); + } +} + +u3_noun +u3ka_sub(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qa_sub(a, b); + + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/b/bind.c b/vere/pkg/noun/jets/b/bind.c new file mode 100644 index 0000000..7f37a69 --- /dev/null +++ b/vere/pkg/noun/jets/b/bind.c @@ -0,0 +1,30 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qb_bind(u3_noun a, + u3_noun b) + { + if ( 0 == a ) { + return 0; + } else { + return u3nc(0, u3n_slam_on(u3k(b), u3k(u3t(a)))); + } + } + u3_noun + u3wb_bind(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qb_bind(a, b); + } + } + diff --git a/vere/pkg/noun/jets/b/clap.c b/vere/pkg/noun/jets/b/clap.c new file mode 100644 index 0000000..9cfb41a --- /dev/null +++ b/vere/pkg/noun/jets/b/clap.c @@ -0,0 +1,36 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qb_clap(u3_noun a, + u3_noun b, + u3_noun c) + { + if ( 0 == a ) { + return u3k(b); + } + else if ( 0 == b ) { + return u3k(a); + } + else { + return u3nc(0, u3n_slam_on(u3k(c), u3nc(u3k(u3t(a)), u3k(u3t(b))))); + } + } + u3_noun + u3wb_clap(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_6, &b, + u3x_sam_7, &c, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qb_clap(a, b, c); + } + } diff --git a/vere/pkg/noun/jets/b/find.c b/vere/pkg/noun/jets/b/find.c new file mode 100644 index 0000000..c0295d2 --- /dev/null +++ b/vere/pkg/noun/jets/b/find.c @@ -0,0 +1,50 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +STATIC_ASSERT( (UINT32_MAX > u3a_cells), + "list index precision" ); + +u3_noun +u3qb_find(u3_noun nedl, u3_noun hstk) +{ + if ( u3_nul != nedl ) { + c3_w i_w = 0; + + while ( u3_nul != hstk ) { + u3_noun i_h, t_h = hstk; + u3_noun i_n, t_n = nedl; + u3x_cell(t_h, &i_h, &t_h); + u3x_cell(t_n, &i_n, &t_n); + + while ( c3y == u3r_sing(i_n, i_h) ) { + if ( u3_nul == t_n ) { + return u3nc(u3_nul, u3i_word(i_w)); + } + else if ( u3_nul == t_h ) { + break; + } + else { + u3x_cell(t_h, &i_h, &t_h); + u3x_cell(t_n, &i_n, &t_n); + } + } + + hstk = u3t(hstk); + i_w++; + } + } + + return u3_nul; +} + +u3_noun +u3wb_find(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qb_find(a, b); +} diff --git a/vere/pkg/noun/jets/b/flop.c b/vere/pkg/noun/jets/b/flop.c new file mode 100644 index 0000000..0574e4e --- /dev/null +++ b/vere/pkg/noun/jets/b/flop.c @@ -0,0 +1,34 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_flop(u3_noun a) +{ + u3_noun i, t = a, b = u3_nul; + + while ( u3_nul != t ) { + u3x_cell(t, &i, &t); + b = u3nc(u3k(i), b); + } + + return b; +} + +u3_noun +u3wb_flop(u3_noun cor) +{ + return u3qb_flop(u3x_at(u3x_sam, cor)); +} + +u3_noun +u3kb_flop(u3_noun a) +{ + u3_noun b = u3qb_flop(a); + u3z(a); + return b; +} diff --git a/vere/pkg/noun/jets/b/lent.c b/vere/pkg/noun/jets/b/lent.c new file mode 100644 index 0000000..aa3a701 --- /dev/null +++ b/vere/pkg/noun/jets/b/lent.c @@ -0,0 +1,37 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +STATIC_ASSERT( (UINT32_MAX > u3a_cells), + "length precision" ); + +u3_noun +u3qb_lent(u3_noun a) +{ + c3_w len_w = 0; + + while ( u3_nul != a ) { + a = u3t(a); + len_w++; + } + + return u3i_word(len_w); +} + +u3_noun +u3wb_lent(u3_noun cor) +{ + return u3qb_lent(u3x_at(u3x_sam, cor)); +} + +u3_noun +u3kb_lent(u3_noun a) +{ + u3_noun b = u3qb_lent(a); + u3z(a); + return b; +} diff --git a/vere/pkg/noun/jets/b/levy.c b/vere/pkg/noun/jets/b/levy.c new file mode 100644 index 0000000..39d6f39 --- /dev/null +++ b/vere/pkg/noun/jets/b/levy.c @@ -0,0 +1,51 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + u3_noun + u3qb_levy(u3_noun a, + u3_noun b) + { + u3_noun pro = c3y; + c3_o loz_o; + + if ( u3_nul != a ) { + u3j_site sit_u; + u3_noun i, t; + u3j_gate_prep(&sit_u, u3k(b)); + u3k(a); + + do { + i = u3h(a); + + loz_o = u3x_loob(u3j_gate_slam(&sit_u, u3k(i))); + if ( c3n == loz_o ) { + pro = c3n; + break; + } + + t = u3k(u3t(a)); + u3z(a), a = t; + } while ( u3_nul != a ); + + u3z(a); + u3j_gate_lose(&sit_u); + } + + return pro; + } + + u3_noun + u3wb_levy(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qb_levy(a, b); + } + } diff --git a/vere/pkg/noun/jets/b/lien.c b/vere/pkg/noun/jets/b/lien.c new file mode 100644 index 0000000..2a9290a --- /dev/null +++ b/vere/pkg/noun/jets/b/lien.c @@ -0,0 +1,51 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + u3_noun + u3qb_lien(u3_noun a, + u3_noun b) + { + u3_noun pro = c3n; + c3_o loz_o; + + if ( u3_nul != a ) { + u3j_site sit_u; + u3_noun i, t; + u3j_gate_prep(&sit_u, u3k(b)); + u3k(a); + + do { + i = u3h(a); + + loz_o = u3x_loob(u3j_gate_slam(&sit_u, u3k(i))); + if ( c3y == loz_o ) { + pro = c3y; + break; + } + + t = u3k(u3t(a)); + u3z(a), a = t; + } while ( u3_nul != a ); + + u3z(a); + u3j_gate_lose(&sit_u); + } + + return pro; + } + + u3_noun + u3wb_lien(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qb_lien(a, b); + } + } diff --git a/vere/pkg/noun/jets/b/mate.c b/vere/pkg/noun/jets/b/mate.c new file mode 100644 index 0000000..f8dbd31 --- /dev/null +++ b/vere/pkg/noun/jets/b/mate.c @@ -0,0 +1,30 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qb_mate(u3_noun a, + u3_noun b) + { + if ( u3_nul == b ) { + return u3k(a); + } else if ( u3_nul == a ) { + return u3k(b); + } else if ( c3y == u3r_sing(u3t(a), u3t(b)) ) { + return u3k(a); + } else { + return u3m_error("mate"); + } + } + u3_noun + u3wb_mate(u3_noun cor) + { + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qb_mate(a, b); + } + diff --git a/vere/pkg/noun/jets/b/murn.c b/vere/pkg/noun/jets/b/murn.c new file mode 100644 index 0000000..dcb592b --- /dev/null +++ b/vere/pkg/noun/jets/b/murn.c @@ -0,0 +1,54 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_murn(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3_noun* lit = &pro; + + if ( u3_nul != a ) { + u3_noun* hed; + u3_noun* tel; + u3_noun res, i, t; + u3j_site sit_u; + + u3j_gate_prep(&sit_u, u3k(b)); + u3k(a); + + do { + i = u3h(a); + + res = u3j_gate_slam(&sit_u, u3k(i)); + + if ( u3_nul != res ) { + *lit = u3i_defcons(&hed, &tel); + *hed = u3k(u3t(res)); + lit = tel; + u3z(res); + } + + t = u3k(u3t(a)); + u3z(a), a = t; + } + while ( u3_nul != a ); + + u3j_gate_lose(&sit_u); + } + + *lit = u3_nul; + + return pro; +} + +u3_noun +u3wb_murn(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qb_murn(a, b); +} diff --git a/vere/pkg/noun/jets/b/need.c b/vere/pkg/noun/jets/b/need.c new file mode 100644 index 0000000..8723699 --- /dev/null +++ b/vere/pkg/noun/jets/b/need.c @@ -0,0 +1,30 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qb_need(u3_noun a) + { + if ( 0 == a ) { + return u3m_bail(c3__exit); + } + else { + return u3k(u3t(a)); + } + } + u3_noun + u3wb_need(u3_noun cor) + { + u3_noun a; + + if ( u3_none == (a = u3r_at(u3x_sam, cor)) ) { + return u3m_bail(c3__exit); + } else { + return u3qb_need(a); + } + } + diff --git a/vere/pkg/noun/jets/b/reap.c b/vere/pkg/noun/jets/b/reap.c new file mode 100644 index 0000000..35dd055 --- /dev/null +++ b/vere/pkg/noun/jets/b/reap.c @@ -0,0 +1,41 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qb_reap(u3_atom a, + u3_noun b) + { + if ( !_(u3a_is_cat(a)) ) { + return u3m_bail(c3__fail); + } + else { + u3_noun acc = u3_nul; + c3_w i_w = a; + + while ( i_w ) { + acc = u3nc(u3k(b), acc); + i_w--; + } + + return acc; + } + } + + u3_noun + u3wb_reap(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qb_reap(a, b); + } + } diff --git a/vere/pkg/noun/jets/b/reel.c b/vere/pkg/noun/jets/b/reel.c new file mode 100644 index 0000000..fe84f5a --- /dev/null +++ b/vere/pkg/noun/jets/b/reel.c @@ -0,0 +1,52 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + u3_noun + u3qb_reel(u3_noun a, + u3_noun b) + { + u3_noun pro = u3k(u3x_at(u3x_sam_3, b)); + + if ( u3_nul != a ) { + u3a_pile pil_u; + u3j_site sit_u; + u3_noun* top; + u3_noun i, t = a; + + u3a_pile_prep(&pil_u, sizeof(u3_noun)); + + // push list onto road stack + // + do { + u3x_cell(t, &i, &t); + top = u3a_push(&pil_u); + *top = u3k(i); + } while ( u3_nul != t ); + + u3j_gate_prep(&sit_u, u3k(b)); + + while ( c3n == u3a_pile_done(&pil_u) ) { + pro = u3j_gate_slam(&sit_u, u3nc(*top, pro)); + top = u3a_pop(&pil_u); + } + + u3j_gate_lose(&sit_u); + } + + return pro; + } + u3_noun + u3wb_reel(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qb_reel(a, b); + } + } diff --git a/vere/pkg/noun/jets/b/roll.c b/vere/pkg/noun/jets/b/roll.c new file mode 100644 index 0000000..66a4726 --- /dev/null +++ b/vere/pkg/noun/jets/b/roll.c @@ -0,0 +1,44 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + u3_noun + u3qb_roll(u3_noun a, + u3_noun b) + { + u3_noun pro = u3k(u3x_at(u3x_sam_3, b)); + + if ( u3_nul != a ) { + u3j_site sit_u; + u3_noun i, t; + u3j_gate_prep(&sit_u, u3k(b)); + u3k(a); + + do { + i = u3h(a); + + pro = u3j_gate_slam(&sit_u, u3nc(u3k(i), pro)); + + t = u3k(u3t(a)); + u3z(a), a = t; + } while ( u3_nul != a ); + u3j_gate_lose(&sit_u); + } + + return pro; + } + u3_noun + u3wb_roll(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qb_roll(a, b); + } + } + diff --git a/vere/pkg/noun/jets/b/scag.c b/vere/pkg/noun/jets/b/scag.c new file mode 100644 index 0000000..d13dd46 --- /dev/null +++ b/vere/pkg/noun/jets/b/scag.c @@ -0,0 +1,53 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_scag(u3_atom a, u3_noun b) +{ + if ( u3_nul == b ) { + return u3_nul; + } + else if ( !_(u3a_is_cat(a)) ) { + return u3m_bail(c3__fail); + } + else { + u3_noun pro; + u3_noun* lit = &pro; + + { + c3_w len_w = (c3_w)a; + u3_noun* hed; + u3_noun* tel; + u3_noun i, t = b; + + while ( len_w-- && (u3_nul != t) ) { + u3x_cell(t, &i, &t); + + *lit = u3i_defcons(&hed, &tel); + *hed = u3k(i); + lit = tel; + } + } + + *lit = u3_nul; + + return pro; + } +} + +u3_noun +u3wb_scag(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + + if ( (c3n == u3ud(a)) && (u3_nul != b) ) { + return u3m_bail(c3__exit); + } + + return u3qb_scag(a, b); +} diff --git a/vere/pkg/noun/jets/b/skid.c b/vere/pkg/noun/jets/b/skid.c new file mode 100644 index 0000000..8d0d7ef --- /dev/null +++ b/vere/pkg/noun/jets/b/skid.c @@ -0,0 +1,62 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_skid(u3_noun a, u3_noun b) +{ + u3_noun l, r; + u3_noun* lef = &l; + u3_noun* rig = &r; + + if ( u3_nul != a) { + u3_noun i, t; + u3_noun* hed; + u3_noun* tel; + u3j_site sit_u; + u3j_gate_prep(&sit_u, u3k(b)); + u3k(a); + + do { + i = u3h(a); + + switch ( u3j_gate_slam(&sit_u, u3k(i)) ) { + case c3y: { + *lef = u3i_defcons(&hed, &tel); + *hed = u3k(i); + lef = tel; + } break; + + case c3n: { + *rig = u3i_defcons(&hed, &tel); + *hed = u3k(i); + rig = tel; + } break; + + default: u3m_bail(c3__exit); + } + + t = u3k(u3t(a)); + u3z(a), a = t; + } + while ( u3_nul != a ); + + u3j_gate_lose(&sit_u); + } + + *lef = u3_nul; + *rig = u3_nul; + + return u3nc(l, r); +} + +u3_noun +u3wb_skid(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qb_skid(a, b); +} diff --git a/vere/pkg/noun/jets/b/skim.c b/vere/pkg/noun/jets/b/skim.c new file mode 100644 index 0000000..b0f2255 --- /dev/null +++ b/vere/pkg/noun/jets/b/skim.c @@ -0,0 +1,56 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_skim(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3_noun* lit = &pro; + + if ( u3_nul != a) { + u3_noun i, t; + u3_noun* hed; + u3_noun* tel; + u3j_site sit_u; + u3j_gate_prep(&sit_u, u3k(b)); + u3k(a); + + do { + i = u3h(a); + + switch ( u3j_gate_slam(&sit_u, u3k(i)) ) { + case c3y: { + *lit = u3i_defcons(&hed, &tel); + *hed = u3k(i); + lit = tel; + } break; + + case c3n: break; + + default: u3m_bail(c3__exit); + } + + t = u3k(u3t(a)); + u3z(a), a = t; + } + while ( u3_nul != a ); + + u3j_gate_lose(&sit_u); + } + + *lit = u3_nul; + + return pro; +} + +u3_noun +u3wb_skim(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qb_skim(a, b); +} diff --git a/vere/pkg/noun/jets/b/skip.c b/vere/pkg/noun/jets/b/skip.c new file mode 100644 index 0000000..67f537d --- /dev/null +++ b/vere/pkg/noun/jets/b/skip.c @@ -0,0 +1,56 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_skip(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3_noun* lit = &pro; + + if ( u3_nul != a) { + u3_noun i, t; + u3_noun* hed; + u3_noun* tel; + u3j_site sit_u; + u3j_gate_prep(&sit_u, u3k(b)); + u3k(a); + + do { + i = u3h(a); + + switch ( u3j_gate_slam(&sit_u, u3k(i)) ) { + case c3y: break; + + case c3n: { + *lit = u3i_defcons(&hed, &tel); + *hed = u3k(i); + lit = tel; + } break; + + default: u3m_bail(c3__exit); + } + + t = u3k(u3t(a)); + u3z(a), a = t; + } + while ( u3_nul != a ); + + u3j_gate_lose(&sit_u); + } + + *lit = u3_nul; + + return pro; +} + +u3_noun +u3wb_skip(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qb_skip(a, b); +} diff --git a/vere/pkg/noun/jets/b/slag.c b/vere/pkg/noun/jets/b/slag.c new file mode 100644 index 0000000..fad88b0 --- /dev/null +++ b/vere/pkg/noun/jets/b/slag.c @@ -0,0 +1,43 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qb_slag(u3_atom a, u3_noun b) + { + if ( u3_nul == b ) { + return u3_nul; + } + else if ( !_(u3a_is_cat(a)) ) { + return u3m_bail(c3__fail); + } + else { + c3_w len_w = a; + + while ( len_w ) { + if ( c3n == u3du(b) ) { + return u3_nul; + } + b = u3t(b); + len_w--; + } + return u3k(b); + } + } + u3_noun + u3wb_slag(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a) && u3_nul != b) ) + { + return u3m_bail(c3__exit); + } else { + return u3qb_slag(a, b); + } + } diff --git a/vere/pkg/noun/jets/b/snag.c b/vere/pkg/noun/jets/b/snag.c new file mode 100644 index 0000000..4b6dad8 --- /dev/null +++ b/vere/pkg/noun/jets/b/snag.c @@ -0,0 +1,44 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qb_snag(u3_atom a, + u3_noun b) + { + if ( !_(u3a_is_cat(a)) ) { + return u3m_bail(c3__fail); + } + else { + c3_w len_w = a; + + while ( len_w ) { + if ( c3n == u3du(b) ) { + return u3m_bail(c3__exit); + } + b = u3t(b); + len_w--; + } + if ( c3n == u3du(b) ) { + return u3m_bail(c3__exit); + } + return u3k(u3h(b)); + } + } + u3_noun + u3wb_snag(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qb_snag(a, b); + } + } diff --git a/vere/pkg/noun/jets/b/sort.c b/vere/pkg/noun/jets/b/sort.c new file mode 100644 index 0000000..ea5507c --- /dev/null +++ b/vere/pkg/noun/jets/b/sort.c @@ -0,0 +1,125 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + +static_assert( (UINT32_MAX > u3a_cells), + "length precision" ); + +static_assert( + (UINT32_MAX < (SIZE_MAX / (2 * sizeof(u3_noun)))), + "len_w * sizeof u3_noun overflow" +); + +static void +_merge_sort(u3_noun* restrict arr_u, + u3_noun* restrict tmp_u, + c3_w lef_w, + c3_w rit_w, + u3j_site* sit_u) +{ + if ( lef_w >= rit_w ) return; + c3_w mid_w = (lef_w + rit_w) / 2; + if (mid_w < lef_w) + { + // addition wrapped around + // + u3m_bail(c3__fail); + } + _merge_sort(arr_u, tmp_u, lef_w, mid_w, sit_u); + _merge_sort(arr_u, tmp_u, mid_w + 1, rit_w, sit_u); + + c3_w i_w = lef_w, j_w = mid_w + 1, k_w = lef_w; + while (i_w <= mid_w && j_w <= rit_w) + { + // reversed comparison to mimick order reversal of pivot + // and compared element in Hoon + // + u3_noun sam = u3nc(u3k(arr_u[j_w]), u3k(arr_u[i_w])); + c3_o hoz_o = u3x_loob(u3j_gate_slam(sit_u, sam)); + if ( c3n == hoz_o ) + tmp_u[k_w++] = arr_u[i_w++]; + else + tmp_u[k_w++] = arr_u[j_w++]; + } + + while (i_w <= mid_w) tmp_u[k_w++] = arr_u[i_w++]; + while (j_w <= rit_w) tmp_u[k_w++] = arr_u[j_w++]; + + for (i_w = lef_w; i_w <= rit_w; i_w++) + { + arr_u[i_w] = tmp_u[i_w]; + } +} + +// RETAINS list, transfers product +// +static u3_noun +_sort(u3j_site* sit_u, u3_noun list) +{ + if (u3_nul == list) return u3_nul; + + c3_w len_w = 1; + { + u3_noun t = u3t(list); + while (u3_nul != t) + { + ++len_w; t = u3t(t); + } + } + + if (1 == len_w) return u3k(list); + u3_noun* arr_u = u3a_malloc(sizeof(u3_noun) * len_w * 2); + u3_noun* tmp_u = arr_u + len_w; + for (c3_w i_w = 0; i_w < len_w; i_w++) + { + // inlined u3r_cell without any checks + // since the list was already validated and measured + // + u3a_cell* cel_u = u3a_to_ptr(list); + arr_u[i_w] = u3k(cel_u->hed); + list = cel_u->tel; + } + + _merge_sort(arr_u, tmp_u, 0, len_w - 1, sit_u); + + u3_noun pro = u3_nul; + for (c3_w i_w = len_w; i_w--;) + { + pro = u3nc(arr_u[i_w], pro); + } + + u3a_free(arr_u); + + return pro; +} + +u3_noun +u3qb_sort(u3_noun a, + u3_noun b) +{ + u3_noun pro; + u3j_site sit_u; + u3j_gate_prep(&sit_u, u3k(b)); + pro = _sort(&sit_u, a); + u3j_gate_lose(&sit_u); + return pro; +} + +u3_noun +u3wb_sort(u3_noun cor) +{ + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) + { + return u3m_bail(c3__exit); + } + else + { + return u3qb_sort(a, b); + } +} diff --git a/vere/pkg/noun/jets/b/turn.c b/vere/pkg/noun/jets/b/turn.c new file mode 100644 index 0000000..e5ee5f7 --- /dev/null +++ b/vere/pkg/noun/jets/b/turn.c @@ -0,0 +1,49 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_turn(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3_noun* lit = &pro; + + if ( u3_nul != a ) { + u3_noun* hed; + u3_noun* tel; + u3_noun i, t; + u3j_site sit_u; + + u3j_gate_prep(&sit_u, u3k(b)); + u3k(a); + + do { + i = u3h(a); + + *lit = u3i_defcons(&hed, &tel); + *hed = u3j_gate_slam(&sit_u, u3k(i)); + lit = tel; + + t = u3k(u3t(a)); + u3z(a), a = t; + } + while ( u3_nul != a ); + + u3j_gate_lose(&sit_u); + } + + *lit = u3_nul; + + return pro; +} + +u3_noun +u3wb_turn(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qb_turn(a, b); +} diff --git a/vere/pkg/noun/jets/b/weld.c b/vere/pkg/noun/jets/b/weld.c new file mode 100644 index 0000000..d50fa1c --- /dev/null +++ b/vere/pkg/noun/jets/b/weld.c @@ -0,0 +1,48 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_weld(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3_noun* lit = &pro; + + { + u3_noun* hed; + u3_noun* tel; + u3_noun i, t = a; + + while ( u3_nul != t ) { + u3x_cell(t, &i, &t); + + *lit = u3i_defcons(&hed, &tel); + *hed = u3k(i); + lit = tel; + } + } + + *lit = u3k(b); + + return pro; +} + +u3_noun +u3wb_weld(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qb_weld(a, b); +} + +u3_noun +u3kb_weld(u3_noun a, u3_noun b) +{ + u3_noun c = u3qb_weld(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/b/zing.c b/vere/pkg/noun/jets/b/zing.c new file mode 100644 index 0000000..1172d5e --- /dev/null +++ b/vere/pkg/noun/jets/b/zing.c @@ -0,0 +1,47 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qb_zing(u3_noun a) +{ + u3_noun pro; + u3_noun* lit = &pro; + + if ( u3_nul == a ) { + *lit = u3_nul; + } + else { + u3_noun i, t = a; + u3x_cell(t, &i, &t); + + while ( u3_nul != t ) { + u3_noun* hed; + u3_noun* tel; + u3_noun i_i, t_i = i; + + while ( u3_nul != t_i ) { + u3x_cell(t_i, &i_i, &t_i); + + *lit = u3i_defcons(&hed, &tel); + *hed = u3k(i_i); + lit = tel; + } + + u3x_cell(t, &i, &t); + } + + *lit = u3k(i); + } + + return pro; +} + +u3_noun +u3wb_zing(u3_noun cor) +{ + return u3qb_zing(u3x_at(u3x_sam, cor)); +} diff --git a/vere/pkg/noun/jets/c/aor.c b/vere/pkg/noun/jets/c/aor.c new file mode 100644 index 0000000..248661e --- /dev/null +++ b/vere/pkg/noun/jets/c/aor.c @@ -0,0 +1,69 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + u3_noun + u3qc_aor(u3_noun a, + u3_noun b) + { + while ( 1 ) { + if ( c3y == u3r_sing(a, b) ) return c3y; + if ( c3n == u3ud(a) ) { + if ( c3y == u3ud(b) ) return c3n; + if ( c3y == u3r_sing(u3h(a), u3h(b)) ) { + a = u3t(a); + b = u3t(b); + } + else { + a = u3h(a); + b = u3h(b); + } + } + else { + if ( c3n == u3ud(b) ) return c3y; + { + c3_w len_a_w = u3r_met(3, a); + c3_w len_b_w = u3r_met(3, b);; + c3_y *buf_a_y, *buf_b_y; + c3_y cut_a_y, cut_b_y; + if ( c3y == u3a_is_cat(a) ) { + buf_a_y = (c3_y*)&a; + } + else { + u3a_atom* a_u = u3a_to_ptr(a); + buf_a_y = (c3_y*)(a_u->buf_w); + } + if ( c3y == u3a_is_cat(b) ) { + buf_b_y = (c3_y*)&b; + } + else { + u3a_atom* b_u = u3a_to_ptr(b); + buf_b_y = (c3_y*)(b_u->buf_w); + } + c3_w len_min_w = c3_min(len_a_w, len_b_w); + for (c3_w i_w = 0; i_w < len_min_w; i_w++) { + cut_a_y = buf_a_y[i_w]; + cut_b_y = buf_b_y[i_w]; + if ( cut_a_y != cut_b_y ) return __(cut_a_y < cut_b_y); + } + return __(len_a_w < len_b_w); + } + } + } + } + + u3_noun + u3wc_aor(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qc_aor(a, b); + } + } + diff --git a/vere/pkg/noun/jets/c/bex.c b/vere/pkg/noun/jets/c/bex.c new file mode 100644 index 0000000..497ebfd --- /dev/null +++ b/vere/pkg/noun/jets/c/bex.c @@ -0,0 +1,55 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qc_bex(u3_atom a) +{ + c3_d a_d; + u3i_slab sab_u; + + if ( a < 31 ) { + return 1U << a; + } + + if ( c3y == u3a_is_cat(a) ) { + a_d = a; + } + else { + if ( c3n == u3r_safe_chub(a, &a_d) ) { + return u3m_bail(c3__fail); + } + + // We don't currently support atoms 2GB or larger (fails while + // mugging). The extra term of 16 is experimentally determined. + if ( a_d >= ((c3_d)1 << (c3_d)34) - 16 ) { + u3l_log("bex: overflow"); + return u3m_bail(c3__fail); + } + } + + u3i_slab_init(&sab_u, 0, a_d + 1); + + sab_u.buf_w[a_d >> 5] = 1U << (a_d & 31); + + return u3i_slab_moot(&sab_u); +} + +u3_noun +u3kc_bex(u3_atom a) +{ + u3_noun b = u3qc_bex(a); + u3z(a); + return b; +} + +u3_noun +u3wc_bex(u3_noun cor) +{ + u3_noun a = u3x_at(u3x_sam, cor); + return u3qc_bex(u3x_atom(a)); +} diff --git a/vere/pkg/noun/jets/c/c0n.c b/vere/pkg/noun/jets/c/c0n.c new file mode 100644 index 0000000..a6fee5b --- /dev/null +++ b/vere/pkg/noun/jets/c/c0n.c @@ -0,0 +1,55 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_con(u3_atom a, + u3_atom b) + { + c3_w lna_w = u3r_met(5, a); + c3_w lnb_w = u3r_met(5, b); + + if ( (lna_w == 0) && (lnb_w == 0) ) { + return 0; + } + else { + c3_w len_w = c3_max(lna_w, lnb_w); + c3_w i_w; + u3i_slab sab_u; + u3i_slab_from(&sab_u, a, 5, len_w); + + for ( i_w = 0; i_w < lnb_w; i_w++ ) { + sab_u.buf_w[i_w] |= u3r_word(i_w, b); + } + + return u3i_slab_mint(&sab_u); + } + } + u3_noun + u3wc_con(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_con(a, b); + } + } + +u3_noun +u3kc_con(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qc_con(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/c/can.c b/vere/pkg/noun/jets/c/can.c new file mode 100644 index 0000000..ca6d97a --- /dev/null +++ b/vere/pkg/noun/jets/c/can.c @@ -0,0 +1,85 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_can(u3_atom a, + u3_noun b) + { + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + else { + c3_g a_g = a; + c3_w tot_w = 0; + u3i_slab sab_u; + + /* Measure and validate the slab required. + */ + { + u3_noun cab = b; + + while ( 1 ) { + u3_noun i_cab, pi_cab, qi_cab; + + if ( 0 == cab ) { + break; + } + if ( c3n == u3du(cab) ) return u3m_bail(c3__fail); + i_cab = u3h(cab); + if ( c3n == u3du(i_cab) ) return u3m_bail(c3__fail); + pi_cab = u3h(i_cab); + qi_cab = u3t(i_cab); + if ( c3n == u3a_is_cat(pi_cab) ) return u3m_bail(c3__fail); + if ( c3n == u3ud(qi_cab) ) return u3m_bail(c3__fail); + if ( (tot_w + pi_cab) < tot_w ) return u3m_bail(c3__fail); + + tot_w += pi_cab; + cab = u3t(cab); + } + + if ( 0 == tot_w ) { + return 0; + } + + u3i_slab_init(&sab_u, a_g, tot_w); + } + + /* Chop the list atoms in. + */ + { + u3_noun cab = b; + c3_w pos_w = 0; + + while ( 0 != cab ) { + u3_noun i_cab = u3h(cab); + u3_atom pi_cab = u3h(i_cab); + u3_atom qi_cab = u3t(i_cab); + + u3r_chop(a_g, 0, pi_cab, pos_w, sab_u.buf_w, qi_cab); + pos_w += pi_cab; + cab = u3t(cab); + } + } + + return u3i_slab_mint(&sab_u); + } + } + u3_noun + u3wc_can(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qc_can(a, b); + } + } + diff --git a/vere/pkg/noun/jets/c/cap.c b/vere/pkg/noun/jets/c/cap.c new file mode 100644 index 0000000..95bef1f --- /dev/null +++ b/vere/pkg/noun/jets/c/cap.c @@ -0,0 +1,25 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qc_cap(u3_atom a) +{ + c3_w met_w = u3r_met(0, a); + + if ( 2 > met_w ) { + return u3m_bail(c3__exit); + } + else { + return 2 + u3r_bit((met_w - 2), a); + } +} + +u3_noun +u3wc_cap(u3_noun cor) +{ + return u3qc_cap(u3x_atom(u3x_at(u3x_sam, cor))); +} diff --git a/vere/pkg/noun/jets/c/cat.c b/vere/pkg/noun/jets/c/cat.c new file mode 100644 index 0000000..f3c4d2d --- /dev/null +++ b/vere/pkg/noun/jets/c/cat.c @@ -0,0 +1,54 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_cat(u3_atom a, + u3_atom b, + u3_atom c) + { + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + else { + c3_g a_g = a; + c3_w lew_w = u3r_met(a_g, b); + c3_w ler_w = u3r_met(a_g, c); + c3_w all_w = (lew_w + ler_w); + + if ( 0 == all_w ) { + return 0; + } + else { + u3i_slab sab_u; + u3i_slab_from(&sab_u, b, a_g, all_w); + + u3r_chop(a_g, 0, ler_w, lew_w, sab_u.buf_w, c); + + return u3i_slab_mint(&sab_u); + } + } + } + + u3_noun + u3wc_cat(u3_noun cor) + { + u3_noun a, b, c; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_6, &b, + u3x_sam_7, &c, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) || + (c3n == u3ud(c)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_cat(a, b, c); + } + } + diff --git a/vere/pkg/noun/jets/c/clz.c b/vere/pkg/noun/jets/c/clz.c new file mode 100644 index 0000000..f8da45a --- /dev/null +++ b/vere/pkg/noun/jets/c/clz.c @@ -0,0 +1,75 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_atom +u3qc_clz(u3_atom boq, u3_atom sep, u3_atom a) +{ + if ( !_(u3a_is_cat(boq)) || (boq >= 32) ) { + return u3m_bail(c3__fail); + } + + if ( !_(u3a_is_cat(sep)) ) { + return u3m_bail(c3__fail); + } + + c3_g boq_g = boq; + c3_w sep_w = sep; + c3_w tot_w = sep_w << boq_g; + + if ( (tot_w >> boq_g) != sep_w ) { + return u3m_bail(c3__fail); + } + + c3_w met_w = u3r_met(0, a); + + if ( met_w <= tot_w ) { + tot_w -= met_w; + return u3i_word(tot_w); + } + else { + c3_w wid_w = tot_w >> 5; + c3_w bit_w = tot_w & 31; + c3_w wor_w; + + if ( bit_w ) { + wor_w = u3r_word(wid_w, a); + wor_w &= (1 << bit_w) - 1; + + if ( wor_w ) { + return bit_w - (32 - c3_lz_w(wor_w)); + } + } + + while ( wid_w-- ) { + wor_w = u3r_word(wid_w, a); + + if ( wor_w ) { + bit_w += c3_lz_w(wor_w); + break; + } + + bit_w += 32; + } + + return u3i_word(bit_w); + } +} + +u3_noun +u3wc_clz(u3_noun cor) +{ + u3_atom boq, sep, vat; + { + u3_noun sam = u3h(u3t(cor)); + u3_noun bit = u3h(sam); + + u3x_bite(bit, &boq, &sep); + vat = u3x_atom(u3t(sam)); + } + + return u3qc_clz(boq, sep, vat); +} diff --git a/vere/pkg/noun/jets/c/ctz.c b/vere/pkg/noun/jets/c/ctz.c new file mode 100644 index 0000000..ff74e24 --- /dev/null +++ b/vere/pkg/noun/jets/c/ctz.c @@ -0,0 +1,34 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_atom +u3qc_ctz(u3_atom a) +{ + c3_w wor_w, i_w = 0; + + if ( 0 == a ) { + return 0; + } + + do { + wor_w = u3r_word(i_w++, a); + } + while ( !wor_w ); + + { + c3_w bit_d = i_w - 1; + bit_d *= 32; + bit_d += c3_tz_w(wor_w); + return u3i_chub(bit_d); + } +} + +u3_noun +u3wc_ctz(u3_noun cor) +{ + return u3qc_ctz(u3x_atom(u3h(u3t(cor)))); +} diff --git a/vere/pkg/noun/jets/c/cut.c b/vere/pkg/noun/jets/c/cut.c new file mode 100644 index 0000000..43ed8c4 --- /dev/null +++ b/vere/pkg/noun/jets/c/cut.c @@ -0,0 +1,68 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_cut(u3_atom a, + u3_atom b, + u3_atom c, + u3_atom d) + { + c3_w b_w, c_w; + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + if ( !_(u3r_safe_word(b, &b_w)) ) { + return u3m_bail(c3__fail); + } + if ( !_(u3r_safe_word(c, &c_w)) ) { + return u3m_bail(c3__fail); + } + + { + c3_g a_g = a; + c3_w len_w = u3r_met(a_g, d); + + if ( (0 == c_w) || (b_w >= len_w) ) { + return 0; + } + if ( b_w + c_w > len_w ) { + c_w = (len_w - b_w); + } + if ( (b_w == 0) && (c_w == len_w) ) { + return u3k(d); + } + else { + u3i_slab sab_u; + u3i_slab_init(&sab_u, a_g, c_w); + + u3r_chop(a_g, b_w, c_w, 0, sab_u.buf_w, d); + + return u3i_slab_mint(&sab_u); + } + } + } + u3_noun + u3wc_cut(u3_noun cor) + { + u3_noun a, b, c, d; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_12, &b, + u3x_sam_13, &c, + u3x_sam_7, &d, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) || + (c3n == u3ud(c)) || + (c3n == u3ud(d)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_cut(a, b, c, d); + } + } + diff --git a/vere/pkg/noun/jets/c/dis.c b/vere/pkg/noun/jets/c/dis.c new file mode 100644 index 0000000..8c41a36 --- /dev/null +++ b/vere/pkg/noun/jets/c/dis.c @@ -0,0 +1,46 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_dis(u3_atom a, + u3_atom b) + { + c3_w lna_w = u3r_met(5, a); + c3_w lnb_w = u3r_met(5, b); + + if ( (lna_w == 0) && (lnb_w == 0) ) { + return 0; + } + else { + c3_w len_w = c3_max(lna_w, lnb_w); + c3_w i_w; + u3i_slab sab_u; + u3i_slab_from(&sab_u, a, 5, len_w); + + for ( i_w = 0; i_w < len_w; i_w++ ) { + sab_u.buf_w[i_w] &= u3r_word(i_w, b); + } + + return u3i_slab_mint(&sab_u); + } + } + u3_noun + u3wc_dis(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_dis(a, b); + } + } + diff --git a/vere/pkg/noun/jets/c/dor.c b/vere/pkg/noun/jets/c/dor.c new file mode 100644 index 0000000..0c1e220 --- /dev/null +++ b/vere/pkg/noun/jets/c/dor.c @@ -0,0 +1,49 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_dor(u3_noun a, + u3_noun b) + { + if ( c3y == u3r_sing(a, b) ) { + return c3y; + } + else { + if ( c3y == u3ud(a) ) { + if ( c3y == u3ud(b) ) { + return u3qa_lth(a, b); + } + else { + return c3y; + } + } + else { + if ( c3y == u3ud(b) ) { + return c3n; + } + else { + if ( c3y == u3r_sing(u3h(a), u3h(b)) ) { + return u3qc_dor(u3t(a), u3t(b)); + } + else return u3qc_dor(u3h(a), u3h(b)); + } + } + } + } + u3_noun + u3wc_dor(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qc_dor(a, b); + } + } + diff --git a/vere/pkg/noun/jets/c/dvr.c b/vere/pkg/noun/jets/c/dvr.c new file mode 100644 index 0000000..d822bf3 --- /dev/null +++ b/vere/pkg/noun/jets/c/dvr.c @@ -0,0 +1,46 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_dvr(u3_atom a, + u3_atom b) + { + if ( 0 == b ) { + return u3m_error("divide-by-zero"); + } + else { + if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { + return u3nc(a / b, a % b); + } + else { + mpz_t a_mp, b_mp; + + u3r_mp(a_mp, a); + u3r_mp(b_mp, b); + + mpz_tdiv_qr(a_mp, b_mp, a_mp, b_mp); + + return u3nc(u3i_mp(a_mp), u3i_mp(b_mp)); + } + } + } + u3_noun + u3wc_dvr(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qc_dvr(a, b); + } + } + diff --git a/vere/pkg/noun/jets/c/end.c b/vere/pkg/noun/jets/c/end.c new file mode 100644 index 0000000..94618ad --- /dev/null +++ b/vere/pkg/noun/jets/c/end.c @@ -0,0 +1,51 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qc_end(u3_atom a, + u3_atom b, + u3_atom c) +{ + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + else if ( !_(u3a_is_cat(b)) ) { + return u3k(c); + } + else { + c3_g a_g = a; + c3_w b_w = b; + c3_w len_w = u3r_met(a_g, c); + + if ( 0 == b_w ) { + return 0; + } + else if ( b_w >= len_w ) { + return u3k(c); + } + else { + u3i_slab sab_u; + u3i_slab_init(&sab_u, a_g, b_w); + + u3r_chop(a_g, 0, b_w, 0, sab_u.buf_w, c); + + return u3i_slab_mint(&sab_u); + } + } +} + +u3_noun +u3wc_end(u3_noun cor) +{ + u3_atom bloq, step; + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, + u3x_sam_3, &b, 0); + u3x_bite(a, &bloq, &step); + + return u3qc_end(bloq, step, u3x_atom(b)); +} diff --git a/vere/pkg/noun/jets/c/gor.c b/vere/pkg/noun/jets/c/gor.c new file mode 100644 index 0000000..91c2d98 --- /dev/null +++ b/vere/pkg/noun/jets/c/gor.c @@ -0,0 +1,32 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_gor(u3_noun a, + u3_noun b) + { + c3_w c_w = u3r_mug(a); + c3_w d_w = u3r_mug(b); + + if ( c_w == d_w ) { + return u3qc_dor(a, b); + } + else return (c_w < d_w) ? c3y : c3n; + } + u3_noun + u3wc_gor(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ) { + return u3m_bail(c3__exit); + } else { + return u3qc_gor(a, b); + } + } + diff --git a/vere/pkg/noun/jets/c/ham.c b/vere/pkg/noun/jets/c/ham.c new file mode 100644 index 0000000..776cf0c --- /dev/null +++ b/vere/pkg/noun/jets/c/ham.c @@ -0,0 +1,27 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_atom +u3qc_ham(u3_atom a) +{ + c3_w len_w = u3r_met(5, a); + c3_d pop_d = 0; + c3_w wor_w; + + for ( c3_w i_w = 0; i_w < len_w; i_w++ ) { + wor_w = u3r_word(i_w, a); + pop_d += c3_pc_w(wor_w); + } + + return u3i_chub(pop_d); +} + +u3_noun +u3wc_ham(u3_noun cor) +{ + return u3qc_ham(u3x_atom(u3h(u3t(cor)))); +} diff --git a/vere/pkg/noun/jets/c/hew.c b/vere/pkg/noun/jets/c/hew.c new file mode 100644 index 0000000..be6b7a7 --- /dev/null +++ b/vere/pkg/noun/jets/c/hew.c @@ -0,0 +1,87 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static c3_w +_hew_in(c3_g a_g, + c3_w pos_w, + u3_atom vat, + u3_noun sam, + u3_noun* out) +{ + u3_noun h, t, *l, *r; + + while ( c3y == u3r_cell(sam, &h, &t) ) { + *out = u3i_defcons(&l, &r); + pos_w = _hew_in(a_g, pos_w, vat, h, l); + sam = t; + out = r; + } + + if ( !_(u3a_is_cat(sam)) ) { + return u3m_bail(c3__fail); + } + + if ( !sam ) { + *out = 0; + return pos_w; + } + else { + c3_w wid_w = (c3_w)sam; + c3_w new_w = pos_w + wid_w; + u3i_slab sab_u; + + if ( new_w < pos_w ) { + return u3m_bail(c3__fail); + } + + u3i_slab_init(&sab_u, a_g, wid_w); + u3r_chop(a_g, pos_w, wid_w, 0, sab_u.buf_w, vat); + + *out = u3i_slab_mint(&sab_u); + return new_w; + } +} + +u3_noun +u3qc_hew(u3_atom boq, + u3_atom sep, + u3_atom vat, + u3_noun sam) +{ + if ( !_(u3a_is_cat(boq)) || (boq >= 32) ) { + return u3m_bail(c3__fail); + } + + if ( !_(u3a_is_cat(sep)) ) { + return u3m_bail(c3__fail); + } + + u3_noun pro; + c3_w pos_w = _hew_in((c3_g)boq, (c3_w)sep, vat, sam, &pro); + return u3nt(pro, boq, u3i_word(pos_w)); +} + +u3_noun +u3wc_hew(u3_noun cor) +{ + u3_atom boq, sep, vat; + u3_noun sam; + { + u3_noun pay = u3t(cor); + u3_noun con = u3t(pay); + u3_noun gat = u3t(con); // outer gate + u3_noun cam = u3h(u3t(gat)); // outer sample + u3_noun d = u3h(con); + + boq = u3x_atom(u3h(d)); + sep = u3x_atom(u3t(d)); + vat = u3x_atom(u3t(cam)); + sam = u3h(pay); + } + + return u3qc_hew(boq, sep, vat, sam); +} diff --git a/vere/pkg/noun/jets/c/lsh.c b/vere/pkg/noun/jets/c/lsh.c new file mode 100644 index 0000000..09a97e6 --- /dev/null +++ b/vere/pkg/noun/jets/c/lsh.c @@ -0,0 +1,63 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qc_lsh(u3_atom a, + u3_atom b, + u3_atom c) +{ + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + else if ( !_(u3a_is_cat(b)) ) { + return u3m_bail(c3__fail); + } + else { + c3_g a_g = a; + c3_w b_w = b; + c3_w len_w = u3r_met(a_g, c); + + if ( 0 == len_w ) { + return 0; + } + else if ( (b_w + len_w) < len_w ) { + return u3m_bail(c3__exit); + } + else { + u3i_slab sab_u; + u3i_slab_init(&sab_u, a_g, (b_w + len_w)); + + u3r_chop(a_g, 0, len_w, b_w, sab_u.buf_w, c); + + return u3i_slab_mint(&sab_u); + } + } +} + +u3_noun +u3wc_lsh(u3_noun cor) +{ + u3_atom bloq, step; + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, + u3x_sam_3, &b, 0); + u3x_bite(a, &bloq, &step); + + return u3qc_lsh(bloq, step, u3x_atom(b)); +} + +u3_noun +u3kc_lsh(u3_noun a, + u3_noun b, + u3_noun c) +{ + u3_noun d = u3qc_lsh(a, b, c); + + u3z(a); u3z(b); u3z(c); + return d; +} diff --git a/vere/pkg/noun/jets/c/mas.c b/vere/pkg/noun/jets/c/mas.c new file mode 100644 index 0000000..b0be6e1 --- /dev/null +++ b/vere/pkg/noun/jets/c/mas.c @@ -0,0 +1,48 @@ +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qc_mas(u3_atom a) +{ + c3_w b_w; + + if ( c3y == u3a_is_cat(a) ) { + b_w = c3_bits_word(a); + + if ( 2 > b_w ) { + return u3m_bail(c3__exit); + } + else { + a &= ~((c3_w)1 << (b_w - 1)); + a |= ((c3_w)1 << (b_w - 2)); + return a; + } + } + else { + b_w = u3r_met(0, a); + + if ( 64 > b_w ) { + c3_d a_d = u3r_chub(0, a); + a_d &= ~((c3_d)1 << (b_w - 1)); + a_d |= ((c3_d)1 << (b_w - 2)); + return u3i_chub(a_d); + } + else { + u3i_slab sab_u; + u3i_slab_from(&sab_u, a, 0, b_w - 1); + + b_w -= 2; + sab_u.buf_w[(b_w >> 5)] |= ((c3_w)1 << (b_w & 31)); + + return u3i_slab_mint(&sab_u); + } + } +} + +u3_noun +u3wc_mas(u3_noun cor) +{ + return u3qc_mas(u3x_atom(u3x_at(u3x_sam, cor))); +} diff --git a/vere/pkg/noun/jets/c/met.c b/vere/pkg/noun/jets/c/met.c new file mode 100644 index 0000000..5f3a6a6 --- /dev/null +++ b/vere/pkg/noun/jets/c/met.c @@ -0,0 +1,42 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_met(u3_atom a, + u3_atom b) + { + if ( 0 == b ) { + return 0; + } + else if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail);; + } + else { + c3_w met_w = u3r_met(a, b); + + if ( !_(u3a_is_cat(met_w)) ) { + return u3i_words(1, &met_w); + } + else return met_w; + } + } + u3_noun + u3wc_met(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(b)) || + (c3n == u3ud(a) && 0 != b) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_met(a, b); + } + } + diff --git a/vere/pkg/noun/jets/c/mix.c b/vere/pkg/noun/jets/c/mix.c new file mode 100644 index 0000000..b497c3f --- /dev/null +++ b/vere/pkg/noun/jets/c/mix.c @@ -0,0 +1,56 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_mix(u3_atom a, + u3_atom b) + { + c3_w lna_w = u3r_met(5, a); + c3_w lnb_w = u3r_met(5, b); + + if ( (lna_w == 0) && (lnb_w == 0) ) { + return 0; + } + else { + c3_w len_w = c3_max(lna_w, lnb_w); + c3_w i_w; + u3i_slab sab_u; + u3i_slab_from(&sab_u, a, 5, len_w); + + // XX use u3r_chop for XOR? + // + for ( i_w = 0; i_w < lnb_w; i_w++ ) { + sab_u.buf_w[i_w] ^= u3r_word(i_w, b); + } + + return u3i_slab_mint(&sab_u); + } + } + u3_noun + u3wc_mix(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_mix(a, b); + } + } + u3_noun + u3kc_mix(u3_atom a, + u3_atom b) + { + u3_noun res = u3qc_mix(a, b); + u3z(a); u3z(b); + return res; + } diff --git a/vere/pkg/noun/jets/c/mor.c b/vere/pkg/noun/jets/c/mor.c new file mode 100644 index 0000000..97ba141 --- /dev/null +++ b/vere/pkg/noun/jets/c/mor.c @@ -0,0 +1,31 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_mor(u3_noun a, + u3_noun b) + { + c3_w c_w = u3r_mug(u3r_mug(a)); + c3_w d_w = u3r_mug(u3r_mug(b)); + + if ( c_w == d_w ) { + return u3qc_dor(a, b); + } + else return (c_w < d_w) ? c3y : c3n; + } + u3_noun + u3wc_mor(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ) { + return u3m_bail(c3__exit); + } else { + return u3qc_mor(a, b); + } + } diff --git a/vere/pkg/noun/jets/c/mug.c b/vere/pkg/noun/jets/c/mug.c new file mode 100644 index 0000000..ec6e483 --- /dev/null +++ b/vere/pkg/noun/jets/c/mug.c @@ -0,0 +1,19 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3wc_mug(u3_noun cor) + { + u3_noun sam; + + if ( u3_none == (sam = u3r_at(u3x_sam, cor)) ) { + return u3m_bail(c3__exit); + } else { + return u3r_mug(sam); + } + } diff --git a/vere/pkg/noun/jets/c/muk.c b/vere/pkg/noun/jets/c/muk.c new file mode 100644 index 0000000..0846ed7 --- /dev/null +++ b/vere/pkg/noun/jets/c/muk.c @@ -0,0 +1,76 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "murmur3.h" + +u3_noun +u3qc_muk(u3_atom sed, + u3_atom len, + u3_atom key) +{ + if ( c3n == u3a_is_cat(len) ) { + return u3m_bail(c3__fail); + } + else { + c3_w len_w = (c3_w)len; + c3_w key_w = u3r_met(3, key); + + // NB: this condition is implicit in the pad subtraction + // + if ( key_w > len_w ) { + return u3m_bail(c3__exit); + } + else { + c3_w sed_w = u3r_word(0, sed); + c3_o loc_o = c3n; + c3_y* key_y = 0; + c3_w out_w; + + // if we're hashing more bytes than we have, allocate and copy + // to ensure trailing null bytes + // + if ( len_w > key_w ) { + loc_o = c3y; + key_y = u3a_calloc(sizeof(c3_y), len_w); + u3r_bytes(0, len_w, key_y, key); + } + else if ( len_w > 0 ) { + // XX assumes little-endian + // + key_y = ( c3y == u3a_is_cat(key) ) + ? (c3_y*)&key + : (c3_y*)((u3a_atom*)u3a_to_ptr(key))->buf_w; + } + + MurmurHash3_x86_32(key_y, len_w, sed_w, &out_w); + + if ( c3y == loc_o ) { + u3a_free(key_y); + } + + return u3i_words(1, &out_w); + } + } +} + +u3_noun +u3wc_muk(u3_noun cor) +{ + u3_noun sed, len, key; + u3x_mean(cor, u3x_sam_2, &sed, + u3x_sam_6, &len, + u3x_sam_7, &key, 0); + + if ( (c3n == u3ud(sed)) + || (c3n == u3ud(len)) + || (c3n == u3ud(key)) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qc_muk(sed, len, key); + } +} diff --git a/vere/pkg/noun/jets/c/peg.c b/vere/pkg/noun/jets/c/peg.c new file mode 100644 index 0000000..a700752 --- /dev/null +++ b/vere/pkg/noun/jets/c/peg.c @@ -0,0 +1,66 @@ +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qc_peg(u3_atom a, u3_atom b) +{ + if ( (0 == a) || (0 == b) ) { + return u3m_bail(c3__exit); + } + else if ( 1 == b ) { + return u3k(a); + } + + c3_d a_d, b_d; + c3_w c_w; + + if ( (c3y == u3a_is_cat(a)) && (c3y == u3a_is_cat(b)) ) { + c_w = c3_bits_word(b) - 1; + a_d = a; + b_d = b; + } + else { + c3_w d_w = u3r_met(0, a); + c3_d e_d; + + c_w = u3r_met(0, b) - 1; + e_d = (c3_d)c_w + d_w; + + if ( 64 <= e_d ) { + u3i_slab sab_u; + u3i_slab_init(&sab_u, 0, e_d); + + u3r_chop(0, 0, c_w, 0, sab_u.buf_w, b); + u3r_chop(0, 0, d_w, c_w, sab_u.buf_w, a); + + return u3i_slab_moot(&sab_u); + } + + a_d = u3r_chub(0, a); + b_d = u3r_chub(0, b); + } + + b_d &= ((c3_d)1 << c_w) - 1; + a_d <<= c_w; + a_d ^= b_d; + + return u3i_chub(a_d); +} + +u3_noun +u3wc_peg(u3_noun cor) +{ + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(b)) || + (c3n == u3ud(a) && b != 1) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qc_peg(a, b); + } +} diff --git a/vere/pkg/noun/jets/c/po.c b/vere/pkg/noun/jets/c/po.c new file mode 100644 index 0000000..2fe8858 --- /dev/null +++ b/vere/pkg/noun/jets/c/po.c @@ -0,0 +1,1427 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3_po_find_prefix(c3_y one, c3_y two, c3_y three) { + switch (one) { + case 'b': switch (two) { + case 'a': switch (three) { + case 'c': return u3nc(0, 238); + case 'l': return u3nc(0, 107); + case 'n': return u3nc(0, 92); + case 'r': return u3nc(0, 183); + case 't': return u3nc(0, 172); + default: return 0; + } + case 'i': switch (three) { + case 'c': return u3nc(0, 56); + case 'd': return u3nc(0, 106); + case 'l': return u3nc(0, 144); + case 'n': return u3nc(0, 2); + case 's': return u3nc(0, 60); + case 't': return u3nc(0, 182); + default: return 0; + } + case 'o': switch (three) { + case 'l': return u3nc(0, 45); + case 'n': return u3nc(0, 244); + case 'r': return u3nc(0, 188); + case 's': return u3nc(0, 171); + case 't': return u3nc(0, 98); + default: return 0; + } + default: return 0; + } + case 'd': switch (two) { + case 'a': switch (three) { + case 'b': return u3nc(0, 181); + case 'c': return u3nc(0, 117); + case 'l': return u3nc(0, 37); + case 'n': return u3nc(0, 234); + case 'p': return u3nc(0, 66); + case 'r': return u3nc(0, 23); + case 's': return u3nc(0, 61); + case 't': return u3nc(0, 215); + case 'v': return u3nc(0, 105); + default: return 0; + } + case 'i': switch (three) { + case 'b': return u3nc(0, 179); + case 'f': return u3nc(0, 57); + case 'g': return u3nc(0, 193); + case 'l': return u3nc(0, 49); + case 'n': return u3nc(0, 217); + case 'r': return u3nc(0, 11); + case 's': return u3nc(0, 129); + case 'v': return u3nc(0, 116); + default: return 0; + } + case 'o': switch (three) { + case 'c': return u3nc(0, 146); + case 'l': return u3nc(0, 102); + case 'n': return u3nc(0, 233); + case 'p': return u3nc(0, 18); + case 'r': return u3nc(0, 24); + case 's': return u3nc(0, 187); + case 't': return u3nc(0, 47); + case 'v': return u3nc(0, 236); + case 'z': return u3nc(0, 0); + default: return 0; + } + default: return 0; + } + case 'f': switch (two) { + case 'a': switch (three) { + case 'b': return u3nc(0, 120); + case 'd': return u3nc(0, 206); + case 'l': return u3nc(0, 152); + case 'm': return u3nc(0, 214); + case 'n': return u3nc(0, 158); + case 's': return u3nc(0, 195); + default: return 0; + } + case 'i': switch (three) { + case 'd': return u3nc(0, 8); + case 'g': return u3nc(0, 138); + case 'l': return u3nc(0, 194); + case 'n': return u3nc(0, 90); + case 'p': return u3nc(0, 255); + case 'r': return u3nc(0, 169); + case 't': return u3nc(0, 226); + default: return 0; + } + case 'o': switch (three) { + case 'd': return u3nc(0, 247); + case 'g': return u3nc(0, 20); + case 'l': return u3nc(0, 27); + case 'n': return u3nc(0, 91); + case 'p': return u3nc(0, 213); + case 'r': return u3nc(0, 50); + case 's': return u3nc(0, 46); + case 't': return u3nc(0, 221); + default: return 0; + } + default: return 0; + } + case 'h': switch (two) { + case 'a': switch (three) { + case 'b': return u3nc(0, 209); + case 'c': return u3nc(0, 174); + case 'd': return u3nc(0, 145); + case 'l': return u3nc(0, 203); + case 'n': return u3nc(0, 41); + case 'p': return u3nc(0, 156); + case 'r': return u3nc(0, 198); + case 's': return u3nc(0, 170); + case 't': return u3nc(0, 218); + case 'v': return u3nc(0, 176); + default: return 0; + } + case 'i': switch (three) { + case 'd': return u3nc(0, 7); + case 'l': return u3nc(0, 190); + case 'n': return u3nc(0, 200); + default: return 0; + } + case 'o': switch (three) { + case 'b': return u3nc(0, 197); + case 'c': return u3nc(0, 223); + case 'd': return u3nc(0, 26); + case 'l': return u3nc(0, 32); + case 'p': return u3nc(0, 22); + case 's': return u3nc(0, 180); + default: return 0; + } + default: return 0; + } + case 'l': switch (two) { + case 'a': switch (three) { + case 'b': return u3nc(0, 161); + case 'c': return u3nc(0, 34); + case 'd': return u3nc(0, 235); + case 'g': return u3nc(0, 205); + case 'n': return u3nc(0, 232); + case 'p': return u3nc(0, 240); + case 'r': return u3nc(0, 225); + case 's': return u3nc(0, 128); + case 't': return u3nc(0, 134); + case 'v': return u3nc(0, 252); + default: return 0; + } + case 'i': switch (three) { + case 'b': return u3nc(0, 39); + case 'd': return u3nc(0, 21); + case 'g': return u3nc(0, 111); + case 'n': return u3nc(0, 178); + case 's': return u3nc(0, 9); + case 't': return u3nc(0, 5); + case 'v': return u3nc(0, 36); + default: return 0; + } + case 'o': switch (three) { + case 'c': return u3nc(0, 69); + case 'd': return u3nc(0, 186); + case 'm': return u3nc(0, 166); + case 'n': return u3nc(0, 135); + case 'p': return u3nc(0, 63); + case 'r': return u3nc(0, 25); + case 's': return u3nc(0, 48); + default: return 0; + } + default: return 0; + } + case 'm': switch (two) { + case 'a': switch (three) { + case 'c': return u3nc(0, 191); + case 'g': return u3nc(0, 103); + case 'l': return u3nc(0, 110); + case 'p': return u3nc(0, 130); + case 'r': return u3nc(0, 1); + case 's': return u3nc(0, 202); + case 't': return u3nc(0, 253); + default: return 0; + } + case 'i': switch (three) { + case 'c': return u3nc(0, 157); + case 'd': return u3nc(0, 62); + case 'g': return u3nc(0, 199); + case 'l': return u3nc(0, 212); + case 'n': return u3nc(0, 79); + case 'p': return u3nc(0, 254); + case 'r': return u3nc(0, 31); + case 's': return u3nc(0, 126); + case 't': return u3nc(0, 196); + default: return 0; + } + case 'o': switch (three) { + case 'c': return u3nc(0, 148); + case 'd': return u3nc(0, 19); + case 'g': return u3nc(0, 162); + case 'l': return u3nc(0, 67); + case 'n': return u3nc(0, 122); + case 'p': return u3nc(0, 208); + case 'r': return u3nc(0, 93); + case 's': return u3nc(0, 231); + case 't': return u3nc(0, 82); + default: return 0; + } + default: return 0; + } + case 'n': switch (two) { + case 'a': switch (three) { + case 'c': return u3nc(0, 219); + case 'l': return u3nc(0, 230); + case 'm': return u3nc(0, 243); + case 'p': return u3nc(0, 87); + case 'r': return u3nc(0, 65); + case 't': return u3nc(0, 77); + case 'v': return u3nc(0, 137); + default: return 0; + } + case 'i': switch (three) { + case 'b': return u3nc(0, 140); + case 'd': return u3nc(0, 72); + case 'l': return u3nc(0, 210); + case 'm': return u3nc(0, 224); + case 's': return u3nc(0, 124); + default: return 0; + } + case 'o': switch (three) { + case 'c': return u3nc(0, 250); + case 'd': return u3nc(0, 136); + case 'l': return u3nc(0, 216); + case 'm': return u3nc(0, 139); + case 'p': return u3nc(0, 88); + case 'r': return u3nc(0, 97); + case 's': return u3nc(0, 211); + case 'v': return u3nc(0, 70); + default: return 0; + } + default: return 0; + } + case 'p': switch (two) { + case 'a': switch (three) { + case 'c': return u3nc(0, 149); + case 'd': return u3nc(0, 114); + case 'g': return u3nc(0, 141); + case 'l': return u3nc(0, 127); + case 'n': return u3nc(0, 78); + case 'r': return u3nc(0, 185); + case 's': return u3nc(0, 33); + case 't': return u3nc(0, 159); + default: return 0; + } + case 'i': switch (three) { + case 'c': return u3nc(0, 104); + case 'd': return u3nc(0, 43); + case 'l': return u3nc(0, 51); + case 'n': return u3nc(0, 165); + case 't': return u3nc(0, 242); + default: return 0; + } + case 'o': switch (three) { + case 'c': return u3nc(0, 173); + case 'd': return u3nc(0, 81); + case 'l': return u3nc(0, 239); + case 'n': return u3nc(0, 248); + case 's': return u3nc(0, 86); + default: return 0; + } + default: return 0; + } + case 'r': switch (two) { + case 'a': switch (three) { + case 'b': return u3nc(0, 131); + case 'c': return u3nc(0, 184); + case 'd': return u3nc(0, 201); + case 'g': return u3nc(0, 204); + case 'l': return u3nc(0, 143); + case 'm': return u3nc(0, 52); + case 'n': return u3nc(0, 123); + case 'p': return u3nc(0, 228); + case 'v': return u3nc(0, 150); + default: return 0; + } + case 'i': switch (three) { + case 'b': return u3nc(0, 222); + case 'c': return u3nc(0, 167); + case 'd': return u3nc(0, 147); + case 'g': return u3nc(0, 16); + case 'l': return u3nc(0, 64); + case 'n': return u3nc(0, 28); + case 'p': return u3nc(0, 151); + case 's': return u3nc(0, 220); + case 't': return u3nc(0, 80); + case 'v': return u3nc(0, 237); + default: return 0; + } + case 'o': switch (three) { + case 'c': return u3nc(0, 58); + case 'l': return u3nc(0, 133); + case 'n': return u3nc(0, 96); + case 'p': return u3nc(0, 75); + case 's': return u3nc(0, 245); + case 'v': return u3nc(0, 35); + default: return 0; + } + default: return 0; + } + case 's': switch (two) { + case 'a': switch (three) { + case 'b': return u3nc(0, 13); + case 'l': return u3nc(0, 115); + case 'm': return u3nc(0, 4); + case 'n': return u3nc(0, 68); + case 'p': return u3nc(0, 177); + case 'r': return u3nc(0, 229); + case 't': return u3nc(0, 38); + case 'v': return u3nc(0, 85); + default: return 0; + } + case 'i': switch (three) { + case 'b': return u3nc(0, 15); + case 'c': return u3nc(0, 74); + case 'd': return u3nc(0, 119); + case 'g': return u3nc(0, 6); + case 'l': return u3nc(0, 30); + case 'm': return u3nc(0, 163); + case 'p': return u3nc(0, 95); + case 't': return u3nc(0, 71); + case 'v': return u3nc(0, 112); + default: return 0; + } + case 'o': switch (three) { + case 'c': return u3nc(0, 100); + case 'g': return u3nc(0, 10); + case 'l': return u3nc(0, 17); + case 'm': return u3nc(0, 89); + case 'n': return u3nc(0, 164); + case 'p': return u3nc(0, 142); + case 'r': return u3nc(0, 251); + case 'v': return u3nc(0, 249); + default: return 0; + } + default: return 0; + } + case 't': switch (two) { + case 'a': switch (three) { + case 'b': return u3nc(0, 40); + case 'c': return u3nc(0, 160); + case 'd': return u3nc(0, 55); + case 'g': return u3nc(0, 113); + case 'l': return u3nc(0, 241); + case 'm': return u3nc(0, 83); + case 'n': return u3nc(0, 118); + case 'p': return u3nc(0, 168); + case 'r': return u3nc(0, 121); + case 's': return u3nc(0, 109); + default: return 0; + } + case 'i': switch (three) { + case 'c': return u3nc(0, 42); + case 'd': return u3nc(0, 175); + case 'l': return u3nc(0, 154); + case 'm': return u3nc(0, 108); + case 'n': return u3nc(0, 155); + case 'p': return u3nc(0, 73); + case 'r': return u3nc(0, 53); + default: return 0; + } + case 'o': switch (three) { + case 'b': return u3nc(0, 132); + case 'c': return u3nc(0, 189); + case 'd': return u3nc(0, 153); + case 'g': return u3nc(0, 29); + case 'l': return u3nc(0, 84); + case 'm': return u3nc(0, 192); + case 'n': return u3nc(0, 246); + case 'p': return u3nc(0, 207); + case 'r': return u3nc(0, 44); + default: return 0; + } + default: return 0; + } + case 'w': switch (two) { + case 'a': switch (three) { + case 'c': return u3nc(0, 12); + case 'l': return u3nc(0, 227); + case 'n': return u3nc(0, 3); + case 't': return u3nc(0, 101); + default: return 0; + } + case 'i': switch (three) { + case 'c': return u3nc(0, 99); + case 'd': return u3nc(0, 59); + case 'n': return u3nc(0, 54); + case 's': return u3nc(0, 14); + case 't': return u3nc(0, 76); + default: return 0; + } + case 'o': switch (three) { + case 'l': return u3nc(0, 125); + case 'r': return u3nc(0, 94); + default: return 0; + } + default: return 0; + } + default: return 0; + } +} + +void +u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c) +{ + switch (id) { + case 0: *a = 'd'; *b = 'o'; *c = 'z'; break; + case 1: *a = 'm'; *b = 'a'; *c = 'r'; break; + case 2: *a = 'b'; *b = 'i'; *c = 'n'; break; + case 3: *a = 'w'; *b = 'a'; *c = 'n'; break; + case 4: *a = 's'; *b = 'a'; *c = 'm'; break; + case 5: *a = 'l'; *b = 'i'; *c = 't'; break; + case 6: *a = 's'; *b = 'i'; *c = 'g'; break; + case 7: *a = 'h'; *b = 'i'; *c = 'd'; break; + case 8: *a = 'f'; *b = 'i'; *c = 'd'; break; + case 9: *a = 'l'; *b = 'i'; *c = 's'; break; + case 10: *a = 's'; *b = 'o'; *c = 'g'; break; + case 11: *a = 'd'; *b = 'i'; *c = 'r'; break; + case 12: *a = 'w'; *b = 'a'; *c = 'c'; break; + case 13: *a = 's'; *b = 'a'; *c = 'b'; break; + case 14: *a = 'w'; *b = 'i'; *c = 's'; break; + case 15: *a = 's'; *b = 'i'; *c = 'b'; break; + case 16: *a = 'r'; *b = 'i'; *c = 'g'; break; + case 17: *a = 's'; *b = 'o'; *c = 'l'; break; + case 18: *a = 'd'; *b = 'o'; *c = 'p'; break; + case 19: *a = 'm'; *b = 'o'; *c = 'd'; break; + case 20: *a = 'f'; *b = 'o'; *c = 'g'; break; + case 21: *a = 'l'; *b = 'i'; *c = 'd'; break; + case 22: *a = 'h'; *b = 'o'; *c = 'p'; break; + case 23: *a = 'd'; *b = 'a'; *c = 'r'; break; + case 24: *a = 'd'; *b = 'o'; *c = 'r'; break; + case 25: *a = 'l'; *b = 'o'; *c = 'r'; break; + case 26: *a = 'h'; *b = 'o'; *c = 'd'; break; + case 27: *a = 'f'; *b = 'o'; *c = 'l'; break; + case 28: *a = 'r'; *b = 'i'; *c = 'n'; break; + case 29: *a = 't'; *b = 'o'; *c = 'g'; break; + case 30: *a = 's'; *b = 'i'; *c = 'l'; break; + case 31: *a = 'm'; *b = 'i'; *c = 'r'; break; + case 32: *a = 'h'; *b = 'o'; *c = 'l'; break; + case 33: *a = 'p'; *b = 'a'; *c = 's'; break; + case 34: *a = 'l'; *b = 'a'; *c = 'c'; break; + case 35: *a = 'r'; *b = 'o'; *c = 'v'; break; + case 36: *a = 'l'; *b = 'i'; *c = 'v'; break; + case 37: *a = 'd'; *b = 'a'; *c = 'l'; break; + case 38: *a = 's'; *b = 'a'; *c = 't'; break; + case 39: *a = 'l'; *b = 'i'; *c = 'b'; break; + case 40: *a = 't'; *b = 'a'; *c = 'b'; break; + case 41: *a = 'h'; *b = 'a'; *c = 'n'; break; + case 42: *a = 't'; *b = 'i'; *c = 'c'; break; + case 43: *a = 'p'; *b = 'i'; *c = 'd'; break; + case 44: *a = 't'; *b = 'o'; *c = 'r'; break; + case 45: *a = 'b'; *b = 'o'; *c = 'l'; break; + case 46: *a = 'f'; *b = 'o'; *c = 's'; break; + case 47: *a = 'd'; *b = 'o'; *c = 't'; break; + case 48: *a = 'l'; *b = 'o'; *c = 's'; break; + case 49: *a = 'd'; *b = 'i'; *c = 'l'; break; + case 50: *a = 'f'; *b = 'o'; *c = 'r'; break; + case 51: *a = 'p'; *b = 'i'; *c = 'l'; break; + case 52: *a = 'r'; *b = 'a'; *c = 'm'; break; + case 53: *a = 't'; *b = 'i'; *c = 'r'; break; + case 54: *a = 'w'; *b = 'i'; *c = 'n'; break; + case 55: *a = 't'; *b = 'a'; *c = 'd'; break; + case 56: *a = 'b'; *b = 'i'; *c = 'c'; break; + case 57: *a = 'd'; *b = 'i'; *c = 'f'; break; + case 58: *a = 'r'; *b = 'o'; *c = 'c'; break; + case 59: *a = 'w'; *b = 'i'; *c = 'd'; break; + case 60: *a = 'b'; *b = 'i'; *c = 's'; break; + case 61: *a = 'd'; *b = 'a'; *c = 's'; break; + case 62: *a = 'm'; *b = 'i'; *c = 'd'; break; + case 63: *a = 'l'; *b = 'o'; *c = 'p'; break; + case 64: *a = 'r'; *b = 'i'; *c = 'l'; break; + case 65: *a = 'n'; *b = 'a'; *c = 'r'; break; + case 66: *a = 'd'; *b = 'a'; *c = 'p'; break; + case 67: *a = 'm'; *b = 'o'; *c = 'l'; break; + case 68: *a = 's'; *b = 'a'; *c = 'n'; break; + case 69: *a = 'l'; *b = 'o'; *c = 'c'; break; + case 70: *a = 'n'; *b = 'o'; *c = 'v'; break; + case 71: *a = 's'; *b = 'i'; *c = 't'; break; + case 72: *a = 'n'; *b = 'i'; *c = 'd'; break; + case 73: *a = 't'; *b = 'i'; *c = 'p'; break; + case 74: *a = 's'; *b = 'i'; *c = 'c'; break; + case 75: *a = 'r'; *b = 'o'; *c = 'p'; break; + case 76: *a = 'w'; *b = 'i'; *c = 't'; break; + case 77: *a = 'n'; *b = 'a'; *c = 't'; break; + case 78: *a = 'p'; *b = 'a'; *c = 'n'; break; + case 79: *a = 'm'; *b = 'i'; *c = 'n'; break; + case 80: *a = 'r'; *b = 'i'; *c = 't'; break; + case 81: *a = 'p'; *b = 'o'; *c = 'd'; break; + case 82: *a = 'm'; *b = 'o'; *c = 't'; break; + case 83: *a = 't'; *b = 'a'; *c = 'm'; break; + case 84: *a = 't'; *b = 'o'; *c = 'l'; break; + case 85: *a = 's'; *b = 'a'; *c = 'v'; break; + case 86: *a = 'p'; *b = 'o'; *c = 's'; break; + case 87: *a = 'n'; *b = 'a'; *c = 'p'; break; + case 88: *a = 'n'; *b = 'o'; *c = 'p'; break; + case 89: *a = 's'; *b = 'o'; *c = 'm'; break; + case 90: *a = 'f'; *b = 'i'; *c = 'n'; break; + case 91: *a = 'f'; *b = 'o'; *c = 'n'; break; + case 92: *a = 'b'; *b = 'a'; *c = 'n'; break; + case 93: *a = 'm'; *b = 'o'; *c = 'r'; break; + case 94: *a = 'w'; *b = 'o'; *c = 'r'; break; + case 95: *a = 's'; *b = 'i'; *c = 'p'; break; + case 96: *a = 'r'; *b = 'o'; *c = 'n'; break; + case 97: *a = 'n'; *b = 'o'; *c = 'r'; break; + case 98: *a = 'b'; *b = 'o'; *c = 't'; break; + case 99: *a = 'w'; *b = 'i'; *c = 'c'; break; + case 100: *a = 's'; *b = 'o'; *c = 'c'; break; + case 101: *a = 'w'; *b = 'a'; *c = 't'; break; + case 102: *a = 'd'; *b = 'o'; *c = 'l'; break; + case 103: *a = 'm'; *b = 'a'; *c = 'g'; break; + case 104: *a = 'p'; *b = 'i'; *c = 'c'; break; + case 105: *a = 'd'; *b = 'a'; *c = 'v'; break; + case 106: *a = 'b'; *b = 'i'; *c = 'd'; break; + case 107: *a = 'b'; *b = 'a'; *c = 'l'; break; + case 108: *a = 't'; *b = 'i'; *c = 'm'; break; + case 109: *a = 't'; *b = 'a'; *c = 's'; break; + case 110: *a = 'm'; *b = 'a'; *c = 'l'; break; + case 111: *a = 'l'; *b = 'i'; *c = 'g'; break; + case 112: *a = 's'; *b = 'i'; *c = 'v'; break; + case 113: *a = 't'; *b = 'a'; *c = 'g'; break; + case 114: *a = 'p'; *b = 'a'; *c = 'd'; break; + case 115: *a = 's'; *b = 'a'; *c = 'l'; break; + case 116: *a = 'd'; *b = 'i'; *c = 'v'; break; + case 117: *a = 'd'; *b = 'a'; *c = 'c'; break; + case 118: *a = 't'; *b = 'a'; *c = 'n'; break; + case 119: *a = 's'; *b = 'i'; *c = 'd'; break; + case 120: *a = 'f'; *b = 'a'; *c = 'b'; break; + case 121: *a = 't'; *b = 'a'; *c = 'r'; break; + case 122: *a = 'm'; *b = 'o'; *c = 'n'; break; + case 123: *a = 'r'; *b = 'a'; *c = 'n'; break; + case 124: *a = 'n'; *b = 'i'; *c = 's'; break; + case 125: *a = 'w'; *b = 'o'; *c = 'l'; break; + case 126: *a = 'm'; *b = 'i'; *c = 's'; break; + case 127: *a = 'p'; *b = 'a'; *c = 'l'; break; + case 128: *a = 'l'; *b = 'a'; *c = 's'; break; + case 129: *a = 'd'; *b = 'i'; *c = 's'; break; + case 130: *a = 'm'; *b = 'a'; *c = 'p'; break; + case 131: *a = 'r'; *b = 'a'; *c = 'b'; break; + case 132: *a = 't'; *b = 'o'; *c = 'b'; break; + case 133: *a = 'r'; *b = 'o'; *c = 'l'; break; + case 134: *a = 'l'; *b = 'a'; *c = 't'; break; + case 135: *a = 'l'; *b = 'o'; *c = 'n'; break; + case 136: *a = 'n'; *b = 'o'; *c = 'd'; break; + case 137: *a = 'n'; *b = 'a'; *c = 'v'; break; + case 138: *a = 'f'; *b = 'i'; *c = 'g'; break; + case 139: *a = 'n'; *b = 'o'; *c = 'm'; break; + case 140: *a = 'n'; *b = 'i'; *c = 'b'; break; + case 141: *a = 'p'; *b = 'a'; *c = 'g'; break; + case 142: *a = 's'; *b = 'o'; *c = 'p'; break; + case 143: *a = 'r'; *b = 'a'; *c = 'l'; break; + case 144: *a = 'b'; *b = 'i'; *c = 'l'; break; + case 145: *a = 'h'; *b = 'a'; *c = 'd'; break; + case 146: *a = 'd'; *b = 'o'; *c = 'c'; break; + case 147: *a = 'r'; *b = 'i'; *c = 'd'; break; + case 148: *a = 'm'; *b = 'o'; *c = 'c'; break; + case 149: *a = 'p'; *b = 'a'; *c = 'c'; break; + case 150: *a = 'r'; *b = 'a'; *c = 'v'; break; + case 151: *a = 'r'; *b = 'i'; *c = 'p'; break; + case 152: *a = 'f'; *b = 'a'; *c = 'l'; break; + case 153: *a = 't'; *b = 'o'; *c = 'd'; break; + case 154: *a = 't'; *b = 'i'; *c = 'l'; break; + case 155: *a = 't'; *b = 'i'; *c = 'n'; break; + case 156: *a = 'h'; *b = 'a'; *c = 'p'; break; + case 157: *a = 'm'; *b = 'i'; *c = 'c'; break; + case 158: *a = 'f'; *b = 'a'; *c = 'n'; break; + case 159: *a = 'p'; *b = 'a'; *c = 't'; break; + case 160: *a = 't'; *b = 'a'; *c = 'c'; break; + case 161: *a = 'l'; *b = 'a'; *c = 'b'; break; + case 162: *a = 'm'; *b = 'o'; *c = 'g'; break; + case 163: *a = 's'; *b = 'i'; *c = 'm'; break; + case 164: *a = 's'; *b = 'o'; *c = 'n'; break; + case 165: *a = 'p'; *b = 'i'; *c = 'n'; break; + case 166: *a = 'l'; *b = 'o'; *c = 'm'; break; + case 167: *a = 'r'; *b = 'i'; *c = 'c'; break; + case 168: *a = 't'; *b = 'a'; *c = 'p'; break; + case 169: *a = 'f'; *b = 'i'; *c = 'r'; break; + case 170: *a = 'h'; *b = 'a'; *c = 's'; break; + case 171: *a = 'b'; *b = 'o'; *c = 's'; break; + case 172: *a = 'b'; *b = 'a'; *c = 't'; break; + case 173: *a = 'p'; *b = 'o'; *c = 'c'; break; + case 174: *a = 'h'; *b = 'a'; *c = 'c'; break; + case 175: *a = 't'; *b = 'i'; *c = 'd'; break; + case 176: *a = 'h'; *b = 'a'; *c = 'v'; break; + case 177: *a = 's'; *b = 'a'; *c = 'p'; break; + case 178: *a = 'l'; *b = 'i'; *c = 'n'; break; + case 179: *a = 'd'; *b = 'i'; *c = 'b'; break; + case 180: *a = 'h'; *b = 'o'; *c = 's'; break; + case 181: *a = 'd'; *b = 'a'; *c = 'b'; break; + case 182: *a = 'b'; *b = 'i'; *c = 't'; break; + case 183: *a = 'b'; *b = 'a'; *c = 'r'; break; + case 184: *a = 'r'; *b = 'a'; *c = 'c'; break; + case 185: *a = 'p'; *b = 'a'; *c = 'r'; break; + case 186: *a = 'l'; *b = 'o'; *c = 'd'; break; + case 187: *a = 'd'; *b = 'o'; *c = 's'; break; + case 188: *a = 'b'; *b = 'o'; *c = 'r'; break; + case 189: *a = 't'; *b = 'o'; *c = 'c'; break; + case 190: *a = 'h'; *b = 'i'; *c = 'l'; break; + case 191: *a = 'm'; *b = 'a'; *c = 'c'; break; + case 192: *a = 't'; *b = 'o'; *c = 'm'; break; + case 193: *a = 'd'; *b = 'i'; *c = 'g'; break; + case 194: *a = 'f'; *b = 'i'; *c = 'l'; break; + case 195: *a = 'f'; *b = 'a'; *c = 's'; break; + case 196: *a = 'm'; *b = 'i'; *c = 't'; break; + case 197: *a = 'h'; *b = 'o'; *c = 'b'; break; + case 198: *a = 'h'; *b = 'a'; *c = 'r'; break; + case 199: *a = 'm'; *b = 'i'; *c = 'g'; break; + case 200: *a = 'h'; *b = 'i'; *c = 'n'; break; + case 201: *a = 'r'; *b = 'a'; *c = 'd'; break; + case 202: *a = 'm'; *b = 'a'; *c = 's'; break; + case 203: *a = 'h'; *b = 'a'; *c = 'l'; break; + case 204: *a = 'r'; *b = 'a'; *c = 'g'; break; + case 205: *a = 'l'; *b = 'a'; *c = 'g'; break; + case 206: *a = 'f'; *b = 'a'; *c = 'd'; break; + case 207: *a = 't'; *b = 'o'; *c = 'p'; break; + case 208: *a = 'm'; *b = 'o'; *c = 'p'; break; + case 209: *a = 'h'; *b = 'a'; *c = 'b'; break; + case 210: *a = 'n'; *b = 'i'; *c = 'l'; break; + case 211: *a = 'n'; *b = 'o'; *c = 's'; break; + case 212: *a = 'm'; *b = 'i'; *c = 'l'; break; + case 213: *a = 'f'; *b = 'o'; *c = 'p'; break; + case 214: *a = 'f'; *b = 'a'; *c = 'm'; break; + case 215: *a = 'd'; *b = 'a'; *c = 't'; break; + case 216: *a = 'n'; *b = 'o'; *c = 'l'; break; + case 217: *a = 'd'; *b = 'i'; *c = 'n'; break; + case 218: *a = 'h'; *b = 'a'; *c = 't'; break; + case 219: *a = 'n'; *b = 'a'; *c = 'c'; break; + case 220: *a = 'r'; *b = 'i'; *c = 's'; break; + case 221: *a = 'f'; *b = 'o'; *c = 't'; break; + case 222: *a = 'r'; *b = 'i'; *c = 'b'; break; + case 223: *a = 'h'; *b = 'o'; *c = 'c'; break; + case 224: *a = 'n'; *b = 'i'; *c = 'm'; break; + case 225: *a = 'l'; *b = 'a'; *c = 'r'; break; + case 226: *a = 'f'; *b = 'i'; *c = 't'; break; + case 227: *a = 'w'; *b = 'a'; *c = 'l'; break; + case 228: *a = 'r'; *b = 'a'; *c = 'p'; break; + case 229: *a = 's'; *b = 'a'; *c = 'r'; break; + case 230: *a = 'n'; *b = 'a'; *c = 'l'; break; + case 231: *a = 'm'; *b = 'o'; *c = 's'; break; + case 232: *a = 'l'; *b = 'a'; *c = 'n'; break; + case 233: *a = 'd'; *b = 'o'; *c = 'n'; break; + case 234: *a = 'd'; *b = 'a'; *c = 'n'; break; + case 235: *a = 'l'; *b = 'a'; *c = 'd'; break; + case 236: *a = 'd'; *b = 'o'; *c = 'v'; break; + case 237: *a = 'r'; *b = 'i'; *c = 'v'; break; + case 238: *a = 'b'; *b = 'a'; *c = 'c'; break; + case 239: *a = 'p'; *b = 'o'; *c = 'l'; break; + case 240: *a = 'l'; *b = 'a'; *c = 'p'; break; + case 241: *a = 't'; *b = 'a'; *c = 'l'; break; + case 242: *a = 'p'; *b = 'i'; *c = 't'; break; + case 243: *a = 'n'; *b = 'a'; *c = 'm'; break; + case 244: *a = 'b'; *b = 'o'; *c = 'n'; break; + case 245: *a = 'r'; *b = 'o'; *c = 's'; break; + case 246: *a = 't'; *b = 'o'; *c = 'n'; break; + case 247: *a = 'f'; *b = 'o'; *c = 'd'; break; + case 248: *a = 'p'; *b = 'o'; *c = 'n'; break; + case 249: *a = 's'; *b = 'o'; *c = 'v'; break; + case 250: *a = 'n'; *b = 'o'; *c = 'c'; break; + case 251: *a = 's'; *b = 'o'; *c = 'r'; break; + case 252: *a = 'l'; *b = 'a'; *c = 'v'; break; + case 253: *a = 'm'; *b = 'a'; *c = 't'; break; + case 254: *a = 'm'; *b = 'i'; *c = 'p'; break; + case 255: *a = 'f'; *b = 'i'; *c = 'p'; break; + default: u3m_bail(c3__exit); + } +} + +u3_noun +u3_po_find_suffix(c3_y one, c3_y two, c3_y three) { + switch (one) { + case 'b': switch (two) { + case 'e': switch (three) { + case 'c': return u3nc(0, 238); + case 'l': return u3nc(0, 107); + case 'n': return u3nc(0, 92); + case 'p': return u3nc(0, 183); + case 'r': return u3nc(0, 172); + case 's': return u3nc(0, 56); + case 't': return u3nc(0, 106); + case 'x': return u3nc(0, 144); + default: return 0; + } + case 'u': switch (three) { + case 'd': return u3nc(0, 2); + case 'r': return u3nc(0, 60); + case 's': return u3nc(0, 182); + default: return 0; + } + case 'y': switch (three) { + case 'l': return u3nc(0, 176); + case 'n': return u3nc(0, 45); + case 'r': return u3nc(0, 244); + case 't': return u3nc(0, 188); + default: return 0; + } + default: return 0; + } + case 'd': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 171); + case 'c': return u3nc(0, 98); + case 'f': return u3nc(0, 181); + case 'g': return u3nc(0, 117); + case 'l': return u3nc(0, 37); + case 'm': return u3nc(0, 234); + case 'n': return u3nc(0, 66); + case 'p': return u3nc(0, 23); + case 'r': return u3nc(0, 61); + case 's': return u3nc(0, 215); + case 't': return u3nc(0, 105); + case 'v': return u3nc(0, 179); + case 'x': return u3nc(0, 57); + default: return 0; + } + case 'u': switch (three) { + case 'c': return u3nc(0, 193); + case 'l': return u3nc(0, 49); + case 'n': return u3nc(0, 217); + case 'r': return u3nc(0, 11); + case 's': return u3nc(0, 129); + case 't': return u3nc(0, 116); + case 'x': return u3nc(0, 146); + default: return 0; + } + case 'y': switch (three) { + case 'l': return u3nc(0, 102); + case 'n': return u3nc(0, 233); + case 'r': return u3nc(0, 18); + case 's': return u3nc(0, 24); + case 't': return u3nc(0, 187); + default: return 0; + } + default: return 0; + } + case 'f': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 47); + case 'd': return u3nc(0, 236); + case 'l': return u3nc(0, 120); + case 'n': return u3nc(0, 206); + case 'p': return u3nc(0, 152); + case 'r': return u3nc(0, 158); + case 's': return u3nc(0, 255); + case 't': return u3nc(0, 214); + case 'x': return u3nc(0, 195); + default: return 0; + } + case 'u': switch (three) { + case 'l': return u3nc(0, 8); + case 'n': return u3nc(0, 138); + case 'r': return u3nc(0, 194); + case 's': return u3nc(0, 90); + default: return 0; + } + case 'y': switch (three) { + case 'l': return u3nc(0, 169); + case 'n': return u3nc(0, 226); + case 'r': return u3nc(0, 247); + default: return 0; + } + default: return 0; + } + case 'h': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 20); + case 'c': return u3nc(0, 27); + case 'p': return u3nc(0, 91); + case 's': return u3nc(0, 213); + case 't': return u3nc(0, 50); + case 'x': return u3nc(0, 46); + default: return 0; + } + case 'u': switch (three) { + case 'l': return u3nc(0, 221); + case 's': return u3nc(0, 209); + case 't': return u3nc(0, 174); + default: return 0; + } + default: return 0; + } + case 'l': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 145); + case 'c': return u3nc(0, 203); + case 'd': return u3nc(0, 41); + case 'g': return u3nc(0, 156); + case 'n': return u3nc(0, 198); + case 'p': return u3nc(0, 170); + case 'r': return u3nc(0, 218); + case 't': return u3nc(0, 7); + case 'v': return u3nc(0, 190); + case 'x': return u3nc(0, 200); + default: return 0; + } + case 'u': switch (three) { + case 'c': return u3nc(0, 197); + case 'd': return u3nc(0, 223); + case 'g': return u3nc(0, 26); + case 'n': return u3nc(0, 32); + case 'p': return u3nc(0, 22); + case 'r': return u3nc(0, 180); + case 's': return u3nc(0, 161); + case 't': return u3nc(0, 34); + case 'x': return u3nc(0, 235); + default: return 0; + } + case 'y': switch (three) { + case 'd': return u3nc(0, 205); + case 'n': return u3nc(0, 232); + case 'r': return u3nc(0, 240); + case 's': return u3nc(0, 225); + case 't': return u3nc(0, 128); + case 'x': return u3nc(0, 134); + default: return 0; + } + default: return 0; + } + case 'm': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 114); + case 'c': return u3nc(0, 141); + case 'd': return u3nc(0, 127); + case 'g': return u3nc(0, 78); + case 'l': return u3nc(0, 185); + case 'p': return u3nc(0, 33); + case 'r': return u3nc(0, 159); + case 's': return u3nc(0, 104); + case 't': return u3nc(0, 43); + case 'v': return u3nc(0, 51); + case 'x': return u3nc(0, 165); + default: return 0; + } + case 'u': switch (three) { + case 'd': return u3nc(0, 242); + case 'g': return u3nc(0, 173); + case 'l': return u3nc(0, 81); + case 'n': return u3nc(0, 239); + case 'r': return u3nc(0, 248); + case 's': return u3nc(0, 93); + case 't': return u3nc(0, 86); + default: return 0; + } + case 'y': switch (three) { + case 'l': return u3nc(0, 191); + case 'n': return u3nc(0, 103); + case 'r': return u3nc(0, 110); + default: return 0; + } + default: return 0; + } + case 'n': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 130); + case 'c': return u3nc(0, 1); + case 'd': return u3nc(0, 202); + case 'l': return u3nc(0, 253); + case 'm': return u3nc(0, 157); + case 'p': return u3nc(0, 62); + case 'r': return u3nc(0, 199); + case 's': return u3nc(0, 212); + case 't': return u3nc(0, 79); + case 'v': return u3nc(0, 254); + case 'x': return u3nc(0, 31); + default: return 0; + } + case 'u': switch (three) { + case 'b': return u3nc(0, 126); + case 'l': return u3nc(0, 196); + case 'm': return u3nc(0, 148); + case 'p': return u3nc(0, 19); + case 's': return u3nc(0, 162); + case 't': return u3nc(0, 67); + case 'x': return u3nc(0, 122); + default: return 0; + } + case 'y': switch (three) { + case 'd': return u3nc(0, 208); + case 'l': return u3nc(0, 231); + case 'm': return u3nc(0, 82); + case 'r': return u3nc(0, 219); + case 's': return u3nc(0, 230); + case 't': return u3nc(0, 243); + case 'x': return u3nc(0, 87); + default: return 0; + } + default: return 0; + } + case 'p': switch (two) { + case 'e': switch (three) { + case 'c': return u3nc(0, 252); + case 'd': return u3nc(0, 39); + case 'g': return u3nc(0, 21); + case 'l': return u3nc(0, 111); + case 'm': return u3nc(0, 178); + case 'n': return u3nc(0, 9); + case 'r': return u3nc(0, 5); + case 's': return u3nc(0, 36); + case 't': return u3nc(0, 69); + case 'x': return u3nc(0, 186); + default: return 0; + } + case 'u': switch (three) { + case 'b': return u3nc(0, 166); + case 'n': return u3nc(0, 135); + case 'r': return u3nc(0, 63); + case 't': return u3nc(0, 25); + default: return 0; + } + case 'y': switch (three) { + case 'l': return u3nc(0, 48); + case 'x': return u3nc(0, 149); + default: return 0; + } + default: return 0; + } + case 'r': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 65); + case 'c': return u3nc(0, 77); + case 'd': return u3nc(0, 137); + case 'f': return u3nc(0, 140); + case 'g': return u3nc(0, 72); + case 'l': return u3nc(0, 210); + case 'm': return u3nc(0, 224); + case 'n': return u3nc(0, 124); + case 'p': return u3nc(0, 250); + case 's': return u3nc(0, 136); + case 't': return u3nc(0, 216); + case 'v': return u3nc(0, 139); + case 'x': return u3nc(0, 88); + default: return 0; + } + case 'u': switch (three) { + case 'c': return u3nc(0, 97); + case 'd': return u3nc(0, 211); + case 'l': return u3nc(0, 70); + case 'm': return u3nc(0, 131); + case 'n': return u3nc(0, 184); + case 'p': return u3nc(0, 201); + case 's': return u3nc(0, 143); + case 't': return u3nc(0, 52); + case 'x': return u3nc(0, 123); + default: return 0; + } + case 'y': switch (three) { + case 'c': return u3nc(0, 228); + case 'd': return u3nc(0, 204); + case 'g': return u3nc(0, 150); + case 'l': return u3nc(0, 222); + case 'm': return u3nc(0, 167); + case 'n': return u3nc(0, 147); + case 'p': return u3nc(0, 16); + case 's': return u3nc(0, 64); + case 't': return u3nc(0, 28); + case 'x': return u3nc(0, 151); + default: return 0; + } + default: return 0; + } + case 's': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 220); + case 'c': return u3nc(0, 80); + case 'd': return u3nc(0, 237); + case 'f': return u3nc(0, 58); + case 'g': return u3nc(0, 133); + case 'l': return u3nc(0, 96); + case 'm': return u3nc(0, 75); + case 'n': return u3nc(0, 245); + case 'p': return u3nc(0, 35); + case 'r': return u3nc(0, 13); + case 't': return u3nc(0, 115); + case 'v': return u3nc(0, 4); + default: return 0; + } + case 'u': switch (three) { + case 'b': return u3nc(0, 68); + case 'd': return u3nc(0, 177); + case 'g': return u3nc(0, 229); + case 'l': return u3nc(0, 38); + case 'm': return u3nc(0, 85); + case 'n': return u3nc(0, 15); + case 'p': return u3nc(0, 74); + case 'r': return u3nc(0, 119); + case 't': return u3nc(0, 6); + default: return 0; + } + case 'y': switch (three) { + case 'd': return u3nc(0, 30); + case 'l': return u3nc(0, 163); + case 'm': return u3nc(0, 95); + case 'n': return u3nc(0, 71); + case 'p': return u3nc(0, 112); + case 'r': return u3nc(0, 100); + case 't': return u3nc(0, 10); + case 'x': return u3nc(0, 17); + default: return 0; + } + default: return 0; + } + case 't': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 89); + case 'c': return u3nc(0, 164); + case 'd': return u3nc(0, 142); + case 'g': return u3nc(0, 251); + case 'l': return u3nc(0, 249); + case 'm': return u3nc(0, 40); + case 'n': return u3nc(0, 160); + case 'p': return u3nc(0, 55); + case 'r': return u3nc(0, 113); + case 's': return u3nc(0, 241); + case 'v': return u3nc(0, 83); + case 'x': return u3nc(0, 118); + default: return 0; + } + case 'u': switch (three) { + case 'c': return u3nc(0, 168); + case 'd': return u3nc(0, 121); + case 'g': return u3nc(0, 109); + case 'l': return u3nc(0, 42); + case 'n': return u3nc(0, 175); + case 's': return u3nc(0, 154); + case 'x': return u3nc(0, 108); + default: return 0; + } + case 'y': switch (three) { + case 'c': return u3nc(0, 155); + case 'd': return u3nc(0, 73); + case 'l': return u3nc(0, 53); + case 'n': return u3nc(0, 132); + case 'p': return u3nc(0, 189); + case 'r': return u3nc(0, 153); + case 'v': return u3nc(0, 29); + default: return 0; + } + default: return 0; + } + case 'w': switch (two) { + case 'e': switch (three) { + case 'b': return u3nc(0, 84); + case 'd': return u3nc(0, 192); + case 'g': return u3nc(0, 246); + case 'l': return u3nc(0, 207); + case 'n': return u3nc(0, 44); + case 'p': return u3nc(0, 12); + case 'r': return u3nc(0, 227); + case 's': return u3nc(0, 3); + case 't': return u3nc(0, 101); + case 'x': return u3nc(0, 99); + default: return 0; + } + case 'y': switch (three) { + case 'c': return u3nc(0, 59); + case 'd': return u3nc(0, 54); + case 'l': return u3nc(0, 14); + case 'n': return u3nc(0, 76); + case 't': return u3nc(0, 125); + case 'x': return u3nc(0, 94); + default: return 0; + } + default: return 0; + } + case 'z': switch (two) { + case 'o': switch (three) { + case 'd': return u3nc(0, 0); + default: return 0; + } + default: return 0; + } + default: return 0; + } +} + +void +u3_po_to_suffix(u3_noun id, c3_y* a, c3_y* b, c3_y* c) +{ + switch (id) { + case 0: *a = 'z'; *b = 'o'; *c = 'd'; break; + case 1: *a = 'n'; *b = 'e'; *c = 'c'; break; + case 2: *a = 'b'; *b = 'u'; *c = 'd'; break; + case 3: *a = 'w'; *b = 'e'; *c = 's'; break; + case 4: *a = 's'; *b = 'e'; *c = 'v'; break; + case 5: *a = 'p'; *b = 'e'; *c = 'r'; break; + case 6: *a = 's'; *b = 'u'; *c = 't'; break; + case 7: *a = 'l'; *b = 'e'; *c = 't'; break; + case 8: *a = 'f'; *b = 'u'; *c = 'l'; break; + case 9: *a = 'p'; *b = 'e'; *c = 'n'; break; + case 10: *a = 's'; *b = 'y'; *c = 't'; break; + case 11: *a = 'd'; *b = 'u'; *c = 'r'; break; + case 12: *a = 'w'; *b = 'e'; *c = 'p'; break; + case 13: *a = 's'; *b = 'e'; *c = 'r'; break; + case 14: *a = 'w'; *b = 'y'; *c = 'l'; break; + case 15: *a = 's'; *b = 'u'; *c = 'n'; break; + case 16: *a = 'r'; *b = 'y'; *c = 'p'; break; + case 17: *a = 's'; *b = 'y'; *c = 'x'; break; + case 18: *a = 'd'; *b = 'y'; *c = 'r'; break; + case 19: *a = 'n'; *b = 'u'; *c = 'p'; break; + case 20: *a = 'h'; *b = 'e'; *c = 'b'; break; + case 21: *a = 'p'; *b = 'e'; *c = 'g'; break; + case 22: *a = 'l'; *b = 'u'; *c = 'p'; break; + case 23: *a = 'd'; *b = 'e'; *c = 'p'; break; + case 24: *a = 'd'; *b = 'y'; *c = 's'; break; + case 25: *a = 'p'; *b = 'u'; *c = 't'; break; + case 26: *a = 'l'; *b = 'u'; *c = 'g'; break; + case 27: *a = 'h'; *b = 'e'; *c = 'c'; break; + case 28: *a = 'r'; *b = 'y'; *c = 't'; break; + case 29: *a = 't'; *b = 'y'; *c = 'v'; break; + case 30: *a = 's'; *b = 'y'; *c = 'd'; break; + case 31: *a = 'n'; *b = 'e'; *c = 'x'; break; + case 32: *a = 'l'; *b = 'u'; *c = 'n'; break; + case 33: *a = 'm'; *b = 'e'; *c = 'p'; break; + case 34: *a = 'l'; *b = 'u'; *c = 't'; break; + case 35: *a = 's'; *b = 'e'; *c = 'p'; break; + case 36: *a = 'p'; *b = 'e'; *c = 's'; break; + case 37: *a = 'd'; *b = 'e'; *c = 'l'; break; + case 38: *a = 's'; *b = 'u'; *c = 'l'; break; + case 39: *a = 'p'; *b = 'e'; *c = 'd'; break; + case 40: *a = 't'; *b = 'e'; *c = 'm'; break; + case 41: *a = 'l'; *b = 'e'; *c = 'd'; break; + case 42: *a = 't'; *b = 'u'; *c = 'l'; break; + case 43: *a = 'm'; *b = 'e'; *c = 't'; break; + case 44: *a = 'w'; *b = 'e'; *c = 'n'; break; + case 45: *a = 'b'; *b = 'y'; *c = 'n'; break; + case 46: *a = 'h'; *b = 'e'; *c = 'x'; break; + case 47: *a = 'f'; *b = 'e'; *c = 'b'; break; + case 48: *a = 'p'; *b = 'y'; *c = 'l'; break; + case 49: *a = 'd'; *b = 'u'; *c = 'l'; break; + case 50: *a = 'h'; *b = 'e'; *c = 't'; break; + case 51: *a = 'm'; *b = 'e'; *c = 'v'; break; + case 52: *a = 'r'; *b = 'u'; *c = 't'; break; + case 53: *a = 't'; *b = 'y'; *c = 'l'; break; + case 54: *a = 'w'; *b = 'y'; *c = 'd'; break; + case 55: *a = 't'; *b = 'e'; *c = 'p'; break; + case 56: *a = 'b'; *b = 'e'; *c = 's'; break; + case 57: *a = 'd'; *b = 'e'; *c = 'x'; break; + case 58: *a = 's'; *b = 'e'; *c = 'f'; break; + case 59: *a = 'w'; *b = 'y'; *c = 'c'; break; + case 60: *a = 'b'; *b = 'u'; *c = 'r'; break; + case 61: *a = 'd'; *b = 'e'; *c = 'r'; break; + case 62: *a = 'n'; *b = 'e'; *c = 'p'; break; + case 63: *a = 'p'; *b = 'u'; *c = 'r'; break; + case 64: *a = 'r'; *b = 'y'; *c = 's'; break; + case 65: *a = 'r'; *b = 'e'; *c = 'b'; break; + case 66: *a = 'd'; *b = 'e'; *c = 'n'; break; + case 67: *a = 'n'; *b = 'u'; *c = 't'; break; + case 68: *a = 's'; *b = 'u'; *c = 'b'; break; + case 69: *a = 'p'; *b = 'e'; *c = 't'; break; + case 70: *a = 'r'; *b = 'u'; *c = 'l'; break; + case 71: *a = 's'; *b = 'y'; *c = 'n'; break; + case 72: *a = 'r'; *b = 'e'; *c = 'g'; break; + case 73: *a = 't'; *b = 'y'; *c = 'd'; break; + case 74: *a = 's'; *b = 'u'; *c = 'p'; break; + case 75: *a = 's'; *b = 'e'; *c = 'm'; break; + case 76: *a = 'w'; *b = 'y'; *c = 'n'; break; + case 77: *a = 'r'; *b = 'e'; *c = 'c'; break; + case 78: *a = 'm'; *b = 'e'; *c = 'g'; break; + case 79: *a = 'n'; *b = 'e'; *c = 't'; break; + case 80: *a = 's'; *b = 'e'; *c = 'c'; break; + case 81: *a = 'm'; *b = 'u'; *c = 'l'; break; + case 82: *a = 'n'; *b = 'y'; *c = 'm'; break; + case 83: *a = 't'; *b = 'e'; *c = 'v'; break; + case 84: *a = 'w'; *b = 'e'; *c = 'b'; break; + case 85: *a = 's'; *b = 'u'; *c = 'm'; break; + case 86: *a = 'm'; *b = 'u'; *c = 't'; break; + case 87: *a = 'n'; *b = 'y'; *c = 'x'; break; + case 88: *a = 'r'; *b = 'e'; *c = 'x'; break; + case 89: *a = 't'; *b = 'e'; *c = 'b'; break; + case 90: *a = 'f'; *b = 'u'; *c = 's'; break; + case 91: *a = 'h'; *b = 'e'; *c = 'p'; break; + case 92: *a = 'b'; *b = 'e'; *c = 'n'; break; + case 93: *a = 'm'; *b = 'u'; *c = 's'; break; + case 94: *a = 'w'; *b = 'y'; *c = 'x'; break; + case 95: *a = 's'; *b = 'y'; *c = 'm'; break; + case 96: *a = 's'; *b = 'e'; *c = 'l'; break; + case 97: *a = 'r'; *b = 'u'; *c = 'c'; break; + case 98: *a = 'd'; *b = 'e'; *c = 'c'; break; + case 99: *a = 'w'; *b = 'e'; *c = 'x'; break; + case 100: *a = 's'; *b = 'y'; *c = 'r'; break; + case 101: *a = 'w'; *b = 'e'; *c = 't'; break; + case 102: *a = 'd'; *b = 'y'; *c = 'l'; break; + case 103: *a = 'm'; *b = 'y'; *c = 'n'; break; + case 104: *a = 'm'; *b = 'e'; *c = 's'; break; + case 105: *a = 'd'; *b = 'e'; *c = 't'; break; + case 106: *a = 'b'; *b = 'e'; *c = 't'; break; + case 107: *a = 'b'; *b = 'e'; *c = 'l'; break; + case 108: *a = 't'; *b = 'u'; *c = 'x'; break; + case 109: *a = 't'; *b = 'u'; *c = 'g'; break; + case 110: *a = 'm'; *b = 'y'; *c = 'r'; break; + case 111: *a = 'p'; *b = 'e'; *c = 'l'; break; + case 112: *a = 's'; *b = 'y'; *c = 'p'; break; + case 113: *a = 't'; *b = 'e'; *c = 'r'; break; + case 114: *a = 'm'; *b = 'e'; *c = 'b'; break; + case 115: *a = 's'; *b = 'e'; *c = 't'; break; + case 116: *a = 'd'; *b = 'u'; *c = 't'; break; + case 117: *a = 'd'; *b = 'e'; *c = 'g'; break; + case 118: *a = 't'; *b = 'e'; *c = 'x'; break; + case 119: *a = 's'; *b = 'u'; *c = 'r'; break; + case 120: *a = 'f'; *b = 'e'; *c = 'l'; break; + case 121: *a = 't'; *b = 'u'; *c = 'd'; break; + case 122: *a = 'n'; *b = 'u'; *c = 'x'; break; + case 123: *a = 'r'; *b = 'u'; *c = 'x'; break; + case 124: *a = 'r'; *b = 'e'; *c = 'n'; break; + case 125: *a = 'w'; *b = 'y'; *c = 't'; break; + case 126: *a = 'n'; *b = 'u'; *c = 'b'; break; + case 127: *a = 'm'; *b = 'e'; *c = 'd'; break; + case 128: *a = 'l'; *b = 'y'; *c = 't'; break; + case 129: *a = 'd'; *b = 'u'; *c = 's'; break; + case 130: *a = 'n'; *b = 'e'; *c = 'b'; break; + case 131: *a = 'r'; *b = 'u'; *c = 'm'; break; + case 132: *a = 't'; *b = 'y'; *c = 'n'; break; + case 133: *a = 's'; *b = 'e'; *c = 'g'; break; + case 134: *a = 'l'; *b = 'y'; *c = 'x'; break; + case 135: *a = 'p'; *b = 'u'; *c = 'n'; break; + case 136: *a = 'r'; *b = 'e'; *c = 's'; break; + case 137: *a = 'r'; *b = 'e'; *c = 'd'; break; + case 138: *a = 'f'; *b = 'u'; *c = 'n'; break; + case 139: *a = 'r'; *b = 'e'; *c = 'v'; break; + case 140: *a = 'r'; *b = 'e'; *c = 'f'; break; + case 141: *a = 'm'; *b = 'e'; *c = 'c'; break; + case 142: *a = 't'; *b = 'e'; *c = 'd'; break; + case 143: *a = 'r'; *b = 'u'; *c = 's'; break; + case 144: *a = 'b'; *b = 'e'; *c = 'x'; break; + case 145: *a = 'l'; *b = 'e'; *c = 'b'; break; + case 146: *a = 'd'; *b = 'u'; *c = 'x'; break; + case 147: *a = 'r'; *b = 'y'; *c = 'n'; break; + case 148: *a = 'n'; *b = 'u'; *c = 'm'; break; + case 149: *a = 'p'; *b = 'y'; *c = 'x'; break; + case 150: *a = 'r'; *b = 'y'; *c = 'g'; break; + case 151: *a = 'r'; *b = 'y'; *c = 'x'; break; + case 152: *a = 'f'; *b = 'e'; *c = 'p'; break; + case 153: *a = 't'; *b = 'y'; *c = 'r'; break; + case 154: *a = 't'; *b = 'u'; *c = 's'; break; + case 155: *a = 't'; *b = 'y'; *c = 'c'; break; + case 156: *a = 'l'; *b = 'e'; *c = 'g'; break; + case 157: *a = 'n'; *b = 'e'; *c = 'm'; break; + case 158: *a = 'f'; *b = 'e'; *c = 'r'; break; + case 159: *a = 'm'; *b = 'e'; *c = 'r'; break; + case 160: *a = 't'; *b = 'e'; *c = 'n'; break; + case 161: *a = 'l'; *b = 'u'; *c = 's'; break; + case 162: *a = 'n'; *b = 'u'; *c = 's'; break; + case 163: *a = 's'; *b = 'y'; *c = 'l'; break; + case 164: *a = 't'; *b = 'e'; *c = 'c'; break; + case 165: *a = 'm'; *b = 'e'; *c = 'x'; break; + case 166: *a = 'p'; *b = 'u'; *c = 'b'; break; + case 167: *a = 'r'; *b = 'y'; *c = 'm'; break; + case 168: *a = 't'; *b = 'u'; *c = 'c'; break; + case 169: *a = 'f'; *b = 'y'; *c = 'l'; break; + case 170: *a = 'l'; *b = 'e'; *c = 'p'; break; + case 171: *a = 'd'; *b = 'e'; *c = 'b'; break; + case 172: *a = 'b'; *b = 'e'; *c = 'r'; break; + case 173: *a = 'm'; *b = 'u'; *c = 'g'; break; + case 174: *a = 'h'; *b = 'u'; *c = 't'; break; + case 175: *a = 't'; *b = 'u'; *c = 'n'; break; + case 176: *a = 'b'; *b = 'y'; *c = 'l'; break; + case 177: *a = 's'; *b = 'u'; *c = 'd'; break; + case 178: *a = 'p'; *b = 'e'; *c = 'm'; break; + case 179: *a = 'd'; *b = 'e'; *c = 'v'; break; + case 180: *a = 'l'; *b = 'u'; *c = 'r'; break; + case 181: *a = 'd'; *b = 'e'; *c = 'f'; break; + case 182: *a = 'b'; *b = 'u'; *c = 's'; break; + case 183: *a = 'b'; *b = 'e'; *c = 'p'; break; + case 184: *a = 'r'; *b = 'u'; *c = 'n'; break; + case 185: *a = 'm'; *b = 'e'; *c = 'l'; break; + case 186: *a = 'p'; *b = 'e'; *c = 'x'; break; + case 187: *a = 'd'; *b = 'y'; *c = 't'; break; + case 188: *a = 'b'; *b = 'y'; *c = 't'; break; + case 189: *a = 't'; *b = 'y'; *c = 'p'; break; + case 190: *a = 'l'; *b = 'e'; *c = 'v'; break; + case 191: *a = 'm'; *b = 'y'; *c = 'l'; break; + case 192: *a = 'w'; *b = 'e'; *c = 'd'; break; + case 193: *a = 'd'; *b = 'u'; *c = 'c'; break; + case 194: *a = 'f'; *b = 'u'; *c = 'r'; break; + case 195: *a = 'f'; *b = 'e'; *c = 'x'; break; + case 196: *a = 'n'; *b = 'u'; *c = 'l'; break; + case 197: *a = 'l'; *b = 'u'; *c = 'c'; break; + case 198: *a = 'l'; *b = 'e'; *c = 'n'; break; + case 199: *a = 'n'; *b = 'e'; *c = 'r'; break; + case 200: *a = 'l'; *b = 'e'; *c = 'x'; break; + case 201: *a = 'r'; *b = 'u'; *c = 'p'; break; + case 202: *a = 'n'; *b = 'e'; *c = 'd'; break; + case 203: *a = 'l'; *b = 'e'; *c = 'c'; break; + case 204: *a = 'r'; *b = 'y'; *c = 'd'; break; + case 205: *a = 'l'; *b = 'y'; *c = 'd'; break; + case 206: *a = 'f'; *b = 'e'; *c = 'n'; break; + case 207: *a = 'w'; *b = 'e'; *c = 'l'; break; + case 208: *a = 'n'; *b = 'y'; *c = 'd'; break; + case 209: *a = 'h'; *b = 'u'; *c = 's'; break; + case 210: *a = 'r'; *b = 'e'; *c = 'l'; break; + case 211: *a = 'r'; *b = 'u'; *c = 'd'; break; + case 212: *a = 'n'; *b = 'e'; *c = 's'; break; + case 213: *a = 'h'; *b = 'e'; *c = 's'; break; + case 214: *a = 'f'; *b = 'e'; *c = 't'; break; + case 215: *a = 'd'; *b = 'e'; *c = 's'; break; + case 216: *a = 'r'; *b = 'e'; *c = 't'; break; + case 217: *a = 'd'; *b = 'u'; *c = 'n'; break; + case 218: *a = 'l'; *b = 'e'; *c = 'r'; break; + case 219: *a = 'n'; *b = 'y'; *c = 'r'; break; + case 220: *a = 's'; *b = 'e'; *c = 'b'; break; + case 221: *a = 'h'; *b = 'u'; *c = 'l'; break; + case 222: *a = 'r'; *b = 'y'; *c = 'l'; break; + case 223: *a = 'l'; *b = 'u'; *c = 'd'; break; + case 224: *a = 'r'; *b = 'e'; *c = 'm'; break; + case 225: *a = 'l'; *b = 'y'; *c = 's'; break; + case 226: *a = 'f'; *b = 'y'; *c = 'n'; break; + case 227: *a = 'w'; *b = 'e'; *c = 'r'; break; + case 228: *a = 'r'; *b = 'y'; *c = 'c'; break; + case 229: *a = 's'; *b = 'u'; *c = 'g'; break; + case 230: *a = 'n'; *b = 'y'; *c = 's'; break; + case 231: *a = 'n'; *b = 'y'; *c = 'l'; break; + case 232: *a = 'l'; *b = 'y'; *c = 'n'; break; + case 233: *a = 'd'; *b = 'y'; *c = 'n'; break; + case 234: *a = 'd'; *b = 'e'; *c = 'm'; break; + case 235: *a = 'l'; *b = 'u'; *c = 'x'; break; + case 236: *a = 'f'; *b = 'e'; *c = 'd'; break; + case 237: *a = 's'; *b = 'e'; *c = 'd'; break; + case 238: *a = 'b'; *b = 'e'; *c = 'c'; break; + case 239: *a = 'm'; *b = 'u'; *c = 'n'; break; + case 240: *a = 'l'; *b = 'y'; *c = 'r'; break; + case 241: *a = 't'; *b = 'e'; *c = 's'; break; + case 242: *a = 'm'; *b = 'u'; *c = 'd'; break; + case 243: *a = 'n'; *b = 'y'; *c = 't'; break; + case 244: *a = 'b'; *b = 'y'; *c = 'r'; break; + case 245: *a = 's'; *b = 'e'; *c = 'n'; break; + case 246: *a = 'w'; *b = 'e'; *c = 'g'; break; + case 247: *a = 'f'; *b = 'y'; *c = 'r'; break; + case 248: *a = 'm'; *b = 'u'; *c = 'r'; break; + case 249: *a = 't'; *b = 'e'; *c = 'l'; break; + case 250: *a = 'r'; *b = 'e'; *c = 'p'; break; + case 251: *a = 't'; *b = 'e'; *c = 'g'; break; + case 252: *a = 'p'; *b = 'e'; *c = 'c'; break; + case 253: *a = 'n'; *b = 'e'; *c = 'l'; break; + case 254: *a = 'n'; *b = 'e'; *c = 'v'; break; + case 255: *a = 'f'; *b = 'e'; *c = 's'; break; + default: u3m_bail(c3__exit); + } +} + +u3_noun +u3qc_po_ins(u3_noun a) +{ + c3_y byt_y[3]; + u3r_bytes(0, 3, byt_y, a); + + return u3_po_find_prefix(byt_y[0], byt_y[1], byt_y[2]); +} + +u3_noun +u3wcp_ins(u3_noun cor) +{ + u3_noun a; + u3x_mean(cor, u3x_sam, &a, 0); + + if ( c3n == u3ud(a) ) { + return u3m_bail(c3__fail); + } + + return u3qc_po_ins(a); +} + +u3_noun +u3qc_po_ind(u3_noun a) +{ + c3_y byt_y[3]; + u3r_bytes(0, 3, byt_y, a); + + return u3_po_find_suffix(byt_y[0], byt_y[1], byt_y[2]); +} + +u3_noun +u3wcp_ind(u3_noun cor) +{ + u3_noun a; + u3x_mean(cor, u3x_sam, &a, 0); + + if ( c3n == u3ud(a) ) { + return u3m_bail(c3__fail); + } + + return u3qc_po_ind(a); +} + +u3_noun +u3wcp_tos(u3_noun cor) +{ + u3_noun a; + + if ( (c3n == u3r_mean(cor, u3x_sam, &a, 0)) || + (c3n == u3ud(a)) || + (a >= 256) ) + { + return u3m_bail(c3__exit); + } + else { + c3_y byt_y[3]; + u3_po_to_prefix(a, &byt_y[0], &byt_y[1], &byt_y[2]); + return (byt_y[0] | (byt_y[1] << 8) | (byt_y[2] << 16)); + } +} + +u3_noun +u3wcp_tod(u3_noun cor) +{ + u3_noun a; + + if ( (c3n == u3r_mean(cor, u3x_sam, &a, 0)) || + (c3n == u3ud(a)) || + (a >= 256) ) + { + return u3m_bail(c3__exit); + } else { + c3_y byt_y[3]; + u3_po_to_suffix(a, &byt_y[0], &byt_y[1], &byt_y[2]); + return (byt_y[0] | (byt_y[1] << 8) | (byt_y[2] << 16)); + } +} diff --git a/vere/pkg/noun/jets/c/pow.c b/vere/pkg/noun/jets/c/pow.c new file mode 100644 index 0000000..8d45fc8 --- /dev/null +++ b/vere/pkg/noun/jets/c/pow.c @@ -0,0 +1,38 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_pow(u3_atom a, + u3_atom b) + { + if ( !_(u3a_is_cat(b)) ) { + return u3m_bail(c3__fail); + } + else { + mpz_t a_mp; + + u3r_mp(a_mp, a); + mpz_pow_ui(a_mp, a_mp, b); + + return u3i_mp(a_mp); + } + } + u3_noun + u3wc_pow(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_pow(a, b); + } + } + diff --git a/vere/pkg/noun/jets/c/rap.c b/vere/pkg/noun/jets/c/rap.c new file mode 100644 index 0000000..4c95693 --- /dev/null +++ b/vere/pkg/noun/jets/c/rap.c @@ -0,0 +1,88 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_rap(u3_atom a, + u3_noun b) + { + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + else { + c3_g a_g = a; + c3_w tot_w = 0; + u3i_slab sab_u; + + /* Measure and validate the slab required. + */ + { + u3_noun cab = b; + + while ( 1 ) { + u3_noun h_cab; + c3_w len_w; + + if ( 0 == cab ) { + break; + } + else if ( c3n == u3du(cab) ) { + return u3m_bail(c3__exit); + } + else if ( c3n == u3ud(h_cab = u3h(cab)) ) { + return u3m_bail(c3__exit); + } + else if ( (tot_w + (len_w = u3r_met(a_g, h_cab))) < tot_w ) { + return u3m_bail(c3__fail); + } + tot_w += len_w; + cab = u3t(cab); + } + + if ( 0 == tot_w ) { + return 0; + } + + u3i_slab_init(&sab_u, a_g, tot_w); + } + + /* Chop the list atoms in. + */ + { + u3_noun cab = b; + c3_w pos_w = 0; + + while ( 0 != cab ) { + u3_noun h_cab = u3h(cab); + c3_w len_w = u3r_met(a_g, h_cab); + + u3r_chop(a_g, 0, len_w, pos_w, sab_u.buf_w, h_cab); + pos_w += len_w; + cab = u3t(cab); + } + } + + return u3i_slab_mint(&sab_u); + } + } + u3_noun + u3wc_rap(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun pro; + + pro = u3qc_rap(a, b); + return pro; + } + } + diff --git a/vere/pkg/noun/jets/c/rep.c b/vere/pkg/noun/jets/c/rep.c new file mode 100644 index 0000000..914e917 --- /dev/null +++ b/vere/pkg/noun/jets/c/rep.c @@ -0,0 +1,199 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* + Get the lowest `n` bits of a word `w` using a bitmask. +*/ +#define TAKEBITS(n,w) \ + ((n)==32) ? (w) : \ + ((n)==0) ? 0 : \ + ((w) & ((1 << (n)) - 1)) + +/* + Divide, rounding up. +*/ +#define DIVCEIL(x,y) \ + (x==0) ? 0 : \ + 1 + ((x - 1) / y); + +static u3_noun +_bit_rep(u3_atom bits, u3_noun blox) +{ + if ( (c3n == u3a_is_cat(bits) || bits==0 || bits>31) ) { + return u3m_bail(c3__fail); + } + + // + // Calculate input and output size. + // + c3_w num_blox_w = u3qb_lent(blox); + c3_w bit_widt_w = num_blox_w * bits; + c3_w wor_widt_w = DIVCEIL(bit_widt_w, 32); + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 5, wor_widt_w); + + // + // Fill the atom buffer with bits from each block. + // + // Bits are pushed into the `acc_w` register and flushed to the buffer + // once full. + // + // acc_w register + // use_w number of register bits filled (used) + // cur_w next buffer word to flush into. + // + { + c3_w acc_w=0, use_w=0, *cur_w=sab_u.buf_w; + +# define FLUSH() *cur_w++=acc_w; acc_w=use_w=0 +# define SLICE(sz,off,val) TAKEBITS(sz, val) << off + + for (c3_w i=0; i<num_blox_w; i++) { + u3_noun blok_n = u3h(blox); + blox = u3t(blox); + + if ( c3n == u3a_is_cat(blok_n) ) { + return u3m_bail(c3__fail); + } + + c3_w blok_w = blok_n; + + for (c3_w rem_in_blok_w=bits; rem_in_blok_w;) { + c3_w rem_in_acc_w = 32 - use_w; + if (rem_in_blok_w == rem_in_acc_w) { // EQ + acc_w |= SLICE(rem_in_blok_w, use_w, blok_w); + FLUSH(); + rem_in_blok_w = 0; + } + else if (rem_in_blok_w < rem_in_acc_w) { // LT + acc_w |= SLICE(rem_in_blok_w, use_w, blok_w); + use_w += rem_in_blok_w; + rem_in_blok_w = 0; + } + else { // GT + acc_w |= SLICE(rem_in_acc_w, use_w, blok_w); + rem_in_blok_w -= rem_in_acc_w; + blok_w = blok_w >> rem_in_acc_w; + FLUSH(); + } + } + } + + // + // If the last word isn't fully used, it will still need to be + // flushed. + // + if (use_w) { + FLUSH(); + } + } + + return u3i_slab_mint(&sab_u); +} + +static u3_noun +_block_rep(u3_atom a, + u3_noun b) +{ + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + else { + c3_g a_g = a; + c3_w tot_w = 0; + u3i_slab sab_u; + + /* Measure and validate the slab required. + */ + { + u3_noun cab = b; + + while ( 1 ) { + u3_noun h_cab; + c3_w len_w; + + if ( 0 == cab ) { + break; + } + else if ( c3n == u3du(cab) ) { + return u3m_bail(c3__exit); + } + else if ( c3n == u3ud(h_cab = u3h(cab)) ) { + return u3m_bail(c3__exit); + } + else if ( (tot_w + (len_w = u3r_met(a_g, h_cab))) < tot_w ) { + return u3m_bail(c3__fail); + } + tot_w++; + cab = u3t(cab); + } + + if ( 0 == tot_w ) { + return 0; + } + + u3i_slab_init(&sab_u, a_g, tot_w); + } + + /* Chop the list atoms in. + */ + { + u3_noun cab = b; + c3_w pos_w = 0; + + while ( 0 != cab ) { + u3_noun h_cab = u3h(cab); + + u3r_chop(a_g, 0, 1, pos_w, sab_u.buf_w, h_cab); + pos_w++; + cab = u3t(cab); + } + } + + return u3i_slab_mint(&sab_u); + } +} + +u3_noun +u3qc_rep(u3_atom a, + u3_atom b, + u3_noun c) +{ + if ( 1 == b ) { + return _block_rep(a, c); + } + + if ( 0 == a ) { + return _bit_rep(b, c); + } + + u3l_log("rep: stub"); + return u3_none; +} + +u3_noun +u3wc_rep(u3_noun cor) +{ + u3_atom bloq, step; + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, + u3x_sam_3, &b, 0); + u3x_bite(a, &bloq, &step); + + return u3qc_rep(bloq, step, b); +} + +u3_noun +u3kc_rep(u3_atom a, + u3_atom b, + u3_noun c) +{ + u3_noun res = u3qc_rep(a, b, c); + u3z(a); u3z(b); u3z(c); + return res; +} diff --git a/vere/pkg/noun/jets/c/rev.c b/vere/pkg/noun/jets/c/rev.c new file mode 100644 index 0000000..1ce74c0 --- /dev/null +++ b/vere/pkg/noun/jets/c/rev.c @@ -0,0 +1,51 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_rev(u3_atom boz, + u3_atom len, + u3_atom dat) + { + if ( !_(u3a_is_cat(boz)) || (boz >= 32) || + !_(u3a_is_cat(len)) ) { + return u3m_bail(c3__fail); + } + + dat = u3qc_end(boz, len, dat); + c3_w met = u3r_met(boz, dat); + return u3kc_lsh(boz, (len - met), u3kc_swp(boz, dat)); + } + + u3_noun + u3wc_rev(u3_noun cor) + { + u3_noun boz, len, dat; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &boz, + u3x_sam_6, &len, + u3x_sam_7, &dat, 0)) || + (c3n == u3ud(boz)) || + (c3n == u3ud(len)) || + (c3n == u3ud(dat)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_rev(boz, len, dat); + } + } + + u3_noun + u3kc_rev(u3_atom boz, + u3_atom len, + u3_atom dat) + { + u3_noun res = u3qc_rev(boz, len, dat); + u3z(boz); u3z(len); u3z(dat); + return res; + } diff --git a/vere/pkg/noun/jets/c/rig.c b/vere/pkg/noun/jets/c/rig.c new file mode 100644 index 0000000..7e5e7b9 --- /dev/null +++ b/vere/pkg/noun/jets/c/rig.c @@ -0,0 +1,82 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +c3_d +u3qc_rig_s(c3_g foq_g, + c3_w sep_w, + c3_g toq_g) +{ + c3_d sep_d = sep_w; + + if ( foq_g >= toq_g ) { + return sep_d << (foq_g - toq_g); + } + else { + c3_g dif_g = toq_g - foq_g; + + sep_d += (1 << dif_g) - 1; + return sep_d >> dif_g; + } +} + +u3_noun +u3qc_rig(u3_atom foq, + u3_atom sep, + u3_atom toq) +{ + if ( c3y == u3r_sing(foq, toq) ) { + return u3k(sep); + } + + if ( (c3y == u3a_is_cat(foq)) && (foq < 32) + && (c3y == u3a_is_cat(toq)) && (toq < 32) + && (c3y == u3a_is_cat(sep)) ) + { + c3_d sep_d = u3qc_rig_s((c3_g)foq, (c3_w)sep, (c3_g)toq); + return u3i_chub(sep_d); + } + + if ( c3y == u3qa_gth(foq, toq) ) { + u3_atom d = u3qa_sub(foq, toq); + u3_atom e = u3qc_lsh(0, d, sep); + u3z(d); + return e; + } + else { + u3_atom d = u3qa_sub(toq, foq); + u3_atom e = u3qc_rsh(0, d, sep); + u3_atom f = u3qc_end(0, d, sep); + + if ( f ) { + e = u3i_vint(e); + u3z(f); + } + + u3z(d); + return e; + } +} + +u3_noun +u3wc_rig(u3_noun cor) +{ + u3_atom boq, sep, vat; + { + u3_noun sam = u3h(u3t(cor)); + u3_noun bit = u3h(sam); + + if ( c3y == u3a_is_atom(bit) ) { + return 0; + } + + boq = u3x_atom(u3h(bit)); + sep = u3x_atom(u3t(bit)); + vat = u3x_atom(u3t(sam)); + } + + return u3qc_rig(boq, sep, vat); +} diff --git a/vere/pkg/noun/jets/c/rip.c b/vere/pkg/noun/jets/c/rip.c new file mode 100644 index 0000000..bff23b8 --- /dev/null +++ b/vere/pkg/noun/jets/c/rip.c @@ -0,0 +1,192 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* + Get the lowest `n` bits of a word `w` using a bitmask. +*/ +#define TAKEBITS(n,w) \ + ((n)==32) ? (w) : \ + ((n)==0) ? 0 : \ + ((w) & ((1 << (n)) - 1)) + +/* + Divide, rounding up. +*/ +#define DIVCEIL(x,y) \ + (x==0) ? 0 : \ + 1 + ((x - 1) / y); + +/* + `ripn` breaks `atom` into a list of blocks, of bit-width `bits`. The + resulting list will be least-significant block first. + + XX TODO This only handles cases where the bit-width is <= 32. + + For each block we produce, we need to grab the relevant words inside + `atom`, so we first compute their indicies. + + `ins_idx` is the word-index of the least-significant word we + care about, and `sig_idx` is the word after that. + + Next we grab those words (`ins_word` and `sig_word`) from the atom + using `u3r_word`. Note that `sig_idx` might be out-of-bounds for the + underlying array of `atom`, but `u3r_word` returns 0 in that case, + which is exatly what we want. + + Now, we need to grab the relevant bits out of both words, and combine + them. `bits_rem_in_ins_word` is the number of remaining (insignificant) + bits in `ins_word`, `nbits_ins` is the number of bits we want from the + less-significant word, and `nbits_sig` from the more-significant one. + + Take the least significant `nbits_sig` bits from `sig_word`, and take + the slice we care about from `ins_word`. In order to take that slice, + we drop `bits_rem_in_ins_word` insignificant bits, and then take the + `nbits_sig` most-significant bits. + + Last, we slice out those bits from the two words, combine them into + one word, and cons them onto the front of the result. +*/ +static u3_noun +_bit_rip(u3_atom bits, u3_atom atom) +{ + if ( !_(u3a_is_cat(bits) || bits==0 || bits>31) ) { + return u3m_bail(c3__fail); + } + + c3_w bit_width = u3r_met(0, atom); + c3_w num_blocks = DIVCEIL(bit_width, bits); + + u3_noun res = u3_nul; + + for ( c3_w blk = 0; blk < num_blocks; blk++ ) { + c3_w next_blk = blk + 1; + c3_w blks_rem = num_blocks - next_blk; + c3_w bits_rem = blks_rem * bits; + c3_w ins_idx = bits_rem / 32; + c3_w sig_idx = ins_idx + 1; + + c3_w bits_rem_in_ins_word = bits_rem % 32; + + c3_w ins_word = u3r_word(ins_idx, atom); + c3_w sig_word = u3r_word(sig_idx, atom); + c3_w nbits_ins = c3_min(bits, 32 - bits_rem_in_ins_word); + c3_w nbits_sig = bits - nbits_ins; + + c3_w ins_word_bits = TAKEBITS(nbits_ins, ins_word >> bits_rem_in_ins_word); + c3_w sig_word_bits = TAKEBITS(nbits_sig, sig_word); + + c3_w item = ins_word_bits | (sig_word_bits << nbits_ins); + + res = u3nc(item, res); + } + + return res; +} + +static u3_noun +_block_rip(u3_atom bloq, u3_atom b) +{ + if ( !_(u3a_is_cat(bloq)) || (bloq >= 32) ) { + return u3m_bail(c3__fail); + } + + c3_g bloq_g = bloq; + + /* + This is a fast-path for the case where all the resulting blocks will + fit in 31-bit direct atoms. + */ + if ( bloq_g < 5 ) { // produce direct atoms + u3_noun acc = u3_nul; + + c3_w met_w = u3r_met(bloq_g, b); // num blocks in atom + c3_w nbits_w = 1 << bloq_g; // block size in bits + c3_w bmask_w = (1 << nbits_w) - 1; // result mask + + for ( c3_w i_w = 0; i_w < met_w; i_w++ ) { // `i_w` is block index + c3_w nex_w = i_w + 1; // next block + c3_w pat_w = met_w - nex_w; // blks left after this + c3_w bit_w = pat_w << bloq_g; // bits left after this + c3_w wor_w = bit_w >> 5; // wrds left after this + c3_w sif_w = bit_w & 31; // bits left in word + c3_w src_w = u3r_word(wor_w, b); // find word by index + c3_w rip_w = (src_w >> sif_w) & bmask_w; // get item from word + + acc = u3nc(rip_w, acc); + } + + return acc; + } + + u3_noun acc = u3_nul; + c3_w met_w = u3r_met(bloq_g, b); + c3_w len_w = u3r_met(5, b); + c3_g san_g = (bloq_g - 5); + c3_w san_w = 1 << san_g; + c3_w dif_w = (met_w << san_g) - len_w; + c3_w tub_w = ((dif_w == 0) ? san_w : (san_w - dif_w)); + + for ( c3_w i_w = 0; i_w < met_w; i_w++ ) { + c3_w pat_w = (met_w - (i_w + 1)); + c3_w wut_w = (pat_w << san_g); + c3_w sap_w = ((0 == i_w) ? tub_w : san_w); + c3_w j_w; + u3_atom rip; + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 5, sap_w); + + for ( j_w = 0; j_w < sap_w; j_w++ ) { + sab_u.buf_w[j_w] = u3r_word(wut_w + j_w, b); + } + + rip = u3i_slab_mint(&sab_u); + acc = u3nc(rip, acc); + len_w -= san_w; + } + + return acc; +} + +u3_noun +u3qc_rip(u3_atom a, + u3_atom b, + u3_atom c) +{ + if ( 1 == b ) { + return _block_rip(a, c); + } + + if ( 0 == a ) { + return _bit_rip(b, c); + } + + u3l_log("rip: stub"); + return u3_none; +} + +u3_noun +u3wc_rip(u3_noun cor) +{ + u3_atom bloq, step; + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, + u3x_sam_3, &b, 0); + u3x_bite(a, &bloq, &step); + + return u3qc_rip(bloq, step, u3x_atom(b)); +} + +u3_noun +u3kc_rip(u3_atom a, + u3_atom b, + u3_atom c) +{ + u3_noun pro = u3qc_rip(a, b, c); + u3z(a); u3z(b); u3z(c); + return pro; +} diff --git a/vere/pkg/noun/jets/c/rsh.c b/vere/pkg/noun/jets/c/rsh.c new file mode 100644 index 0000000..6fc8ddf --- /dev/null +++ b/vere/pkg/noun/jets/c/rsh.c @@ -0,0 +1,60 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qc_rsh(u3_atom a, + u3_atom b, + u3_atom c) +{ + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + else if ( !_(u3a_is_cat(b)) ) { + return 0; + } + else { + c3_g a_g = a; + c3_w b_w = b; + c3_w len_w = u3r_met(a_g, c); + + if ( b_w >= len_w ) { + return 0; + } + else { + u3i_slab sab_u; + u3i_slab_init(&sab_u, a_g, (len_w - b_w)); + + u3r_chop(a_g, b_w, (len_w - b_w), 0, sab_u.buf_w, c); + + return u3i_slab_mint(&sab_u); + } + } +} + +u3_noun +u3wc_rsh(u3_noun cor) +{ + u3_atom bloq, step; + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, + u3x_sam_3, &b, 0); + u3x_bite(a, &bloq, &step); + + return u3qc_rsh(bloq, step, u3x_atom(b)); +} + +u3_noun +u3kc_rsh(u3_noun a, + u3_noun b, + u3_noun c) +{ + u3_noun d = u3qc_rsh(a, b, c); + + u3z(a); u3z(b); u3z(c); + return d; +} diff --git a/vere/pkg/noun/jets/c/sew.c b/vere/pkg/noun/jets/c/sew.c new file mode 100644 index 0000000..02359f7 --- /dev/null +++ b/vere/pkg/noun/jets/c/sew.c @@ -0,0 +1,74 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_weak +u3qc_sew(u3_atom a, + u3_atom b, + u3_atom c, + u3_atom d, + u3_atom e + ) +{ + c3_w b_w, c_w; + if (0 == c) return u3k(e); + if ( !_(u3r_safe_word(b, &b_w)) || + !_(u3r_safe_word(c, &c_w)) ) { + return u3_none; + } + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + + c3_g a_g = a; + c3_w len_e_w = u3r_met(a_g, e); + u3i_slab sab_u; + c3_w* src_w; + c3_w len_src_w; + if ( _(u3a_is_cat(e)) ) { + len_src_w = e ? 1 : 0; + src_w = &e; + } + else { + u3a_atom* src_u = u3a_to_ptr(e); + len_src_w = src_u->len_w; + src_w = src_u->buf_w; + } + u3i_slab_init(&sab_u, a_g, c3_max(len_e_w, b_w + c_w)); + u3r_chop_words(a_g, 0, b_w, 0, sab_u.buf_w, len_src_w, src_w); + u3r_chop(a_g, 0, c_w, b_w, sab_u.buf_w, d); + if (len_e_w > b_w + c_w) { + u3r_chop_words(a_g, + b_w + c_w, + len_e_w - (b_w + c_w), + b_w + c_w, + sab_u.buf_w, + len_src_w, + src_w); + } + return u3i_slab_mint(&sab_u); +} + +u3_weak +u3wc_sew(u3_noun cor) +{ + u3_noun a, b, c, d, e; + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_12, &b, + 106, &c, + 107, &d, + u3x_sam_7, &e, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) || + (c3n == u3ud(c)) || + (c3n == u3ud(d)) || + (c3n == u3ud(e)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qc_sew(a, b, c, d, e); + } +} diff --git a/vere/pkg/noun/jets/c/sqt.c b/vere/pkg/noun/jets/c/sqt.c new file mode 100644 index 0000000..b20db59 --- /dev/null +++ b/vere/pkg/noun/jets/c/sqt.c @@ -0,0 +1,33 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_sqt(u3_atom a) + { + mpz_t a_mp, b_mp; + + u3r_mp(a_mp, a); + mpz_init(b_mp); + mpz_sqrtrem(a_mp, b_mp, a_mp); + + return u3nc(u3i_mp(a_mp), u3i_mp(b_mp)); + } + u3_noun + u3wc_sqt(u3_noun cor) + { + u3_noun a; + + if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_sqt(a); + } + } + diff --git a/vere/pkg/noun/jets/c/swp.c b/vere/pkg/noun/jets/c/swp.c new file mode 100644 index 0000000..4f503e7 --- /dev/null +++ b/vere/pkg/noun/jets/c/swp.c @@ -0,0 +1,50 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qc_swp(u3_atom a, + u3_atom b) +{ + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + c3_g a_g = a; + c3_w len_w = u3r_met(a_g, b); + u3i_slab sab_u; + u3i_slab_init(&sab_u, a_g, len_w); + + for (c3_w i = 0; i < len_w; i++) { + u3r_chop(a_g, i, 1, len_w - i - 1, sab_u.buf_w, b); + } + + return u3i_slab_mint(&sab_u); +} + +u3_noun +u3wc_swp(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + + if ( (c3n == u3ud(a)) + || (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } + + return u3qc_swp(a, b); + } + +u3_noun +u3kc_swp(u3_atom a, + u3_atom b) +{ + u3_noun pro = u3qc_swp(a, b); + u3z(a); u3z(b); + return pro; +} diff --git a/vere/pkg/noun/jets/c/xeb.c b/vere/pkg/noun/jets/c/xeb.c new file mode 100644 index 0000000..6a23ac1 --- /dev/null +++ b/vere/pkg/noun/jets/c/xeb.c @@ -0,0 +1,32 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qc_xeb(u3_atom a) + { + c3_w met_w = u3r_met(0, a); + + if ( !_(u3a_is_cat(met_w)) ) { + return u3i_words(1, &met_w); + } + else return met_w; + } + u3_noun + u3wc_xeb(u3_noun cor) + { + u3_noun a; + + if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_xeb(a); + } + } + diff --git a/vere/pkg/noun/jets/d/by_all.c b/vere/pkg/noun/jets/d/by_all.c new file mode 100644 index 0000000..25926a7 --- /dev/null +++ b/vere/pkg/noun/jets/d/by_all.c @@ -0,0 +1,51 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_noun +_by_all(u3_noun a, u3j_site* sit_u) +{ + if ( u3_nul == a ) { + return c3y; + } + else { + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + switch ( u3j_gate_slam(sit_u, u3k(u3t(n_a))) ) { + case c3y: break; + case c3n: return c3n; + default: return u3m_bail(c3__exit); + } + + if ( c3n == _by_all(l_a, sit_u) ) { + return c3n; + } + + return _by_all(r_a, sit_u); + } +} + +u3_noun +u3qdb_all(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3j_site sit_u; + + u3j_gate_prep(&sit_u, u3k(b)); + pro = _by_all(a, &sit_u); + u3j_gate_lose(&sit_u); + + return pro; +} + +u3_noun +u3wdb_all(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_all(a, b); +} diff --git a/vere/pkg/noun/jets/d/by_any.c b/vere/pkg/noun/jets/d/by_any.c new file mode 100644 index 0000000..b81f32d --- /dev/null +++ b/vere/pkg/noun/jets/d/by_any.c @@ -0,0 +1,51 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_noun +_by_any(u3_noun a, u3j_site* sit_u) +{ + if ( u3_nul == a ) { + return c3n; + } + else { + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + switch ( u3j_gate_slam(sit_u, u3k(u3t(n_a))) ) { + case c3y: return c3y; + case c3n: break; + default: return u3m_bail(c3__exit); + } + + if ( c3y == _by_any(l_a, sit_u) ) { + return c3y; + } + + return _by_any(r_a, sit_u); + } +} + +u3_noun +u3qdb_any(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3j_site sit_u; + + u3j_gate_prep(&sit_u, u3k(b)); + pro = _by_any(a, &sit_u); + u3j_gate_lose(&sit_u); + + return pro; +} + +u3_noun +u3wdb_any(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_any(a, b); +} diff --git a/vere/pkg/noun/jets/d/by_apt.c b/vere/pkg/noun/jets/d/by_apt.c new file mode 100644 index 0000000..66a6414 --- /dev/null +++ b/vere/pkg/noun/jets/d/by_apt.c @@ -0,0 +1,78 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static c3_o +_by_apt(u3_noun a, u3_weak l, u3_weak r) +{ + if ( u3_nul == a ) { + return c3y; + } + else { + u3_noun p_n_a, l_a, r_a; + { + u3_noun n_a; + u3x_trel(a, &n_a, &l_a, &r_a); + p_n_a = u3h(n_a); + } + + if ( u3_none != l ) { + if ( (c3n == u3qc_gor(p_n_a, l)) + || (c3y == u3r_sing(p_n_a, l)) ) + { + return c3n; + } + } + + if ( u3_none != r ) { + if ( (c3n == u3qc_gor(r, p_n_a)) + || (c3y == u3r_sing(r, p_n_a)) ) + { + return c3n; + } + } + + if ( u3_nul != l_a ) { + u3_noun p_n_l_a = u3h(u3h(l_a)); + + if ( (c3n == u3qc_mor(p_n_a, p_n_l_a)) + || (c3y == u3r_sing(p_n_a, p_n_l_a)) ) + { + return c3n; + } + + if ( c3n == _by_apt(l_a, p_n_a, r) ) { + return c3n; + } + } + + if ( u3_nul != r_a ) { + u3_noun p_n_r_a = u3h(u3h(r_a)); + + if ( (c3n == u3qc_mor(p_n_a, p_n_r_a)) + || (c3y == u3r_sing(p_n_a, p_n_r_a)) ) + { + return c3n; + } + + return _by_apt(r_a, l, p_n_a); + } + + return c3y; + } +} + +u3_noun +u3qdb_apt(u3_noun a) +{ + return _by_apt(a, u3_none, u3_none); +} + +u3_noun +u3wdb_apt(u3_noun cor) +{ + return u3qdb_apt(u3x_at(u3x_con_sam, cor)); +} diff --git a/vere/pkg/noun/jets/d/by_bif.c b/vere/pkg/noun/jets/d/by_bif.c new file mode 100644 index 0000000..0a2f23a --- /dev/null +++ b/vere/pkg/noun/jets/d/by_bif.c @@ -0,0 +1,74 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* internal functions +*/ +static u3_noun +_b_bif_putroot(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a ) { + return u3nt(u3k(b), u3_nul, u3_nul); + } + else { + u3_noun n_a, l_a, r_a; + u3_noun p_n_a, q_n_a; + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_cell(n_a, &p_n_a, &q_n_a); + + if ( c3y == u3r_sing(b, p_n_a) ) { + return u3nt(u3k(b), u3k(l_a), u3k(r_a)); + } + else { + u3_noun c, n_c, l_c, r_c; + u3_noun d; + + if ( c3y == u3qc_gor(b, p_n_a) ) { + c = _b_bif_putroot(l_a, b); + u3r_trel(c, &n_c, &l_c, &r_c); + d = u3nt(u3k(n_c), + u3k(l_c), + u3nt(u3k(n_a), u3k(r_c), u3k(r_a)) + ); + u3z(c); + return d; + } + else { + c = _b_bif_putroot(r_a, b); + u3r_trel(c, &n_c, &l_c, &r_c); + d = u3nt(u3k(n_c), + u3nt(u3k(n_a), u3k(l_a), u3k(l_c)), + u3k(r_c) + ); + u3z(c); + return d; + } + } + } +} + +u3_noun +u3wdb_bif(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_bif(a, b); +} + +u3_noun +u3qdb_bif(u3_noun a, + u3_noun b) +{ + u3_noun c, n_c, l_c, r_c; + u3_noun d; + + c = _b_bif_putroot(a, b); + u3r_trel(c, &n_c, &l_c, &r_c); + d = u3nc(u3k(l_c), u3k(r_c)); + u3z(c); + return d; +} diff --git a/vere/pkg/noun/jets/d/by_del.c b/vere/pkg/noun/jets/d/by_del.c new file mode 100644 index 0000000..86ba416 --- /dev/null +++ b/vere/pkg/noun/jets/d/by_del.c @@ -0,0 +1,93 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_noun +_rebalance(u3_noun a) +{ + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + if ( u3_nul == l_a) { + return u3k(r_a); + } + else if ( u3_nul == r_a) { + return u3k(l_a); + } + else { + u3_noun n_l_a, l_l_a, r_l_a; + u3_noun n_r_a, l_r_a, r_r_a; + u3x_trel(l_a, &n_l_a, &l_l_a, &r_l_a); + u3x_trel(r_a, &n_r_a, &l_r_a, &r_r_a); + + if ( c3y == u3qc_mor(u3h(n_l_a), u3h(n_r_a)) ) { + u3_noun new_right = u3nt(u3k(n_a), + u3k(r_l_a), + u3k(r_a)); + + u3_noun ret = u3nt(u3k(n_l_a), + u3k(l_l_a), + _rebalance(new_right)); + u3z(new_right); + + return ret; + } + else { + u3_noun new_left = u3nt(u3k(n_a), + u3k(l_a), + u3k(l_r_a)); + + u3_noun ret = u3nt(u3k(n_r_a), + _rebalance(new_left), + u3k(r_r_a)); + u3z(new_left); + + return ret; + } + } +} + +u3_noun +u3qdb_del(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a ) { + return u3_nul; + } + else { + u3_noun n_a, lr_a; + u3_noun pn_a; + u3x_cell(a, &n_a, &lr_a); + u3x_cell(n_a, &pn_a, 0); + + if ( c3y == u3r_sing(pn_a, b) ) { + return _rebalance(a); + } + else { + u3_noun l_a, r_a; + u3x_cell(lr_a, &l_a, &r_a); + + if ( c3y == u3qc_gor(b, pn_a) ) { + return u3nt(u3k(n_a), + u3qdb_del(l_a, b), + u3k(r_a)); + } + else { + return u3nt(u3k(n_a), + u3k(l_a), + u3qdb_del(r_a, b)); + } + } + } +} + +u3_noun +u3wdb_del(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_del(a, b); +} diff --git a/vere/pkg/noun/jets/d/by_dif.c b/vere/pkg/noun/jets/d/by_dif.c new file mode 100644 index 0000000..44dcd1a --- /dev/null +++ b/vere/pkg/noun/jets/d/by_dif.c @@ -0,0 +1,83 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* internal functions +*/ + +/* RETAIN +*/ +static u3_noun +_b_dif_join(u3_noun d, + u3_noun e) +{ + if ( u3_nul == d ) { + return u3k(e); + } + else if ( u3_nul == e ) { + return u3k(d); + } + else { + u3_noun n_d, lr_d; + u3_noun n_e, lr_e; + u3x_cell(d, &n_d, &lr_d); + u3x_cell(e, &n_e, &lr_e); + + if ( c3y == u3qc_mor(u3h(n_d), u3h(n_e)) ) { + u3_noun l_d, r_d; + u3x_cell(lr_d, &l_d, &r_d); + + return u3nt(u3k(n_d), + u3k(l_d), + _b_dif_join(r_d, e)); + } + else { + u3_noun l_e, r_e; + u3x_cell(lr_e, &l_e, &r_e); + + return u3nt(u3k(n_e), + _b_dif_join(d, l_e), + u3k(r_e)); + } + } +} + +u3_noun +u3wdb_dif(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_dif(a, b); +} + +u3_noun +u3qdb_dif(u3_noun a, + u3_noun b) +{ + if ( u3_nul == b ) { + return u3k(a); + } + else { + u3_noun n_b, p_n_b, q_n_b, l_b, r_b; + u3_noun c, l_c, r_c; + u3x_trel(b, &n_b, &l_b, &r_b); + u3x_cell(n_b, &p_n_b, &q_n_b); + + c = u3qdb_bif(a, p_n_b); + u3x_cell(c, &l_c, &r_c); + + u3_noun d = u3qdb_dif(l_c, l_b); + u3_noun e = u3qdb_dif(r_c, r_b); + + u3z(c); + + u3_noun pro = _b_dif_join(d, e); + u3z(d); + u3z(e); + + return pro; + } +} diff --git a/vere/pkg/noun/jets/d/by_gas.c b/vere/pkg/noun/jets/d/by_gas.c new file mode 100644 index 0000000..2da171d --- /dev/null +++ b/vere/pkg/noun/jets/d/by_gas.c @@ -0,0 +1,44 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdb_gas(u3_noun a, + u3_noun b) +{ + if ( u3_nul == b ) { + return u3k(a); + } + else { + u3_noun i_b, t_b, + pi_b, qi_b; + u3x_cell(b, &i_b, &t_b); + u3x_cell(i_b, &pi_b, &qi_b); + + u3_noun c = u3qdb_put(a, pi_b, qi_b); + u3_noun d = u3qdb_gas(c, t_b); + u3z(c); + return d; + } +} + +u3_noun +u3wdb_gas(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_gas(a, b); +} + +u3_noun +u3kdb_gas(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qdb_gas(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/d/by_get.c b/vere/pkg/noun/jets/d/by_get.c new file mode 100644 index 0000000..19e77b9 --- /dev/null +++ b/vere/pkg/noun/jets/d/by_get.c @@ -0,0 +1,63 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdb_get(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a ) { + return u3_nul; + } + else { + u3_noun n_a, lr_a; + u3_noun pn_a, qn_a; + u3x_cell(a, &n_a, &lr_a); + u3x_cell(n_a, &pn_a, &qn_a); + + if ( (c3y == u3r_sing(b, pn_a)) ) { + return u3nc(u3_nul, u3k(qn_a)); + } + else { + return ( c3y == u3qc_gor(b, pn_a) ) ? u3qdb_get(u3h(lr_a), b) + : u3qdb_get(u3t(lr_a), b); + } + } +} + +u3_noun +u3wdb_get(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_get(a, b); +} + +u3_weak +u3kdb_get(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qdb_get(a, b); + u3z(a); u3z(b); + + if ( c3n == u3du(c) ) { + u3z(c); + return u3_none; + } + else { + u3_noun pro = u3k(u3t(c)); + u3z(c); + return pro; + } +} + +u3_noun +u3kdb_got(u3_noun a, + u3_noun b) +{ + return u3x_good(u3kdb_get(a, b)); +} diff --git a/vere/pkg/noun/jets/d/by_has.c b/vere/pkg/noun/jets/d/by_has.c new file mode 100644 index 0000000..24bcb31 --- /dev/null +++ b/vere/pkg/noun/jets/d/by_has.c @@ -0,0 +1,47 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdb_has(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a ) { + return c3n; + } + else { + u3_noun n_a, lr_a; + u3_noun pn_a; + u3x_cell(a, &n_a, &lr_a); + u3x_cell(n_a, &pn_a, 0); + + if ( (c3y == u3r_sing(b, pn_a)) ) { + return c3y; + } + else { + return ( c3y == u3qc_gor(b, pn_a) ) ? u3qdb_has(u3h(lr_a), b) + : u3qdb_has(u3t(lr_a), b); + } + } +} + +u3_noun +u3wdb_has(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_has(a, b); +} + +u3_noun +u3kdb_has(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qdb_has(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/d/by_int.c b/vere/pkg/noun/jets/d/by_int.c new file mode 100644 index 0000000..5caa8aa --- /dev/null +++ b/vere/pkg/noun/jets/d/by_int.c @@ -0,0 +1,72 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdb_int(u3_noun a, u3_noun b) +{ + if ( (u3_nul == a) + || (u3_nul == b) ) + { + return u3_nul; + } + else { + u3_noun n_a, l_a, r_a; + u3_noun n_b, l_b, r_b; + u3_noun p_n_a, q_n_a; + u3_noun p_n_b, q_n_b; + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_trel(b, &n_b, &l_b, &r_b); + u3x_cell(n_a, &p_n_a, &q_n_a); + u3x_cell(n_b, &p_n_b, &q_n_b); + + if ( c3y == u3qc_mor(p_n_a, p_n_b) ) { + if ( c3y == u3r_sing(p_n_b, p_n_a) ) { + return u3nt(u3k(n_b), u3qdb_int(l_a, l_b), u3qdb_int(r_a, r_b)); + } + else if ( c3y == u3qc_gor(p_n_b, p_n_a) ) { + u3_noun new_l_b = u3nt(u3k(n_b), u3k(l_b), u3_nul); + u3_noun new_a = u3qdb_int(l_a, new_l_b); + + u3z(new_l_b); + return u3kdb_uni(new_a, u3qdb_int(a, r_b)); + } + else { + u3_noun new_r_b = u3nt(u3k(n_b), u3_nul, u3k(r_b)); + u3_noun new_a = u3qdb_int(r_a, new_r_b); + + u3z(new_r_b); + return u3kdb_uni(new_a, u3qdb_int(a, l_b)); + } + } + else if ( c3y == u3r_sing(p_n_a, p_n_b) ) { + return u3nt(u3k(n_b), u3qdb_int(l_a, l_b), u3qdb_int(r_a, r_b)); + } + else if ( c3y == u3qc_gor(p_n_a, p_n_b) ) { + u3_noun new_l_a = u3nt(u3k(n_a), u3k(l_a), u3_nul); + u3_noun new_a = u3qdb_int(new_l_a, l_b); + + u3z(new_l_a); + return u3kdb_uni(new_a, u3qdb_int(r_a, b)); + } + else { + u3_noun new_r_a = u3nt(u3k(n_a), u3_nul, u3k(r_a)); + u3_noun new_a = u3qdb_int(new_r_a, r_b); + + u3z(new_r_a); + return u3kdb_uni(new_a, u3qdb_int(l_a, b)); + } + } +} + +u3_noun +u3wdb_int(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_int(a, b); +} diff --git a/vere/pkg/noun/jets/d/by_jab.c b/vere/pkg/noun/jets/d/by_jab.c new file mode 100644 index 0000000..597e454 --- /dev/null +++ b/vere/pkg/noun/jets/d/by_jab.c @@ -0,0 +1,63 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3kdb_jab(u3_noun a, + u3_noun key, + u3_noun fun) + { + if ( u3_nul == a ) { + return u3m_bail(c3__exit); + } + else { + u3_noun n_a, lr_a; + u3_noun pn_a, qn_a; + u3_noun pro; + u3x_cell(a, &n_a, &lr_a); + u3x_cell(n_a, &pn_a, &qn_a); + + if ( (c3y == u3r_sing(key, pn_a)) ) { + u3_noun value = u3n_slam_on(fun, u3k(qn_a)); + pro = u3nc(u3nc(u3k(u3h(u3h(a))), value), u3k(u3t(a))); + u3z(a); u3z(key); + return pro; + } + else { + u3_noun l_a, r_a; + u3x_cell(lr_a, &l_a, &r_a); + + u3k(n_a); u3k(l_a); u3k(r_a); + if ( c3y == u3qc_gor(key, pn_a) ) { + pro = u3nt(n_a, u3kdb_jab(l_a, key, fun), r_a); + } + else { + pro = u3nt(n_a, l_a, u3kdb_jab(r_a, key, fun)); + } + u3z(a); + return pro; + } + } +} + +u3_noun +u3qdb_jab(u3_noun a, + u3_noun key, + u3_noun fun) +{ + return u3kdb_jab(u3k(a), u3k(key), u3k(fun)); +} + +u3_noun +u3wdb_jab(u3_noun cor) +{ + u3_noun a, key, fun; + u3x_mean(cor, u3x_sam_2, &key, + u3x_sam_3, &fun, + u3x_con_sam, &a, 0); + + return u3qdb_jab(a, key, fun); +} diff --git a/vere/pkg/noun/jets/d/by_key.c b/vere/pkg/noun/jets/d/by_key.c new file mode 100644 index 0000000..b4f8a09 --- /dev/null +++ b/vere/pkg/noun/jets/d/by_key.c @@ -0,0 +1,42 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +// [a] is RETAINED, [set] is TRANSFERRED +// +static u3_noun +_by_key(u3_noun a, u3_noun set) +{ + if ( u3_nul == a ) { + return set; + } + else { + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + { + u3_noun new = u3qdi_put(set, u3h(n_a)); + u3z(set); + set = new; + } + + set = _by_key(l_a, set); + + return _by_key(r_a, set); + } +} + +u3_noun +u3qdb_key(u3_noun a) +{ + return _by_key(a, u3_nul); +} + +u3_noun +u3wdb_key(u3_noun cor) +{ + return u3qdb_key(u3x_at(u3x_con_sam, cor)); +} diff --git a/vere/pkg/noun/jets/d/by_put.c b/vere/pkg/noun/jets/d/by_put.c new file mode 100644 index 0000000..ad0e7ec --- /dev/null +++ b/vere/pkg/noun/jets/d/by_put.c @@ -0,0 +1,102 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdb_put(u3_noun a, + u3_noun b, + u3_noun c) +{ + if ( u3_nul == a ) { + return u3nt(u3nc(u3k(b), u3k(c)), + u3_nul, + u3_nul); + } + else { + u3_noun n_a, l_a, r_a; + u3_noun pn_a, qn_a; + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_cell(n_a, &pn_a, &qn_a); + + if ( c3y == u3r_sing(pn_a, b) ) { + if ( c3y == u3r_sing(qn_a, c) ) { + return u3k(a); + } + else { + return u3nt(u3nc(u3k(b), u3k(c)), + u3k(l_a), + u3k(r_a)); + } + } + else { + u3_noun d, n_d, l_d, r_d; + + if ( c3y == u3qc_gor(b, pn_a) ) { + d = u3qdb_put(l_a, b, c); + + if ( c3y == u3qc_mor(pn_a, u3h(u3h(d))) ) { + return u3nt(u3k(n_a), + d, + u3k(r_a)); + } + else { + u3r_trel(d, &n_d, &l_d, &r_d); + + u3_noun e = u3nt(u3k(n_d), + u3k(l_d), + u3nt(u3k(n_a), + u3k(r_d), + u3k(r_a))); + + u3z(d); + return e; + } + } + else { + d = u3qdb_put(r_a, b, c); + + if ( c3y == u3qc_mor(pn_a, u3h(u3h(d))) ) { + return u3nt(u3k(n_a), + u3k(l_a), + d); + } + else { + u3r_trel(d, &n_d, &l_d, &r_d); + + u3_noun e = u3nt(u3k(n_d), + u3nt(u3k(n_a), + u3k(l_a), + u3k(l_d)), + u3k(r_d)); + + u3z(d); + return e; + } + } + } + } +} + +u3_noun +u3wdb_put(u3_noun cor) +{ + u3_noun a, b, c; + u3x_mean(cor, u3x_sam_2, &b, + u3x_sam_3, &c, + u3x_con_sam, &a, 0); + return u3qdb_put(a, b, c); +} + +u3_noun +u3kdb_put(u3_noun a, + u3_noun b, + u3_noun c) +{ + u3_noun pro = u3qdb_put(a, b, c); + u3z(a); u3z(b); u3z(c); + return pro; +} diff --git a/vere/pkg/noun/jets/d/by_run.c b/vere/pkg/noun/jets/d/by_run.c new file mode 100644 index 0000000..491a32c --- /dev/null +++ b/vere/pkg/noun/jets/d/by_run.c @@ -0,0 +1,53 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_noun +_by_run(u3_noun a, u3j_site* sit_u) +{ + if ( u3_nul == a ) { + return u3_nul; + } + else { + u3_noun n_a, l_a, r_a; + u3_noun p_n_a, q_n_a; + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_cell(n_a, &p_n_a, &q_n_a); + + u3k(p_n_a); + u3k(q_n_a); + u3k(l_a); + u3k(r_a); + + u3_noun pro = u3nt(u3nc(p_n_a, u3j_gate_slam(sit_u, q_n_a)), + _by_run(l_a, sit_u), + _by_run(r_a, sit_u)); + + u3z(a); + return pro; + } +} + +u3_noun +u3qdb_run(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3j_site sit_u; + + u3j_gate_prep(&sit_u, u3k(b)); + pro = _by_run(u3k(a), &sit_u); + u3j_gate_lose(&sit_u); + + return pro; +} + +u3_noun +u3wdb_run(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_run(a, b); +} diff --git a/vere/pkg/noun/jets/d/by_uni.c b/vere/pkg/noun/jets/d/by_uni.c new file mode 100644 index 0000000..6bdcd4c --- /dev/null +++ b/vere/pkg/noun/jets/d/by_uni.c @@ -0,0 +1,101 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +u3_noun +u3qdb_uni(u3_noun a, u3_noun b) +{ + if ( u3_nul == b ) { + return u3k(a); + } + else if ( u3_nul == a ) { + return u3k(b); + } + else { + u3_noun n_a, l_a, r_a; + u3_noun n_b, l_b, r_b; + u3_noun p_n_a, q_n_a; + u3_noun p_n_b, q_n_b; + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_trel(b, &n_b, &l_b, &r_b); + u3x_cell(n_a, &p_n_a, &q_n_a); + u3x_cell(n_b, &p_n_b, &q_n_b); + + if ( c3y == u3r_sing(p_n_a, p_n_b) ) { + return u3nt(u3k(n_b), + u3qdb_uni(l_a, l_b), + u3qdb_uni(r_a, r_b)); + } + else if ( c3y == u3qc_mor(p_n_a, p_n_b) ) { + u3_noun new_a, old_b; + + if ( c3y == u3qc_gor(p_n_b, p_n_a) ) { + u3_noun new_b = u3nt(u3k(n_b), u3k(l_b), u3_nul); + u3_noun new_la = u3qdb_uni(l_a, new_b); + u3z(new_b); + + new_a = u3nt(u3k(n_a), new_la, u3k(r_a)); + old_b = r_b; + } + else { + u3_noun new_b = u3nt(u3k(n_b), u3_nul, u3k(r_b)); + u3_noun new_ra = u3qdb_uni(r_a, new_b); + u3z(new_b); + + new_a = u3nt(u3k(n_a), u3k(l_a), new_ra); + old_b = l_b; + } + + { + u3_noun pro = u3qdb_uni(new_a, old_b); + u3z(new_a); + return pro; + } + } + else { + u3_noun old_a, new_b; + + if ( c3y == u3qc_gor(p_n_a, p_n_b) ) { + u3_noun new_a = u3nt(u3k(n_a), u3k(l_a), u3_nul); + u3_noun new_lb = u3qdb_uni(new_a, l_b); + u3z(new_a); + + new_b = u3nt(u3k(n_b), new_lb, u3k(r_b)); + old_a = r_a; + } + else { + u3_noun new_a = u3nt(u3k(n_a), u3_nul, u3k(r_a)); + u3_noun new_rb = u3qdb_uni(new_a, r_b); + u3z(new_a); + + new_b = u3nt(u3k(n_b), u3k(l_b), new_rb); + old_a = l_a; + } + + { + u3_noun pro = u3qdb_uni(old_a, new_b); + u3z(new_b); + return pro; + } + } + } +} + +u3_noun +u3wdb_uni(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_uni(a, b); +} + +u3_noun +u3kdb_uni(u3_noun a, u3_noun b) +{ + u3_noun pro = u3qdb_uni(a, b); + u3z(a); u3z(b); + return pro; +} diff --git a/vere/pkg/noun/jets/d/by_urn.c b/vere/pkg/noun/jets/d/by_urn.c new file mode 100644 index 0000000..5c82876 --- /dev/null +++ b/vere/pkg/noun/jets/d/by_urn.c @@ -0,0 +1,52 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_noun +_by_urn(u3_noun a, u3j_site* sit_u) +{ + if ( u3_nul == a ) { + return u3_nul; + } + else { + u3_noun n_a, l_a, r_a, p_n_a; + u3x_trel(a, &n_a, &l_a, &r_a); + p_n_a = u3h(n_a); + + u3k(p_n_a); + u3k(n_a); + u3k(l_a); + u3k(r_a); + + u3_noun pro = u3nt(u3nc(p_n_a, u3j_gate_slam(sit_u, n_a)), + _by_urn(l_a, sit_u), + _by_urn(r_a, sit_u)); + + u3z(a); + return pro; + } +} + +u3_noun +u3qdb_urn(u3_noun a, u3_noun b) +{ + u3_noun pro; + u3j_site sit_u; + + u3j_gate_prep(&sit_u, u3k(b)); + pro = _by_urn(u3k(a), &sit_u); + u3j_gate_lose(&sit_u); + + return pro; +} + +u3_noun +u3wdb_urn(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdb_urn(a, b); +} diff --git a/vere/pkg/noun/jets/d/in_apt.c b/vere/pkg/noun/jets/d/in_apt.c new file mode 100644 index 0000000..93e7b48 --- /dev/null +++ b/vere/pkg/noun/jets/d/in_apt.c @@ -0,0 +1,121 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static c3_o +_in_apt_140(u3_noun a, u3_weak l, u3_weak r) +{ + if ( u3_nul == a ) { + return c3y; + } + else { + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + if ( (u3_none != l) && (c3n == u3qc_gor(n_a, l)) ) { + return c3n; + } + + if ( (u3_none != r) && (c3n == u3qc_gor(r, n_a)) ) { + return c3n; + } + + if ( u3_nul != l_a ) { + if ( c3n == u3qc_mor(n_a, u3h(l_a)) ) { + return c3n; + } + + if ( c3n == _in_apt_140(l_a, n_a, r) ) { + return c3n; + } + } + + if ( u3_nul != r_a ) { + if ( c3n == u3qc_mor(n_a, u3h(r_a)) ) { + return c3n; + } + + return _in_apt_140(r_a, l, n_a); + } + + return c3y; + } +} + +u3_noun +u3qdi_apt_140(u3_noun a) +{ + return _in_apt_140(a, u3_none, u3_none); +} + +u3_noun +u3wdi_apt_140(u3_noun cor) +{ + return u3qdi_apt_140(u3x_at(u3x_con_sam, cor)); +} + + +static c3_o +_in_apt(u3_noun a, u3_weak l, u3_weak r) +{ + if ( u3_nul == a ) { + return c3y; + } + else { + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + if ( (u3_none != l) && + ( (c3y == u3r_sing(n_a, l)) || (c3n == u3qc_gor(n_a, l)) )) { + return c3n; + } + + if ( (u3_none != r) && + ( (c3y == u3r_sing(r, n_a)) || (c3n == u3qc_gor(r, n_a)) )) { + return c3n; + } + + if ( u3_nul != l_a ) { + if ( c3y == u3r_sing(n_a, u3h(l_a)) ) { + return c3n; + } + + if ( c3n == u3qc_mor(n_a, u3h(l_a)) ) { + return c3n; + } + + if ( c3n == _in_apt(l_a, n_a, r) ) { + return c3n; + } + } + + if ( u3_nul != r_a ) { + if ( c3y == u3r_sing(n_a, u3h(r_a)) ) { + return c3n; + } + + if ( c3n == u3qc_mor(n_a, u3h(r_a)) ) { + return c3n; + } + + return _in_apt(r_a, l, n_a); + } + + return c3y; + } +} + +u3_noun +u3qdi_apt(u3_noun a) +{ + return _in_apt(a, u3_none, u3_none); +} + +u3_noun +u3wdi_apt(u3_noun cor) +{ + return u3qdi_apt(u3x_at(u3x_con_sam, cor)); +} diff --git a/vere/pkg/noun/jets/d/in_bif.c b/vere/pkg/noun/jets/d/in_bif.c new file mode 100644 index 0000000..76596b1 --- /dev/null +++ b/vere/pkg/noun/jets/d/in_bif.c @@ -0,0 +1,72 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* internal functions +*/ +static u3_noun +_i_bif_putroot(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a) { + return u3nt(u3k(b), u3_nul, u3_nul); + } + else { + u3_noun n_a, lr_a; + u3x_cell(a, &n_a, &lr_a); + + if ( c3y == u3r_sing(b, n_a) ) { + return u3k(a); + } + else { + u3_noun c, n_c, l_c, r_c; + u3_noun d; + u3_noun l_a, r_a; + u3x_cell(lr_a, &l_a, &r_a); + + if ( c3y == u3qc_gor(b, n_a) ) { + c = _i_bif_putroot(l_a, b); + u3r_trel(c, &n_c, &l_c, &r_c); + d = u3nt(u3k(n_c), + u3k(l_c), + u3nt(u3k(n_a), u3k(r_c), u3k(r_a))); + u3z(c); + return d; + } + else { + c = _i_bif_putroot(r_a, b); + u3r_trel(c, &n_c, &l_c, &r_c); + d = u3nt(u3k(n_c), + u3nt(u3k(n_a), u3k(l_a), u3k(l_c)), + u3k(r_c)); + u3z(c); + return d; + } + } + } +} + +u3_noun +u3wdi_bif(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_bif(a, b); +} + +u3_noun +u3qdi_bif(u3_noun a, + u3_noun b) +{ + u3_noun c, n_c, l_c, r_c; + u3_noun d; + + c = _i_bif_putroot(a, b); + u3r_trel(c, &n_c, &l_c, &r_c); + d = u3nc(u3k(l_c), u3k(r_c)); + u3z(c); + return d; +} diff --git a/vere/pkg/noun/jets/d/in_del.c b/vere/pkg/noun/jets/d/in_del.c new file mode 100644 index 0000000..5871a45 --- /dev/null +++ b/vere/pkg/noun/jets/d/in_del.c @@ -0,0 +1,88 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_noun +_rebalance(u3_noun a) +{ + u3_noun l_a, n_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + if ( u3_nul == l_a) { + return u3k(r_a); + } + else if ( u3_nul == r_a) { + return u3k(l_a); + } + else { + u3_noun n_l_a, l_l_a, r_l_a; + u3_noun n_r_a, l_r_a, r_r_a; + u3x_trel(l_a, &n_l_a, &l_l_a, &r_l_a); + u3x_trel(r_a, &n_r_a, &l_r_a, &r_r_a); + + if ( c3y == u3qc_mor(n_l_a, n_r_a) ) { + u3_noun new_right = u3nt(u3k(n_a), + u3k(r_l_a), + u3k(r_a)); + + u3_noun ret = u3nt(u3k(n_l_a), + u3k(l_l_a), + _rebalance(new_right)); + u3z(new_right); + + return ret; + } + else { + u3_noun new_left = u3nt(u3k(n_a), + u3k(l_a), + u3k(l_r_a)); + + u3_noun ret = u3nt(u3k(n_r_a), + _rebalance(new_left), + u3k(r_r_a)); + u3z(new_left); + + return ret; + } + } +} + +u3_noun +u3qdi_del(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a ) { + return u3_nul; + } + else { + u3_noun l_a, n_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + if ( c3y == u3r_sing(n_a, b) ) { + return _rebalance(a); + } + else { + if ( c3y == u3qc_gor(b, n_a) ) { + return u3nt(u3k(n_a), + u3qdi_del(l_a, b), + u3k(r_a)); + } + else { + return u3nt(u3k(n_a), + u3k(l_a), + u3qdi_del(r_a, b)); + } + } + } +} + +u3_noun +u3wdi_del(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_del(a, b); +} diff --git a/vere/pkg/noun/jets/d/in_dif.c b/vere/pkg/noun/jets/d/in_dif.c new file mode 100644 index 0000000..bff391d --- /dev/null +++ b/vere/pkg/noun/jets/d/in_dif.c @@ -0,0 +1,82 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* internal functions +*/ + +/* RETAIN +*/ +static u3_noun +_i_dif_join(u3_noun d, + u3_noun e) +{ + if ( u3_nul == d ) { + return u3k(e); + } + else if ( u3_nul == e ) { + return u3k(d); + } + else { + u3_noun n_d, lr_d; + u3_noun n_e, lr_e; + u3x_cell(d, &n_d, &lr_d); + u3x_cell(e, &n_e, &lr_e); + + if ( c3y == u3qc_mor(n_d, n_e) ) { + u3_noun l_d, r_d; + u3x_cell(lr_d, &l_d, &r_d); + + return u3nt(u3k(n_d), + u3k(l_d), + _i_dif_join(r_d, e)); + } + else { + u3_noun l_e, r_e; + u3x_cell(lr_e, &l_e, &r_e); + + return u3nt(u3k(n_e), + _i_dif_join(d, l_e), + u3k(r_e)); + } + } +} + +u3_noun +u3wdi_dif(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_dif(a, b); +} + +u3_noun +u3qdi_dif(u3_noun a, + u3_noun b) +{ + if ( u3_nul == b ) { + return u3k(a); + } + else { + u3_noun n_b, l_b, r_b; + u3_noun c, l_c, r_c; + u3_noun d, e; + + u3x_trel(b, &n_b, &l_b, &r_b); + c = u3qdi_bif(a, n_b); + u3x_cell(c, &l_c, &r_c); + + d = u3qdi_dif(l_c, l_b); + e = u3qdi_dif(r_c, r_b); + u3z(c); + + u3_noun pro = _i_dif_join(d, e); + u3z(d); + u3z(e); + + return pro; + } +} diff --git a/vere/pkg/noun/jets/d/in_gas.c b/vere/pkg/noun/jets/d/in_gas.c new file mode 100644 index 0000000..888e070 --- /dev/null +++ b/vere/pkg/noun/jets/d/in_gas.c @@ -0,0 +1,42 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdi_gas(u3_noun a, + u3_noun b) +{ + if ( u3_nul == b ) { + return u3k(a); + } + else { + u3_noun i_b, t_b; + u3x_cell(b, &i_b, &t_b); + + u3_noun c = u3qdi_put(a, i_b); + u3_noun d = u3qdi_gas(c, t_b); + u3z(c); + return d; + } +} + +u3_noun +u3wdi_gas(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_gas(a, b); +} + +u3_noun +u3kdi_gas(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qdi_gas(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/d/in_has.c b/vere/pkg/noun/jets/d/in_has.c new file mode 100644 index 0000000..ea6fb5f --- /dev/null +++ b/vere/pkg/noun/jets/d/in_has.c @@ -0,0 +1,45 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdi_has(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a ) { + return c3n; + } + else { + u3_noun n_a, lr_a; + u3x_cell(a, &n_a, &lr_a); + + if ( (c3y == u3r_sing(b, n_a)) ) { + return c3y; + } + else { + return ( c3y == u3qc_gor(b, n_a) ) ? u3qdi_has(u3h(lr_a), b) + : u3qdi_has(u3t(lr_a), b); + } + } +} + +u3_noun +u3wdi_has(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_has(a, b); +} + +u3_noun +u3kdi_has(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qdi_has(a, b); + u3z(a); u3z(b); + return c; +} diff --git a/vere/pkg/noun/jets/d/in_int.c b/vere/pkg/noun/jets/d/in_int.c new file mode 100644 index 0000000..fc5bfaa --- /dev/null +++ b/vere/pkg/noun/jets/d/in_int.c @@ -0,0 +1,65 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdi_int(u3_noun a, u3_noun b) +{ + if ( (u3_nul == a) + || (u3_nul == b) ) + { + return u3_nul; + } + else { + u3_noun n_a, l_a, r_a; + u3_noun n_b, l_b, r_b; + + { + u3_noun lr_a, lr_b; + u3x_cell(a, &n_a, &lr_a); + u3x_cell(b, &n_b, &lr_b); + + if ( c3y == u3qc_mor(n_a, n_b) ) { + u3_noun c; + c = a; a = b; b = c; + c = n_a; n_a = n_b; n_b = c; + c = lr_a; lr_a = lr_b; lr_b = c; + } + + u3x_cell(lr_a, &l_a, &r_a); + u3x_cell(lr_b, &l_b, &r_b); + } + + if ( c3y == u3r_sing(n_b, n_a) ) { + return u3nt(u3k(n_a), + u3qdi_int(l_a, l_b), + u3qdi_int(r_a, r_b)); + } + else if ( c3y == u3qc_gor(n_b, n_a) ) { + u3_noun new_l_b = u3nt(u3k(n_b), u3k(l_b), u3_nul); + u3_noun new_a = u3qdi_int(l_a, new_l_b); + + u3z(new_l_b); + return u3kdi_uni(new_a, u3qdi_int(a, r_b)); + } + else { + u3_noun new_r_b = u3nt(u3k(n_b), u3_nul, u3k(r_b)); + u3_noun new_a = u3qdi_int(r_a, new_r_b); + + u3z(new_r_b); + return u3kdi_uni(new_a, u3qdi_int(a, l_b)); + } + } +} + +u3_noun +u3wdi_int(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_int(a, b); +} diff --git a/vere/pkg/noun/jets/d/in_put.c b/vere/pkg/noun/jets/d/in_put.c new file mode 100644 index 0000000..909d48e --- /dev/null +++ b/vere/pkg/noun/jets/d/in_put.c @@ -0,0 +1,87 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qdi_put(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a ) { + return u3nt(u3k(b), u3_nul, u3_nul); + } + else { + u3_noun n_a, lr_a; + u3x_cell(a, &n_a, &lr_a); + + if ( c3y == u3r_sing(n_a, b) ) { + return u3k(a); + } + else { + u3_noun c, n_c, l_c, r_c; + u3_noun l_a, r_a; + u3x_cell(lr_a, &l_a, &r_a); + + if ( c3y == u3qc_gor(b, n_a) ) { + c = u3qdi_put(l_a, b); + + if ( c3y == u3qc_mor(n_a, u3h(c)) ) { + return u3nt(u3k(n_a), + c, + u3k(r_a)); + } + else { + u3r_trel(c, &n_c, &l_c, &r_c); + { + u3_noun d = u3nt(u3k(n_c), + u3k(l_c), + u3nt(u3k(n_a), u3k(r_c), u3k(r_a))); + + u3z(c); + return d; + } + } + } + else { + c = u3qdi_put(r_a, b); + + if ( c3y == u3qc_mor(n_a, u3h(c)) ) { + return u3nt(u3k(n_a), + u3k(l_a), + c); + } + else { + u3r_trel(c, &n_c, &l_c, &r_c); + { + u3_noun d = u3nt(u3k(n_c), + u3nt(u3k(n_a), u3k(l_a), u3k(l_c)), + u3k(r_c)); + + u3z(c); + return d; + } + } + } + } + } +} + +u3_noun +u3wdi_put(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_put(a, b); +} + +u3_noun +u3kdi_put(u3_noun a, + u3_noun b) +{ + u3_noun pro = u3qdi_put(a, b); + u3z(a); u3z(b); + return pro; +} diff --git a/vere/pkg/noun/jets/d/in_rep.c b/vere/pkg/noun/jets/d/in_rep.c new file mode 100644 index 0000000..fafdad5 --- /dev/null +++ b/vere/pkg/noun/jets/d/in_rep.c @@ -0,0 +1,52 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +// [a] and [out] are TRANSFERRED +// +static void +_in_rep(u3_noun a, u3j_site* sit_u, u3_noun* out) +{ + if ( u3_nul == a ) { + return; + } + else { + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + u3k(n_a); + u3k(l_a); + u3k(r_a); + + *out = u3j_gate_slam(sit_u, u3nc(n_a, *out)); + + _in_rep(l_a, sit_u, out); + _in_rep(r_a, sit_u, out); + + u3z(a); + } +} + +u3_noun +u3qdi_rep(u3_noun a, u3_noun b) +{ + u3_noun out = u3k(u3x_at(u3x_sam_3, b)); + u3j_site sit_u; + + u3j_gate_prep(&sit_u, u3k(b)); + _in_rep(u3k(a), &sit_u, &out); + u3j_gate_lose(&sit_u); + + return out; +} + +u3_noun +u3wdi_rep(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_rep(a, b); +} diff --git a/vere/pkg/noun/jets/d/in_run.c b/vere/pkg/noun/jets/d/in_run.c new file mode 100644 index 0000000..2216a5c --- /dev/null +++ b/vere/pkg/noun/jets/d/in_run.c @@ -0,0 +1,59 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +// [a] and [out] are TRANSFERRED +// +static void +_in_run(u3_noun a, u3j_site* sit_u, u3_noun* out) +{ + if ( u3_nul == a ) { + return; + } + else { + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + u3k(n_a); + u3k(l_a); + u3k(r_a); + + { + u3_noun new = u3j_gate_slam(sit_u, n_a); + u3_noun pro = u3qdi_put(*out, new); + + u3z(new); + u3z(*out); + *out = pro; + } + + _in_run(l_a, sit_u, out); + _in_run(r_a, sit_u, out); + + u3z(a); + } +} + +u3_noun +u3qdi_run(u3_noun a, u3_noun b) +{ + u3_noun out = u3_nul; + u3j_site sit_u; + + u3j_gate_prep(&sit_u, u3k(b)); + _in_run(u3k(a), &sit_u, &out); + u3j_gate_lose(&sit_u); + + return out; +} + +u3_noun +u3wdi_run(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_run(a, b); +} diff --git a/vere/pkg/noun/jets/d/in_tap.c b/vere/pkg/noun/jets/d/in_tap.c new file mode 100644 index 0000000..a9af4f1 --- /dev/null +++ b/vere/pkg/noun/jets/d/in_tap.c @@ -0,0 +1,46 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_noun +_tap_in(u3_noun a, + u3_noun b) +{ + if ( u3_nul == a ) { + return b; + } + else { + u3_noun n_a, l_a, r_a; + u3x_trel(a, &n_a, &l_a, &r_a); + + return _tap_in(r_a, + u3nc(u3k(n_a), + _tap_in(l_a, b))); + } +} + +u3_noun +u3qdi_tap(u3_noun a) +{ + return _tap_in(a, u3_nul); +} + +u3_noun +u3wdi_tap(u3_noun cor) +{ + u3_noun a; + u3x_mean(cor, u3x_con_sam, &a, 0); + return u3qdi_tap(a); +} + +u3_noun +u3kdi_tap(u3_noun a) +{ + u3_noun b = u3qdi_tap(a); + u3z(a); + return b; +} diff --git a/vere/pkg/noun/jets/d/in_uni.c b/vere/pkg/noun/jets/d/in_uni.c new file mode 100644 index 0000000..504ddcb --- /dev/null +++ b/vere/pkg/noun/jets/d/in_uni.c @@ -0,0 +1,98 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* internal functions +*/ +static u3_noun +_in_uni(u3_noun a, u3_noun b) +{ + if ( u3_nul == a ) { + return u3k(b); + } + else if ( u3_nul == b ) { + return u3k(a); + } + else { + u3_noun n_a, l_a, r_a, + n_b, l_b, r_b, + neb, sub, naw, pro; + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_trel(b, &n_b, &l_b, &r_b); + + if ( c3n == u3qc_mor(n_a, n_b) ) { + if ( c3y == u3r_sing(n_a, n_b) ) { + return u3nt(u3k(n_b), _in_uni(l_a, l_b), _in_uni(r_a, r_b)); + } + else if ( c3y == u3qc_gor(n_a, n_b) ) { + naw = u3nt(u3k(n_a), u3k(l_a), u3_nul); + sub = _in_uni(naw, l_b); + neb = u3nt(u3k(n_b), sub, u3k(r_b)); + pro = _in_uni(r_a, neb); + u3z(naw); u3z(neb); + return pro; + } + else { + naw = u3nt(u3k(n_a), u3_nul, u3k(r_a)); + sub = _in_uni(naw, r_b); + neb = u3nt(u3k(n_b), u3k(l_b), sub); + pro = _in_uni(l_a, neb); + u3z(naw); u3z(neb); + return pro; + } + } + else if ( c3y == u3r_sing(n_b, n_a) ) { + return u3nt(u3k(n_b), _in_uni(l_a, l_b), _in_uni(r_a, r_b)); + } + else if ( c3y == u3qc_gor(n_b, n_a) ) { + neb = u3nt(u3k(n_b), u3k(l_b), u3_nul); + sub = _in_uni(l_a, neb); + naw = u3nt(u3k(n_a), sub, u3k(r_a)); + pro = _in_uni(naw, r_b); + u3z(neb); u3z(naw); + return pro; + } + else { + neb = u3nt(u3k(n_b), u3_nul, u3k(r_b)); + sub = _in_uni(r_a, neb); + naw = u3nt(u3k(n_a), u3k(l_a), sub); + pro = _in_uni(naw, l_b); + u3z(neb); u3z(naw); + return pro; + } + } +} + +u3_noun +u3kdi_uni(u3_noun a, + u3_noun b) +{ + u3_noun c = u3qdi_uni(a, b); + u3z(a); u3z(b); + return c; +} + +u3_noun +u3qdi_uni(u3_noun a, + u3_noun b) +{ + if ( c3y == u3r_sing(a, b) ) { + return u3k(a); + } + else { + return _in_uni(a, b); + } +} + +u3_noun +u3wdi_uni(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); + return u3qdi_uni(a, b); +} + diff --git a/vere/pkg/noun/jets/d/in_wyt.c b/vere/pkg/noun/jets/d/in_wyt.c new file mode 100644 index 0000000..2ae72fa --- /dev/null +++ b/vere/pkg/noun/jets/d/in_wyt.c @@ -0,0 +1,35 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +STATIC_ASSERT( (UINT32_MAX > u3a_cells), + "width precision" ); + +static c3_w +_wyt_in(u3_noun a) +{ + if ( u3_nul == a ) { + return 0; + } + else { + u3_noun l_a, r_a; + u3x_trel(a, 0, &l_a, &r_a); + + return 1 + _wyt_in(l_a) + _wyt_in(r_a); + } +} + +u3_noun +u3qdi_wyt(u3_noun a) +{ + return u3i_word(_wyt_in(a)); +} + +u3_noun +u3wdi_wyt(u3_noun cor) +{ + return u3qdi_wyt(u3x_at(u3x_con_2, cor)); +} diff --git a/vere/pkg/noun/jets/e/adler.c b/vere/pkg/noun/jets/e/adler.c new file mode 100644 index 0000000..d7e1211 --- /dev/null +++ b/vere/pkg/noun/jets/e/adler.c @@ -0,0 +1,127 @@ +#include <imprison.h> +#include <jets/k.h> +#include <log.h> +#include <nock.h> +#include <retrieve.h> +#include <types.h> +#include <xtract.h> + +static void _x_octs(u3_noun octs, u3_atom* p_octs, u3_atom* q_octs) { + + if (c3n == u3r_mean(octs, + 2, p_octs, + 3, q_octs, 0)){ + u3m_bail(c3__exit); + } + + if (c3n == u3a_is_atom(*p_octs) || + c3n == u3a_is_atom(*q_octs)) { + u3m_bail(c3__exit); + } +} + +static c3_o _x_octs_buffer(u3_atom* p_octs, u3_atom *q_octs, + c3_w* p_octs_w, c3_y** buf_y, + c3_w* len_w, c3_w* lead_w) +{ + if (c3n == u3r_safe_word(*p_octs, p_octs_w)) { + return c3n; + } + + *len_w = u3r_met(3, *q_octs); + + if (c3y == u3a_is_cat(*q_octs)) { + *buf_y = (c3_y*)q_octs; + } + else { + u3a_atom* ptr_a = u3a_to_ptr(*q_octs); + *buf_y = (c3_y*)ptr_a->buf_w; + } + + *lead_w = 0; + + if (*p_octs_w > *len_w) { + *lead_w = *p_octs_w - *len_w; + } + else { + *len_w = *p_octs_w; + } + + return c3y; +} + +#define BASE 65521 +#define NMAX 5552 + +u3_noun _qe_adler32(u3_noun octs) +{ + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w, len_w, lead_w; + c3_y *buf_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &buf_y, + &len_w, &lead_w)) { + return u3_none; + } + + c3_w adler_w, sum2_w; + + adler_w = 0x1; + sum2_w = 0x0; + + c3_w pos_w = 0; + + // Process all non-zero bytes + // + while (pos_w < len_w) { + + c3_w rem_w = (len_w - pos_w); + + if (rem_w > NMAX) { + rem_w = NMAX; + } + + while (rem_w--) { + adler_w += *(buf_y + pos_w++); + sum2_w += adler_w; + } + + adler_w %= BASE; + sum2_w %= BASE; + } + + // Process leading zeros + // + while (pos_w < p_octs_w) { + + c3_w rem_w = (p_octs_w - pos_w); + + if (rem_w > NMAX) { + rem_w = NMAX; + } + + // leading zeros: adler sum is unchanged + sum2_w += rem_w*adler_w; + pos_w += rem_w; + + adler_w %= BASE; + sum2_w %= BASE; + } + + return u3i_word(sum2_w << 16 | adler_w); +} + + +u3_noun +u3we_adler32(u3_noun cor) +{ + u3_noun octs; + + u3x_mean(cor, u3x_sam, &octs, 0); + + return _qe_adler32(octs); +} diff --git a/vere/pkg/noun/jets/e/aes_cbc.c b/vere/pkg/noun/jets/e/aes_cbc.c new file mode 100644 index 0000000..f5369e0 --- /dev/null +++ b/vere/pkg/noun/jets/e/aes_cbc.c @@ -0,0 +1,182 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + +/* All of the CBC hoon truncates its key and prv inputs by passing them to + * the ECB functions, which truncate them, hence the raw u3r_bytes unpacking. + */ + +typedef int (*urcrypt_cbc)(c3_y**, + size_t*, + c3_y*, + c3_y*, + urcrypt_realloc_t); + + static u3_atom + _cqea_cbc_help(c3_y* key_y, u3_atom iv, u3_atom msg, urcrypt_cbc low_f) + { + u3_atom ret; + c3_w met_w; + c3_y iv_y[16]; + c3_y* msg_y = u3r_bytes_all(&met_w, msg); + size_t len = met_w; + + u3r_bytes(0, 16, iv_y, iv); + if ( 0 != (*low_f)(&msg_y, &len, key_y, iv_y, &u3a_realloc) ) { + ret = u3_none; + } + else { + ret = u3i_bytes(len, msg_y); + } + u3a_free(msg_y); + + return ret; + } + + static u3_atom + _cqea_cbca_en(u3_atom key, + u3_atom iv, + u3_atom msg) + { + c3_y key_y[16]; + u3r_bytes(0, 16, key_y, key); + return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbca_en); + } + + u3_noun + u3wea_cbca_en(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("cbca-en", _cqea_cbca_en(a, b, c)); + } + } + + static u3_atom + _cqea_cbca_de(u3_atom key, + u3_atom iv, + u3_atom msg) + { + c3_y key_y[16]; + u3r_bytes(0, 16, key_y, key); + return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbca_de); + } + + u3_noun + u3wea_cbca_de(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("cbca-de", _cqea_cbca_de(a, b, c)); + } + } + + static u3_atom + _cqea_cbcb_en(u3_atom key, + u3_atom iv, + u3_atom msg) + { + c3_y key_y[24]; + u3r_bytes(0, 24, key_y, key); + return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcb_en); + } + + u3_noun + u3wea_cbcb_en(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("cbcb-en", _cqea_cbcb_en(a, b, c)); + } + } + + static u3_atom + _cqea_cbcb_de(u3_atom key, + u3_atom iv, + u3_atom msg) + { + c3_y key_y[24]; + u3r_bytes(0, 24, key_y, key); + return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcb_de); + } + + u3_noun + u3wea_cbcb_de(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("cbcb-de", _cqea_cbcb_de(a, b, c)); + } + } + + static u3_atom + _cqea_cbcc_en(u3_atom key, + u3_atom iv, + u3_atom msg) + { + c3_y key_y[32]; + u3r_bytes(0, 32, key_y, key); + return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcc_en); + } + + u3_noun + u3wea_cbcc_en(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("cbcc-en", _cqea_cbcc_en(a, b, c)); + } + } + + static u3_atom + _cqea_cbcc_de(u3_atom key, + u3_atom iv, + u3_atom msg) + { + c3_y key_y[32]; + u3r_bytes(0, 32, key_y, key); + return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcc_de); + } + + u3_noun + u3wea_cbcc_de(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("cbcc-de", _cqea_cbcc_de(a, b, c)); + } + } diff --git a/vere/pkg/noun/jets/e/aes_ecb.c b/vere/pkg/noun/jets/e/aes_ecb.c new file mode 100644 index 0000000..eff536d --- /dev/null +++ b/vere/pkg/noun/jets/e/aes_ecb.c @@ -0,0 +1,166 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + +typedef int (*urcrypt_ecb)(c3_y*, c3_y[16], c3_y[16]); + + + /* All of the ECB hoon truncates its key and blk inputs with +fe, in these + * jets we unpack with an unconditional u3r_bytes */ + + static u3_atom + _cqea_ecb_help(c3_y* key_y, u3_atom blk, urcrypt_ecb low_f) + { + c3_y blk_y[16], out_y[16]; + + u3r_bytes(0, 16, blk_y, blk); + + if ( 0 != (*low_f)(key_y, blk_y, out_y) ) { + return u3_none; + } + else { + return u3i_bytes(16, out_y); + } + } + + static u3_atom + _cqea_ecba_en(u3_atom key, + u3_atom blk) + { + c3_y key_y[16]; + u3r_bytes(0, 16, key_y, key); + return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecba_en); + } + + u3_noun + u3wea_ecba_en(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("ecba-en", _cqea_ecba_en(a, b)); + } + } + + static u3_atom + _cqea_ecba_de(u3_atom key, + u3_atom blk) + { + c3_y key_y[16]; + u3r_bytes(0, 16, key_y, key); + return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecba_de); + } + + u3_noun + u3wea_ecba_de(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("ecba-de", _cqea_ecba_de(a, b)); + } + } + + static u3_atom + _cqea_ecbb_en(u3_atom key, + u3_atom blk) + { + c3_y key_y[24]; + u3r_bytes(0, 24, key_y, key); + return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbb_en); + } + + u3_noun + u3wea_ecbb_en(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("ecbb-en", _cqea_ecbb_en(a, b)); + } + } + + static u3_atom + _cqea_ecbb_de(u3_atom key, + u3_atom blk) + { + c3_y key_y[24]; + u3r_bytes(0, 24, key_y, key); + return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbb_de); + } + + u3_noun + u3wea_ecbb_de(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("ecbb-de", _cqea_ecbb_de(a, b)); + } + } + + static u3_atom + _cqea_ecbc_en(u3_atom key, + u3_atom blk) + { + c3_y key_y[32]; + u3r_bytes(0, 32, key_y, key); + return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbc_en); + } + + u3_noun + u3wea_ecbc_en(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("ecbc-en", _cqea_ecbc_en(a, b)); + } + } + + static u3_atom + _cqea_ecbc_de(u3_atom key, + u3_atom blk) + { + c3_y key_y[32]; + u3r_bytes(0, 32, key_y, key); + return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbc_de); + } + + u3_noun + u3wea_ecbc_de(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("ecbc-de", _cqea_ecbc_de(a, b)); + } + } diff --git a/vere/pkg/noun/jets/e/aes_siv.c b/vere/pkg/noun/jets/e/aes_siv.c new file mode 100644 index 0000000..f88ba6a --- /dev/null +++ b/vere/pkg/noun/jets/e/aes_siv.c @@ -0,0 +1,370 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + +typedef int (*urcrypt_siv)(c3_y*, size_t, + urcrypt_aes_siv_data*, size_t, + c3_y*, c3_y[16], c3_y*); + + +// soc_w = number of items +// mat_w = size in bytes of assoc array +// dat_w = size of allocation (array + atom storage) +static void +_cqea_measure_ads(u3_noun ads, c3_w* soc_w, c3_w *mat_w, c3_w *dat_w) +{ + u3_noun i, t; + c3_w a_w, b_w, tmp_w; + + for ( a_w = b_w = 0, t = ads; u3_nul != t; ++a_w ) { + u3x_cell(t, &i, &t); + if ( c3n == u3ud(i) ) { + u3m_bail(c3__exit); + return; + } + else { + tmp_w = b_w; + b_w += u3r_met(3, i); + if ( b_w < tmp_w ) { + u3m_bail(c3__fail); + return; + } + } + } + + // check for size overflows + tmp_w = a_w * sizeof(urcrypt_aes_siv_data); + if ( (tmp_w / a_w) != sizeof(urcrypt_aes_siv_data) ) { + u3m_bail(c3__fail); + } + else if ( (*dat_w = tmp_w + b_w) < tmp_w ) { + u3m_bail(c3__fail); + } + else { + *soc_w = a_w; + *mat_w = tmp_w; + } +} + +// assumes ads is a valid (list @) because it's already been measured +static void +_cqea_encode_ads(u3_noun ads, + c3_w mat_w, + urcrypt_aes_siv_data *dat_u) +{ + c3_w met_w; + u3_noun i, t; + urcrypt_aes_siv_data *cur_u; + c3_y *dat_y = ((c3_y*) dat_u) + mat_w; + + for ( cur_u = dat_u, t = ads; u3_nul != t; t = u3t(t), ++cur_u ) { + i = u3h(t); + met_w = u3r_met(3, i); + u3r_bytes(0, met_w, dat_y, i); + cur_u->length = met_w; + cur_u->bytes = dat_y; + dat_y += met_w; + } +} + +static void +_cqea_ads_free(urcrypt_aes_siv_data *dat_u) +{ + if ( NULL != dat_u ) { + u3a_free(dat_u); + } +} + +static urcrypt_aes_siv_data* +_cqea_ads_alloc(u3_noun ads, c3_w *soc_w) +{ + if ( !ads ) { + *soc_w = 0; + return NULL; + } + else { + c3_w mat_w, dat_w; + urcrypt_aes_siv_data *dat_u; + + _cqea_measure_ads(ads, soc_w, &mat_w, &dat_w); + dat_u = u3a_malloc(dat_w); + _cqea_encode_ads(ads, mat_w, dat_u); + return dat_u; + } +} + +static u3_noun +_cqea_siv_en(c3_y* key_y, + c3_w key_w, + u3_noun ads, + u3_atom txt, + urcrypt_siv low_f) +{ + u3_noun ret; + c3_w txt_w, soc_w; + c3_y *txt_y, *out_y, iv_y[16]; + urcrypt_aes_siv_data *dat_u; + + dat_u = _cqea_ads_alloc(ads, &soc_w); + txt_y = u3r_bytes_all(&txt_w, txt); + out_y = u3a_malloc(txt_w); + + ret = ( 0 != (*low_f)(txt_y, txt_w, dat_u, soc_w, key_y, iv_y, out_y) ) + ? u3_none + : u3nt(u3i_bytes(16, iv_y), + u3i_words(1, &txt_w), + u3i_bytes(txt_w, out_y)); + + u3a_free(txt_y); + u3a_free(out_y); + _cqea_ads_free(dat_u); + return ret; +} + +static u3_noun +_cqea_siv_de(c3_y* key_y, + c3_w key_w, + u3_noun ads, + u3_atom iv, + u3_atom len, + u3_atom txt, + urcrypt_siv low_f) +{ + c3_w txt_w; + if ( !u3r_word_fit(&txt_w, len) ) { + return u3m_bail(c3__fail); + } + else { + u3_noun ret; + c3_w soc_w; + c3_y *txt_y, *out_y, iv_y[16]; + urcrypt_aes_siv_data *dat_u; + + u3r_bytes(0, 16, iv_y, iv); + dat_u = _cqea_ads_alloc(ads, &soc_w); + txt_y = u3r_bytes_alloc(0, txt_w, txt); + out_y = u3a_malloc(txt_w); + + if ( 0 != (*low_f)(txt_y, txt_w, dat_u, soc_w, key_y, iv_y, out_y) ) { + return u3m_bail(c3__evil); + } + + ret = u3nc(0, u3i_bytes(txt_w, out_y)); + + u3a_free(txt_y); + u3a_free(out_y); + _cqea_ads_free(dat_u); + + return ret; + } +} + +// the siv* hoon doesn't explicitly check keysizes, but all of these functions +// have fixed maximum keysizes, so we will punt if we get a key that is too +// large. + +static u3_noun +_cqea_siva_en(u3_atom key, + u3_noun ads, + u3_atom txt) +{ + if ( u3r_met(3, key) > 32 ) { + return u3_none; + } + else { + c3_y key_y[32]; + u3r_bytes(0, 32, key_y, key); + return _cqea_siv_en(key_y, 32, ads, txt, &urcrypt_aes_siva_en); + } +} + +u3_noun +u3wea_siva_en(u3_noun cor) +{ + u3_noun key, ads, txt; + + if ( c3n == u3r_mean(cor, u3x_sam, &txt, + u3x_con_sam_2, &key, + u3x_con_sam_3, &ads, 0) || + c3n == u3ud(key) || + c3n == u3ud(txt) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("siva-en", _cqea_siva_en(key, ads, txt)); + } +} + +static u3_noun +_cqea_siva_de(u3_atom key, + u3_noun ads, + u3_atom iv, + u3_atom len, + u3_atom txt) +{ + if ( u3r_met(3, key) > 32 ) { + return u3_none; + } + else { + c3_y key_y[32]; + u3r_bytes(0, 32, key_y, key); + return _cqea_siv_de(key_y, 32, ads, iv, len, txt, &urcrypt_aes_siva_de); + } +} + +u3_noun +u3wea_siva_de(u3_noun cor) +{ + u3_noun key, ads, iv, len, txt; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &iv, + u3x_sam_6, &len, + u3x_sam_7, &txt, + u3x_con_sam_2, &key, + u3x_con_sam_3, &ads, 0) || + c3n == u3ud(key) || + c3n == u3ud(txt) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("siva-de", _cqea_siva_de(key, ads, iv, len, txt)); + } +} + +static u3_noun +_cqea_sivb_en(u3_atom key, + u3_noun ads, + u3_atom txt) +{ + if ( u3r_met(3, key) > 48 ) { + return u3_none; + } + else { + c3_y key_y[48]; + u3r_bytes(0, 48, key_y, key); + return _cqea_siv_en(key_y, 48, ads, txt, &urcrypt_aes_sivb_en); + } +} + + +u3_noun +u3wea_sivb_en(u3_noun cor) +{ + u3_noun key, ads, txt; + + if ( c3n == u3r_mean(cor, u3x_sam, &txt, + u3x_con_sam_2, &key, + u3x_con_sam_3, &ads, 0) || + c3n == u3ud(key) || + c3n == u3ud(txt) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("sivb-en", _cqea_sivb_en(key, ads, txt)); + } +} + +static u3_noun +_cqea_sivb_de(u3_atom key, + u3_noun ads, + u3_atom iv, + u3_atom len, + u3_atom txt) +{ + if ( u3r_met(3, key) > 48 ) { + return u3_none; + } + else { + c3_y key_y[48]; + u3r_bytes(0, 48, key_y, key); + return _cqea_siv_de(key_y, 48, ads, iv, len, txt, &urcrypt_aes_sivb_de); + } +} + +u3_noun +u3wea_sivb_de(u3_noun cor) +{ + u3_noun key, ads, iv, len, txt; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &iv, + u3x_sam_6, &len, + u3x_sam_7, &txt, + u3x_con_sam_2, &key, + u3x_con_sam_3, &ads, 0) || + c3n == u3ud(key) || + c3n == u3ud(txt) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("sivb-de", _cqea_sivb_de(key, ads, iv, len, txt)); + } +} + +static u3_noun +_cqea_sivc_en(u3_atom key, + u3_noun ads, + u3_atom txt) +{ + if ( u3r_met(3, key) > 64 ) { + return u3_none; + } + else { + c3_y key_y[64]; + u3r_bytes(0, 64, key_y, key); + return _cqea_siv_en(key_y, 64, ads, txt, &urcrypt_aes_sivc_en); + } +} + +u3_noun +u3wea_sivc_en(u3_noun cor) +{ + u3_noun key, ads, txt; + + if ( c3n == u3r_mean(cor, u3x_sam, &txt, + u3x_con_sam_2, &key, + u3x_con_sam_3, &ads, 0) || + c3n == u3ud(key) || + c3n == u3ud(txt) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("sivc-en", _cqea_sivc_en(key, ads, txt)); + } +} + +static u3_noun +_cqea_sivc_de(u3_atom key, + u3_noun ads, + u3_atom iv, + u3_atom len, + u3_atom txt) +{ + if ( u3r_met(3, key) > 64 ) { + return u3_none; + } + else { + c3_y key_y[64]; + u3r_bytes(0, 64, key_y, key); + return _cqea_siv_de(key_y, 64, ads, iv, len, txt, &urcrypt_aes_sivc_de); + } +} + +u3_noun +u3wea_sivc_de(u3_noun cor) +{ + u3_noun key, ads, iv, len, txt; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &iv, + u3x_sam_6, &len, + u3x_sam_7, &txt, + u3x_con_sam_2, &key, + u3x_con_sam_3, &ads, 0) || + c3n == u3ud(key) || + c3n == u3ud(txt) ) { + return u3m_bail(c3__exit); + } else { + return u3l_punt("sivc-de", _cqea_sivc_de(key, ads, iv, len, txt)); + } +} diff --git a/vere/pkg/noun/jets/e/argon2.c b/vere/pkg/noun/jets/e/argon2.c new file mode 100644 index 0000000..e52d42c --- /dev/null +++ b/vere/pkg/noun/jets/e/argon2.c @@ -0,0 +1,151 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + +/* helpers +*/ + + static int + argon2_alloc(uint8_t** output, size_t bytes) + { + *output = u3a_malloc(bytes); + return 1; + } + + static void + argon2_free(uint8_t* memory, size_t bytes) + { + u3a_free(memory); + } + + static c3_t + _cqear_unpack_type(c3_y* out, u3_atom in) + { + switch ( in ) { + default: + return 0; + case c3__d: + *out = urcrypt_argon2_d; + return 1; + case c3__i: + *out = urcrypt_argon2_i; + return 1; + case c3__id: + *out = urcrypt_argon2_id; + return 1; + case c3__u: + *out = urcrypt_argon2_u; + return 1; + } + } + + + static u3_atom + _cqe_argon2( // configuration params, + u3_atom out, u3_atom type, u3_atom version, + u3_atom threads, u3_atom mem_cost, u3_atom time_cost, + u3_atom wik, u3_atom key, u3_atom wix, u3_atom extra, + // input params + u3_atom wid, u3_atom dat, u3_atom wis, u3_atom sat ) + { + c3_y typ_u; + c3_w out_w, wik_w, wix_w, wid_w, wis_w, ver_w, ted_w, mem_w, tim_w; + + if ( !(u3r_word_fit(&out_w, out) && + u3r_word_fit(&wik_w, wik) && + u3r_word_fit(&wix_w, wix) && + u3r_word_fit(&wid_w, wid) && + u3r_word_fit(&wis_w, wis)) ) { + // too big to allocate + return u3m_bail(c3__fail); + } + else if ( !(_cqear_unpack_type(&typ_u, type) && + u3r_word_fit(&ver_w, version) && + u3r_word_fit(&ted_w, threads) && + u3r_word_fit(&mem_w, mem_cost) && + u3r_word_fit(&tim_w, time_cost)) ) { + return u3_none; + } + else { + u3_atom ret; + c3_y *key_y = u3r_bytes_alloc(0, wik_w, key), + *ex_y = u3r_bytes_alloc(0, wix_w, extra), + *dat_y = u3r_bytes_alloc(0, wid_w, dat), + *sat_y = u3r_bytes_alloc(0, wis_w, sat), + *out_y = u3a_malloc(out_w); + + const c3_c* err_c = urcrypt_argon2( + typ_u, ver_w, ted_w, mem_w, tim_w, + wik_w, key_y, + wix_w, ex_y, + wid_w, dat_y, + wis_w, sat_y, + out_w, out_y, + &argon2_alloc, + &argon2_free); + + u3a_free(key_y); + u3a_free(ex_y); + u3a_free(dat_y); + u3a_free(sat_y); + + if ( NULL == err_c ) { + ret = u3i_bytes(out_w, out_y); + } + else { + ret = u3_none; + u3l_log("argon2-error: %s", err_c); + } + + u3a_free(out_y); + return ret; + } + } + + u3_noun + u3we_argon2(u3_noun cor) + { + u3_noun // configuration params + out, type, version, + threads, mem_cost, time_cost, + wik, key, wix, extra, + // input params + wid, dat, wis, sat, + // for use during unpacking + wmsg, wsat, arg, brg, wkey, wext; + + // the hoon code for argon2 takes configuration parameters, + // and then produces a gate. we jet that inner gate. + // this does mean that the config params have gotten buried + // pretty deep in the subject, hence the +510. + if ( c3n == u3r_mean(cor, u3x_sam_2, &wmsg, + u3x_sam_3, &wsat, + 510, &arg, 0) || + u3r_cell(wmsg, &wid, &dat) || u3ud(wid) || u3ud(dat) || + u3r_cell(wsat, &wis, &sat) || u3ud(wis) || u3ud(sat) || + // + u3r_qual(arg, &out, &type, &version, &brg) || + u3ud(out) || u3ud(type) || u3ud(version) || + // + u3r_qual(brg, &threads, &mem_cost, &time_cost, &arg) || + u3ud(threads) || u3ud(mem_cost) || u3ud(time_cost) || + // + u3r_cell(arg, &wkey, &wext) || + u3r_cell(wkey, &wik, &key) || u3ud(wik) || u3ud(key) || + u3r_cell(wext, &wix, &extra) || u3ud(wix) || u3ud(extra) + ) + { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("argon2", + _cqe_argon2(out, type, version, + threads, mem_cost, time_cost, + wik, key, wix, extra, + wid, dat, wis, sat)); + } + } diff --git a/vere/pkg/noun/jets/e/base.c b/vere/pkg/noun/jets/e/base.c new file mode 100644 index 0000000..8bbc761 --- /dev/null +++ b/vere/pkg/noun/jets/e/base.c @@ -0,0 +1,152 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qe_en_base16(u3_atom len, u3_atom dat) +{ + if ( c3n == u3a_is_cat(len) ) { + return u3m_bail(c3__fail); + } + else { + c3_w len_w = (c3_w)len; + u3i_slab sab_u; + + u3i_slab_bare(&sab_u, 4, len_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + { + c3_y* buf_y = sab_u.buf_y; + c3_y inp_y; + + while ( len_w-- ) { + inp_y = u3r_byte(len_w, dat); + + *buf_y++ = u3s_dit_y[inp_y >> 4]; + *buf_y++ = u3s_dit_y[inp_y & 0xf]; + } + } + + return u3i_slab_moot_bytes(&sab_u); + } +} + +static inline c3_o +_of_hex_digit(c3_y inp_y, c3_y* out_y) +{ + if ( inp_y >= '0' && inp_y <= '9' ) { + *out_y = inp_y - '0'; + return c3y; + } + else if ( inp_y >= 'a' && inp_y <= 'f' ) { + *out_y = inp_y - 87; + return c3y; + } + else if ( inp_y >= 'A' && inp_y <= 'F' ) { + *out_y = inp_y - 55; + return c3y; + } + + return c3n; +} + +static inline c3_o +_of_hex_odd(u3_atom inp, c3_w len_w, c3_w byt_w, c3_y* buf_y) +{ + c3_y low_y, hig_y, lit_y, hit_y; + + hig_y = u3r_byte(--byt_w, inp); + + while ( --len_w ) { + low_y = u3r_byte(--byt_w, inp); + + if ( (c3n == _of_hex_digit(low_y, &lit_y)) + || (c3n == _of_hex_digit(hig_y, &hit_y)) ) + { + return c3n; + } + else { + *buf_y++ = (hit_y & 0xf) ^ (lit_y << 4); + } + + hig_y = u3r_byte(--byt_w, inp); + } + + if ( c3n == _of_hex_digit(hig_y, &hit_y) ) { + return c3n; + } + else { + *buf_y = hit_y & 0xf; + } + + return c3y; +} + +static inline c3_o +_of_hex_even(u3_atom inp, c3_w len_w, c3_y* buf_y) +{ + c3_y lit_y, hit_y; + c3_s inp_s; + + while ( len_w-- ) { + inp_s = u3r_short(len_w, inp); + + if ( (c3n == _of_hex_digit(inp_s & 0xff, &lit_y)) + || (c3n == _of_hex_digit(inp_s >> 8, &hit_y)) ) + { + return c3n; + } + else { + *buf_y++ = (hit_y & 0xf) ^ (lit_y << 4); + } + } + + return c3y; +} + +u3_noun +u3qe_de_base16(u3_atom inp) +{ + c3_w len_w = u3r_met(4, inp); + u3i_slab sab_u; + + u3i_slab_bare(&sab_u, 3, len_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + // even byte-length input can be parsed in aligned, 16-bit increments, + // but odd byte-length input cannot, and is expressed more simply in bytes. + // + { + c3_w byt_w = u3r_met(3, inp); + c3_o ret_o = ( byt_w & 1 ) + ? _of_hex_odd(inp, len_w, byt_w, sab_u.buf_y) + : _of_hex_even(inp, len_w, sab_u.buf_y); + + if ( c3n == ret_o ) { + u3i_slab_free(&sab_u); + return u3_nul; + } + else { + u3_noun dat = u3i_slab_mint_bytes(&sab_u); + return u3nt(u3_nul, u3i_word(len_w), dat); + } + } +} + +u3_noun +u3we_en_base16(u3_noun cor) +{ + u3_noun a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qe_en_base16(u3x_atom(a), u3x_atom(b)); +} + +u3_noun +u3we_de_base16(u3_noun cor) +{ + u3_noun sam = u3x_at(u3x_sam, cor); + return u3qe_de_base16(u3x_atom(sam)); +} diff --git a/vere/pkg/noun/jets/e/blake.c b/vere/pkg/noun/jets/e/blake.c new file mode 100644 index 0000000..cac4c48 --- /dev/null +++ b/vere/pkg/noun/jets/e/blake.c @@ -0,0 +1,163 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqe_blake2b(u3_atom wid, u3_atom dat, + u3_atom wik, u3_atom dak, + u3_atom out) + { + c3_w wid_w; + if ( !u3r_word_fit(&wid_w, wid) ) { + // impossible to represent an atom this large + return u3m_bail(c3__fail); + } + else { + // the hoon adjusts these widths to its liking + int err; + c3_y out_y[64], dak_y[64]; + c3_w wik_w = c3_min(wik, 64), + out_w = c3_max(1, c3_min(out, 64)); + c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat); + + u3r_bytes(0, wik_w, dak_y, dak); + err = urcrypt_blake2(wid_w, dat_y, wik_w, dak_y, out_w, out_y); + u3a_free(dat_y); + + if ( 0 == err ) { + return u3i_bytes(out_w, out_y); + } + else { + return u3_none; + } + } + } + + u3_noun + u3we_blake2b(u3_noun cor) + { + u3_noun msg, key, out, // arguments + wid, dat, // destructured msg + wik, dak; // destructured key + + if ( c3n == u3r_mean(cor, u3x_sam_2, &msg, + u3x_sam_6, &key, + u3x_sam_7, &out, 0) || + u3r_cell(msg, &wid, &dat) || u3ud(wid) || u3ud(dat) || + u3r_cell(key, &wik, &dak) || u3ud(wik) || u3ud(dak) || + u3ud(out) ) + { + return u3m_bail(c3__exit); + } else { + return u3l_punt("blake2b", _cqe_blake2b(wid, dat, wik, dak, out)); + } + } + + static u3_atom + _cqe_blake3_hash(u3_atom wid, u3_atom dat, + u3_atom key, u3_atom flags, u3_atom out) + { + c3_w wid_w, out_w; + if ( !u3r_word_fit(&wid_w, wid) || !u3r_word_fit(&out_w, out) ) { + return u3m_bail(c3__fail); + } + else { + c3_y key_y[32]; + u3r_bytes(0, 32, key_y, key); + c3_y flags_y = u3r_byte(0, flags); + c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat); + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 3, out_w); + c3_y* out_y = sab_u.buf_y; + urcrypt_blake3_hash(wid_w, dat_y, key_y, flags_y, out, out_y); + u3a_free(dat_y); + return u3i_slab_mint(&sab_u); + } + } + + u3_noun + u3we_blake3_hash(u3_noun cor) + { + u3_noun out, msg, // arguments + wid, dat, // destructured msg + sam, key, flags; // context + + if ( c3n == u3r_mean(cor, u3x_sam_2, &out, + u3x_sam_3, &msg, + u3x_con_sam, &sam, 0) || + u3ud(out) || + u3r_cell(msg, &wid, &dat) || u3ud(wid) || u3ud(dat) || + u3r_cell(sam, &key, &flags) || u3ud(key) || u3ud(flags) ) + { + return u3m_bail(c3__exit); + } else { + return u3l_punt("blake3_hash", _cqe_blake3_hash(wid, dat, key, flags, out)); + } + } + + static u3_noun + _cqe_blake3_chunk_output(u3_atom wid, u3_atom dat, u3_atom cv, u3_atom counter, u3_atom flags) + { + c3_w wid_w; + if ( !u3r_word_fit(&wid_w, wid) ) { + return u3m_bail(c3__fail); + } else { + c3_y cv_y[32], block_y[64], block_len; + c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat); + c3_d counter_d = u3r_chub(0, counter); + c3_y flags_y = u3r_byte(0, flags); + u3r_bytes(0, 32, cv_y, cv); + urcrypt_blake3_chunk_output(wid_w, dat_y, cv_y, block_y, &block_len, &counter_d, &flags_y); + return u3i_cell(u3i_bytes(32, cv_y), u3i_qual(u3k(counter), u3i_bytes(64, block_y), block_len, flags_y)); + } + } + + u3_noun + u3we_blake3_chunk_output(u3_noun cor) + { + u3_noun counter, msg, // arguments + wid, dat, // destructured msg + key, flags; // context + + if ( c3n == u3r_mean(cor, u3x_sam_2, &counter, + u3x_sam_3, &msg, + u3x_con_sam_2, &key, + u3x_con_sam_3, &flags, 0) || + u3r_cell(msg, &wid, &dat) || u3ud(wid) || u3ud(dat) || + u3ud(key) || u3ud(flags)) + { + return u3m_bail(c3__exit); + } else { + return u3l_punt("blake3_chunk_output", _cqe_blake3_chunk_output(wid, dat, key, counter, flags)); + } + } + + static u3_atom + _cqe_blake3_compress(u3_atom cv, u3_atom counter, + u3_atom block, u3_atom block_len, u3_atom flags) + { + c3_y cv_y[32], block_y[64], out_y[64]; + u3r_bytes(0, 32, cv_y, cv); + u3r_bytes(0, 64, block_y, block); + urcrypt_blake3_compress(cv_y, block_y, block_len, counter, flags, out_y); + return u3i_bytes(64, out_y); + } + + u3_noun + u3we_blake3_compress(u3_noun cor) + { + u3_noun output = u3x_at(u3x_sam, cor); + u3_noun cv, counter, block, block_len, flags; // destructured output + + if ( u3r_quil(output, &cv, &counter, &block, &block_len, &flags) || + u3ud(cv) || u3ud(block) || u3ud(block_len) || u3ud(counter) || u3ud(flags)) + { + return u3m_bail(c3__exit); + } else { + return u3l_punt("blake3_compress", _cqe_blake3_compress(cv, counter, block, block_len, flags)); + } + } diff --git a/vere/pkg/noun/jets/e/bytestream.c b/vere/pkg/noun/jets/e/bytestream.c new file mode 100644 index 0000000..71761e1 --- /dev/null +++ b/vere/pkg/noun/jets/e/bytestream.c @@ -0,0 +1,1247 @@ +#include <types.h> +#include <imprison.h> +#include <jets/k.h> +#include <nock.h> +#include <retrieve.h> +#include <xtract.h> +#include <log.h> + +// XX do not crash on indirect atoms, but default to Hoon +// XX use u3i_word to imprison all indirect atoms +// +static void +_x_octs(u3_noun octs, u3_atom* p_octs, u3_atom* q_octs) { + + if (c3n == u3r_mean(octs, + 2, p_octs, + 3, q_octs, 0)){ + u3m_bail(c3__exit); + } + + if (c3n == u3a_is_atom(*p_octs) || + c3n == u3a_is_atom(*q_octs)) { + u3m_bail(c3__exit); + } +} +static c3_o +_x_octs_buffer(u3_atom* p_octs, u3_atom *q_octs, + c3_w* p_octs_w, c3_y** buf_y, + c3_w* len_w, c3_w* lead_w) +{ + if (c3n == u3r_safe_word(*p_octs, p_octs_w)) { + return c3n; + } + + *len_w = u3r_met(3, *q_octs); + + if (c3y == u3a_is_cat(*q_octs)) { + *buf_y = (c3_y*)q_octs; + } + else { + u3a_atom* ptr_a = u3a_to_ptr(*q_octs); + *buf_y = (c3_y*)ptr_a->buf_w; + } + + *lead_w = 0; + + if (*p_octs_w > *len_w) { + *lead_w = *p_octs_w - *len_w; + } + else { + *len_w = *p_octs_w; + } + + return c3y; +} + +u3_noun +_qe_bytestream_rip_octs(u3_atom p_octs, u3_atom q_octs) { + + c3_w p_octs_w, len_w, lead_w; + c3_y* buf_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &buf_y, + &len_w, &lead_w)){ + return u3_none; + } + + if (p_octs_w == 0) { + return u3_nul; + } + + u3_noun rip = u3_nul; + + while (lead_w--) { + rip = u3nc(0x0, rip); + } + + buf_y += len_w - 1; + + while (len_w--) { + rip = u3nc(*(buf_y--), rip); + } + + return rip; +} + +u3_noun +u3we_bytestream_rip_octs(u3_noun cor){ + + u3_noun sam = u3x_at(u3x_sam, cor); + + u3_atom p_octs, q_octs; + _x_octs(sam, &p_octs, &q_octs); + + return _qe_bytestream_rip_octs(p_octs, q_octs); + +} + +u3_noun +_qe_bytestream_cat_octs(u3_noun octs_a, u3_noun octs_b) { + + u3_atom p_octs_a, p_octs_b; + u3_atom q_octs_a, q_octs_b; + + _x_octs(octs_a, &p_octs_a, &q_octs_a); + _x_octs(octs_b, &p_octs_b, &q_octs_b); + + c3_w p_octs_a_w, p_octs_b_w; + c3_w len_w, lem_w; + c3_w lead_w, leaf_w; + + c3_y* sea_y; + c3_y* seb_y; + + if (c3n == _x_octs_buffer(&p_octs_a, &q_octs_a, + &p_octs_a_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + if (c3n == _x_octs_buffer(&p_octs_b, &q_octs_b, + &p_octs_b_w, &seb_y, + &lem_w, &leaf_w)) { + return u3_none; + } + + if (p_octs_a_w == 0) { + return u3k(octs_b); + } + + if (p_octs_b_w == 0) { + return u3k(octs_a); + } + + c3_d p_octs_d = p_octs_a_w + p_octs_b_w; + + u3_noun ret; + + // Both a and b are 0. + // + if (len_w == 0 && lem_w == 0) { + ret = u3nc(u3i_chub(p_octs_d), u3i_word(0)); + } + else { + u3i_slab sab_u; + + u3i_slab_bare(&sab_u, 3, (c3_d)p_octs_a_w + lem_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + memcpy(sab_u.buf_y, sea_y, len_w); + memset(sab_u.buf_y + len_w, 0, lead_w); + memcpy(sab_u.buf_y + p_octs_a_w, seb_y, lem_w); + + u3_noun q_octs = u3i_slab_moot(&sab_u); + ret = u3nc(u3i_chub(p_octs_d), q_octs); + } + return ret; +} + +u3_noun +u3we_bytestream_cat_octs(u3_noun cor) { + + u3_noun octs_a, octs_b; + + u3x_mean(cor, u3x_sam_2, &octs_a, u3x_sam_3, &octs_b, 0); + + return _qe_bytestream_cat_octs(octs_a, octs_b); + +} + +u3_noun +_qe_bytestream_can_octs(u3_noun octs_list) { + + if (u3_nul == octs_list) { + return u3nc(0, 0); + } + + if (u3_nul == u3t(octs_list)) { + return u3k(u3h(octs_list)); + } + + /* We can octs in two steps: + * first loop iteration computes the total required + * buffer size in bytes, factoring in the leading bytes + * of the final octs. The second loop iterates over each octs, + * copying the data to the output buffer. + */ + + // Compute total size + // + c3_d tot_d = 0; + + u3_noun octs_list_start = octs_list; + u3_noun octs = u3_none; + // Last non-zero octs + u3_noun last_octs = u3_none; + + while (octs_list != u3_nul) { + + octs = u3h(octs_list); + + if (c3n == u3a_is_atom(u3h(octs)) || + c3n == u3a_is_atom(u3t(octs))) { + u3m_bail(c3__exit); + } + c3_w p_octs_w; + + if (c3n == u3r_safe_word(u3h(octs), &p_octs_w)) { + u3z(octs_list); + return u3_none; + } + // Check for overflow + // + if ( p_octs_w > (UINT64_MAX - tot_d)){ + return u3_none; + } + tot_d += p_octs_w; + + octs_list = u3t(octs_list); + } + + // Compute leading zeros of last non-zero octs -- the buffer + // size is decreased by this much. + // + // =leading-zeros (sub p.octs (met 3 q.octs)) + // + // p.octs fits into a word -- this has been verified + // in the loop above. + // + // The resulting buf_len_w is correct only if the last + // octs is non-zero: but at the return u3i_slab_mint + // takes care of trimming. + // + c3_w last_lead_w = (u3r_word(0, u3h(octs)) - u3r_met(3, u3t(octs))); + c3_d buf_len_w = tot_d - last_lead_w; + + if (buf_len_w == 0) { + return u3nc(u3i_word(tot_d), 0); + } + + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 3, buf_len_w); + c3_y* buf_y = sab_u.buf_y; + + sab_u.buf_w[sab_u.len_w - 1] = 0; + + c3_y* sea_y; + u3_atom p_octs, q_octs; + c3_w p_octs_w, q_octs_w; + c3_w len_w, lead_w; + + // Bytes written so far + // + c3_d wit_d = 0; + + octs_list = octs_list_start; + + while (octs_list != u3_nul) { + + octs = u3h(octs_list); + + _x_octs(octs, &p_octs, &q_octs); + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)){ + return u3_none; + } + + if (p_octs_w == 0) { + octs_list = u3t(octs_list); + continue; + } + + memcpy(buf_y, sea_y, len_w); + buf_y += len_w; + wit_d += len_w; + + // More bytes to follow, write leading zeros + // + if (wit_d < buf_len_w) { + memset(buf_y, 0, lead_w); + buf_y += lead_w; + wit_d += lead_w; + } + + octs_list = u3t(octs_list); + } + + u3_assert((buf_y - sab_u.buf_y) == buf_len_w); + + return u3nc(u3i_chub(tot_d), u3i_slab_mint(&sab_u)); +} + +u3_noun +u3we_bytestream_can_octs(u3_noun cor) +{ + u3_noun octs_list; + + u3x_mean(cor, u3x_sam_1, &octs_list, 0); + + return _qe_bytestream_can_octs(octs_list); +} +u3_noun +_qe_bytestream_skip_line(u3_atom pos, u3_noun octs) +{ + c3_w pos_w; + + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + while (pos_w < len_w) { + if (*(sea_y + pos_w) == '\n') { + break; + } + pos_w++; + } + // Newline not found, position at the end + if (*(sea_y + pos_w) != '\n') { + pos_w = p_octs; + } + else { + pos_w++; + } + + return u3nc(u3i_word(pos_w), u3k(octs)); +} +u3_noun +u3we_bytestream_skip_line(u3_noun cor) +{ + + u3_atom pos; + u3_noun octs; + + u3x_mean(cor, u3x_sam_2, &pos, u3x_sam_3, &octs, 0); + + return _qe_bytestream_skip_line(pos, octs); + +} +u3_noun +_qe_bytestream_find_byte(u3_atom bat, u3_atom pos, u3_noun octs) +{ + c3_w bat_w, pos_w; + + if (c3n == u3r_safe_word(bat, &bat_w) || bat_w > 0xff) { + return u3_none; + } + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + while (pos_w < len_w) { + + if (*(sea_y + pos_w) == bat_w) { + return u3nc(u3_nul, u3i_word(pos_w)); + } + + pos_w++; + } + // Here we are sure that: + // (1) bat_w has not been found + // (2) therefore pos_w == len_w + // + // If bat_w == 0, and there is still input + // in the stream, it means pos_w points at + // the first leading zero. + // + if (pos_w < p_octs && bat_w == 0) { + return u3nc(u3_nul, u3i_word(pos_w)); + } + + return u3_nul; +} +u3_noun +u3we_bytestream_find_byte(u3_noun cor) +{ + u3_atom bat; + u3_atom pos; + u3_noun octs; + + u3x_mean(cor, u3x_sam_2, &bat, + u3x_sam_6, &pos, + u3x_sam_7, &octs, 0); + + return _qe_bytestream_find_byte(bat, pos, octs); +} +u3_noun +_qe_bytestream_seek_byte(u3_atom bat, u3_atom pos, u3_noun octs) +{ + c3_w bat_w, pos_w; + + if (c3n == u3r_safe_word(bat, &bat_w) || bat_w > 0xff) { + return u3_none; + } + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + while (pos_w < len_w) { + + if (*(sea_y + pos_w) == bat_w) { + u3_noun idx = u3nc(u3_nul, u3i_word(pos_w)); + u3_noun new_bays = u3nc(u3i_word(pos_w), u3k(octs)); + return u3nc(idx, new_bays); + } + + pos_w++; + } + + // find leading zero: see comment in *_find_byte + // + if (pos_w < p_octs && bat_w == 0) { + u3_noun idx = u3nc(u3_nul, u3i_word(pos_w)); + u3_noun new_bays = u3nc(u3i_word(pos_w), u3k(octs)); + return u3nc(idx, new_bays); + } + + return u3nc(u3_nul, u3nc(u3k(pos), u3k(octs))); + +} +u3_noun +u3we_bytestream_seek_byte(u3_noun cor) +{ + u3_atom bat; + u3_atom pos; + u3_noun octs; + + u3x_mean(cor, u3x_sam_2, &bat, + u3x_sam_6, &pos, + u3x_sam_7, &octs, 0); + + return _qe_bytestream_seek_byte(bat, pos, octs); +} + +u3_noun +_qe_bytestream_read_byte(u3_atom pos, u3_noun octs) +{ + c3_w pos_w; + + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + if (pos_w + 1 > p_octs_w) { + u3m_bail(c3__exit); + } + + c3_y bat_y; + + if (pos_w < len_w) { + bat_y = *(sea_y + pos_w); + } + else { + bat_y = 0; + } + + u3_noun new_bays = u3nc(u3i_word(pos_w + 1), u3k(octs)); + + return u3nc(bat_y, new_bays); +} + +u3_noun +u3we_bytestream_read_byte(u3_noun cor) +{ + u3_atom pos; + u3_noun octs; + + u3x_mean(cor, u3x_sam_2, &pos, + u3x_sam_3, &octs, 0); + + return _qe_bytestream_read_byte(pos, octs); +} + +u3_noun +_qe_bytestream_read_octs(u3_atom n, u3_atom pos, u3_noun octs) +{ + c3_w n_w, pos_w; + + if (c3n == u3r_safe_word(n, &n_w)) { + return u3_none; + } + + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + if (n_w == 0) { + return u3nc(u3nc(0,0), u3nc(u3k(pos), u3k(octs))); + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + if (pos_w + n_w > p_octs_w) { + u3m_bail(c3__exit); + } + + // Number of bytes to read, excluding leading zeros + // + c3_w red_w = n_w; + + if (pos_w + n_w > len_w) { + if (pos_w < len_w) { + red_w = len_w - pos_w; + } + // leading zeros - nothing to read + // + else { + red_w = 0; + } + } + + u3_noun read_octs; + + if (red_w == 0) { + read_octs = u3nc(u3i_word(n_w), 0); + } + else { + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 3, n_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + memcpy(sab_u.buf_y, sea_y + pos_w, red_w); + + if (red_w < n_w) { + memset(sab_u.buf_y + red_w, 0, (n_w - red_w)); + } + + read_octs = u3nc(u3i_word(n_w), u3i_slab_moot(&sab_u)); + } + + u3_noun new_bays = u3nc(u3i_word(pos_w + n_w), u3k(octs)); + + return u3nc(read_octs, new_bays); +} + +u3_noun +u3we_bytestream_read_octs(u3_noun cor) +{ + u3_atom n; + u3_atom pos; + u3_noun octs; + + u3x_mean(cor, u3x_sam_2, &n, + u3x_sam_6, &pos, + u3x_sam_7, &octs, 0); + + return _qe_bytestream_read_octs(n, pos, octs); +} + + +u3_noun +_qe_peek_octs(c3_w n_w, c3_w pos_w, c3_w p_octs_w, c3_y* sea_y, + c3_w len_w) +{ + if (n_w == 0) { + return u3nc(0, 0); + } + + if (pos_w + n_w > p_octs_w) { + return u3m_bail(c3__exit); + } + + // Read leading zeros only + // + if (pos_w >= len_w) { + return u3nc(u3i_word(n_w), 0); + } + // Number of remaining buffer bytes + c3_w reb_w = len_w - pos_w; + + u3i_slab sab_u; + c3_w my_len_w; + + if (n_w < reb_w) { + my_len_w = n_w; + } + else { + my_len_w = reb_w; + } + u3i_slab_bare(&sab_u, 3, my_len_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + memcpy(sab_u.buf_y, sea_y + pos_w, my_len_w); + + return u3nc(u3i_word(n_w), u3i_slab_moot(&sab_u)); +} +u3_noun _qe_bytestream_chunk(u3_atom size, u3_noun pos, u3_noun octs) +{ + c3_w size_w, pos_w; + + if (c3n == u3r_safe_word(size, &size_w)) { + return u3_none; + } + + if (size_w == 0) { + return u3_nul; + } + + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + u3_noun hun = u3_nul; + + while (pos_w < p_octs) { + // Remaining bytes + // + c3_w rem = (p_octs - pos_w); + + if (rem < size) { + u3_noun octs = _qe_peek_octs(rem, pos_w, p_octs_w, sea_y, + len_w); + hun = u3nc(octs, hun); + pos_w += rem; + } + else { + u3_noun octs = _qe_peek_octs(size, pos_w, p_octs_w, sea_y, + len_w); + hun = u3nc(octs, hun); + pos_w += size; + } + } + + return u3kb_flop(hun); +} + +u3_noun +u3we_bytestream_chunk(u3_noun cor) +{ + u3_atom size; + u3_atom pos; + u3_noun octs; + + u3x_mean(cor, u3x_sam_2, &size, + u3x_sam_6, &pos, + u3x_sam_7, &octs, 0); + + return _qe_bytestream_chunk(size, pos, octs); +} + +u3_noun +_qe_bytestream_extract(u3_noun sea, u3_noun rac) +{ + u3_atom pos; + u3_noun octs; + + u3x_mean(sea, 2, &pos, 3, &octs, 0); + + c3_w pos_w; + + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + u3_noun dal = u3_nul; + + u3_noun new_sea = u3_none; + + while (pos_w < p_octs_w) { + new_sea = u3nc(u3i_word(pos_w), u3k(octs)); + u3_noun ext = u3x_good(u3n_slam_on(u3k(rac), new_sea)); + + u3_atom sip, ken; + c3_w sip_w, ken_w; + + u3x_mean(ext, 2, &sip, 3, &ken, 0); + + if (c3n == u3r_safe_word(sip, &sip_w)) { + // XX is u3z necessary here? + // does memory get freed on bail? + // + u3l_log("bytestream: sip fail"); + u3z(dal); + u3z(ext); + return u3_none; + } + + if (c3n == u3r_safe_word(ken, &ken_w)) { + u3l_log("bytestream: ken fail"); + u3z(dal); + u3z(ext); + return u3_none; + } + + u3z(ext); + + if (sip_w == 0 && ken_w == 0) { + break; + } + + if (pos_w + sip_w > p_octs_w) { + u3z(dal); + return u3_none; + } + + pos_w += sip_w; + + if (ken_w == 0) { + continue; + } + + u3_noun octs = _qe_peek_octs(ken_w, pos_w, p_octs_w, sea_y, len_w); + pos_w += ken_w; + dal = u3nc(octs, dal); + } + + new_sea = u3nc(u3i_word(pos_w), u3k(octs)); + + return u3nc(u3kb_flop(dal), new_sea); +} +u3_noun +u3we_bytestream_extract(u3_noun cor) +{ + u3_noun sea; + u3_noun rac; + + u3x_mean(cor, u3x_sam_2, &sea, + u3x_sam_3, &rac, 0); + + return _qe_bytestream_extract(sea, rac); +} + +u3_noun +_qe_bytestream_fuse_extract(u3_noun sea, u3_noun rac) +{ + u3_atom pos; + u3_noun octs; + + u3x_mean(sea, 2, &pos, 3, &octs, 0); + + c3_w pos_w; + + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + u3_noun dal = u3_nul; + + u3_noun new_sea = u3_none; + + while (pos_w < p_octs_w) { + new_sea = u3nc(u3i_word(pos_w), u3k(octs)); + u3_noun ext = u3x_good(u3n_slam_on(u3k(rac), new_sea)); + + u3_atom sip, ken; + c3_w sip_w, ken_w; + + u3x_mean(ext, 2, &sip, 3, &ken, 0); + + if (c3n == u3r_safe_word(sip, &sip_w)) { + // XX is u3z necessary here? + // does memory get freed on bail? + // + u3l_log("bytestream: sip fail"); + u3z(dal); + u3z(ext); + return u3_none; + } + if (c3n == u3r_safe_word(ken, &ken_w)) { + u3l_log("bytestream: ken fail"); + u3z(dal); + u3z(ext); + return u3_none; + } + + u3z(ext); + + if (sip_w == 0 && ken_w == 0) { + break; + } + + if (pos_w + sip_w > p_octs_w) { + u3z(dal); + return u3_none; + } + + pos_w += sip_w; + + if (ken_w == 0) { + continue; + } + + u3_noun octs = _qe_peek_octs(ken_w, pos_w, p_octs_w, sea_y, len_w); + pos_w += ken_w; + dal = u3nc(octs, dal); + } + + u3_noun lad = u3kb_flop(dal); + u3_noun data = _qe_bytestream_can_octs(lad); + u3z(lad); + + new_sea = u3nc(u3i_word(pos_w), u3k(octs)); + + return u3nc(data, new_sea); +} + +u3_noun +u3we_bytestream_fuse_extract(u3_noun cor) +{ + u3_noun sea; + u3_noun rac; + + u3x_mean(cor, u3x_sam_2, &sea, + u3x_sam_3, &rac, 0); + + return _qe_bytestream_fuse_extract(sea, rac); +} + +#define BITS_D (sizeof(c3_d)*8) + +u3_noun +_qe_bytestream_need_bits(u3_atom n, u3_noun bits) +{ + u3_atom num, bit; + u3_noun bays; + + u3x_mean(bits, 2, &num, + 6, &bit, + 7, &bays, 0); + + + c3_w n_w, num_w; + c3_d bit_d; + + if (c3n == u3r_safe_word(n, &n_w)) { + return u3_none; + } + if (c3n == u3r_safe_word(num, &num_w)) { + return u3_none; + } + if (c3n == u3r_safe_chub(bit, &bit_d)) { + return u3_none; + } + + if (num_w >= n_w) { + return u3k(bits); + } + + // How many bytes to read + // + c3_w need_bits_w = n_w - num_w; + + // Requires indirect atom, drop to Hoon + // + if (need_bits_w > BITS_D) { + return u3_none; + } + + c3_w need_bytes_w = need_bits_w / 8; + + if (need_bits_w % 8) { + need_bytes_w += 1; + } + + c3_w pos_w; + u3_atom pos; + u3_noun octs; + + + u3x_mean(bays, 2, &pos, 3, &octs, 0); + + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + u3_atom p_octs, q_octs; + + _x_octs(octs, &p_octs, &q_octs); + + c3_w p_octs_w; + c3_w len_w, lead_w; + + c3_y* sea_y; + + if (c3n == _x_octs_buffer(&p_octs, &q_octs, + &p_octs_w, &sea_y, + &len_w, &lead_w)) { + return u3_none; + } + + if (pos_w + need_bytes_w > p_octs_w) { + u3m_bail(c3__exit); + } + + while (need_bytes_w--) { + + if (pos_w < len_w) { + bit_d += *(sea_y + pos_w) << num_w; + } + num_w += 8; + pos_w++; + + u3_assert(num_w <= BITS_D); + } + + u3_noun new_bays = u3nc(u3i_word(pos_w), u3k(octs)); + + return u3nt(u3i_word(num_w), u3i_chub(bit_d), new_bays); +} +// +$ bits $+ bits +// $: num=@ud +// bit=@ub +// =bays +// == +u3_noun +u3we_bytestream_need_bits(u3_noun cor) +{ + u3_atom n; + u3_noun bits; + + u3x_mean(cor, u3x_sam_2, &n, + u3x_sam_3, &bits, 0); + + return _qe_bytestream_need_bits(n, bits); +} + +u3_noun +_qe_bytestream_drop_bits(u3_atom n, u3_noun bits) +{ + + u3_atom num, bit; + u3_noun bays; + + u3x_mean(bits, 2, &num, + 6, &bit, + 7, &bays, 0); + + c3_w n_w, num_w; + c3_d bit_d; + + if (c3n == u3r_safe_word(n, &n_w)) { + return u3_none; + } + if (c3n == u3r_safe_word(num, &num_w)) { + return u3_none; + } + if (c3n == u3r_safe_chub(bit, &bit_d)) { + return u3_none; + } + + if(n_w == 0) { + return u3k(bits); + } + + c3_w dop_w = n_w; + + if (dop_w > num_w) { + dop_w = num_w; + } + + bit_d >>= dop_w; + num_w -= dop_w; + + return u3nt(u3i_word(num_w), u3i_chub(bit_d), u3k(bays)); +} +u3_noun +u3we_bytestream_drop_bits(u3_noun cor) +{ + u3_atom n; + u3_noun bits; + + u3x_mean(cor, u3x_sam_2, &n, + u3x_sam_3, &bits, 0); + + return _qe_bytestream_drop_bits(n, bits); +} + +u3_noun +_qe_bytestream_peek_bits(u3_atom n, u3_noun bits) +{ + + u3_atom num, bit; + u3_noun bays; + + u3x_mean(bits, 2, &num, + 6, &bit, + 7, &bays, 0); + + c3_w n_w, num_w; + c3_d bit_d; + + if (c3n == u3r_safe_word(n, &n_w)) { + return u3_none; + } + if (c3n == u3r_safe_word(num, &num_w)) { + return u3_none; + } + if (c3n == u3r_safe_chub(bit, &bit_d)) { + return u3_none; + } + + if (n_w == 0) { + return u3i_word(0); + } + + if (n_w > num_w) { + u3m_bail(c3__exit); + } + + if (n_w > BITS_D) { + return u3_none; + } + + if (n_w == BITS_D) { + return u3i_chub(bit_d); + } + else { + c3_d mak_d = ((c3_d)1 << n_w) - 1; + + return u3i_chub(bit_d & mak_d); + } +} +u3_noun +u3we_bytestream_peek_bits(u3_noun cor) +{ + u3_atom n; + u3_noun bits; + + u3x_mean(cor, u3x_sam_2, &n, + u3x_sam_3, &bits, 0); + + return _qe_bytestream_peek_bits(n, bits); +} + +u3_noun +_qe_bytestream_read_bits(u3_atom n, u3_noun bits) +{ + + u3_atom num, bit; + u3_noun bays; + + u3x_mean(bits, 2, &num, + 6, &bit, + 7, &bays, 0); + + c3_w n_w, num_w; + c3_d bit_d; + + if (c3n == u3r_safe_word(n, &n_w)) { + return u3_none; + } + if (c3n == u3r_safe_word(num, &num_w)) { + return u3_none; + } + if (c3n == u3r_safe_chub(bit, &bit_d)) { + return u3_none; + } + + if (n_w > num_w) { + u3m_bail(c3__exit); + } + + if (n_w > BITS_D) { + return u3_none; + } + + c3_d bet_d = 0; + + if (n_w == BITS_D) { + bet_d = bit_d; + } + else { + c3_d mak_d = ((c3_d)1 << n_w) - 1; + bet_d = bit_d & mak_d; + } + + bit_d >>= n_w; + num_w -= n_w; + + u3_noun new_bits = u3nt(u3i_word(num_w), u3i_chub(bit_d), u3k(bays)); + + return u3nc(u3i_chub(bet_d), new_bits); +} + +u3_noun +u3we_bytestream_read_bits(u3_noun cor) +{ + u3_atom n; + u3_noun bits; + + u3x_mean(cor, u3x_sam_2, &n, + u3x_sam_3, &bits, 0); + + return _qe_bytestream_read_bits(n, bits); +} + +u3_noun +_qe_bytestream_byte_bits(u3_noun bits) +{ + + u3_atom num, bit; + u3_noun bays; + + u3x_mean(bits, 2, &num, + 6, &bit, + 7, &bays, 0); + + c3_w num_w; + c3_d bit_d; + + if (c3n == u3r_safe_word(num, &num_w)) { + return u3_none; + } + if (c3n == u3r_safe_chub(bit, &bit_d)) { + return u3_none; + } + + c3_y rem_y = num_w & 0x7; + + if (rem_y == 0) { + return u3k(bits); + } + + u3_noun new_bits = u3nt(u3i_word(num_w - rem_y), + u3i_chub(bit_d >> rem_y), + u3k(bays)); + + return new_bits; +} + +u3_noun +u3we_bytestream_byte_bits(u3_noun cor) +{ + u3_noun bits; + + u3x_mean(cor, u3x_sam, &bits, 0); + + return _qe_bytestream_byte_bits(bits); +} diff --git a/vere/pkg/noun/jets/e/chacha.c b/vere/pkg/noun/jets/e/chacha.c new file mode 100644 index 0000000..e42f8e2 --- /dev/null +++ b/vere/pkg/noun/jets/e/chacha.c @@ -0,0 +1,74 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqe_chacha_crypt(u3_atom rounds, u3_atom key, u3_atom nonce, u3_atom counter, u3_atom wid, u3_atom dat) + { + c3_w rounds_w, wid_w; + c3_d counter_d; + if ( !u3r_word_fit(&rounds_w, rounds) || !u3r_word_fit(&wid_w, wid) || c3n == u3r_safe_chub(counter, &counter_d) ) { + return u3m_bail(c3__fail); + } + else { + c3_y key_y[32], nonce_y[8]; + u3r_bytes(0, 32, key_y, key); + u3r_bytes(0, 8, nonce_y, nonce); + c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat); + urcrypt_chacha_crypt(rounds_w, key_y, nonce_y, counter_d, wid_w, dat_y); + u3_noun cry = u3i_bytes(wid_w, dat_y); + u3a_free(dat_y); + return u3i_cell(wid, cry); + } + } + + u3_noun + u3we_chacha_crypt(u3_noun cor) + { + u3_noun sam = u3x_at(u3x_sam, cor); + u3_noun rounds, key, nonce, counter, msg; + u3_noun wid, dat; + + if ( u3r_quil(sam, &rounds, &key, &nonce, &counter, &msg) || + u3ud(rounds) || u3ud(key) || u3ud(nonce) || u3ud(counter) || u3r_cell(msg, &wid, &dat) ) + { + return u3m_bail(c3__exit); + } else { + return u3l_punt("chacha_crypt", _cqe_chacha_crypt(rounds, key, nonce, counter, wid, dat)); + } + } + + + static u3_noun + _cqe_chacha_xchacha(u3_atom rounds, u3_atom key, u3_atom nonce) + { + c3_w rounds_w; + if ( !u3r_word_fit(&rounds_w, rounds) ) { + return u3m_bail(c3__fail); + } + c3_y key_y[32], nonce_y[64], xkey_y[32], xnonce_y[8]; + u3r_bytes(0, 32, key_y, key); + u3r_bytes(0, 24, nonce_y, nonce); + urcrypt_chacha_xchacha(rounds, key_y, nonce_y, xkey_y, xnonce_y); + return u3i_cell(u3i_bytes(32, xkey_y), u3i_bytes(8, xnonce_y)); + } + + u3_noun + u3we_chacha_xchacha(u3_noun cor) + { + u3_noun sam = u3x_at(u3x_sam, cor); + u3_noun rounds, key, nonce; + if ( c3n == u3r_trel(sam, &rounds, &key, &nonce) || + c3n == u3ud(rounds) || + c3n == u3ud(key) || + c3n == u3ud(nonce) ) + { + return u3m_bail(c3__exit); + } else { + return u3l_punt("chacha_xchacha", _cqe_chacha_xchacha(rounds, key, nonce)); + } + } diff --git a/vere/pkg/noun/jets/e/crc.c b/vere/pkg/noun/jets/e/crc.c new file mode 100644 index 0000000..496b8d5 --- /dev/null +++ b/vere/pkg/noun/jets/e/crc.c @@ -0,0 +1,59 @@ +/// @file + +#include <stdio.h> +#include <allocate.h> +#include "zlib.h" + +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qe_crc32(u3_noun input_octs) +{ + u3_atom head = u3h(input_octs); + u3_atom tail = u3t(input_octs); + c3_w tel_w = u3r_met(3, tail); + c3_w hed_w; + if ( c3n == u3r_safe_word(head, &hed_w) ) { + return u3m_bail(c3__fail); + } + c3_y* input; + + if (c3y == u3a_is_cat(tail)) { + input = (c3_y*)&tail; + } + else { + u3a_atom* vat_u = u3a_to_ptr(tail); + input = (c3_y*)vat_u->buf_w; + } + + if ( tel_w > hed_w ) { + return u3m_error("subtract-underflow"); + } + + c3_w led_w = hed_w - tel_w; + c3_w crc_w = 0; + + crc_w = crc32(crc_w, input, tel_w); + + while ( led_w > 0 ) { + c3_y byt_y = 0; + crc_w = crc32(crc_w, &byt_y, 1); + led_w--; + } + + return u3i_word(crc_w); +} + +u3_noun +u3we_crc32(u3_noun cor) +{ + u3_noun a = u3r_at(u3x_sam, cor); + + if ( (u3du(a) == c3y) && (u3ud(u3h(a)) == c3y) && (u3ud(u3t(a)) == c3y) ) { + return u3qe_crc32(a); + } else { + return u3m_bail(c3__exit); + } +} diff --git a/vere/pkg/noun/jets/e/cue.c b/vere/pkg/noun/jets/e/cue.c new file mode 100644 index 0000000..643b408 --- /dev/null +++ b/vere/pkg/noun/jets/e/cue.c @@ -0,0 +1,27 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qe_cue(u3_atom a) +{ + return u3s_cue_atom(a); +} + +u3_noun +u3we_cue(u3_noun cor) +{ + return u3qe_cue(u3x_atom(u3x_at(u3x_sam, cor))); +} + +u3_noun +u3ke_cue(u3_atom a) +{ + u3_noun b = u3qe_cue(a); + u3z(a); + return b; +} diff --git a/vere/pkg/noun/jets/e/ed_add_double_scalarmult.c b/vere/pkg/noun/jets/e/ed_add_double_scalarmult.c new file mode 100644 index 0000000..6512919 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_add_double_scalarmult.c @@ -0,0 +1,72 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_add_double_scalarmult(u3_atom a, + u3_atom a_point, + u3_atom b, + u3_atom b_point) + { + c3_y a_y[32], a_point_y[32], + b_y[32], b_point_y[32], + out_y[32]; + c3_w met_w; + + met_w = u3r_met(3, a); + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, a)) ) + ) { + u3_noun a_recs = u3qee_recs(a); + u3r_bytes(0, 32, a_y, a_recs); + u3z(a_recs); + } else { + u3r_bytes(0, 32, a_y, a); + } + + met_w = u3r_met(3, b); + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, b)) ) + ) { + u3_noun b_recs = u3qee_recs(b); + u3r_bytes(0, 32, b_y, b_recs); + u3z(b_recs); + } else { + u3r_bytes(0, 32, b_y, b); + } + + if ( (0 != u3r_bytes_fit(32, a_point_y, a_point)) || + (0 != u3r_bytes_fit(32, b_point_y, b_point)) || + (0 != urcrypt_ed_add_double_scalarmult(a_y, a_point_y, b_y, b_point_y, out_y)) ) { + return u3m_bail(c3__exit); + } + else { + return u3i_bytes(32, out_y); + } + } + + u3_noun + u3wee_add_double_scalarmult(u3_noun cor) + { + u3_noun a, b, c, d; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_6, &b, + u3x_sam_14, &c, + u3x_sam_15, &d, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) || + (c3n == u3ud(c)) || + (c3n == u3ud(d)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqee_add_double_scalarmult(a, b, c, d); + } + } diff --git a/vere/pkg/noun/jets/e/ed_add_scalarmult_scalarmult_base.c b/vere/pkg/noun/jets/e/ed_add_scalarmult_scalarmult_base.c new file mode 100644 index 0000000..39eda53 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_add_scalarmult_scalarmult_base.c @@ -0,0 +1,66 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_add_scalarmult_scalarmult_base(u3_atom a, + u3_atom a_point, + u3_atom b) + { + c3_y a_y[32], a_point_y[32], b_y[32], out_y[32]; + c3_w met_w; + + met_w = u3r_met(3, a); + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, a)) ) + ) { + u3_noun a_recs = u3qee_recs(a); + u3r_bytes(0, 32, a_y, a_recs); + u3z(a_recs); + } else { + u3r_bytes(0, 32, a_y, a); + } + + met_w = u3r_met(3, b); + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, b)) ) + ) { + u3_noun b_recs = u3qee_recs(b); + u3r_bytes(0, 32, b_y, b_recs); + u3z(b_recs); + } else { + u3r_bytes(0, 32, b_y, b); + } + + if ( (0 != u3r_bytes_fit(32, a_point_y, a_point)) || + (0 != urcrypt_ed_add_scalarmult_scalarmult_base(a_y, a_point_y, b_y, out_y)) ) { + return u3m_bail(c3__exit); + } + else { + return u3i_bytes(32, out_y); + } + } + + u3_noun + u3wee_add_scalarmult_scalarmult_base(u3_noun cor) + { + u3_noun a, b, c; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_6, &b, + u3x_sam_7, &c, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) || + (c3n == u3ud(c)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqee_add_scalarmult_scalarmult_base(a, b, c); + } + } diff --git a/vere/pkg/noun/jets/e/ed_luck.c b/vere/pkg/noun/jets/e/ed_luck.c new file mode 100644 index 0000000..c21889e --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_luck.c @@ -0,0 +1,37 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_luck(u3_atom sed) + { + c3_y sed_y[32]; + + if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + else { + c3_y pub_y[32]; + c3_y sec_y[64]; + urcrypt_ed_luck(sed_y, pub_y, sec_y); + return u3nc(u3i_bytes(32, pub_y), u3i_bytes(64, sec_y)); + } + } + + u3_noun + u3wee_luck(u3_noun cor) + { + u3_noun a = u3r_at(u3x_sam, cor); + + if ( (u3_none == a) || (c3n == u3ud(a)) ) { + return u3m_bail(c3__exit); + } + else { + return _cqee_luck(a); + } + } diff --git a/vere/pkg/noun/jets/e/ed_point_add.c b/vere/pkg/noun/jets/e/ed_point_add.c new file mode 100644 index 0000000..70fe563 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_point_add.c @@ -0,0 +1,40 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + + static u3_atom + _cqee_point_add(u3_atom a, + u3_atom b) + { + c3_y a_y[32], b_y[32], out_y[32]; + + if ( (0 != u3r_bytes_fit(32, a_y, a)) || + (0 != u3r_bytes_fit(32, b_y, b)) || + (0 != urcrypt_ed_point_add(a_y, b_y, out_y)) ) { + return u3m_bail(c3__exit); + } + else { + return u3i_bytes(32, out_y); + } + } + + u3_noun + u3wee_point_add(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqee_point_add(a, b); + } + } diff --git a/vere/pkg/noun/jets/e/ed_point_neg.c b/vere/pkg/noun/jets/e/ed_point_neg.c new file mode 100644 index 0000000..5a1a5bd --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_point_neg.c @@ -0,0 +1,37 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + + static u3_atom + _cqee_point_neg(u3_atom a) + { + c3_y a_y[32]; + + if ( (0 != u3r_bytes_fit(32, a_y, a)) || + (0 != urcrypt_ed_point_neg(a_y)) ) { + return u3m_bail(c3__exit); + } + else { + return u3i_bytes(32, a_y); + } + } + + u3_noun + u3wee_point_neg(u3_noun cor) + { + + u3_noun a; + + if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqee_point_neg(a); + } + } diff --git a/vere/pkg/noun/jets/e/ed_puck.c b/vere/pkg/noun/jets/e/ed_puck.c new file mode 100644 index 0000000..98581d7 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_puck.c @@ -0,0 +1,36 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_puck(u3_atom sed) + { + c3_y sed_y[32]; + + if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + else { + c3_y pub_y[32]; + urcrypt_ed_puck(sed_y, pub_y); + return u3i_bytes(32, pub_y); + } + } + + u3_noun + u3wee_puck(u3_noun cor) + { + u3_noun a = u3r_at(u3x_sam, cor); + + if ( (u3_none == a) || (c3n == u3ud(a)) ) { + return u3m_bail(c3__exit); + } + else { + return _cqee_puck(a); + } + } diff --git a/vere/pkg/noun/jets/e/ed_recs.c b/vere/pkg/noun/jets/e/ed_recs.c new file mode 100644 index 0000000..bdcf224 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_recs.c @@ -0,0 +1,48 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + // `@ux`(rev 3 32 l:ed:crypto) + static c3_y _cqee_l_prime[] = { + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + }; + + u3_atom + u3qee_recs(u3_atom a) + { + c3_w met_w = u3r_met(3, a); + + if ( 64 < met_w ) { + u3_atom l_prime = u3i_bytes(32, _cqee_l_prime); + u3_atom pro = u3qa_mod(a, l_prime); + u3z(l_prime); + return pro; + } + + c3_y a_y[64]; + + u3r_bytes(0, 64, a_y, a); + urcrypt_ed_scalar_reduce(a_y); + return u3i_bytes(32, a_y); + } + + u3_noun + u3wee_recs(u3_noun cor) + { + u3_noun a; + + if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qee_recs(a); + } + } diff --git a/vere/pkg/noun/jets/e/ed_scad.c b/vere/pkg/noun/jets/e/ed_scad.c new file mode 100644 index 0000000..af95563 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_scad.c @@ -0,0 +1,124 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_scad(u3_atom pub, u3_atom sek, u3_atom sca) + { + c3_y pub_y[32]; + c3_y sek_y[64]; + c3_y sca_y[32]; + + if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + if ( 0 != u3r_bytes_fit(32, sca_y, sca) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + else { + urcrypt_ed_add_scalar_public_private(pub_y, sek_y, sca_y); + return u3nc(u3i_bytes(32, pub_y), u3i_bytes(64, sek_y)); + } + } + + u3_noun + u3wee_scad(u3_noun cor) + { + u3_noun pub, sek, sca; + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &pub, + u3x_sam_6, &sek, + u3x_sam_7, &sca, 0)) || + (c3n == u3ud(pub)) || + (c3n == u3ud(sek)) || + (c3n == u3ud(sca)) ) { + return u3m_bail(c3__exit); + } + else { + return _cqee_scad(pub, sek, sca); + } + } + + static u3_atom + _cqee_scas(u3_atom sek, u3_atom sca) + { + c3_y sek_y[64]; + c3_y sca_y[32]; + + if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + if ( 0 != u3r_bytes_fit(32, sca_y, sca) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + else { + urcrypt_ed_add_scalar_private(sek_y, sca_y); + return u3i_bytes(64, sek_y); + } + } + + u3_noun + u3wee_scas(u3_noun cor) + { + u3_noun sek, sca; + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &sek, + u3x_sam_3, &sca, 0)) || + (c3n == u3ud(sek)) || + (c3n == u3ud(sca)) ) { + return u3m_bail(c3__exit); + } + else { + return _cqee_scas(sek, sca); + } + } + + static u3_atom + _cqee_scap(u3_atom pub, u3_atom sca) + { + c3_y pub_y[32]; + c3_y sca_y[32]; + + if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + if ( 0 != u3r_bytes_fit(32, sca_y, sca) ) { + // hoon explicitly crashes on mis-size + return u3m_bail(c3__exit); + } + else { + urcrypt_ed_add_scalar_public(pub_y, sca_y); + return u3i_bytes(32, pub_y); + } + } + + u3_noun + u3wee_scap(u3_noun cor) + { + u3_noun pub, sca; + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &pub, + u3x_sam_3, &sca, 0)) || + (c3n == u3ud(pub)) || + (c3n == u3ud(sca)) ) { + return u3m_bail(c3__exit); + } + else { + return _cqee_scap(pub, sca); + } + } + + diff --git a/vere/pkg/noun/jets/e/ed_scalarmult.c b/vere/pkg/noun/jets/e/ed_scalarmult.c new file mode 100644 index 0000000..8585c29 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_scalarmult.c @@ -0,0 +1,54 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_scalarmult(u3_atom a, + u3_atom b) + { + c3_y a_y[32], b_y[32], out_y[32]; + if (0 != u3r_bytes_fit(32, b_y, b)) { + return u3m_bail(c3__exit); + } + + c3_w met_w = u3r_met(3, a); + // scalarmult expects a_y[31] <= 127 + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, a)) ) + ) { + u3_noun a_recs = u3qee_recs(a); + u3r_bytes(0, 32, a_y, a_recs); + u3z(a_recs); + } else { + u3r_bytes(0, 32, a_y, a); + } + + if ( (0 != urcrypt_ed_scalarmult(a_y, b_y, out_y)) ) { + // at this point, will only fail if b is bad point + return u3m_bail(c3__exit); + } + else { + return u3i_bytes(32, out_y); + } + } + + u3_noun + u3wee_scalarmult(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqee_scalarmult(a, b); + } + } diff --git a/vere/pkg/noun/jets/e/ed_scalarmult_base.c b/vere/pkg/noun/jets/e/ed_scalarmult_base.c new file mode 100644 index 0000000..6193584 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_scalarmult_base.c @@ -0,0 +1,46 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_scalarmult_base(u3_atom a) + { + c3_y a_y[32], out_y[32]; + c3_w met_w = u3r_met(3, a); + // scalarmult_base expects a_y[31] <= 127 + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, a)) ) + ) { + u3_noun a_recs = u3qee_recs(a); + u3r_bytes(0, 32, a_y, a_recs); + u3z(a_recs); + } else { + u3r_bytes(0, 32, a_y, a); + } + + if (0 != urcrypt_ed_scalarmult_base(a_y, out_y)) { + // should be unreachable, as scalar already reduced + return u3m_bail(c3__exit); + } + else { + return u3i_bytes(32, out_y); + } + } + + u3_noun + u3wee_scalarmult_base(u3_noun cor) + { + u3_noun a = u3r_at(u3x_sam, cor); + + if ( (u3_none == a) || (c3n == u3ud(a)) ) { + return u3m_bail(c3__exit); + } + else { + return _cqee_scalarmult_base(a); + } + } diff --git a/vere/pkg/noun/jets/e/ed_shar.c b/vere/pkg/noun/jets/e/ed_shar.c new file mode 100644 index 0000000..ed293f7 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_shar.c @@ -0,0 +1,74 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_shar(u3_atom pub, u3_atom sed) + { + c3_y pub_y[32], sed_y[32]; + + if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) { + return u3m_bail(c3__exit); + } + else if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) { + // hoon calls luck, which crashes + return u3m_bail(c3__exit); + } + else { + c3_y shr_y[32]; + urcrypt_ed_shar(pub_y, sed_y, shr_y); + return u3i_bytes(32, shr_y); + } + } + + u3_noun + u3wee_shar(u3_noun cor) + { + u3_noun pub, sed; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &pub, u3x_sam_3, &sed, 0)) || + (c3n == u3ud(pub)) || + (c3n == u3ud(sed)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqee_shar(pub, sed); + } + } + + static u3_atom + _cqee_slar(u3_atom pub, u3_atom sek) + { + c3_y pub_y[32], sek_y[64]; + + if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) { + return u3m_bail(c3__exit); + } + else if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) { + return u3m_bail(c3__exit); + } + else { + c3_y shr_y[32]; + urcrypt_ed_slar(pub_y, sek_y, shr_y); + return u3i_bytes(32, shr_y); + } + } + + u3_noun + u3wee_slar(u3_noun cor) + { + u3_noun pub, sek; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &pub, u3x_sam_3, &sek, 0)) || + (c3n == u3ud(pub)) || + (c3n == u3ud(sek)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqee_slar(pub, sek); + } + } diff --git a/vere/pkg/noun/jets/e/ed_sign.c b/vere/pkg/noun/jets/e/ed_sign.c new file mode 100644 index 0000000..cd1797d --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_sign.c @@ -0,0 +1,166 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" +#include <retrieve.h> +#include <types.h> + + static u3_atom + _cqee_sign_octs(u3_noun len, u3_noun dat, u3_noun sed) + { + c3_y sed_y[32]; + c3_w len_w; + if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) { + // hoon calls luck, which crashes + return u3m_bail(c3__exit); + } + else if ( !u3r_word_fit(&len_w, len) ) { + return u3m_bail(c3__fail); + } + else { + c3_y sig_y[64]; + c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); + urcrypt_ed_sign(dat_y, len_w, sed_y, sig_y); + u3a_free(dat_y); + return u3i_bytes(64, sig_y); + } + } + + u3_noun + u3wee_sign_octs(u3_noun cor) + { + u3_noun msg, sed; + u3_noun len, dat; + if ( c3n == u3r_mean(cor, u3x_sam_2, &msg, u3x_sam_3, &sed, 0) || + c3n == u3r_cell(msg, &len, &dat) || + c3n == u3ud(sed) || + c3n == u3ud(len) || + c3n == u3ud(dat) ) { + return u3m_bail(c3__fail); + } else { + return _cqee_sign_octs(len, dat, sed); + } + } + + static u3_atom + _cqee_sign_octs_raw(u3_noun len, u3_noun dat, u3_noun pub, u3_noun sek) + { + c3_y pub_y[32], sek_y[64]; + c3_w len_w; + if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) { + // hoon asserts size + return u3m_bail(c3__exit); + } + if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) { + // hoon asserts size + return u3m_bail(c3__exit); + } + else if ( !u3r_word_fit(&len_w, len) ) { + return u3m_bail(c3__fail); + } + else { + c3_y sig_y[64]; + c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); + urcrypt_ed_sign_raw(dat_y, len_w, pub_y, sek_y, sig_y); + u3a_free(dat_y); + return u3i_bytes(64, sig_y); + } + } + + u3_noun + u3wee_sign_octs_raw(u3_noun cor) + { + u3_noun msg, pub, sek; + u3_noun len, dat; + if ( c3n == u3r_mean(cor, u3x_sam_2, &msg, u3x_sam_6, &pub, u3x_sam_7, &sek, 0) || + c3n == u3r_cell(msg, &len, &dat) || + c3n == u3ud(pub) || + c3n == u3ud(sek) || + c3n == u3ud(len) || + c3n == u3ud(dat) ) { + return u3m_bail(c3__fail); + } else { + return _cqee_sign_octs_raw(len, dat, pub, sek); + } + } + + static u3_atom + _cqee_sign(u3_noun msg, + u3_noun sed) + { + c3_y sed_y[32]; + + if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) { + // hoon calls luck, which crashes + return u3m_bail(c3__exit); + } + else { + c3_y sig_y[64]; + c3_w met_w; + c3_y* msg_y = u3r_bytes_all(&met_w, msg); + + urcrypt_ed_sign(msg_y, met_w, sed_y, sig_y); + u3a_free(msg_y); + + return u3i_bytes(64, sig_y); + } + } + + u3_noun + u3wee_sign(u3_noun cor) + { + u3_noun msg, sed; + if ( c3n == u3r_mean(cor, + u3x_sam_2, &msg, u3x_sam_3, &sed, 0) || + c3n == u3ud(msg) || + c3n == u3ud(sed) ) { + return u3m_bail(c3__fail); + } else { + return _cqee_sign(msg, sed); + } + } + + static u3_atom + _cqee_sign_raw(u3_noun msg, + u3_noun pub, + u3_noun sek) + { + c3_y pub_y[32], sek_y[64]; + + if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) { + // hoon asserts size + return u3m_bail(c3__exit); + } + if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) { + // hoon asserts size + return u3m_bail(c3__exit); + } + else { + c3_y sig_y[64]; + c3_w met_w; + c3_y* msg_y = u3r_bytes_all(&met_w, msg); + + urcrypt_ed_sign_raw(msg_y, met_w, pub_y, sek_y, sig_y); + u3a_free(msg_y); + + return u3i_bytes(64, sig_y); + } + } + + u3_noun + u3wee_sign_raw(u3_noun cor) + { + u3_noun msg, pub, sek; + if ( c3n == u3r_mean(cor, + u3x_sam_2, &msg, u3x_sam_6, &pub, u3x_sam_7, &sek, 0) || + c3n == u3ud(msg) || + c3n == u3ud(pub) || + c3n == u3ud(sek) ) { + return u3m_bail(c3__fail); + } else { + return _cqee_sign_raw(msg, pub, sek); + } + } diff --git a/vere/pkg/noun/jets/e/ed_smac.c b/vere/pkg/noun/jets/e/ed_smac.c new file mode 100644 index 0000000..ce0ffac --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_smac.c @@ -0,0 +1,73 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_smac(u3_atom a, + u3_atom b, + u3_atom c) + { + c3_y a_y[32], b_y[32], c_y[32], out_y[32]; + c3_w met_w; + + met_w = u3r_met(3, a); + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, a)) ) + ) { + u3_noun a_recs = u3qee_recs(a); + u3r_bytes(0, 32, a_y, a_recs); + u3z(a_recs); + } else { + u3r_bytes(0, 32, a_y, a); + } + + met_w = u3r_met(3, b); + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, b)) ) + ) { + u3_noun b_recs = u3qee_recs(b); + u3r_bytes(0, 32, b_y, b_recs); + u3z(b_recs); + } else { + u3r_bytes(0, 32, b_y, b); + } + + met_w = u3r_met(3, c); + if ( (32 < met_w) || + ( (32 == met_w) && + (127 < u3r_byte(31, c)) ) + ) { + u3_noun c_recs = u3qee_recs(c); + u3r_bytes(0, 32, c_y, c_recs); + u3z(c_recs); + } else { + u3r_bytes(0, 32, c_y, c); + } + + urcrypt_ed_scalar_muladd(a_y, b_y, c_y, out_y); + return u3i_bytes(32, out_y); + } + + u3_noun + u3wee_smac(u3_noun cor) + { + u3_noun a, b, c; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_6, &b, + u3x_sam_7, &c, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) || + (c3n == u3ud(c)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqee_smac(a, b, c); + } + } diff --git a/vere/pkg/noun/jets/e/ed_veri.c b/vere/pkg/noun/jets/e/ed_veri.c new file mode 100644 index 0000000..6d7b750 --- /dev/null +++ b/vere/pkg/noun/jets/e/ed_veri.c @@ -0,0 +1,85 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqee_veri_octs(u3_noun sig, + u3_noun len, + u3_noun dat, + u3_noun pub) + { + c3_y sig_y[64], pub_y[32]; + c3_w len_w; + if ( (0 != u3r_bytes_fit(64, sig_y, sig)) || + (0 != u3r_bytes_fit(32, pub_y, pub)) || + !u3r_word_fit(&len_w, len) ) { + return c3n; + } + else { + c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); + c3_t val_t = urcrypt_ed_veri(dat_y, len_w, pub_y, sig_y); + u3a_free(dat_y); + + return val_t ? c3y : c3n; + } + } + + u3_noun + u3wee_veri_octs(u3_noun cor) + { + u3_noun sig, msg, pub; + u3_noun len, dat; + if ( c3n == u3r_mean(cor, + u3x_sam_2, &sig, u3x_sam_6, &msg, + u3x_sam_7, &pub, 0) || + c3n == u3r_cell(msg, &len, &dat) || + (c3n == u3ud(sig)) || + (c3n == u3ud(pub)) || + (c3n == u3ud(len)) || + (c3n == u3ud(dat)) ) { + return u3m_bail(c3__fail); + } else { + return _cqee_veri_octs(sig, len, dat, pub); + } + } + + static u3_atom + _cqee_veri(u3_noun s, + u3_noun m, + u3_noun pk) + { + c3_y sig_y[64], pub_y[32]; + + if ( (0 != u3r_bytes_fit(64, sig_y, s)) || + (0 != u3r_bytes_fit(32, pub_y, pk)) ) { + return c3n; + } + else { + c3_w met_w; + c3_y* mes_y = u3r_bytes_all(&met_w, m); + c3_t val_t = urcrypt_ed_veri(mes_y, met_w, pub_y, sig_y); + u3a_free(mes_y); + + return val_t ? c3y : c3n; + } + } + + u3_noun + u3wee_veri(u3_noun cor) + { + u3_noun a, b, c; + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &a, u3x_sam_6, &b, + u3x_sam_7, &c, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) || + (c3n == u3ud(c)) ) { + return u3m_bail(c3__fail); + } else { + return _cqee_veri(a, b, c); + } + } diff --git a/vere/pkg/noun/jets/e/fein_ob.c b/vere/pkg/noun/jets/e/fein_ob.c new file mode 100644 index 0000000..65d0f3a --- /dev/null +++ b/vere/pkg/noun/jets/e/fein_ob.c @@ -0,0 +1,90 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "murmur3.h" + +// +feis:ob constant parameters to +fe:ob +// +static const c3_w a_w = 0xffff; +static const c3_w b_w = 0x10000; +static const c3_w k_w = 0xffff0000; + +// +raku:ob +// +static const c3_w rak_w[4] = { 0xb76d5eed, 0xee281300, 0x85bcae01, 0x4b387af7 }; + +/* _fe_ob(): +fe:ob, with constant parameters factored out. +** correct over the domain [0x0, 0xfffe.ffff] +*/ +static c3_w +_fe_ob(c3_w m_w) +{ + c3_w l_w = m_w % a_w; + c3_w r_w = m_w / a_w; + c3_w f_w, t_w; + c3_y j_y, k_y[2]; + + for ( j_y = 0; j_y < 4; j_y++ ) { + k_y[0] = r_w & 0xff; + k_y[1] = (r_w >> 8) & 0xff; + + MurmurHash3_x86_32(k_y, 2, rak_w[j_y], &f_w); + + // NB: this addition can overflow a c3_w (before mod) + // + t_w = ((c3_d)f_w + l_w) % (!(j_y & 1) ? a_w : b_w); + l_w = r_w; + r_w = t_w; + } + + // legendary @max19 + // + return ( a_w == r_w ) + ? (r_w * a_w) + l_w + : (l_w * a_w) + r_w; +} + +/* _feis_ob(): +feis:ob, also offsetting by 0x1.000 (as in +fein:ob). +** correct over the domain [0x1.0000, 0xffff.ffff] +*/ +static c3_w +_feis_ob(c3_w m_w) +{ + c3_w c_w = _fe_ob(m_w - b_w); + return b_w + (( c_w < k_w ) ? c_w : _fe_ob(c_w)); +} + +u3_atom +u3qe_fein_ob(u3_atom pyn) +{ + c3_w sor_w = u3r_met(4, pyn); + + if ( (sor_w < 2) || (sor_w > 4) ) { + return u3k(pyn); + } + + if ( 2 == sor_w ) { + return u3i_word(_feis_ob(u3r_word(0, pyn))); + } + else { + c3_w pyn_w[2]; + u3r_words(0, 2, pyn_w, pyn); + + if ( pyn_w[0] < b_w ) { + return u3k(pyn); + } + else { + pyn_w[0] = _feis_ob(pyn_w[0]); + return u3i_words(2, pyn_w); + } + } +} + +u3_noun +u3we_fein_ob(u3_noun cor) +{ + return u3qe_fein_ob(u3x_atom(u3x_at(u3x_sam, cor))); +} diff --git a/vere/pkg/noun/jets/e/fl.c b/vere/pkg/noun/jets/e/fl.c new file mode 100644 index 0000000..c52309e --- /dev/null +++ b/vere/pkg/noun/jets/e/fl.c @@ -0,0 +1,441 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* structures +*/ + typedef struct _flOptions { + c3_w precision; + mpz_t minExp; + mpz_t expWidth; + c3_w rMode; + c3_w eMode; + } flOptions; + + typedef struct _ea { + mpz_t e; + mpz_t a; + } ea; + + static void + _satom_to_mp(mpz_t a_mp, + u3_atom b) + { + if ( _(u3a_is_cat(b)) ) { + c3_ws c = (b + 1) >> 1; + if ( (b & 1) ) { + c = -c; + } + mpz_init_set_si(a_mp, c); + } + else { + u3r_mp(a_mp, b); + c3_t x = mpz_odd_p(a_mp); + mpz_add_ui(a_mp, a_mp, 1); + mpz_tdiv_q_2exp(a_mp, a_mp, 1); + if ( x ) { + mpz_neg(a_mp, a_mp); + } + } + } + + static u3_noun + _mp_to_satom(mpz_t a_mp) + { + c3_ws b = mpz_sgn(a_mp); + switch ( b ) { + default: return u3m_bail(c3__fail); + case 0: { + mpz_clear(a_mp); + return 0; + } + case 1: { + mpz_mul_2exp(a_mp, a_mp, 1); + return u3i_mp(a_mp); + } + case -1: { + mpz_abs(a_mp, a_mp); + mpz_mul_2exp(a_mp, a_mp, 1); + mpz_sub_ui(a_mp, a_mp, 1); + return u3i_mp(a_mp); + } + } + } + + static void + _noun_to_flOptions(flOptions* a, + u3_noun b) + { + u3_noun c; + u3_atom d, e, f, g, h; + u3x_trel(b, &c, &d, &e); + u3x_trel(c, &f, &g, &h); + + mpz_t i; + u3r_mp(i, f); + if ( !mpz_fits_uint_p(i) ) { + mpz_clear(i); + u3m_bail(c3__exit); + } + a->precision = mpz_get_ui(i); + mpz_clear(i); + + if ( a->precision < 2 ) u3m_bail(c3__exit); + + _satom_to_mp(a->minExp, g); + u3r_mp(a->expWidth, h); + + if ( !(_(u3a_is_cat(d)) && _(u3a_is_cat(e))) ) { + mpz_clear(a->minExp); + mpz_clear(a->expWidth); + u3m_bail(c3__exit); + } + a->rMode = d; + a->eMode = e; + } + + static void + _noun_to_ea(ea* a, + u3_noun b) + { + u3_atom c, d; + u3x_cell(b, &c, &d); + + if ( !(_(u3a_is_cat(c))) ) { + u3m_bail(c3__exit); + } + + _satom_to_mp(a->e, c); + u3r_mp(a->a, d); + } + + static u3_noun + _ea_to_noun(ea* a) + { + u3_atom b = _mp_to_satom(a->e); + u3_atom c = u3i_mp(a->a); + + return u3nc(b, c); + } + + static void + _xpd(ea* a, + flOptions* b) + { + size_t z = mpz_sizeinbase(a->a, 2); + if ( z >= b->precision ) return; + c3_w c = b->precision - z; + + if ( b->eMode != c3__i ) { + mpz_t i; + mpz_init_set(i, a->e); + mpz_sub(i, i, b->minExp); + if ( mpz_sgn(i) < 0 ) { + c = 0; + } + else if ( mpz_fits_uint_p(i) ) + { + c3_w d = mpz_get_ui(i); + c = c3_min(c, d); + } + mpz_clear(i); + } + + mpz_mul_2exp(a->a, a->a, c); + mpz_sub_ui(a->e, a->e, c); + } + + /* a: floating point number, b: flOptions, i: rounding mode, j: sticky bit */ + u3_noun + u3qef_lug(u3_noun a, + u3_noun b, + u3_atom i, + u3_atom j) + { + mpz_t v, g, h; + ea c; + flOptions d; + _noun_to_ea(&c, a); + _noun_to_flOptions(&d, b); + if ( mpz_sgn(c.a) == 0 ) { + mpz_clear(d.minExp); mpz_clear(d.expWidth); + mpz_clear(c.a); mpz_clear(c.e); + return u3m_bail(c3__exit); + } + size_t m = mpz_sizeinbase(c.a, 2); + if ( !_(j) && (m <= d.precision) ) { + mpz_clear(d.minExp); mpz_clear(d.expWidth); + mpz_clear(c.a); mpz_clear(c.e); + return u3m_bail(c3__exit); + } + c3_w q = 0; + c3_w f = (m > d.precision) ? m - d.precision : 0; + mpz_init(g); + if ( (d.eMode != c3__i) && + (mpz_cmp(c.e, d.minExp) < 0) ) { + mpz_sub(g, d.minExp, c.e); + if ( !mpz_fits_uint_p(g) ) { + mpz_clear(g); + mpz_clear(d.minExp); mpz_clear(d.expWidth); + mpz_clear(c.a); mpz_clear(c.e); + return u3m_bail(c3__exit); + } + q = mpz_get_ui(g); + } + q = c3_max(f, q); + mpz_init(v); + mpz_tdiv_r_2exp(v, c.a, q); + mpz_tdiv_q_2exp(c.a, c.a, q); + mpz_add_ui(c.e, c.e, q); + mpz_init_set_ui(h, 1); + if ( q > 0 ) mpz_mul_2exp(h, h, q - 1); + + if ( mpz_sgn(c.a) == 0 ) { + c3_t y; + switch ( i ) { + default: + mpz_clear(v); mpz_clear(h); mpz_clear(g); + mpz_clear(d.minExp); mpz_clear(d.expWidth); + mpz_clear(c.a); mpz_clear(c.e); + return u3m_bail(c3__exit); + case c3__fl: + case c3__sm: + mpz_set_ui(c.a, 0); + mpz_set_ui(c.e, 0); + mpz_clear(v); mpz_clear(h); mpz_clear(g); + break; + case c3__ce: + case c3__lg: + mpz_set_ui(c.a, 1); + mpz_set(c.e, d.minExp); + mpz_clear(v); mpz_clear(h); mpz_clear(g); + break; + case c3__ne: + case c3__nt: + case c3__na: + if ( (i != c3__na) && _(j) ) { + y = (mpz_cmp(v, h) <= 0); + } else { + y = (mpz_cmp(v, h) < 0); + } + if ( y ) { + mpz_set_ui(c.a, 0); + mpz_set_ui(c.e, 0); + } else { + mpz_set_ui(c.a, 1); + mpz_set(c.e, d.minExp); + } + mpz_clear(v); mpz_clear(h); mpz_clear(g); + break; + } + goto end; + } + _xpd(&c, &d); + switch ( i ) { + c3_ws x; + default: + mpz_clear(v); mpz_clear(h); mpz_clear(g); + mpz_clear(d.minExp); mpz_clear(d.expWidth); + mpz_clear(c.a); mpz_clear(c.e); + return u3m_bail(c3__exit); + case c3__fl: + break; + case c3__lg: + mpz_add_ui(c.a, c.a, 1); + break; + case c3__sm: + if ( (mpz_sgn(v) != 0) || !_(j) ) break; + if ( (mpz_cmp(c.e, d.minExp) == 0) && (d.eMode != c3__i) ) { + mpz_sub_ui(c.a, c.a, 1); + break; + } + mpz_mul_2exp(g, c.a, 1); + mpz_sub_ui(g, g, 1); + if ( mpz_sizeinbase(g, 2) <= d.precision ) { + mpz_sub_ui(c.e, c.e, 1); + mpz_set(c.a, g); + } else { + mpz_sub_ui(c.a, c.a, 1); + } + break; + case c3__ce: + if ( (mpz_sgn(v) != 0) || !_(j) ) { + mpz_add_ui(c.a, c.a, 1); + } + break; + case c3__ne: + if ( mpz_sgn(v) == 0 ) break; + x = mpz_cmp(v, h); + if ( (x == 0) && _(j) ) { + if ( mpz_odd_p(c.a) ) { + mpz_add_ui(c.a, c.a, 1); + } + } + else if ( x >= 0 ) { + mpz_add_ui(c.a, c.a, 1); + } + break; + case c3__na: + case c3__nt: + if ( mpz_sgn(v) == 0 ) break; + x = mpz_cmp(v, h); + if ( (x < 0) ) break; + if ( (i == c3__nt) && (x == 0) ) { + if (!_(j)) mpz_add_ui(c.a, c.a, 1); + } else { + mpz_add_ui(c.a, c.a, 1); + } + break; + } + if ( mpz_sizeinbase(c.a, 2) == (d.precision + 1) ) { + mpz_tdiv_q_2exp(c.a, c.a, 1); + mpz_add_ui(c.e, c.e, 1); + } + if ( mpz_sgn(c.a) == 0 ) { + mpz_set_ui(c.e, 0); + mpz_clear(v); mpz_clear(h); mpz_clear(g); + goto end; + } + mpz_set(g, d.minExp); + mpz_add(g, g, d.expWidth); + if ( (d.eMode != c3__i) && (mpz_cmp(g, c.e) < 0) ) { + mpz_clear(v); mpz_clear(h); mpz_clear(g); + mpz_clear(d.minExp); mpz_clear(d.expWidth); + mpz_clear(c.a); mpz_clear(c.e); + return u3nc(c3__i, c3y); + } + mpz_clear(v); mpz_clear(h); mpz_clear(g); + + // all mpz except in c, d structures cleared; c contains result + end: + if ( d.eMode == c3__f ) { + if ( mpz_sizeinbase(c.a, 2) != d.precision ) { + mpz_set_ui(c.a, 0); + mpz_set_ui(c.e, 0); + } + } + u3_noun ret = u3nq(c3__f, c3y, _mp_to_satom(c.e), u3i_mp(c.a)); + mpz_clear(d.minExp); mpz_clear(d.expWidth); + return ret; + } + + u3_noun + u3wef_lug(u3_noun cor) + { + u3_noun a, b, c, d, e; + a = u3x_at(u3x_sam, cor); + b = u3x_at(30, cor); + u3x_trel(a, &c, &d, &e); + + return u3qef_lug(d, b, c, e); + } + + u3_noun + u3qef_drg(u3_noun a, + u3_noun b) + { + ea c; + flOptions d; + _noun_to_ea(&c, a); + _noun_to_flOptions(&d, b); + if ( mpz_sgn(c.a) == 0 ) { + mpz_clear(d.minExp); mpz_clear(d.expWidth); + mpz_clear(c.a); mpz_clear(c.e); + u3m_bail(c3__exit); + } + _xpd(&c, &d); + if ( !mpz_fits_sint_p(c.e) ) { + mpz_clear(d.minExp); mpz_clear(d.expWidth); + mpz_clear(c.a); mpz_clear(c.e); + u3m_bail(c3__exit); + } + mpz_t r, s, mn, mp, i, j, u, o; + mpz_init_set(r, c.a); + mpz_init_set_ui(s, 1); + mpz_init_set_ui(mn, 1); + mpz_init(i); + mpz_init(j); + c3_w se = mpz_sgn(c.e); + if ( se == 1 ) { + mpz_mul_2exp(r, r, mpz_get_ui(c.e)); + mpz_mul_2exp(mn, mn, mpz_get_ui(c.e)); + } + else if ( se == -1 ) { + mpz_mul_2exp(s, s, mpz_get_ui(c.e)); + } + mpz_init_set(mp, mn); + mpz_set_ui(i, 1); + mpz_mul_2exp(i, i, d.precision - 1); + if ( (mpz_cmp(c.a, i) == 0) && + ((mpz_cmp(c.e, d.minExp) != 0 ) || + (d.eMode == c3__i)) ) { + mpz_mul_2exp(mp, mp, 1); + mpz_mul_2exp(r, r, 1); + mpz_mul_2exp(s, s, 1); + } + mpz_cdiv_q_ui(i, s, 10); + mpz_set_ui(c.e, 0); + while ( mpz_cmp(r, i) < 0 ) { + mpz_sub_ui(c.e, c.e, 1); + mpz_mul_ui(r, r, 10); + mpz_mul_ui(mn, mn, 10); + mpz_mul_ui(mp, mp, 10); + } + while ( 1 ) { + mpz_mul_2exp(i, r, 1); + mpz_add(i, i, mp); + mpz_mul_2exp(j, s, 1); + if ( mpz_cmp(i, j) < 0 ) { + break; + } + mpz_mul_ui(s, s, 10); + mpz_add_ui(c.e, c.e, 1); + } + mpz_init(u); + mpz_init_set_ui(o, 0); + while ( 1 ) { + mpz_sub_ui(c.e, c.e, 1); + mpz_mul_ui(r, r, 10); + mpz_mul_ui(mn, mn, 10); + mpz_mul_ui(mp, mp, 10); + mpz_tdiv_qr(u, r, r, s); + mpz_mul_2exp(i, r, 1); + mpz_mul_2exp(j, s, 1); + c3_t l = mpz_cmp(i, mn) < 0; + c3_t h = mpz_cmp(j, mp) < 0; + if ( !h ) { + mpz_sub(j, j, mp); + h = mpz_cmp(i, j) > 0; + } + if ( l || h ) { + mpz_mul_ui(o, o, 10); + mpz_add(o, o, u); + if ( h && (!l || (mpz_cmp(i, s) > 0)) ) { + mpz_add_ui(o, o, 1); + } + break; + } + mpz_mul_ui(o, o, 10); + mpz_add(o, o, u); + } + mpz_set(c.a, o); + mpz_clear(r); mpz_clear(s); + mpz_clear(mn); mpz_clear(mp); + mpz_clear(i); mpz_clear(j); mpz_clear(u); + mpz_clear(o); mpz_clear(d.minExp); mpz_clear(d.expWidth); + + return _ea_to_noun(&c); + } + + u3_noun + u3wef_drg(u3_noun cor) + { + u3_noun a, b; + a = u3x_at(u3x_sam, cor); + b = u3x_at(30, cor); + + return u3qef_drg(a, b); + } diff --git a/vere/pkg/noun/jets/e/fynd_ob.c b/vere/pkg/noun/jets/e/fynd_ob.c new file mode 100644 index 0000000..62e65d1 --- /dev/null +++ b/vere/pkg/noun/jets/e/fynd_ob.c @@ -0,0 +1,94 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "murmur3.h" + +// +tail:ob constant parameters to +fe:ob +// +static const c3_w a_w = 0xffff; +static const c3_w b_w = 0x10000; +static const c3_w k_w = 0xffff0000; + +// (flop raku:ob) +// +static const c3_w kar_w[4] = { 0x4b387af7, 0x85bcae01, 0xee281300, 0xb76d5eed }; + +/* _fen_ob(): +fen:ob, with constant parameters factored out. +** correct over the domain [0x0 ... 0xfffe.ffff] +*/ +static c3_w +_fen_ob(c3_w m_w) +{ + c3_w l_w = m_w / a_w; + c3_w r_w = m_w % a_w; + c3_w f_w, t_w; + c3_y j_y, k_y[2]; + + // legendary @max19 + // + if ( a_w == l_w ) { + t_w = l_w; + l_w = r_w; + r_w = t_w; + } + + for ( j_y = 0; j_y < 4; j_y++ ) { + k_y[0] = l_w & 0xff; + k_y[1] = (l_w >> 8) & 0xff; + + MurmurHash3_x86_32(k_y, 2, kar_w[j_y], &f_w); + + t_w = ( j_y & 1 ) + ? ((r_w + a_w) - (f_w % a_w)) % a_w + : ((r_w + b_w) - (f_w % b_w)) % b_w; + r_w = l_w; + l_w = t_w; + } + + return (r_w * a_w) + l_w; +} + +/* _tail_ob(): +feis:ob, also offsetting by 0x1.000 (as in +fynd:ob). +** correct over the domain [0x1.0000, 0xffff.ffff] +*/ +static c3_w +_tail_ob(c3_w m_w) +{ + c3_w c_w = _fen_ob(m_w - b_w); + return b_w + (( c_w < k_w ) ? c_w : _fen_ob(c_w)); +} + +u3_atom +u3qe_fynd_ob(u3_atom pyn) +{ + c3_w sor_w = u3r_met(4, pyn); + + if ( (sor_w < 2) || (sor_w > 4) ) { + return u3k(pyn); + } + + if ( 2 == sor_w ) { + return u3i_word(_tail_ob(u3r_word(0, pyn))); + } + else { + c3_w pyn_w[2]; + u3r_words(0, 2, pyn_w, pyn); + + if ( pyn_w[0] < b_w ) { + return u3k(pyn); + } + else { + pyn_w[0] = _tail_ob(pyn_w[0]); + return u3i_words(2, pyn_w); + } + } +} + +u3_noun +u3we_fynd_ob(u3_noun cor) +{ + return u3qe_fynd_ob(u3x_atom(u3x_at(u3x_sam, cor))); +} diff --git a/vere/pkg/noun/jets/e/hmac.c b/vere/pkg/noun/jets/e/hmac.c new file mode 100644 index 0000000..b14ec1e --- /dev/null +++ b/vere/pkg/noun/jets/e/hmac.c @@ -0,0 +1,94 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qe_hmac(u3_noun haj, + u3_atom boq, + u3_atom out, + u3_atom wik, + u3_atom key, + u3_atom wid, + u3_atom dat) + { + u3_assert(_(u3a_is_cat(boq)) && _(u3a_is_cat(wik)) && _(u3a_is_cat(wid))); + + // prep the hashing gate + u3j_site sit_u; + u3j_gate_prep(&sit_u, u3k(haj)); + + // ensure key and message fit signaled lengths + key = u3qc_end(3, wik, key); + dat = u3qc_end(3, wid, dat); + + // keys longer than block size are shortened by hashing + if (wik > boq) { + key = u3j_gate_slam(&sit_u, u3nc(wik, key)); + wik = out; + } + + // keys shorter than block size are right-padded + if (wik < boq) { + key = u3kc_lsh(3, (boq - wik), key); + } + + // pad key, inner and outer + c3_y trail = (boq % 4); + c3_y padwords = (boq / 4) + (trail == 0 ? 0 : 1); + c3_w innpad[padwords], outpad[padwords]; + memset(innpad, 0x36, padwords * 4); + memset(outpad, 0x5c, padwords * 4); + if ( trail > 0 ) { + innpad[padwords-1] = 0x36363636 >> (8 * (4 - trail)); + outpad[padwords-1] = 0x5c5c5c5c >> (8 * (4 - trail)); + } + u3_atom innkey = u3kc_mix(u3k(key), u3i_words(padwords, innpad)); + u3_atom outkey = u3kc_mix( key , u3i_words(padwords, outpad)); + + // append inner padding to message, then hash + u3_atom innmsg = u3ka_add(u3kc_lsh(3, wid, innkey), dat); + u3_atom innhaj = u3j_gate_slam(&sit_u, u3nc((wid + boq), innmsg)); + + // prepend outer padding to result, hash again + u3_atom outmsg = u3ka_add(u3kc_lsh(3, out, outkey), innhaj); + u3_atom outhaj = u3j_gate_slam(&sit_u, u3nc((out + boq), outmsg)); + + u3j_gate_lose(&sit_u); + return outhaj; + } + + u3_noun + u3we_hmac(u3_noun cor) + { + u3_noun haj, boq, out, wik, key, wid, dat; + + // sample is [[haj boq out] [wik key] [wid dat]] + if ( (c3n == u3r_mean(cor, u3x_sam_4, &haj, + 50, &boq, // +<->- + 51, &out, // +<->+ + u3x_sam_12, &wik, + u3x_sam_13, &key, + u3x_sam_14, &wid, + u3x_sam_15, &dat, 0)) || + (c3n == u3ud(boq)) || + (c3n == u3a_is_cat(boq)) || + (c3n == u3ud(out)) || + (c3n == u3a_is_cat(out)) || + (c3n == u3ud(wik)) || + (c3n == u3a_is_cat(wik)) || + (c3n == u3ud(key)) || + (c3n == u3ud(wid)) || + (c3n == u3a_is_cat(wid)) || + (c3n == u3ud(dat)) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qe_hmac(haj, boq, out, wik, key, wid, dat); + } + } diff --git a/vere/pkg/noun/jets/e/jam.c b/vere/pkg/noun/jets/e/jam.c new file mode 100644 index 0000000..2291bc0 --- /dev/null +++ b/vere/pkg/noun/jets/e/jam.c @@ -0,0 +1,60 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qe_jam(u3_atom a) +{ +#if 0 + if (c3y == u3du(a) && 1337 == u3h(a)) { + c3_w siz_w, tot_w = 0; + u3_noun som; + for ( som = u3t(a); c3y == u3du(som); som = u3t(som) ) { + siz_w = u3a_count_noun(u3h(som)); + tot_w += siz_w; + if ( 0 == siz_w ) { + u3l_log("item: B/0"); + } + else { + u3a_print_memory(stderr, "item", siz_w); + } + } + if ( u3_blip != som ) { + u3l_log("forgot to terminate list!"); + } + c3_w mem_w = u3h_count(u3R->cax.har_p); + + for ( som = u3t(a); c3y == u3du(som); som = u3t(som) ) u3a_discount_noun(u3h(som)); + u3h_discount(u3R->cax.har_p); + + u3a_print_memory(stderr, "total", tot_w); + u3a_print_memory(stderr, "memoization cache", mem_w); + u3h_root* har_u = u3to(u3h_root, u3R->cax.har_p); + u3l_log("memoization entries: %d", har_u->use_w); + u3a_print_memory(stderr, "unused free", u3a_open(u3R)); + return tot_w; + } +#endif + + u3i_slab sab_u; + u3s_jam_fib(&sab_u, a); + return u3i_slab_mint(&sab_u); +} + +u3_noun +u3we_jam(u3_noun cor) +{ + return u3qe_jam(u3x_at(u3x_sam, cor)); +} + +u3_atom +u3ke_jam(u3_noun a) +{ + u3_atom b = u3qe_jam(a); + u3z(a); + return b; +} diff --git a/vere/pkg/noun/jets/e/json_de.c b/vere/pkg/noun/jets/e/json_de.c new file mode 100644 index 0000000..e54393a --- /dev/null +++ b/vere/pkg/noun/jets/e/json_de.c @@ -0,0 +1,258 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +#include "pdjson.h" + +/* +** custom code for interfacing with external parser: +** https://github.com/skeeto/pdjson +*/ + +typedef struct _u3qedj_coll { + u3_noun col; // collection (list for array, map for object) + union { // store context for recursive arrays/objects: + u3_noun* tel; // - pointer to tail for array + u3_atom key; // - key for object + }; +} u3qedj_coll; + +static u3qedj_coll* +_push_stack(const u3a_pile *pil_u) +{ + u3qedj_coll *res_u = u3a_push(pil_u); + u3a_pile_done(pil_u); + + res_u->col = u3_nul; + res_u->key = u3_none; + + return res_u; +} + +static u3qedj_coll* +_pop_stack(const u3a_pile *pil_u) +{ + return u3a_pop(pil_u); +} + +static void +_close_stack(const u3a_pile *pil_u) +{ + while ( c3n == u3a_pile_done(pil_u) ) { + u3qedj_coll *tak_u = u3a_peek(pil_u); + + u3z(tak_u->col); + if ( u3_none != tak_u->key ) { + u3z(tak_u->key); + } + + u3a_drop(pil_u); + } +} + +static void +_close_on_error(json_stream *sam_u, const u3a_pile *pil_u) +{ + _close_stack(pil_u); + json_close(sam_u); +} + +static u3_atom +_json_get_string_as_atom(json_stream *sam_u) { + // length returned by json_get_string includes the trailing null byte + // it's possible for json_get_string to return a length of 0, but only if: + // - it's called directly after init + // - it's called directly after init_string + size_t len_i; + const c3_c *str_c = json_get_string(sam_u, &len_i); + return (len_i <= 1) ? + u3_nul : + u3i_bytes(len_i - 1, (const c3_y *)str_c); +} + +static u3_noun +_parse(u3_atom txt) +{ + // + // vars + // + + u3qedj_coll *tak_u; + + json_allocator loc_u = {u3a_malloc, u3a_realloc, u3a_free}; + json_stream sem_u; + json_stream* sam_u = &sem_u; + + u3a_pile pel_u; + u3a_pile *pil_u = &pel_u; + + u3_noun res = u3_none; + u3_noun val; + + const c3_y *byt_y; + c3_z cnt_z; + c3_w len_w = u3r_met(3, txt); + + // + // initialization + // + + // XX assumes little-endian + // + if ( c3y == u3a_is_cat(txt) ) { + byt_y = (c3_y*)&txt; + } + else { + u3a_atom* vat_u = u3a_to_ptr(txt); + byt_y = (c3_y*)vat_u->buf_w; + } + json_open_buffer(sam_u, byt_y, len_w); + json_set_allocator(sam_u, &loc_u); + u3a_pile_prep(pil_u, sizeof(u3qedj_coll)); + + // + // core logic + // + + while ( json_peek(sam_u) != JSON_DONE ) { + switch ( json_next(sam_u) ) { + // unreachable barring programming error + default: u3_assert(0); + + case JSON_ARRAY: + case JSON_OBJECT: { + tak_u = _push_stack(pil_u); + } continue; + + case JSON_ARRAY_END: { + val = u3nc(c3__a, tak_u->col); + tak_u = _pop_stack(pil_u); + } break; + + case JSON_OBJECT_END: { + val = u3nc(c3__o, tak_u->col); + tak_u = _pop_stack(pil_u); + } break; + + case JSON_STRING: { + if ( (json_get_context(sam_u, &cnt_z) == JSON_OBJECT) && (cnt_z & 1) ) { + // since object key must be followed by value, skip ahead + tak_u->key = _json_get_string_as_atom(sam_u); + continue; + } + else { + val = u3nc(c3__s, _json_get_string_as_atom(sam_u)); + break; + } + } + + case JSON_NUMBER: { + // read number from string in the JSON reparser + val = u3nc(c3__n, _json_get_string_as_atom(sam_u)); + } break; + + case JSON_TRUE: { + val = u3nc(c3__b, c3y); + } break; + + case JSON_FALSE: { + val = u3nc(c3__b, c3n); + } break; + + case JSON_NULL: { + val = u3_nul; + } break; + + case JSON_ERROR: { + _close_on_error(sam_u, pil_u); + return u3_nul; + } break; + } + + switch ( json_get_context(sam_u, &cnt_z) ) { + // unreachable barring programming error + default: u3_assert(0); + + case JSON_DONE: { + res = val; + } break; + + case JSON_ARRAY: { + u3_noun* nex; + u3_noun* hed; + + if ( tak_u->col == u3_nul ) { + nex = &(tak_u->col); + } + else { + nex = tak_u->tel; + } + + *nex = u3i_defcons(&hed, &(tak_u->tel)); + *hed = val; + *(tak_u->tel) = u3_nul; + } break; + + case JSON_OBJECT: { + // odd cnt_z and unset key weeded out by continue command on key + u3_assert(!(cnt_z & 1)); + u3_assert(tak_u->key != u3_none); + // cnt_z == 0 weeded out by continue command on array/object open + u3_assert(cnt_z); + + tak_u->col = u3kdb_put(tak_u->col, tak_u->key, val); + tak_u->key = u3_none; + } break; + } + } + + // + // clean up + // + + u3_assert(c3y == u3a_pile_done(pil_u)); + + // skip over whitespce + while ( json_isspace(json_source_peek(sam_u)) ) { + json_source_get(sam_u); + } + + json_close(sam_u); + + // return null if trailing trash/multiple JSON objects + if ( json_get_position(sam_u) != len_w ) { + u3z(res); + return u3_nul; + } + else { + return u3nc(u3_nul, res); + } +} + +/* +** jet interface functions +*/ + +u3_noun +u3qe_json_de(u3_atom a) +{ + return _parse(a); +} + +u3_noun +u3ke_json_de(u3_atom a) +{ + u3_noun res = u3qe_json_de(a); + u3z(a); + return res; +} + +u3_noun +u3we_json_de(u3_noun cor) +{ + return u3qe_json_de(u3x_atom(u3x_at(u3x_sam, cor))); +} diff --git a/vere/pkg/noun/jets/e/json_en.c b/vere/pkg/noun/jets/e/json_en.c new file mode 100644 index 0000000..f605ab4 --- /dev/null +++ b/vere/pkg/noun/jets/e/json_en.c @@ -0,0 +1,416 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* +** structs +*/ + +typedef struct _json_buffer { + c3_y *buf_y; + c3_w len_w; +} json_buffer; + +/* +** constants +*/ + +const c3_y _JSON_NULL[] = "null"; +const c3_y _JSON_TRUE[] = "true"; +const c3_y _JSON_FALSE[] = "false"; +const c3_y _JSON_NEWLINE[] = "\\n"; +const c3_y _JSON_DOQ[] = "\\\""; +const c3_y _JSON_BAS[] = "\\\\"; +const c3_y _JSON_DEL[] = "\\u007f"; +const c3_y *_JSON_UNICODES[] = { + (c3_y*)"\\u0000", // 0 + (c3_y*)"\\u0001", // 1 + (c3_y*)"\\u0002", // 2 + (c3_y*)"\\u0003", // 3 + (c3_y*)"\\u0004", // 4 + (c3_y*)"\\u0005", // 5 + (c3_y*)"\\u0006", // 6 + (c3_y*)"\\u0007", // 7 + (c3_y*)"\\u0008", // 8 + (c3_y*)"\\u0009", // 9 + (c3_y*)"\\u000a", // 10 + (c3_y*)"\\u000b", // 11 + (c3_y*)"\\u000c", // 12 + (c3_y*)"\\u000d", // 13 + (c3_y*)"\\u000e", // 14 + (c3_y*)"\\u000f", // 15 + (c3_y*)"\\u0010", // 16 + (c3_y*)"\\u0011", // 17 + (c3_y*)"\\u0012", // 18 + (c3_y*)"\\u0013", // 19 + (c3_y*)"\\u0014", // 20 + (c3_y*)"\\u0015", // 21 + (c3_y*)"\\u0016", // 22 + (c3_y*)"\\u0017", // 23 + (c3_y*)"\\u0018", // 24 + (c3_y*)"\\u0019", // 25 + (c3_y*)"\\u001a", // 26 + (c3_y*)"\\u001b", // 27 + (c3_y*)"\\u001c", // 28 + (c3_y*)"\\u001d", // 29 + (c3_y*)"\\u001e", // 30 + (c3_y*)"\\u001f", // 31 +}; + +/* +** forward declarations +*/ + +static c3_w +_measure(u3_noun a); + +static void +_serialize(json_buffer*, u3_noun); + +/* +** core jet logic +*/ + +static void +_append_char(json_buffer *buf_u, c3_y c_y) +{ + buf_u->buf_y[(buf_u->len_w)++] = c_y; +} + +static void +_append_text(json_buffer *buf_u, const c3_y *buf_y, c3_w len_w) +{ + memcpy(&(buf_u->buf_y[buf_u->len_w]), buf_y, len_w); + buf_u->len_w += len_w; +} + +static c3_w +_measure_loobean(u3_noun a) +{ + switch ( a ) { + default: u3m_bail(c3__exit); + case c3y: return sizeof(_JSON_TRUE) - 1; + case c3n: return sizeof(_JSON_FALSE) - 1; + } +} + +static void +_serialize_loobean(json_buffer *buf_u, u3_noun a) +{ + switch ( a ) { + default: u3_assert(0); + case c3y: _append_text(buf_u, _JSON_TRUE, sizeof(_JSON_TRUE) - 1); break; + case c3n: _append_text(buf_u, _JSON_FALSE, sizeof(_JSON_FALSE) - 1); break; + } +} + +static c3_w +_measure_number(u3_noun a) +{ + if ( _(u3du(a)) ) { + u3m_bail(c3__exit); + } + + return u3r_met(3, a); +} + +static void +_serialize_number(json_buffer *buf_u, u3_noun a) +{ + const c3_y *byt_y; + + // XX assumes little-endian + // + if ( c3y == u3a_is_cat(a) ) { + byt_y = (c3_y*)&a; + } + else { + u3a_atom* vat_u = u3a_to_ptr(a); + byt_y = (c3_y*)vat_u->buf_w; + } + + _append_text(buf_u, byt_y, u3r_met(3, a)); +} + +static c3_w +_measure_string(u3_noun a) +{ + if ( _(u3du(a)) ) { + u3m_bail(c3__exit); + } + + c3_w len_w = u3r_met(3, a); + c3_w siz_w = 0; + + for (c3_w i = 0; i < len_w; ++i) { + c3_y c_y = u3r_byte(i, a); + + switch ( c_y ) { + case 0 ... 9: + case 11 ... 31: { + siz_w += 6; + } break; + + case 10: { + siz_w += sizeof(_JSON_NEWLINE) - 1; + } break; + + case 34: { + siz_w += sizeof(_JSON_DOQ) - 1; + } break; + + case 92: { + siz_w += sizeof(_JSON_BAS) - 1; + } break; + + case 127: { + siz_w += sizeof(_JSON_DEL) - 1; + } break; + + default: { + siz_w += 1; + } break; + } + } + + // surrounding double quotes + return (siz_w + 2); +} + +static void +_serialize_string(json_buffer *buf_u, u3_noun a) +{ + c3_w len_w = u3r_met(3, a); + + _append_char(buf_u, '"'); + for (c3_w i = 0; i < len_w; ++i) { + c3_y c_y = u3r_byte(i, a); + + switch ( c_y ) { + case 0 ... 9: + case 11 ... 31: { + _append_text(buf_u, _JSON_UNICODES[c_y], 6); + } break; + + case 10: { + _append_text(buf_u, _JSON_NEWLINE, sizeof(_JSON_NEWLINE) - 1); + } break; + + case 34: { + _append_text(buf_u, _JSON_DOQ, sizeof(_JSON_DOQ) - 1); + } break; + + case 92: { + _append_text(buf_u, _JSON_BAS, sizeof(_JSON_BAS) - 1); + } break; + + case 127: { + _append_text(buf_u, _JSON_DEL, sizeof(_JSON_DEL) - 1); + } break; + + default: { + _append_char(buf_u, c_y); + } break; + } + } + _append_char(buf_u, '"'); +} + +static c3_w +_measure_array(u3_noun a) +{ + if ( u3_nul != a ) { + u3_noun i, t = a; + // array open brace + c3_w siz_w = 1; + + while ( u3_nul != t ) { + u3x_cell(t, &i, &t); + siz_w += _measure(i); + // comma or array close brace + siz_w += 1; + } + + return siz_w; + } + else { + // empty array + return 2; + } +} + +static void +_serialize_array(json_buffer *buf_u, u3_noun a) +{ + _append_char(buf_u, '['); + + if ( u3_nul != a ) { + u3_noun i, t = a; + + while ( u3_nul != t ) { + u3x_cell(t, &i, &t); + _serialize(buf_u, i); + _append_char(buf_u, ','); + } + + // Remove trailing comma from array contents + --buf_u->len_w; + } + + _append_char(buf_u, ']'); +} + +static c3_w +_measure_object_helper(u3_noun a) +{ + c3_w siz_w = 0; + + if ( u3_nul != a ) { + u3_noun n_a, l_a, r_a; + u3_noun pn_a, qn_a; + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_cell(n_a, &pn_a, &qn_a); + + siz_w += _measure_object_helper(r_a); + siz_w += _measure_object_helper(l_a); + + siz_w += _measure_string(pn_a); + siz_w += _measure(qn_a); + + // colon and comma (or closing brace) + siz_w += 2; + } + + return siz_w; +} + +static void +_serialize_object_helper(json_buffer *buf_u, u3_noun a) +{ + if ( u3_nul != a ) { + u3_noun n_a, l_a, r_a; + u3_noun pn_a, qn_a; + u3x_trel(a, &n_a, &l_a, &r_a); + u3x_cell(n_a, &pn_a, &qn_a); + + // order is important to match unjetted tree traversal + _serialize_object_helper(buf_u, r_a); + + _serialize_string(buf_u, pn_a); + _append_char(buf_u, ':'); + _serialize(buf_u, qn_a); + _append_char(buf_u, ','); + + _serialize_object_helper(buf_u, l_a); + } +} + +static c3_w +_measure_object(u3_noun a) +{ + if ( u3_nul != a ) { + // opening brace + return 1 + _measure_object_helper(a); + } + else { + // empty object + return 2; + } +} + +static void +_serialize_object(json_buffer *buf_u, u3_noun a) +{ + _append_char(buf_u, '{'); + + if ( u3_nul != a ) { + _serialize_object_helper(buf_u, a); + + // Remove trailing comma from object contents + --buf_u->len_w; + } + + _append_char(buf_u, '}'); +} + +static c3_w +_measure(u3_noun a) +{ + if ( u3_nul == a ) { + return sizeof(_JSON_NULL) - 1; + } + else { + u3_noun s, p; + u3x_cell(a, &s, &p); + + switch ( s ) { + default: u3m_bail(c3__fail); + case c3__a: return _measure_array(p); + case c3__o: return _measure_object(p); + case c3__b: return _measure_loobean(p); + case c3__n: return _measure_number(p); + case c3__s: return _measure_string(p); + } + } +} + +static void +_serialize(json_buffer *buf_u, u3_noun a) +{ + if ( u3_nul == a ) { + _append_text(buf_u, _JSON_NULL, sizeof(_JSON_NULL) - 1); + } + else { + u3_noun s, p; + u3x_cell(a, &s, &p); + + switch ( s ) { + default: u3_assert(0); + case c3__a: _serialize_array(buf_u, p); break; + case c3__o: _serialize_object(buf_u, p); break; + case c3__b: _serialize_loobean(buf_u, p); break; + case c3__n: _serialize_number(buf_u, p); break; + case c3__s: _serialize_string(buf_u, p); break; + } + } +} + +/* +** jet interface functions +*/ + +u3_atom +u3qe_json_en(u3_noun a) +{ + u3i_slab sab_u; + json_buffer bof_u; + json_buffer *buf_u = &bof_u; + c3_w siz_w = _measure(a); + + u3i_slab_init(&sab_u, 3, siz_w); + buf_u->buf_y = sab_u.buf_y; + buf_u->len_w = 0; + + // note that it's structurally integral to call measure before serialize + _serialize(buf_u, a); + + return u3i_slab_mint_bytes(&sab_u); +} + +u3_atom +u3ke_json_en(u3_noun a) +{ + u3_atom res = u3qe_json_en(a); + u3z(a); + return res; +} + +u3_atom +u3we_json_en(u3_noun cor) +{ + return u3qe_json_en(u3x_at(u3x_sam, cor)); +} diff --git a/vere/pkg/noun/jets/e/keccak.c b/vere/pkg/noun/jets/e/keccak.c new file mode 100644 index 0000000..6149c55 --- /dev/null +++ b/vere/pkg/noun/jets/e/keccak.c @@ -0,0 +1,42 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + +#define defw(bits,byts) \ + u3_atom \ + _kecc_##bits(c3_w len_w, u3_atom a) \ + { \ + c3_y out[byts]; \ + c3_y* buf_y = u3r_bytes_alloc(0, len_w, a); \ + if ( 0 != urcrypt_keccak_##bits(buf_y, len_w, out) ) { \ + /* urcrypt_keccac_##bits always succeeds when called correctly */ \ + return u3m_bail(c3__oops); \ + } \ + else { \ + u3_atom pro = u3i_bytes(byts, out); \ + u3a_free(buf_y); \ + return pro; \ + } \ + } \ + \ + u3_weak \ + u3we_kecc##bits(u3_noun cor) \ + { \ + c3_w len_w; \ + u3_noun len, tom; \ + u3x_mean(cor, u3x_sam_2, &len, u3x_sam_3, &tom, 0); \ + return ( (c3n == u3ud(len)) || (c3n == u3ud(tom)) ) \ + ? u3m_bail(c3__exit) \ + : (!u3r_word_fit(&len_w, len)) \ + ? u3m_bail(c3__fail) \ + : _kecc_##bits(len_w, tom); \ + } + +defw(224, 28) +defw(256, 32) +defw(384, 48) +defw(512, 64) diff --git a/vere/pkg/noun/jets/e/leer.c b/vere/pkg/noun/jets/e/leer.c new file mode 100644 index 0000000..8ffe372 --- /dev/null +++ b/vere/pkg/noun/jets/e/leer.c @@ -0,0 +1,131 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_atom +_leer_cut(c3_w pos_w, c3_w len_w, u3_atom src) +{ + if ( 0 == len_w ) { + return 0; + } + else { + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 3, len_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + u3r_bytes(pos_w, len_w, sab_u.buf_y, src); + + return u3i_slab_mint_bytes(&sab_u); + } +} + +// Leaving the lore jet in place for backwards compatibility. +// TODO: remove u3[qw]e_lore (also from jet tree) + +u3_noun +u3qe_lore(u3_atom lub) +{ + c3_w len_w = u3r_met(3, lub); + c3_w pos_w = 0; + u3_noun tez = u3_nul; + + while ( 1 ) { + c3_w meg_w = 0; + c3_y end_y; + + c3_y byt_y; + while ( 1 ) { + if ( pos_w >= len_w ) { + byt_y = 0; + end_y = c3y; + break; + } + byt_y = u3r_byte(pos_w + meg_w, lub); + + if ( (10 == byt_y) || (0 == byt_y) ) { + end_y = __(byt_y == 0); + break; + } else meg_w++; + } + + if ((byt_y == 0) && ((pos_w + meg_w + 1) < len_w)) { + return u3m_bail(c3__exit); + } + + if ( !_(end_y) && pos_w >= len_w ) { + return u3kb_flop(tez); + } + else { + tez = u3nc(_leer_cut(pos_w, meg_w, lub), tez); + if ( _(end_y) ) { + return u3kb_flop(tez); + } + pos_w += (meg_w + 1); + } + } +} + +u3_noun +u3we_lore(u3_noun cor) +{ + u3_noun lub; + + if ( (u3_none == (lub = u3r_at(u3x_sam, cor))) || + (c3n == u3ud(lub)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qe_lore(lub); + } +} + +u3_noun +u3qe_leer(u3_atom txt) +{ + u3_noun pro; + u3_noun* lit = &pro; + + { + c3_w pos_w, i_w = 0, len_w = u3r_met(3, txt); + u3_noun* hed; + u3_noun* tel; + + while ( i_w < len_w ) { + // scan till end or newline + // + for ( pos_w = i_w; i_w < len_w; ++i_w ) { + if ( 10 == u3r_byte(i_w, txt) ) { + break; + } + } + + // append to list + // + *lit = u3i_defcons(&hed, &tel); + *hed = _leer_cut(pos_w, i_w - pos_w, txt); + lit = tel; + + i_w++; + } + } + + *lit = u3_nul; + + return pro; +} + +u3_noun +u3we_leer(u3_noun cor) +{ + u3_noun txt = u3x_at(u3x_sam, cor); + + if ( c3n == u3ud(txt) ) { + return u3m_bail(c3__fail); + } + + return u3qe_leer(txt); +} diff --git a/vere/pkg/noun/jets/e/loss.c b/vere/pkg/noun/jets/e/loss.c new file mode 100644 index 0000000..35cdc4e --- /dev/null +++ b/vere/pkg/noun/jets/e/loss.c @@ -0,0 +1,297 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + typedef struct _u3_loss { // loss problem + u3_noun hel; // a as a list + c3_w lel_w; // length of a + c3_w lev_w; // length of b + u3_noun* hev; // b as an array + u3_noun sev; // b as a set of lists + c3_w kct_w; // candidate count + u3_noun* kad; // candidate array + } u3_loss; + + // free loss object + // + static void + _flem(u3_loss* loc_u) + { + u3z(loc_u->sev); + { + c3_w i_w; + + for ( i_w = 0; i_w < loc_u->kct_w; i_w++ ) { + u3z(loc_u->kad[i_w]); + } + } + u3a_free(loc_u->hev); + u3a_free(loc_u->kad); + } + + // extract lcs - XX don't use the stack like this + // + static u3_noun + _lext(u3_loss* loc_u, + u3_noun kad) + { + if ( u3_nul == kad ) { + return u3_nul; + } else { + return u3nc(u3k(loc_u->hev[u3r_word(0, u3h(kad))]), + _lext(loc_u, u3t(kad))); + } + } + + // extract lcs + // + static u3_noun + _lexs(u3_loss* loc_u) + { + if ( 0 == loc_u->kct_w ) { + return u3_nul; + } else return u3kb_flop(_lext(loc_u, loc_u->kad[loc_u->kct_w - 1])); + } + + // initialize loss object + // + static void + _lemp(u3_loss* loc_u, + u3_noun hel, + u3_noun hev) + { + loc_u->hel = hel; + loc_u->lel_w = u3kb_lent(u3k(hel)); + + // Read hev into array. + { + c3_w i_w; + + loc_u->hev = u3a_malloc(u3kb_lent(u3k(hev)) * sizeof(u3_noun)); + + for ( i_w = 0; u3_nul != hev; i_w++ ) { + loc_u->hev[i_w] = u3h(hev); + hev = u3t(hev); + } + loc_u->lev_w = i_w; + } + loc_u->kct_w = 0; + loc_u->kad = u3a_malloc((1 + c3_min(loc_u->lev_w, loc_u->lel_w)) * + sizeof(u3_noun)); + + // Compute equivalence classes. + // + loc_u->sev = u3_nul; + { + c3_w i_w; + + for ( i_w = 0; i_w < loc_u->lev_w; i_w++ ) { + u3_noun how = loc_u->hev[i_w]; + u3_noun hav; + u3_noun teg; + + hav = u3kdb_get(u3k(loc_u->sev), u3k(how)); + teg = u3nc(u3i_words(1, &i_w), + (hav == u3_none) ? u3_nul : hav); + loc_u->sev = u3kdb_put(loc_u->sev, u3k(how), teg); + } + } + } + + // apply + // + static void + _lune(u3_loss* loc_u, + c3_w inx_w, + c3_w goy_w) + { + u3_noun kad; + + kad = u3nc(u3i_words(1, &goy_w), + (inx_w == 0) ? u3_nul + : u3k(loc_u->kad[inx_w - 1])); + if ( loc_u->kct_w == inx_w ) { + u3_assert(loc_u->kct_w < (1 << 31)); + loc_u->kct_w++; + } else { + u3z(loc_u->kad[inx_w]); + } + loc_u->kad[inx_w] = kad; + } + + // extend fits top + // + static u3_noun + _hink(u3_loss* loc_u, + c3_w inx_w, + c3_w goy_w) + { + return __ + ( (loc_u->kct_w == inx_w) || + (u3r_word(0, u3h(loc_u->kad[inx_w])) > goy_w) ); + } + + // extend fits bottom + // + static u3_noun + _lonk(u3_loss* loc_u, + c3_w inx_w, + c3_w goy_w) + { + return __ + ( (0 == inx_w) || + (u3r_word(0, u3h(loc_u->kad[inx_w - 1])) < goy_w) ); + } + +#if 0 + // search for first index >= inx_w and <= max_w that fits + // the hink and lonk criteria. + // + static u3_noun + _binka(u3_loss* loc_u, + c3_w* inx_w, + c3_w max_w, + c3_w goy_w) + { + while ( *inx_w <= max_w ) { + if ( c3n == _lonk(loc_u, *inx_w, goy_w) ) { + return c3n; + } + if ( c3y == _hink(loc_u, *inx_w, goy_w) ) { + return c3y; + } + else ++*inx_w; + } + return c3n; + } +#endif + + // search for lowest index >= inx_w and <= max_w for which + // both hink(inx_w) and lonk(inx_w) are true. lonk is false + // if inx_w is too high, hink is false if it is too low. + // + static u3_noun + _bink(u3_loss* loc_u, + c3_w* inx_w, + c3_w max_w, + c3_w goy_w) + { + u3_assert(max_w >= *inx_w); + + if ( max_w == *inx_w ) { + if ( c3n == _lonk(loc_u, *inx_w, goy_w) ) { + return c3n; + } + if ( c3y == _hink(loc_u, *inx_w, goy_w) ) { + return c3y; + } + else { + ++*inx_w; + return c3n; + } + } + else { + c3_w mid_w = *inx_w + ((max_w - *inx_w) / 2); + + if ( (c3n == _lonk(loc_u, mid_w, goy_w)) || + (c3y == _hink(loc_u, mid_w, goy_w)) ) + { + return _bink(loc_u, inx_w, mid_w, goy_w); + } else { + *inx_w = mid_w + 1; + return _bink(loc_u, inx_w, max_w, goy_w); + } + } + } + + + static void + _merg(u3_loss* loc_u, + c3_w inx_w, + u3_noun gay) + { + if ( (u3_nul == gay) || (inx_w > loc_u->kct_w) ) { + return; + } + else { + u3_noun i_gay = u3h(gay); + c3_w goy_w = u3r_word(0, i_gay); + u3_noun bik; + + bik = _bink(loc_u, &inx_w, loc_u->kct_w, goy_w); + + if ( c3y == bik ) { + _merg(loc_u, inx_w + 1, u3t(gay)); + _lune(loc_u, inx_w, goy_w); + } + else { + _merg(loc_u, inx_w, u3t(gay)); + } + } + } + + // compute lcs + // + static void + _loss(u3_loss* loc_u) + { + while ( u3_nul != loc_u->hel ) { + u3_noun i_hel = u3h(loc_u->hel); + u3_noun guy = u3kdb_get(u3k(loc_u->sev), u3k(i_hel)); + + if ( u3_none != guy ) { + u3_noun gay = u3kb_flop(guy); + + _merg(loc_u, 0, gay); + u3z(gay); + } + + loc_u->hel = u3t(loc_u->hel); + } + } + + u3_noun + u3qe_loss(u3_noun hel, + u3_noun hev) + { + u3_loss loc_u; + u3_noun lcs; + + _lemp(&loc_u, hel, hev); + _loss(&loc_u); + lcs = _lexs(&loc_u); + + _flem(&loc_u); + return lcs; + } + + static u3_noun + _listp(u3_noun lix) + { + while ( 1 ) { + if ( u3_nul == lix ) return c3y; + if ( c3n == u3du(lix) ) return c3n; + lix = u3t(lix); + } + } + + u3_noun + u3we_loss(u3_noun cor) + { + u3_noun hel, hev; + + if ( (u3_none == (hel = u3r_at(u3x_sam_2, cor))) || + (u3_none == (hev = u3r_at(u3x_sam_3, cor))) || + (c3n == _listp(hel)) || + (c3n == _listp(hev)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qe_loss(hel, hev); + } + } diff --git a/vere/pkg/noun/jets/e/lune.c b/vere/pkg/noun/jets/e/lune.c new file mode 100644 index 0000000..1187073 --- /dev/null +++ b/vere/pkg/noun/jets/e/lune.c @@ -0,0 +1,57 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qe_lune(u3_atom lub) + { + if (lub == 0) { + return u3_nul; + } + + { + c3_w end_w = u3r_met(3, lub) - 1; + c3_w pos_w = end_w; + u3_noun lin = u3_nul; + + if (u3r_byte(pos_w, lub) != 10) { + return u3m_error("noeol"); + } + + if (pos_w == 0) { + return u3nc(u3_nul, lin); + } + + while (--pos_w) { + if (u3r_byte(pos_w, lub) == 10) { + lin = u3nc(u3qc_cut(3, (pos_w + 1), (end_w - pos_w - 1), lub), lin); + end_w = pos_w; + } + } + + if (u3r_byte(pos_w, lub) == 10) { + return u3nc(u3_nul, + u3nc(u3qc_cut(3, (pos_w + 1), (end_w - pos_w - 1), lub), lin)); + } + + return u3nc(u3qc_cut(3, pos_w, (end_w - pos_w), lub), lin); + } + } + + u3_noun + u3we_lune(u3_noun cor) + { + u3_noun lub; + + if ( (u3_none == (lub = u3r_at(u3x_sam, cor))) || + (c3n == u3ud(lub)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qe_lune(lub); + } + } diff --git a/vere/pkg/noun/jets/e/mat.c b/vere/pkg/noun/jets/e/mat.c new file mode 100644 index 0000000..89de386 --- /dev/null +++ b/vere/pkg/noun/jets/e/mat.c @@ -0,0 +1,49 @@ + /// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + u3_noun + u3qe_mat(u3_atom a) + { + if ( 0 == a ) { + return u3nc(1, 1); + } else { + u3_atom b = u3qc_met(0, a); + u3_atom c = u3qc_met(0, b); + u3_atom u, v, w, x, y, z; + u3_atom p, q; + + u = u3qa_dec(c); + v = u3qa_add(c, c); + w = u3qc_bex(c); + x = u3qc_end(0, u, b); + y = u3qc_lsh(0, u, a); + z = u3qc_mix(x, y); + + p = u3qa_add(v, b); + q = u3qc_cat(0, w, z); + + u3z(u); + u3z(v); + u3z(w); + u3z(x); + u3z(y); + u3z(z); + + return u3nc(p, q); + } + } + u3_noun + u3we_mat(u3_noun cor) + { + u3_noun a; + + if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ) { + return u3m_bail(c3__fail); + } else { + return u3qe_mat(a); + } + } diff --git a/vere/pkg/noun/jets/e/mice.c b/vere/pkg/noun/jets/e/mice.c new file mode 100644 index 0000000..81b4a33 --- /dev/null +++ b/vere/pkg/noun/jets/e/mice.c @@ -0,0 +1,23 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +/* variant of u3we_mink() / u3m_soft_run(). caching, no scry. +*/ +u3_noun +u3we_mice(u3_noun cor) { + u3_noun bus, fol; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &bus, + u3x_sam_3, &fol, + 0) ) + { + return u3m_bail(c3__exit); + } + else { + return u3m_soft_cax(u3n_nock_on, u3k(bus), u3k(fol)); + } +} diff --git a/vere/pkg/noun/jets/e/mink.c b/vere/pkg/noun/jets/e/mink.c new file mode 100644 index 0000000..4caa208 --- /dev/null +++ b/vere/pkg/noun/jets/e/mink.c @@ -0,0 +1,27 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + u3_noun + u3we_mink(u3_noun cor) + { + u3_noun bus, fol, gul; + + if ( c3n == u3r_mean(cor, u3x_sam_4, &bus, + u3x_sam_5, &fol, + u3x_sam_3, &gul, + 0) ) + { + return u3m_bail(c3__exit); + } + else { + u3_noun som; + + som = u3n_nock_et(u3k(gul), u3k(bus), u3k(fol)); + + return som; + } + } diff --git a/vere/pkg/noun/jets/e/mole.c b/vere/pkg/noun/jets/e/mole.c new file mode 100644 index 0000000..a318390 --- /dev/null +++ b/vere/pkg/noun/jets/e/mole.c @@ -0,0 +1,18 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3we_mole(u3_noun cor) +{ + u3_noun hok = u3j_cook("u3we_mole-mure", u3k(cor), "mure"); + + // just like +mule and +mute, this takes advantage of the fact that + // +mure's result is identical to that of +mole, and safely produces + // a statically-typed value while only evaluating the trap once. + // + return u3n_slam_on(hok, u3k(u3x_at(u3x_sam, cor))); +} diff --git a/vere/pkg/noun/jets/e/mule.c b/vere/pkg/noun/jets/e/mule.c new file mode 100644 index 0000000..79e4656 --- /dev/null +++ b/vere/pkg/noun/jets/e/mule.c @@ -0,0 +1,19 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3we_mule(u3_noun cor) +{ + u3_noun hok = u3j_cook("u3we_mule-mute", u3k(cor), "mute"); + + + // this takes advantage of the fact that +mute's result is + // identical to that of +mule, and safely produces a statically-typed + // value while only evaluating the trap once. + // + return u3n_slam_on(hok, u3k(u3x_at(u3x_sam, cor))); +} diff --git a/vere/pkg/noun/jets/e/parse.c b/vere/pkg/noun/jets/e/parse.c new file mode 100644 index 0000000..4ae8ab0 --- /dev/null +++ b/vere/pkg/noun/jets/e/parse.c @@ -0,0 +1,1052 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + // get p.u.q.vex from an $edge, assumes that the unit is non-empty + // RETAIN [vex] + // + static inline u3_noun + _puq(u3_noun vex) + { + u3_weak pro = u3r_at(14, vex); + c3_dessert(u3_none != pro); + return (u3_noun)pro; + } + + // get q.u.q.vex from an $edge, assumes that the unit is non-empty + // RETAIN [vex] + // + static inline u3_noun + _quq(u3_noun vex) + { + u3_weak pro = u3r_at(15, vex); + c3_dessert(u3_none != pro); + return (u3_noun)pro; + } + + #define _p u3h + #define _q u3t + + static u3_noun + _slip(u3_noun weq, + u3_noun naz) + { + u3_noun p_naz, q_naz; + + u3x_cell(naz, &p_naz, &q_naz); + if ( 10 == weq ) { + return u3nc(u3i_vint(u3k(p_naz)), 1); + } else { + return u3nc(u3k(p_naz), u3i_vint(u3k(q_naz))); + } + } + + static u3_noun + _fail(u3_noun tub) + { + u3_noun p_tub, q_tub; + + u3x_cell(tub, &p_tub, &q_tub); + return u3nc(u3k(p_tub), u3_nul); + } + + static u3_noun + _last(u3_noun zyc, + u3_noun naz) + { + u3_noun p_zyc, q_zyc, p_naz, q_naz; + + u3x_cell(zyc, &p_zyc, &q_zyc); + u3x_cell(naz, &p_naz, &q_naz); + + if ( !_(u3a_is_cat(p_zyc)) || !_(u3a_is_cat(q_zyc)) || + !_(u3a_is_cat(p_naz)) || !_(u3a_is_cat(q_naz)) ) + { + return u3m_bail(c3__fail); + } else { + if ( p_zyc == p_naz ) { + return (q_zyc > q_naz) ? u3k(zyc) : u3k(naz); + } + else { + return (p_zyc > p_naz) ? u3k(zyc) : u3k(naz); + } + } + } + + static u3_noun + _last_k(u3_noun zyc, u3_noun naz) + { + u3_noun pro = _last(zyc, naz); + u3z(zyc); u3z(naz); + return pro; + } + + static u3_noun + _next(u3_noun tub) + { + u3_noun p_tub, q_tub; + u3_noun zac; + + u3x_cell(tub, &p_tub, &q_tub); + if ( c3n == u3du(q_tub) ) { + return _fail(tub); + } + else { + u3_noun iq_tub = u3h(q_tub); + u3_noun tq_tub = u3t(q_tub); + + zac = _slip(iq_tub, p_tub); + + return u3nc(zac, + u3nq(u3_nul, + u3k(iq_tub), + u3k(zac), + u3k(tq_tub))); + } + } + +/* bend +*/ + static u3_noun + _cqe_bend_fun(u3_noun raq, + u3_noun vex, + u3_noun sab) + { + u3_noun p_vex, q_vex; + + u3x_cell(vex, &p_vex, &q_vex); + if ( c3n == u3du(q_vex) ) { + return u3k(vex); + } else { + u3_noun uq_vex = u3t(q_vex); + u3_noun quq_vex; + u3_noun yit, yur; + u3_noun p_yit, q_yit; + u3_noun ret; + + quq_vex = u3t(uq_vex); + + yit = u3n_slam_on(u3k(sab), u3k(quq_vex)); + + u3x_cell(yit, &p_yit, &q_yit); + yur = _last(_p(vex), p_yit); + + if ( c3n == u3du(q_yit) ) { + ret = u3nc(yur, u3k(q_vex)); + } + else { + u3_noun uq_yit = u3t(q_yit); + u3_noun puq_yit; + u3_noun vux; + + puq_yit = u3h(uq_yit); + + vux = u3n_slam_on(u3k(raq), + u3nc(u3k(_puq(vex)), + u3k(puq_yit))); + if ( u3_nul == vux ) { + ret = u3nc(yur, u3k(_q(vex))); + } + else { + ret = u3nq(yur, + u3_nul, + u3k(u3t(vux)), + u3k(_quq(yit))); + u3z(vux); + } + } + u3z(yit); + return ret; + } + } + + u3_noun + u3we_bend_fun(u3_noun cor) + { + u3_noun van, raq, vex, sab; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, + u3x_sam_3, &sab, + u3x_con, &van, 0)) || + (u3_none == (raq = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_bend_fun(raq, vex, sab); + } + } + +/* cold +*/ + static u3_noun + _cqe_cold_fun(u3_noun cus, + u3_noun sef, + u3_noun tub) + { + u3_noun vex = u3n_slam_on(u3k(sef), u3k(tub)); + u3_noun p_vex, q_vex; + + u3x_cell(vex, &p_vex, &q_vex); + + if ( c3n == u3du(q_vex) ) { + return vex; + } + else { + u3_noun uq_vex = u3t(q_vex); + u3_noun quq_vex; + u3_noun ret; + + u3x_cell(uq_vex, 0, &quq_vex); + ret = u3nq(u3k(p_vex), + u3_nul, + u3k(cus), + u3k(quq_vex)); + + u3z(vex); + return ret; + } + } + + u3_noun + u3we_cold_fun(u3_noun cor) + { + u3_noun van, cus, sef, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (c3n == u3r_mean(van, u3x_sam_2, &cus, u3x_sam_3, &sef, 0)) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_cold_fun(cus, sef, tub); + } + } + +/* cook +*/ + static u3_noun + _cqe_cook_fun(u3_noun poq, + u3_noun sef, + u3_noun tub) + { + u3_noun vex = u3n_slam_on(u3k(sef), u3k(tub)); + u3_noun p_vex, q_vex; + + u3x_cell(vex, &p_vex, &q_vex); + + if ( c3n == u3du(q_vex) ) { + return vex; + } + else { + u3_noun uq_vex = u3t(q_vex); + u3_noun puq_vex, quq_vex; + u3_noun wag; + u3_noun ret; + + u3x_cell(uq_vex, &puq_vex, &quq_vex); + + u3k(quq_vex); + u3k(p_vex); + wag = u3n_slam_on(u3k(poq), u3k(puq_vex)); + + ret = u3nq(p_vex, + u3_nul, + wag, + quq_vex); + + u3z(vex); + return ret; + } + } + + u3_noun + u3we_cook_fun(u3_noun cor) + { + u3_noun van, poq, sef, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (c3n == u3r_mean(van, u3x_sam_2, &poq, u3x_sam_3, &sef, 0)) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_cook_fun(poq, sef, tub); + } + } + +/* comp +*/ + static u3_noun + _cqe_comp_fun(u3_noun raq, + u3_noun vex, + u3_noun sab) + { + u3_noun p_vex, q_vex; + + u3x_cell(vex, &p_vex, &q_vex); + if ( c3n == u3du(q_vex) ) { + return u3k(vex); + } else { + u3_noun uq_vex = u3t(q_vex); + u3_noun puq_vex, quq_vex; + u3_noun yit, yur; + u3_noun p_yit, q_yit; + u3_noun ret; + + u3x_cell(uq_vex, &puq_vex, &quq_vex); + yit = u3n_slam_on(u3k(sab), u3k(quq_vex)); + + u3x_cell(yit, &p_yit, &q_yit); + yur = _last(_p(vex), p_yit); + + if ( c3n == u3du(q_yit) ) { + ret = u3nc(yur, u3k(q_yit)); + } + else { + u3_noun uq_yit = u3t(q_yit); + u3_noun puq_yit, quq_yit; + + u3x_cell(uq_yit, &puq_yit, &quq_yit); + + u3k(quq_yit); + ret = u3nq(yur, + u3_nul, + u3n_slam_on(u3k(raq), + u3nc(u3k(_puq(vex)), + u3k(puq_yit))), + quq_yit); + } + u3z(yit); + return ret; + } + } + + u3_noun + u3we_comp_fun(u3_noun cor) + { + u3_noun van, raq, vex, sab; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, + u3x_sam_3, &sab, + u3x_con, &van, 0)) || + (u3_none == (raq = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_comp_fun(raq, vex, sab); + } + } + +/* easy +*/ + static u3_noun + _cqe_easy_fun(u3_noun huf, + u3_noun tub) + { + u3_noun p_tub, q_tub; + + u3x_cell(tub, &p_tub, &q_tub); + return u3nq(u3k(p_tub), + u3_nul, + u3k(huf), + u3k(tub)); + } + + u3_noun + u3we_easy_fun(u3_noun cor) + { + u3_noun van, huf, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (u3_none == (huf = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_easy_fun(huf, tub); + } + } + +/* glue +*/ + static u3_noun + _cqe_glue_fun(u3_noun bus, + u3_noun vex, + u3_noun sab) + { + u3_noun p_vex, q_vex; + + u3x_cell(vex, &p_vex, &q_vex); + if ( c3n == u3du(q_vex) ) { + return u3k(vex); + } + else { + u3_noun uq_vex = u3t(q_vex); + u3_noun puq_vex, quq_vex; + u3_noun yit, yur; + u3_noun p_yit, q_yit; + u3_noun ret; + + u3x_cell(uq_vex, &puq_vex, &quq_vex); + yit = u3n_slam_on(u3k(bus), u3k(quq_vex)); + + u3x_cell(yit, &p_yit, &q_yit); + yur = _last(_p(vex), p_yit); + + if ( c3n == u3du(q_yit) ) { + ret = u3nc(yur, u3_nul); + } + else { + u3_noun uq_yit = u3t(q_yit); + u3_noun puq_yit, quq_yit; + u3_noun wam, p_wam, q_wam, goy; + + u3x_cell(uq_yit, &puq_yit, &quq_yit); + wam = u3n_slam_on(u3k(sab), u3k(quq_yit)); + + u3x_cell(wam, &p_wam, &q_wam); + goy = _last(yur, p_wam); + u3z(yur); + + if ( c3n == u3du(q_wam) ) { + ret = u3nc(goy, u3_nul); + } else { + u3_noun uq_wam = u3t(q_wam); + u3_noun puq_wam, quq_wam; + + u3x_cell(uq_wam, &puq_wam, &quq_wam); + ret = u3nq(goy, + u3_nul, + u3nc(u3k(_puq(vex)), + u3k(puq_wam)), + u3k(quq_wam)); + } + u3z(wam); + } + u3z(yit); + return ret; + } + } + + u3_noun + u3we_glue_fun(u3_noun cor) + { + u3_noun van, bus, vex, sab; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, + u3x_sam_3, &sab, + u3x_con, &van, 0)) || + (u3_none == (bus = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_glue_fun(bus, vex, sab); + } + } + +/* here +*/ + static u3_noun + _cqe_here_fun(u3_noun hez, + u3_noun sef, + u3_noun tub) + { + u3_noun vex = u3n_slam_on(u3k(sef), u3k(tub)); + u3_noun p_vex, q_vex; + + u3x_cell(vex, &p_vex, &q_vex); + + if ( c3n == u3du(q_vex) ) { + return vex; + } + else { + u3_noun uq_vex = u3t(q_vex); + u3_noun p_tub, q_tub; + u3_noun puq_vex, quq_vex, pquq_vex; + u3_noun gud, wag; + u3_noun ret; + + u3x_cell(tub, &p_tub, &q_tub); + u3x_cell(uq_vex, &puq_vex, &quq_vex); + u3x_cell(quq_vex, &pquq_vex, 0); + gud = u3nc( + u3nc(u3k(p_tub), + u3k(pquq_vex)), + u3k(puq_vex)); + + u3k(p_vex); + u3k(quq_vex); + wag = u3n_slam_on(u3k(hez), gud); + ret = u3nq(p_vex, + u3_nul, + wag, + quq_vex); + + u3z(vex); + return ret; + } + } + + u3_noun + u3we_here_fun(u3_noun cor) + { + u3_noun van, hez, sef, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (c3n == u3r_mean(van, u3x_sam_2, &hez, u3x_sam_3, &sef, 0)) ) + { + return u3m_bail(c3__fail); + } + else { + return _cqe_here_fun(hez, sef, tub); + } + } + +/* just +*/ + static u3_noun + _cqe_just_fun(u3_noun daf, + u3_noun tub) + { + u3_noun p_tub, q_tub; + + u3x_cell(tub, &p_tub, &q_tub); + + if ( c3n == u3du(q_tub) ) { + return _fail(tub); + } + else { + u3_noun iq_tub = u3h(q_tub); + + if ( c3y == u3r_sing(daf, iq_tub) ) { + return _next(tub); + } + else return _fail(tub); + } + } + u3_noun + u3we_just_fun(u3_noun cor) + { + u3_noun van, daf, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (u3_none == (daf = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_just_fun(daf, tub); + } + } + +/* mask +*/ + static u3_noun + _cqe_mask_fun(u3_noun bud, + u3_noun tub) + { + u3_noun p_tub, q_tub; + + u3x_cell(tub, &p_tub, &q_tub); + + if ( c3n == u3du(q_tub) ) { + return _fail(tub); + } + else { + u3_noun iq_tub = u3h(q_tub); + + while ( c3y == u3du(bud) ) { + if ( c3y == u3r_sing(u3h(bud), iq_tub) ) { + return _next(tub); + } + bud = u3t(bud); + } + return _fail(tub); + } + } + u3_noun + u3we_mask_fun(u3_noun cor) + { + u3_noun van, bud, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (u3_none == (bud = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_mask_fun(bud, tub); + } + } +/* pfix +*/ + static u3_noun + _cqe_pfix(u3_noun vex, + u3_noun sab) + { + u3_noun q_vex; + + q_vex = u3t(vex); + if ( c3n == u3du(q_vex) ) { + return u3k(vex); + } + else { + u3_noun uq_vex = u3t(q_vex); + u3_noun quq_vex; + u3_noun yit, p_yit, q_yit; + u3_noun ret; + + quq_vex = u3t(uq_vex); + + yit = u3n_slam_on(u3k(sab), u3k(quq_vex)); + + u3x_cell(yit, &p_yit, &q_yit); + ret = u3nc(_last(_p(vex), p_yit), + u3k(q_yit)); + + u3z(yit); + return ret; + } + } + u3_noun + u3we_pfix(u3_noun cor) + { + u3_noun vex, sab; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) { + return u3m_bail(c3__exit); + } else { + return _cqe_pfix(vex, sab); + } + } + +/* plug +*/ + static u3_noun + _cqe_plug(u3_noun vex, + u3_noun sab) + { + u3_noun p_vex, q_vex; + + u3x_cell(vex, &p_vex, &q_vex); + if ( c3n == u3du(q_vex) ) { + return u3k(vex); + } + else { + u3_noun uq_vex = u3t(q_vex); + u3_noun puq_vex, quq_vex; + u3_noun yit, yur; + u3_noun p_yit, q_yit; + u3_noun ret; + + u3x_cell(uq_vex, &puq_vex, &quq_vex); + yit = u3n_slam_on(u3k(sab), u3k(quq_vex)); + + u3x_cell(yit, &p_yit, &q_yit); + yur = _last(_p(vex), p_yit); + + if ( c3n == u3du(q_yit) ) { + ret = u3nc(yur, u3k(q_yit)); + } + else { + u3_noun uq_yit = u3t(q_yit); + u3_noun puq_yit, quq_yit; + + u3x_cell(uq_yit, &puq_yit, &quq_yit); + ret = u3nq(yur, + u3_nul, + u3nc(u3k(_puq(vex)), + u3k(puq_yit)), + u3k(quq_yit)); + } + u3z(yit); + return ret; + } + } + u3_noun + u3we_plug(u3_noun cor) + { + u3_noun vex, sab; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) { + return u3m_bail(c3__exit); + } else { + return _cqe_plug(vex, sab); + } + } + +/* pose +*/ + u3_noun + u3qe_pose(u3_noun vex, + u3_noun sab) + { + u3_noun q_vex; + + q_vex = u3t(vex); + if ( c3y == u3du(q_vex) ) { + return u3k(vex); + } else { + u3_noun roq = u3n_kick_on(u3k(sab)); + u3_noun p_roq, q_roq; + u3_noun ret; + + u3x_cell(roq, &p_roq, &q_roq); + ret = u3nc(_last(_p(vex), p_roq), + u3k(q_roq)); + + u3z(roq); + return ret; + } + } + u3_noun + u3we_pose(u3_noun cor) + { + u3_noun vex, sab; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) { + return u3m_bail(c3__exit); + } else { + return u3qe_pose(vex, sab); + } + } + +/* sfix +*/ + static u3_noun + _cqe_sfix(u3_noun vex, + u3_noun sab) + { + u3_noun q_vex; + + q_vex = u3t(vex); + if ( c3n == u3du(q_vex) ) { + return u3k(vex); + } + else { + u3_noun uq_vex = u3t(q_vex); + u3_noun quq_vex; + u3_noun yit, p_yit, q_yit, yur; + u3_noun ret; + + quq_vex = u3t(uq_vex); + + yit = u3n_slam_on(u3k(sab), u3k(quq_vex)); + + u3x_cell(yit, &p_yit, &q_yit); + yur = _last(_p(vex), p_yit); + + if ( c3n == u3du(q_yit) ) { + ret = u3nc(yur, u3_nul); + } + else { + u3_noun uq_yit = u3t(q_yit); + u3_noun puq_yit, quq_yit; + + u3x_cell(uq_yit, &puq_yit, &quq_yit); + + ret = u3nq(yur, + u3_nul, + u3k(_puq(vex)), + u3k(quq_yit)); + } + u3z(yit); + return ret; + } + } + u3_noun + u3we_sfix(u3_noun cor) + { + u3_noun vex, sab; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) { + return u3m_bail(c3__exit); + } else { + return _cqe_sfix(vex, sab); + } + } + +/* shim +*/ + static u3_noun + _cqe_shim_fun(u3_noun zep, + u3_noun tub) + { + u3_noun p_tub, q_tub; + + u3x_cell(tub, &p_tub, &q_tub); + + if ( c3n == u3du(q_tub) ) { + return _fail(tub); + } + else { + u3_noun p_zep, q_zep; + u3_noun iq_tub = u3h(q_tub); + + u3x_cell(zep, &p_zep, &q_zep); + if ( _(u3a_is_cat(p_zep)) && + _(u3a_is_cat(q_zep)) && + _(u3a_is_cat(iq_tub)) ) + { + if ( (iq_tub >= p_zep) && (iq_tub <= q_zep) ) { + return _next(tub); + } + else return _fail(tub); + } + else { + return u3m_bail(c3__fail); + } + } + } + u3_noun + u3we_shim_fun(u3_noun cor) + { + u3_noun van, zep, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (u3_none == (zep = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_shim_fun(zep, tub); + } + } + +/* stag +*/ + static u3_noun + _cqe_stag_fun(u3_noun gob, + u3_noun sef, + u3_noun tub) + { + u3_noun vex = u3n_slam_on(u3k(sef), u3k(tub)); + u3_noun p_vex, q_vex; + + u3x_cell(vex, &p_vex, &q_vex); + + if ( c3n == u3du(q_vex) ) { + return vex; + } + else { + u3_noun uq_vex = u3t(q_vex); + u3_noun puq_vex, quq_vex; + u3_noun wag; + u3_noun ret; + + u3x_cell(uq_vex, &puq_vex, &quq_vex); + wag = u3nc(u3k(gob), u3k(puq_vex)); + ret = u3nq(u3k(p_vex), + u3_nul, + wag, + u3k(quq_vex)); + + u3z(vex); + return ret; + } + } + + u3_noun + u3we_stag_fun(u3_noun cor) + { + u3_noun van, gob, sef, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (c3n == u3r_mean(van, u3x_sam_2, &gob, u3x_sam_3, &sef, 0)) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_stag_fun(gob, sef, tub); + } + } + +/* stew +*/ + static u3_noun + _stew_wor(u3_noun ort, + u3_noun wan) + { + if ( !_(u3a_is_cat(ort)) ) { + return u3m_bail(c3__fail); + } + else { + if ( c3n == u3du(wan) ) { + if ( !_(u3a_is_cat(wan)) ) { + return u3m_bail(c3__fail); + } + else return (ort < wan) ? c3y : c3n; + } + else { + u3_noun h_wan = u3h(wan); + + if ( !_(u3a_is_cat(h_wan)) ) { + return u3m_bail(c3__fail); + } + else return (ort < h_wan) ? c3y : c3n; + } + } + } + + static u3_noun + _cqe_stew_fun(u3_noun hel, + u3_noun tub) + { + u3_noun p_tub, q_tub; + + u3x_cell(tub, &p_tub, &q_tub); + if ( c3n == u3du(q_tub) ) { + return _fail(tub); + } + else { + u3_noun iq_tub = u3h(q_tub); + + if ( !_(u3a_is_cat(iq_tub)) ) { + return u3m_bail(c3__fail); + } + else while ( 1 ) { + if ( c3n == u3du(hel) ) { + return _fail(tub); + } + else { + u3_noun n_hel, l_hel, r_hel; + u3_noun pn_hel, qn_hel; + c3_o bit_o; + + u3x_trel(hel, &n_hel, &l_hel, &r_hel); + u3x_cell(n_hel, &pn_hel, &qn_hel); + + if ( (c3n == u3du(pn_hel)) ) { + bit_o = __((iq_tub == pn_hel)); + } + else { + u3_noun hpn_hel = u3h(pn_hel); + u3_noun tpn_hel = u3t(pn_hel); + + if ( !_(u3a_is_cat(hpn_hel)) || + !_(u3a_is_cat(tpn_hel)) ) { + return _fail(tub); + } + else bit_o = __((iq_tub >= hpn_hel) && (iq_tub <= tpn_hel)); + } + + if ( c3y == bit_o ) { + return u3n_slam_on(u3k(qn_hel), u3k(tub)); + } else { + if ( c3y == _stew_wor(iq_tub, pn_hel) ) { + hel = l_hel; + } + else hel = r_hel; + } + } + } + } + } + u3_noun + u3we_stew_fun(u3_noun cor) + { + u3_noun con, hel, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &con, 0)) || + (u3_none == (hel = u3r_at(2, con))) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_stew_fun(hel, tub); + } + } + +/* _stir_pair(): stack frame recording intermediate parse results +*/ + typedef struct { + u3_noun har; // hair, p_vex + u3_noun res; // parse-result, puq_vex + } _stir_pair; + +/* stir +*/ + static u3_noun + _cqe_stir_fun(u3_noun rud, + u3_noun raq, + u3_noun fel, + u3_noun tub) + { + // pil_u: stack control structure + // par_u: frame pointer + // wag: initial accumulator (deconstructed) + // + u3a_pile pil_u; + _stir_pair* par_u; + u3_noun p_wag, puq_wag, quq_wag; + + u3a_pile_prep(&pil_u, sizeof(*par_u)); + + // push incremental, successful [fel] parse results onto road stack + // + { + u3_noun vex, p_vex, q_vex, puq_vex, quq_vex; + u3j_site fel_u; + u3j_gate_prep(&fel_u, u3k(fel)); + + vex = u3j_gate_slam(&fel_u, u3k(tub)); + u3x_cell(vex, &p_vex, &q_vex); + + u3k(tub); + + while ( u3_nul != q_vex ) { + u3x_trel(q_vex, 0, &puq_vex, &quq_vex); + + par_u = u3a_push(&pil_u); + par_u->har = u3k(p_vex); + par_u->res = u3k(puq_vex); + + u3z(tub); + tub = u3k(quq_vex); + + u3z(vex); + vex = u3j_gate_slam(&fel_u, u3k(tub)); + u3x_cell(vex, &p_vex, &q_vex); + } + + p_wag = u3k(p_vex); + puq_wag = u3k(rud); + quq_wag = tub; + + u3z(vex); + u3j_gate_lose(&fel_u); + } + + // unwind the stack, folding parse results into [wag] by way of [raq] + // + if ( c3n == u3a_pile_done(&pil_u) ) { + u3j_site raq_u; + u3j_gate_prep(&raq_u, u3k(raq)); + + while ( c3n == u3a_pile_done(&pil_u) ) { + p_wag = _last_k(par_u->har, p_wag); + puq_wag = u3j_gate_slam(&raq_u, u3nc(par_u->res, puq_wag)); + par_u = u3a_pop(&pil_u); + } + + u3j_gate_lose(&raq_u); + } + + return u3nq(p_wag, u3_nul, puq_wag, quq_wag); + } + + u3_noun + u3we_stir_fun(u3_noun cor) + { + u3_noun van, rud, raq, fel, tub; + + if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || + (c3n == u3r_mean(van, u3x_sam_2, &rud, + u3x_sam_6, &raq, + u3x_sam_7, &fel, + 0)) ) + { + return u3m_bail(c3__fail); + } else { + return _cqe_stir_fun(rud, raq, fel, tub); + } + } + + #undef _p + #undef _q +
\ No newline at end of file diff --git a/vere/pkg/noun/jets/e/rd.c b/vere/pkg/noun/jets/e/rd.c new file mode 100644 index 0000000..a693e3f --- /dev/null +++ b/vere/pkg/noun/jets/e/rd.c @@ -0,0 +1,390 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "softfloat.h" + +#define DOUBNAN 0x7ff8000000000000 + + union doub { + float64_t d; + c3_d c; + }; + + static inline c3_t + _nan_test(float64_t a) + { + return !f64_eq(a, a); + } + + static inline float64_t + _nan_unify(float64_t a) + { + if ( _nan_test(a) ) + { + *(c3_d*)(&a) = DOUBNAN; + } + return a; + } + + static inline void + _set_rounding(c3_w a) + { + switch ( a ) + { + default: + u3m_bail(c3__fail); + break; + case c3__n: + softfloat_roundingMode = softfloat_round_near_even; + break; + case c3__z: + softfloat_roundingMode = softfloat_round_minMag; + break; + case c3__u: + softfloat_roundingMode = softfloat_round_max; + break; + case c3__d: + softfloat_roundingMode = softfloat_round_min; + break; + } + } + +/* add +*/ + u3_noun + u3qer_add(u3_atom a, + u3_atom b, + u3_atom r) + { + union doub c, d, e; + _set_rounding(r); + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + e.d = _nan_unify(f64_add(c.d, d.d)); + + return u3i_chubs(1, &e.c); + } + + u3_noun + u3wer_add(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_add(a, b, u3x_at(30, cor)); + } + } + +/* sub +*/ + u3_noun + u3qer_sub(u3_atom a, + u3_atom b, + u3_atom r) + { + union doub c, d, e; + _set_rounding(r); + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + e.d = _nan_unify(f64_sub(c.d, d.d)); + + return u3i_chubs(1, &e.c); + } + + u3_noun + u3wer_sub(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_sub(a, b, u3x_at(30, cor)); + } + } + +/* mul +*/ + u3_noun + u3qer_mul(u3_atom a, + u3_atom b, + u3_atom r) + { + union doub c, d, e; + _set_rounding(r); + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + e.d = _nan_unify(f64_mul(c.d, d.d)); + + return u3i_chubs(1, &e.c); + } + + u3_noun + u3wer_mul(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_mul(a, b, u3x_at(30, cor)); + } + } + +/* div +*/ + u3_noun + u3qer_div(u3_atom a, + u3_atom b, + u3_atom r) + { + union doub c, d, e; + _set_rounding(r); + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + e.d = _nan_unify(f64_div(c.d, d.d)); + + return u3i_chubs(1, &e.c); + } + + u3_noun + u3wer_div(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_div(a, b, u3x_at(30, cor)); + } + } + +/* sqt +*/ + u3_noun + u3qer_sqt(u3_atom a, + u3_atom r) + { + union doub c, d; + _set_rounding(r); + c.c = u3r_chub(0, a); + d.d = _nan_unify(f64_sqrt(c.d)); + + return u3i_chubs(1, &d.c); + } + + u3_noun + u3wer_sqt(u3_noun cor) + { + u3_noun a; + + if ( c3n == (a = u3r_at(u3x_sam, cor)) || + c3n == u3ud(a) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_sqt(a, u3x_at(30, cor)); + } + } + +/* fma +*/ + u3_noun + u3qer_fma(u3_atom a, + u3_atom b, + u3_atom c, + u3_atom r) + { + union doub d, e, f, g; + _set_rounding(r); + d.c = u3r_chub(0, a); + e.c = u3r_chub(0, b); + f.c = u3r_chub(0, c); + g.d = _nan_unify(f64_mulAdd(d.d, e.d, f.d)); + + return u3i_chubs(1, &g.c); + } + + u3_noun + u3wer_fma(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) || + c3n == u3ud(c) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_fma(a, b, c, u3x_at(30, cor)); + } + } + +/* lth +*/ + u3_noun + u3qer_lth(u3_atom a, + u3_atom b) + { + union doub c, d; + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + + return __(f64_lt(c.d, d.d)); + } + + u3_noun + u3wer_lth(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_lth(a, b); + } + } + +/* lte +*/ + u3_noun + u3qer_lte(u3_atom a, + u3_atom b) + { + union doub c, d; + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + + return __(f64_le(c.d, d.d)); + } + + u3_noun + u3wer_lte(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_lte(a, b); + } + } + +/* equ +*/ + u3_noun + u3qer_equ(u3_atom a, + u3_atom b) + { + union doub c, d; + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + + return __(f64_eq(c.d, d.d)); + } + + u3_noun + u3wer_equ(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_equ(a, b); + } + } + +/* gte +*/ + u3_noun + u3qer_gte(u3_atom a, + u3_atom b) + { + union doub c, d; + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + + return __(f64_le(d.d, c.d)); + } + + u3_noun + u3wer_gte(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_gte(a, b); + } + } + +/* gth +*/ + u3_noun + u3qer_gth(u3_atom a, + u3_atom b) + { + union doub c, d; + c.c = u3r_chub(0, a); + d.c = u3r_chub(0, b); + + return __(f64_lt(d.d, c.d)); + } + + u3_noun + u3wer_gth(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qer_gth(a, b); + } + } diff --git a/vere/pkg/noun/jets/e/rh.c b/vere/pkg/noun/jets/e/rh.c new file mode 100644 index 0000000..3bbb8d4 --- /dev/null +++ b/vere/pkg/noun/jets/e/rh.c @@ -0,0 +1,390 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "softfloat.h" + +#define HALFNAN 0x7e00 + + union half { + float16_t h; + c3_s c; + }; + + static inline c3_t + _nan_test(float16_t a) + { + return !f16_eq(a, a); + } + + static inline float16_t + _nan_unify(float16_t a) + { + if ( _nan_test(a) ) + { + *(c3_s*)(&a) = HALFNAN; + } + return a; + } + + static inline void + _set_rounding(c3_w a) + { + switch ( a ) + { + default: + u3m_bail(c3__fail); + break; + case c3__n: + softfloat_roundingMode = softfloat_round_near_even; + break; + case c3__z: + softfloat_roundingMode = softfloat_round_minMag; + break; + case c3__u: + softfloat_roundingMode = softfloat_round_max; + break; + case c3__d: + softfloat_roundingMode = softfloat_round_min; + break; + } + } + +/* add +*/ + u3_noun + u3qes_add(u3_atom a, + u3_atom b, + u3_atom r) + { + union half c, d, e; + _set_rounding(r); + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + e.h = _nan_unify(f16_add(c.h, d.h)); + + return e.c; + } + + u3_noun + u3wes_add(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_add(a, b, u3x_at(30, cor)); + } + } + +/* sub +*/ + u3_noun + u3qes_sub(u3_atom a, + u3_atom b, + u3_atom r) + { + union half c, d, e; + _set_rounding(r); + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + e.h = _nan_unify(f16_sub(c.h, d.h)); + + return e.c; + } + + u3_noun + u3wes_sub(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_sub(a, b, u3x_at(30, cor)); + } + } + +/* mul +*/ + u3_noun + u3qes_mul(u3_atom a, + u3_atom b, + u3_atom r) + { + union half c, d, e; + _set_rounding(r); + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + e.h = _nan_unify(f16_mul(c.h, d.h)); + + return e.c; + } + + u3_noun + u3wes_mul(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_mul(a, b, u3x_at(30, cor)); + } + } + +/* div +*/ + u3_noun + u3qes_div(u3_atom a, + u3_atom b, + u3_atom r) + { + union half c, d, e; + _set_rounding(r); + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + e.h = _nan_unify(f16_div(c.h, d.h)); + + return e.c; + } + + u3_noun + u3wes_div(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_div(a, b, u3x_at(30, cor)); + } + } + +/* sqt +*/ + u3_noun + u3qes_sqt(u3_atom a, + u3_atom r) + { + union half c, d; + _set_rounding(r); + c.c = u3r_word(0, a); + d.h = _nan_unify(f16_sqrt(c.h)); + + return d.c; + } + + u3_noun + u3wes_sqt(u3_noun cor) + { + u3_noun a; + + if ( c3n == (a = u3r_at(u3x_sam, cor)) || + c3n == u3ud(a) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_sqt(a, u3x_at(30, cor)); + } + } + +/* fma +*/ + u3_noun + u3qes_fma(u3_atom a, + u3_atom b, + u3_atom c, + u3_atom r) + { + union half d, e, f, g; + _set_rounding(r); + d.c = u3r_word(0, a); + e.c = u3r_word(0, b); + f.c = u3r_word(0, c); + g.h = _nan_unify(f16_mulAdd(d.h, e.h, f.h)); + + return g.c; + } + + u3_noun + u3wes_fma(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) || + c3n == u3ud(c) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_fma(a, b, c, u3x_at(30, cor)); + } + } + +/* lth +*/ + u3_noun + u3qes_lth(u3_atom a, + u3_atom b) + { + union half c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f16_lt(c.h, d.h)); + } + + u3_noun + u3wes_lth(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_lth(a, b); + } + } + +/* lte +*/ + u3_noun + u3qes_lte(u3_atom a, + u3_atom b) + { + union half c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f16_le(c.h, d.h)); + } + + u3_noun + u3wes_lte(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_lte(a, b); + } + } + +/* equ +*/ + u3_noun + u3qes_equ(u3_atom a, + u3_atom b) + { + union half c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f16_eq(c.h, d.h)); + } + + u3_noun + u3wes_equ(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_equ(a, b); + } + } + +/* gte +*/ + u3_noun + u3qes_gte(u3_atom a, + u3_atom b) + { + union half c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f16_le(d.h, c.h)); + } + + u3_noun + u3wes_gte(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_gte(a, b); + } + } + +/* gth +*/ + u3_noun + u3qes_gth(u3_atom a, + u3_atom b) + { + union half c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f16_lt(d.h, c.h)); + } + + u3_noun + u3wes_gth(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qes_gth(a, b); + } + } diff --git a/vere/pkg/noun/jets/e/ripe.c b/vere/pkg/noun/jets/e/ripe.c new file mode 100644 index 0000000..5d08a9d --- /dev/null +++ b/vere/pkg/noun/jets/e/ripe.c @@ -0,0 +1,45 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_atom + _cqe_ripe(u3_atom wid, u3_atom dat) + { + c3_w len_w; + if ( !u3r_word_fit(&len_w, wid) ) { + return u3m_bail(c3__fail); + } + else { + u3_atom ret; + c3_y out_y[20]; + c3_y *dat_y = u3r_bytes_alloc(0, len_w, dat); + + ret = ( 0 == urcrypt_ripemd160(dat_y, len_w, out_y) ) + ? u3i_bytes(20, out_y) + : u3_none; + + u3a_free(dat_y); + return ret; + } + } + + u3_noun + u3we_ripe(u3_noun cor) + { + u3_noun wid, dat; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &wid, + u3x_sam_3, &dat, 0) || + u3ud(wid) || u3ud(dat)) + ) + { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("ripe", _cqe_ripe(wid, dat)); + } + } diff --git a/vere/pkg/noun/jets/e/rq.c b/vere/pkg/noun/jets/e/rq.c new file mode 100644 index 0000000..e26a4de --- /dev/null +++ b/vere/pkg/noun/jets/e/rq.c @@ -0,0 +1,446 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "softfloat.h" + +#define QUADNAN 0x7fff800000000000 + + union quad { + float128_t* q; + c3_w* c; + }; + + static inline c3_t + _nan_test(float128_t* a) + { + return !f128M_eq(a, a); + } + + static inline void + _nan_unify(float128_t* a) + { + if ( _nan_test(a) ) + { + *( (c3_d*)a) = 0; + *(((c3_d*)a)+1) = QUADNAN; + } + } + + static inline void + _set_rounding(c3_w a) + { + switch ( a ) + { + default: + u3m_bail(c3__fail); + break; + case c3__n: + softfloat_roundingMode = softfloat_round_near_even; + break; + case c3__z: + softfloat_roundingMode = softfloat_round_minMag; + break; + case c3__u: + softfloat_roundingMode = softfloat_round_max; + break; + case c3__d: + softfloat_roundingMode = softfloat_round_min; + break; + } + } + +/* add +*/ + u3_noun + u3qeq_add(u3_atom a, + u3_atom b, + u3_atom r) + { + union quad c, d, e; + _set_rounding(r); + c.c = alloca(16); + d.c = alloca(16); + e.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + f128M_add(c.q, d.q, e.q); + _nan_unify(e.q); + + u3_atom f = u3i_words(4, e.c); + return f; + } + + u3_noun + u3weq_add(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_add(a, b, u3x_at(30, cor)); + } + } + +/* sub +*/ + u3_noun + u3qeq_sub(u3_atom a, + u3_atom b, + u3_atom r) + { + union quad c, d, e; + _set_rounding(r); + c.c = alloca(16); + d.c = alloca(16); + e.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + f128M_sub(c.q, d.q, e.q); + _nan_unify(e.q); + + u3_atom f = u3i_words(4, e.c); + return f; + } + + u3_noun + u3weq_sub(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_sub(a, b, u3x_at(30, cor)); + } + } + +/* mul +*/ + u3_noun + u3qeq_mul(u3_atom a, + u3_atom b, + u3_atom r) + { + union quad c, d, e; + _set_rounding(r); + c.c = alloca(16); + d.c = alloca(16); + e.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + f128M_mul(c.q, d.q, e.q); + _nan_unify(e.q); + + u3_atom f = u3i_words(4, e.c); + return f; + } + + u3_noun + u3weq_mul(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_mul(a, b, u3x_at(30, cor)); + } + } + +/* div +*/ + u3_noun + u3qeq_div(u3_atom a, + u3_atom b, + u3_atom r) + { + union quad c, d, e; + _set_rounding(r); + c.c = alloca(16); + d.c = alloca(16); + e.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + f128M_div(c.q, d.q, e.q); + _nan_unify(e.q); + + u3_atom f = u3i_words(4, e.c); + return f; + } + + u3_noun + u3weq_div(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_div(a, b, u3x_at(30, cor)); + } + } + +/* sqt +*/ + u3_noun + u3qeq_sqt(u3_atom a, + u3_atom r) + { + union quad c, d; + _set_rounding(r); + c.c = alloca(16); + d.c = alloca(16); + + u3r_words(0, 4, c.c, a); + f128M_sqrt(c.q, d.q); + _nan_unify(d.q); + + u3_atom e = u3i_words(4, d.c); + return e; + } + + u3_noun + u3weq_sqt(u3_noun cor) + { + u3_noun a; + + if ( c3n == (a = u3r_at(u3x_sam, cor)) || + c3n == u3ud(a) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_sqt(a, u3x_at(30, cor)); + } + } + +/* fma +*/ + u3_noun + u3qeq_fma(u3_atom a, + u3_atom b, + u3_atom c, + u3_atom r) + { + union quad d, e, f, g; + _set_rounding(r); + d.c = alloca(16); + e.c = alloca(16); + f.c = alloca(16); + g.c = alloca(16); + + u3r_words(0, 4, d.c, a); + u3r_words(0, 4, e.c, b); + u3r_words(0, 4, f.c, c); + f128M_mulAdd(d.q, e.q, f.q, g.q); + _nan_unify(g.q); + + u3_atom h = u3i_words(4, g.c); + return h; + } + + u3_noun + u3weq_fma(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) || + c3n == u3ud(c) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_fma(a, b, c, u3x_at(30, cor)); + } + } + +/* lth +*/ + u3_noun + u3qeq_lth(u3_atom a, + u3_atom b) + { + union quad c, d; + c.c = alloca(16); + d.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + c3_o e = __(f128M_lt(c.q, d.q)); + + return e; + } + + u3_noun + u3weq_lth(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_lth(a, b); + } + } + +/* lte +*/ + u3_noun + u3qeq_lte(u3_atom a, + u3_atom b) + { + union quad c, d; + c.c = alloca(16); + d.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + c3_o e = __(f128M_le(c.q, d.q)); + + return e; + } + + u3_noun + u3weq_lte(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_lte(a, b); + } + } + +/* equ +*/ + u3_noun + u3qeq_equ(u3_atom a, + u3_atom b) + { + union quad c, d; + c.c = alloca(16); + d.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + c3_o e = __(f128M_eq(c.q, d.q)); + + return e; + } + + u3_noun + u3weq_equ(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_equ(a, b); + } + } + +/* gte +*/ + u3_noun + u3qeq_gte(u3_atom a, + u3_atom b) + { + union quad c, d; + c.c = alloca(16); + d.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + c3_o e = __(f128M_le(d.q, c.q)); + + return e; + } + + u3_noun + u3weq_gte(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_gte(a, b); + } + } + +/* gth +*/ + u3_noun + u3qeq_gth(u3_atom a, + u3_atom b) + { + union quad c, d; + c.c = alloca(16); + d.c = alloca(16); + + u3r_words(0, 4, c.c, a); + u3r_words(0, 4, d.c, b); + c3_o e = __(f128M_lt(d.q, c.q)); + + return e; + } + + u3_noun + u3weq_gth(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qeq_gth(a, b); + } + } diff --git a/vere/pkg/noun/jets/e/rs.c b/vere/pkg/noun/jets/e/rs.c new file mode 100644 index 0000000..360d1c9 --- /dev/null +++ b/vere/pkg/noun/jets/e/rs.c @@ -0,0 +1,390 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "softfloat.h" + +#define SINGNAN 0x7fc00000 + + union sing { + float32_t s; + c3_w c; + }; + + static inline c3_t + _nan_test(float32_t a) + { + return !f32_eq(a, a); + } + + static inline float32_t + _nan_unify(float32_t a) + { + if ( _nan_test(a) ) + { + *(c3_w*)(&a) = SINGNAN; + } + return a; + } + + static inline void + _set_rounding(c3_w a) + { + switch ( a ) + { + default: + u3m_bail(c3__fail); + break; + case c3__n: + softfloat_roundingMode = softfloat_round_near_even; + break; + case c3__z: + softfloat_roundingMode = softfloat_round_minMag; + break; + case c3__u: + softfloat_roundingMode = softfloat_round_max; + break; + case c3__d: + softfloat_roundingMode = softfloat_round_min; + break; + } + } + +/* add +*/ + u3_noun + u3qet_add(u3_atom a, + u3_atom b, + u3_atom r) + { + union sing c, d, e; + _set_rounding(r); + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + e.s = _nan_unify(f32_add(c.s, d.s)); + + return u3i_words(1, &e.c); + } + + u3_noun + u3wet_add(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_add(a, b, u3x_at(30, cor)); + } + } + +/* sub +*/ + u3_noun + u3qet_sub(u3_atom a, + u3_atom b, + u3_atom r) + { + union sing c, d, e; + _set_rounding(r); + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + e.s = _nan_unify(f32_sub(c.s, d.s)); + + return u3i_words(1, &e.c); + } + + u3_noun + u3wet_sub(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_sub(a, b, u3x_at(30, cor)); + } + } + +/* mul +*/ + u3_noun + u3qet_mul(u3_atom a, + u3_atom b, + u3_atom r) + { + union sing c, d, e; + _set_rounding(r); + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + e.s = _nan_unify(f32_mul(c.s, d.s)); + + return u3i_words(1, &e.c); + } + + u3_noun + u3wet_mul(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_mul(a, b, u3x_at(30, cor)); + } + } + +/* div +*/ + u3_noun + u3qet_div(u3_atom a, + u3_atom b, + u3_atom r) + { + union sing c, d, e; + _set_rounding(r); + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + e.s = _nan_unify(f32_div(c.s, d.s)); + + return u3i_words(1, &e.c); + } + + u3_noun + u3wet_div(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_div(a, b, u3x_at(30, cor)); + } + } + +/* sqt +*/ + u3_noun + u3qet_sqt(u3_atom a, + u3_atom r) + { + union sing c, d; + _set_rounding(r); + c.c = u3r_word(0, a); + d.s = _nan_unify(f32_sqrt(c.s)); + + return u3i_words(1, &d.c); + } + + u3_noun + u3wet_sqt(u3_noun cor) + { + u3_noun a; + + if ( c3n == (a = u3r_at(u3x_sam, cor)) || + c3n == u3ud(a) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_sqt(a, u3x_at(30, cor)); + } + } + +/* fma +*/ + u3_noun + u3qet_fma(u3_atom a, + u3_atom b, + u3_atom c, + u3_atom r) + { + union sing d, e, f, g; + _set_rounding(r); + d.c = u3r_word(0, a); + e.c = u3r_word(0, b); + f.c = u3r_word(0, c); + g.s = _nan_unify(f32_mulAdd(d.s, e.s, f.s)); + + return u3i_words(1, &g.c); + } + + u3_noun + u3wet_fma(u3_noun cor) + { + u3_noun a, b, c; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) || + c3n == u3ud(c) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_fma(a, b, c, u3x_at(30, cor)); + } + } + +/* lth +*/ + u3_noun + u3qet_lth(u3_atom a, + u3_atom b) + { + union sing c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f32_lt(c.s, d.s)); + } + + u3_noun + u3wet_lth(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_lth(a, b); + } + } + +/* lte +*/ + u3_noun + u3qet_lte(u3_atom a, + u3_atom b) + { + union sing c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f32_le(c.s, d.s)); + } + + u3_noun + u3wet_lte(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_lte(a, b); + } + } + +/* equ +*/ + u3_noun + u3qet_equ(u3_atom a, + u3_atom b) + { + union sing c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f32_eq(c.s, d.s)); + } + + u3_noun + u3wet_equ(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_equ(a, b); + } + } + +/* gte +*/ + u3_noun + u3qet_gte(u3_atom a, + u3_atom b) + { + union sing c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f32_le(d.s, c.s)); + } + + u3_noun + u3wet_gte(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_gte(a, b); + } + } + +/* gth +*/ + u3_noun + u3qet_gth(u3_atom a, + u3_atom b) + { + union sing c, d; + c.c = u3r_word(0, a); + d.c = u3r_word(0, b); + + return __(f32_lt(d.s, c.s)); + } + + u3_noun + u3wet_gth(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || + c3n == u3ud(a) || + c3n == u3ud(b) ) + { + return u3m_bail(c3__exit); + } + else { + return u3qet_gth(a, b); + } + } diff --git a/vere/pkg/noun/jets/e/rub.c b/vere/pkg/noun/jets/e/rub.c new file mode 100644 index 0000000..81739be --- /dev/null +++ b/vere/pkg/noun/jets/e/rub.c @@ -0,0 +1,85 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qe_rub(u3_atom a, + u3_atom b) + { + u3_atom c, d, e; + u3_atom w, x, y, z; + u3_atom p, q; + + u3_atom m; + { + c3_w bit_w = u3r_met(0, b); + u3_noun bit = u3i_words(1, &bit_w); + m = u3qa_add(a, bit); + u3z(bit); + } + + // Compute c and d. + { + x = u3k(a); + + while ( 0 == u3qc_cut(0, x, 1, b) ) { + u3_atom y = u3qa_inc(x); + + // Sanity check: crash if decoding more bits than available + if ( c3y == u3qa_gth(x, m)) { + // u3l_log("[%%rub-hard %d %d %d]", a, x, m); + return u3m_bail(c3__exit); + } + + u3z(x); + x = y; + } + if ( c3y == u3r_sing(x, a) ) { + u3z(x); + return u3nc(1, 0); + } + c = u3qa_sub(x, a); + d = u3qa_inc(x); + + u3z(x); + } + + // Compute e, p, q. + { + x = u3qa_dec(c); + y = u3qc_bex(x); + z = u3qc_cut(0, d, x, b); + + e = u3qa_add(y, z); + u3z(y); u3z(z); + + w = u3qa_add(c, c); + y = u3qa_add(w, e); + z = u3qa_add(d, x); + + p = u3qa_add(w, e); + q = u3qc_cut(0, z, e, b); + + u3z(w); u3z(x); u3z(y); u3z(z); + + return u3nc(p, q); + } + } + u3_noun + u3we_rub(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qe_rub(a, b); + } + } diff --git a/vere/pkg/noun/jets/e/scot.c b/vere/pkg/noun/jets/e/scot.c new file mode 100644 index 0000000..f39c46b --- /dev/null +++ b/vere/pkg/noun/jets/e/scot.c @@ -0,0 +1,30 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +#include <ctype.h> + +u3_atom +u3qe_scot(u3_atom a, u3_atom b) +{ + switch (a) { + case c3__tas: return u3k(b); + case c3__ud: return u3s_etch_ud(b); + case c3__ux: return u3s_etch_ux(b); + case c3__uv: return u3s_etch_uv(b); + case c3__uw: return u3s_etch_uw(b); + default: return u3_none; + } +} + +u3_noun +u3we_scot(u3_noun cor) +{ + u3_atom a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qe_scot(u3x_atom(a), u3x_atom(b)); +} diff --git a/vere/pkg/noun/jets/e/scow.c b/vere/pkg/noun/jets/e/scow.c new file mode 100644 index 0000000..986dc41 --- /dev/null +++ b/vere/pkg/noun/jets/e/scow.c @@ -0,0 +1,251 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +#include <ctype.h> + +static +c3_y to_digit(c3_y tig) +{ + if (tig >= 10) { + return 87 + tig; + } else { + return '0' + tig; + } +} + +// gives the characters for a four 'digit' small hex atom. +static +void +_x_co_four(c3_w src, c3_y* a, c3_y* b, c3_y* c, c3_y* d) +{ + *d = to_digit(src & 0xF); + src >>= 4; + *c = to_digit(src & 0xF); + src >>= 4; + *b = to_digit(src & 0xF); + src >>= 4; + *a = to_digit(src & 0xF); +} + +// The parser always prints two digits on 0 in y-co. +static +void +_y_co_two(c3_w src, c3_y* a, c3_y* b) +{ + *b = to_digit(src % 10); + *a = to_digit(src / 10); +} + +// +static +u3_noun +_add_year(c3_w year, u3_noun out) +{ + while (year > 0) { + out = u3nc(to_digit(year % 10), out); + year = year / 10; + } + + return out; +} + +static +u3_noun +_print_da(u3_noun cor, u3_atom raw_da) +{ + u3_noun hok = u3j_cook("u3we_scow_print_da", u3k(cor), "yore"); + u3_noun yod = u3n_slam_on(hok, u3k(raw_da)); + + u3_noun out = 0; + + u3_atom age, year, month, day, hour, min, sec, f; + if (c3n == u3r_mean(yod, 4, &age, + 5, &year, + 6, &month, + 14, &day, + 30, &hour, + 62, &min, + 126, &sec, + 127, &f, + 0)) { + return u3m_bail(c3__exit); + } + + if (f != 0) { + u3_noun f_list = u3qb_flop(f); + + for (u3_noun cur = f_list; + _(u3a_is_cell(cur)); + cur = u3t(cur)) { + if (_(u3a_is_cat(u3h(cur)))) { + c3_y a, b, c, d; + _x_co_four(u3h(cur), &a, &b, &c, &d); + out = u3nq('.', a, b, u3nt(c, d, out)); + } else { + // No way to deal with big atoms. fall back. + u3z(yod); + u3z(out); + u3z(f_list); + return u3_none; + } + } + + u3z(f_list); + out = u3nc('.', out); + } + + // if there isn't a hex list and the h/m/s are all 0, skip printing hours. + if (f != 0 || hour != 0 || min != 0 || sec != 0) { + if (!_(u3a_is_cat(hour)) || + !_(u3a_is_cat(min)) || + !_(u3a_is_cat(sec))) { + // Input is weird, fallback to nock. + u3z(yod); + u3z(out); + return u3_none; + } + + c3_y sa, sb, ma, mb, ha, hb; + _y_co_two(sec, &sa, &sb); + out = u3nq('.', sa, sb, out); + + _y_co_two(min, &ma, &mb); + out = u3nq('.', ma, mb, out); + + _y_co_two(hour, &ha, &hb); + out = u3nq('.', ha, hb, out); + + out = u3nc('.', out); + } + + // We always print the Y.M.D. Unlike others, these numbers are unconstrained + // by length, but in practice, the month number and day number can only be up + // to two digits because of +yore. We still need to remove 0 prefixes, + // though. + if (!_(u3a_is_cat(day)) || day > 99 || + !_(u3a_is_cat(month)) || month > 99 || + !_(u3a_is_cat(year))) { + // Input is weird, fallback to nock. + u3z(yod); + u3z(out); + return u3_none; + } + + c3_y da, db; + _y_co_two(day, &da, &db); + out = u3nc(db, out); + if (da != '0') { + out = u3nc(da, out); + } + out = u3nc('.', out); + + c3_y ma, mb; + _y_co_two(month, &ma, &mb); + out = u3nc(mb, out); + if (ma != '0') { + out = u3nc(ma, out); + } + out = u3nc('.', out); + + // suffix the year with a '-' for BC dates + if (age == c3n) { + out = u3nc('-', out); + } + + // The year part is the only place where we have to explicitly loop over the + // input because it can be arbitrarily large or small. + out = _add_year(year, out); + + out = u3nc('~', out); + + u3z(yod); + return out; +} + +static +u3_noun +_print_p(u3_atom cor, u3_atom p) +{ + // Scramble the raw number to the concealed version. + u3_noun ob = u3j_cook("u3we_scow_ob_p", u3k(cor), "ob"); + u3_noun hok = u3j_cook("u3we_scow_fein_p", ob, "fein"); + u3_atom sxz = u3n_slam_on(hok, u3k(p)); + + // Simple galaxy case + if (c3y == u3qa_lth(sxz, 256)) { + c3_y a, b, c; + u3_po_to_suffix(sxz, &a, &b, &c); + u3z(sxz); + return u3nq('~', a, b, u3nc(c, 0)); + } + + u3_atom dyy = u3qc_met(4, sxz); + if (!_(u3a_is_cat(dyy))) { + u3z(sxz); + u3z(dyy); + return u3_none; + } + + u3_noun list = 0; + for (c3_w imp = 0; imp != dyy; ++imp) { + c3_w log = u3qc_end(4, 1, sxz); + c3_w prefix = u3qc_rsh(3, 1, log); + c3_w suffix = u3qc_end(3, 1, log); + + c3_y a, b, c, d, e, f; + u3_po_to_prefix(prefix, &a, &b, &c); + u3_po_to_suffix(suffix, &d, &e, &f); + + if (imp % 4 == 0) { + if (imp != 0) { + list = u3nt('-', '-', list); + } + } else { + list = u3nc('-', list); + } + + list = u3nq(a, b, c, u3nq(d, e, f, list)); + + sxz = u3qc_rsh(4, 1, sxz); + } + + u3z(sxz); + return u3nc('~', list); +} + +u3_atom +u3qe_scow(u3_atom a, u3_atom b) +{ + switch (a) { + // XX disabled due to memory corruption + // rewrite for +scot jet and test there + // + // case c3__da: return _print_da(cor, atom); + // case 'p': return _print_p(cor, atom); + + default: { + u3_weak dat = u3qe_scot(a, b); + u3_weak pro = u3_none; + + if ( u3_none != dat ) { + pro = u3qc_rip(3, 1, dat); + u3z(dat); + } + + return pro; + } + } +} + +u3_noun +u3we_scow(u3_noun cor) +{ + u3_atom a, b; + u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); + return u3qe_scow(u3x_atom(a), u3x_atom(b)); +} diff --git a/vere/pkg/noun/jets/e/scr.c b/vere/pkg/noun/jets/e/scr.c new file mode 100644 index 0000000..e9d0725 --- /dev/null +++ b/vere/pkg/noun/jets/e/scr.c @@ -0,0 +1,227 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_weak + _cqes_hs(u3_atom p, c3_w pwd_w, + u3_atom s, c3_w sal_w, + u3_atom n, + u3_atom r, + u3_atom z, + u3_atom d) + { + u3_noun chk; + c3_w out_w; + + if ( !u3r_word_fit(&out_w, d) ) { + return u3m_bail(c3__fail); + } + if ( 0 == r || 0 == z ) { + return u3m_bail(c3__exit); + } + chk = u3qc_bex(31); + if ( (c3n == u3qa_lth(pwd_w, chk)) || + (c3n == u3qa_lth(sal_w, chk)) ) { + return u3m_bail(c3__exit); + } + u3z(chk); + chk = u3kc_bex(u3ka_dec(u3qc_xeb(n))); + if ( c3n == u3r_sing(n, chk) ) { + return u3m_bail(c3__exit); + } + u3z(chk); + if ( c3n == u3ka_lte( + u3ka_mul(u3qa_mul(128, r), u3ka_dec(u3qa_add(n, z))), + u3qc_bex(30)) ) { + return u3m_bail(c3__exit); + } + + if ( (u3r_met(6, n) > 1) || + (u3r_met(5, r) > 1) || + (u3r_met(5, z) > 1) ) { + return u3_none; + } + else { + u3_noun pro; + c3_d n_d = u3r_chub(0, n); + c3_w r_w = u3r_word(0, r), + z_w = u3r_word(0, z); + c3_y *pwd_y = u3a_malloc(pwd_w), + *sal_y = u3a_malloc(sal_w), + *out_y = u3a_malloc(d); + u3r_bytes(0, pwd_w, pwd_y, p); + u3r_bytes(0, sal_w, sal_y, s); + pro = ( 0 == urcrypt_scrypt(pwd_y, pwd_w, + sal_y, sal_w, + n_d, r_w, z_w, + out_w, out_y) ) + ? u3i_bytes(out_w, out_y) + : u3_none; + u3a_free(pwd_y); + u3a_free(sal_y); + u3a_free(out_y); + return pro; + } + } + + static u3_weak + _cqes_hsl(u3_atom p, u3_atom pl, + u3_atom s, u3_atom sl, + u3_atom n, + u3_atom r, + u3_atom z, + u3_atom d) + { + c3_w pwd_w, sal_w; + if ( !(u3r_word_fit(&pwd_w, pl) && + u3r_word_fit(&sal_w, sl)) ) { + return u3m_bail(c3__fail); + } + else { + return _cqes_hs(p, pwd_w, s, sal_w, n, r, z, d); + } + } + + u3_noun + u3wes_hsl(u3_noun cor) + { + u3_noun p, pl, s, sl, n, r, z, d; + u3_noun q; + + u3x_quil(u3x_at(u3x_sam, cor), &p, &pl, &s, &sl, &q); + u3x_qual(q, &n, &r, &z, &d); + + if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(pl)) && + _(u3a_is_atom(s)) && _(u3a_is_atom(sl)) && + _(u3a_is_atom(n)) && _(u3a_is_atom(r)) && + _(u3a_is_atom(z)) && _(u3a_is_atom(d))) ) { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("scr-hsl", _cqes_hsl(p, pl, s, sl, n, r, z, d)); + } + } + + static u3_weak + _cqes_hsh(u3_atom p, + u3_atom s, + u3_atom n, + u3_atom r, + u3_atom z, + u3_atom d) + { + return _cqes_hs(p, u3r_met(3, p), + s, u3r_met(3, s), + n, r, z, d); + } + + u3_noun + u3wes_hsh(u3_noun cor) + { + u3_noun p, s, n, r, z, d; + u3_noun q; + + u3x_quil(u3x_at(u3x_sam, cor), &p, &s, &n, &r, &q); + u3x_cell(q, &z, &d); + + if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) && + _(u3a_is_atom(n)) && _(u3a_is_atom(r)) && + _(u3a_is_atom(z)) && _(u3a_is_atom(d))) ) { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("scr-hsh", _cqes_hsh(p, s, n, r, z, d)); + } + } + + static u3_atom + _cqes_pb(u3_atom p, c3_w pwd_w, + u3_atom s, c3_w sal_w, + u3_atom c, + u3_atom d) + { + if ( (c > (1 << 28)) || + (d > (1 << 30)) ) { + // max key length 1gb + // max iterations 2^28 + return u3m_bail(c3__exit); + } + else { + u3_noun pro; + c3_y *pwd_y = u3a_malloc(pwd_w), + *sal_y = u3a_malloc(sal_w), + *out_y = u3a_malloc(d); + u3r_bytes(0, pwd_w, pwd_y, p); + u3r_bytes(0, sal_w, sal_y, s); + urcrypt_scrypt_pbkdf_sha256(pwd_y, pwd_w, sal_y, sal_w, c, d, out_y); + pro = u3i_bytes(d, out_y); + u3a_free(pwd_y); + u3a_free(sal_y); + u3a_free(out_y); + return pro; + } + } + + static u3_noun + _cqes_pbl(u3_atom p, u3_atom pl, + u3_atom s, u3_atom sl, + u3_atom c, + u3_atom d) + { + c3_w pwd_w, sal_w; + if ( !(u3r_word_fit(&pwd_w, pl) && + u3r_word_fit(&sal_w, sl)) ) { + return u3m_bail(c3__fail); + } + else { + return _cqes_pb(p, pwd_w, s, sal_w, c, d); + } + } + + u3_noun + u3wes_pbl(u3_noun cor) + { + u3_noun p, pl, s, sl, c, d; + u3_noun q; + + u3x_quil(u3x_at(u3x_sam, cor), &p, &pl, &s, &sl, &q); + u3x_cell(q, &c, &d); + + if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) && + _(u3a_is_atom(pl)) && _(u3a_is_atom(sl)) && + _(u3a_is_atom(c)) && _(u3a_is_atom(d))) ) { + return u3m_bail(c3__exit); + } + else { + return _cqes_pbl(p, pl, s, sl, c, d); + } + } + + static u3_atom + _cqes_pbk(u3_atom p, u3_atom s, u3_atom c, u3_atom d) + { + return _cqes_pb(p, u3r_met(3, p), + s, u3r_met(3, s), + c, d); + } + + u3_noun + u3wes_pbk(u3_noun cor) + { + u3_noun p, s, c, d; + + u3x_qual(u3x_at(u3x_sam, cor), &p, &s, &c, &d); + + if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) && + _(u3a_is_atom(c)) && _(u3a_is_atom(d))) ) { + return u3m_bail(c3__exit); + } + else { + return _cqes_pbk(p, s, c, d); + } + } diff --git a/vere/pkg/noun/jets/e/secp.c b/vere/pkg/noun/jets/e/secp.c new file mode 100644 index 0000000..fa0fbd2 --- /dev/null +++ b/vere/pkg/noun/jets/e/secp.c @@ -0,0 +1,298 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" +#include "ent/ent.h" + +static urcrypt_secp_context* sec_u; + +/* call at process start */ +void +u3je_secp_init() +{ + c3_y ent_y[32]; + ent_getentropy(ent_y, 32); + sec_u = malloc(urcrypt_secp_prealloc_size()); + + if ( 0 != urcrypt_secp_init(sec_u, ent_y) ) { + u3l_log("u3e_secp_init failed"); + abort(); + } +} + +/* call at process end */ +void +u3je_secp_stop() +{ + urcrypt_secp_destroy(sec_u); + free(sec_u); + sec_u = NULL; +} + +/* util funcs + */ +static c3_t +_cqes_in_order(u3_atom a) +{ + // this is the "n" parameter of the secp256k1 curve + static const c3_w now_w[8] = { + 0xd0364141, 0xbfd25e8c, 0xaf48a03b, 0xbaaedce6, + 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff + }; + + if ( 0 == a ) { + return 0; + } + else if ( c3y == u3a_is_cat(a) ) { + return 1; + } + else { + u3a_atom* a_u = u3a_to_ptr(a); + c3_w len_w = a_u->len_w; + + if ( len_w < 8 ) { + return 1; + } + else if ( len_w > 8 ) { + return 0; + } + else { + c3_y i_y; + c3_w *buf_w = a_u->buf_w; + // loop from most to least significant words + for ( i_y = 8; i_y > 0; ) { + c3_w b_w = buf_w[i_y], + o_w = now_w[--i_y]; + if ( b_w < o_w ) { + return 1; + } + else if ( b_w > o_w ) { + return 0; + } + } + return 1; + } + } +} + +static void +_cqes_unpack_fe(u3_atom k, c3_y out_y[32]) +{ + if ( _cqes_in_order(k) ) { + u3r_bytes(0, 32, out_y, k); + } + else { + u3m_bail(c3__exit); + } +} + +/* sign hash with priv key + */ +static u3_noun +_cqes_sign(u3_atom has, + u3_atom prv) +{ + c3_y has_y[32]; + + if ( 0 != u3r_bytes_fit(32, has_y, has) ) { + return u3m_bail(c3__exit); + } + else { + c3_y prv_y[32], v_y, r_y[32], s_y[32]; + _cqes_unpack_fe(prv, prv_y); + + return( 0 == urcrypt_secp_sign(sec_u, has_y, prv_y, &v_y, r_y, s_y) ) + ? u3nt(v_y, u3i_bytes(32, r_y), u3i_bytes(32, s_y)) + : u3_none; + } +} + +u3_noun +u3we_sign(u3_noun cor) +{ + + u3_noun has, prv; + + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &has, + u3x_sam_3, &prv, + 0)) || + (c3n == u3ud(has)) || + (c3n == u3ud(prv))) { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("secp-sign", _cqes_sign(has, prv)); + } +} + +/* recover pubkey from signature (which is how we verify signatures) +*/ +static u3_noun +_cqes_reco(u3_atom has, + u3_atom siv, /* signature: v */ + u3_atom sir, /* signature: r */ + u3_atom sis) /* signature: s */ +{ + c3_y has_y[32]; + if ( !((siv < 4) && (0 == u3r_bytes_fit(32, has_y, has)) ) ) { + return u3m_bail(c3__exit); + } + else { + c3_y sir_y[32], sis_y[32], x_y[32], y_y[32]; + _cqes_unpack_fe(sir, sir_y); + _cqes_unpack_fe(sis, sis_y); + return + ( 0 == urcrypt_secp_reco(sec_u, has_y, siv, sir_y, sis_y, x_y, y_y) ) + ? u3nc(u3i_bytes(32, x_y), u3i_bytes(32, y_y)) + : u3_none; + } +} + +u3_noun +u3we_reco(u3_noun cor) +{ + u3_noun has, /* hash */ + siv, sir, sis; /* signature: v, r, s */ + + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &has, + u3x_sam_6, &siv, + u3x_sam_14, &sir, + u3x_sam_15, &sis, + 0)) || + (c3n == u3ud(has)) || + (c3n == u3ud(siv)) || + (c3n == u3ud(sir)) || + (c3n == u3ud(sis)) ) { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("secp-reco", _cqes_reco(has, siv, sir, sis)); + } +} + +static u3_atom +_cqes_make(u3_atom has, + u3_atom prv) +{ + c3_y has_y[32]; + + if ( 0 != u3r_bytes_fit(32, has_y, has) ) { + return u3m_bail(c3__exit); + } + else { + c3_y prv_y[32], out_y[32]; + _cqes_unpack_fe(prv, prv_y); + return ( 0 == urcrypt_secp_make(has_y, prv_y, out_y) ) + ? u3i_bytes(32, out_y) + : u3_none; + } +} + +u3_noun +u3we_make(u3_noun cor) +{ + u3_noun has, prv; + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &has, + u3x_sam_3, &prv, + 0)) || + (c3n == u3ud(has)) || + (c3n == u3ud(prv)) ) { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("secp-make", _cqes_make(has, prv)); + } +} + +/* create a schnorr signature +*/ +static u3_weak +_cqes_sosi(u3_atom sk, u3_atom m, u3_atom a) +{ + c3_y key_y[32]; + c3_y mes_y[32]; + c3_y aux_y[32]; + + if ( (0 != u3r_bytes_fit(32, key_y, sk)) || + (0 != u3r_bytes_fit(32, mes_y, m)) || + (0 != u3r_bytes_fit(32, aux_y, a)) ) + { + return u3m_bail(c3__exit); + } + else { + c3_y sig_y[64]; + + return + ( 0 == urcrypt_secp_schnorr_sign(sec_u, key_y, mes_y, aux_y, sig_y) ) + ? u3i_bytes(64, sig_y) + : u3_none; + } +} + +u3_noun +u3we_sosi(u3_noun cor) +{ + u3_noun key, mes, aux; + + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &key, + u3x_sam_6, &mes, + u3x_sam_7, &aux, + 0)) || + (c3n == u3ud(key)) || + (c3n == u3ud(mes)) || + (c3n == u3ud(aux)) ) + { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("secp-sosi", _cqes_sosi(key, mes, aux)); + } +} + +/* verify a schnorr signature +*/ +static u3_atom +_cqes_sove(u3_atom pk, u3_atom m, u3_atom sig) +{ + c3_y pub_y[32]; + c3_y mes_y[32]; + c3_y sig_y[64]; + + if ( (0 != u3r_bytes_fit(32, pub_y, pk)) || + (0 != u3r_bytes_fit(32, mes_y, m)) || + (0 != u3r_bytes_fit(64, sig_y, sig)) ) + { + return u3m_bail(c3__exit); + } + else { + return __(urcrypt_secp_schnorr_veri(sec_u, sig_y, mes_y, pub_y)); + } +} + +u3_noun +u3we_sove(u3_noun cor) +{ + u3_noun pub, mes, sig; + + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &pub, + u3x_sam_6, &mes, + u3x_sam_7, &sig, + 0)) || + (c3n == u3ud(pub)) || + (c3n == u3ud(mes)) || + (c3n == u3ud(sig)) ) + { + return u3m_bail(c3__exit); + } + else { + return _cqes_sove(pub, mes, sig); + } +} diff --git a/vere/pkg/noun/jets/e/sha1.c b/vere/pkg/noun/jets/e/sha1.c new file mode 100644 index 0000000..729faf6 --- /dev/null +++ b/vere/pkg/noun/jets/e/sha1.c @@ -0,0 +1,40 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + static u3_noun + _cqe_sha1(u3_atom wid, u3_atom dat) + { + c3_w len_w; + if ( !u3r_word_fit(&len_w, wid) ) { + return u3m_bail(c3__fail); + } + else { + c3_y out_y[20]; + c3_y *dat_y = u3r_bytes_alloc(0, len_w, dat); + + urcrypt_sha1(dat_y, len_w, out_y); + u3a_free(dat_y); + return u3i_bytes(20, out_y); + } + } + + u3_noun + u3we_sha1(u3_noun cor) + { + u3_noun wid, dat; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &wid, u3x_sam_3, &dat, 0)) || + (c3n == u3ud(wid)) || + (c3n == u3ud(dat)) ) + { + return u3m_bail(c3__exit); + } + else { + return _cqe_sha1(wid, dat); + } + } diff --git a/vere/pkg/noun/jets/e/shax.c b/vere/pkg/noun/jets/e/shax.c new file mode 100644 index 0000000..856d0fa --- /dev/null +++ b/vere/pkg/noun/jets/e/shax.c @@ -0,0 +1,194 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" + + + static u3_atom + _cqe_shay(u3_atom wid, + u3_atom dat) + { + c3_w len_w; + if ( !u3r_word_fit(&len_w, wid) ) { + return u3m_bail(c3__fail); + } + else { + c3_y out_y[32]; + c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); + urcrypt_shay(dat_y, len_w, out_y); + u3a_free(dat_y); + return u3i_bytes(32, out_y); + } + } + + static u3_atom + _cqe_shax(u3_atom a) + { + c3_w len_w; + c3_y out_y[32]; + c3_y* dat_y = u3r_bytes_all(&len_w, a); + urcrypt_shay(dat_y, len_w, out_y); + u3a_free(dat_y); + return u3i_bytes(32, out_y); + } + + static u3_atom + _cqe_shal(u3_atom wid, + u3_atom dat) + { + c3_w len_w; + if ( !u3r_word_fit(&len_w, wid) ) { + return u3m_bail(c3__fail); + } + else { + c3_y out_y[64]; + c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); + urcrypt_shal(dat_y, len_w, out_y); + u3a_free(dat_y); + return u3i_bytes(64, out_y); + } + } + + static u3_atom + _cqe_shas(u3_atom sal, + u3_atom ruz) + { + c3_w sal_w, ruz_w; + c3_y *sal_y, *ruz_y, out_y[32]; + + sal_y = u3r_bytes_all(&sal_w, sal); + ruz_y = u3r_bytes_all(&ruz_w, ruz); + urcrypt_shas(sal_y, sal_w, ruz_y, ruz_w, out_y); + u3a_free(sal_y); + u3a_free(ruz_y); + return u3i_bytes(32, out_y); + } + + u3_noun + u3we_shax(u3_noun cor) + { + u3_noun a; + + if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || + (c3n == u3ud(a)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqe_shax(a); + } + } + + u3_noun + u3we_shay(u3_noun cor) + { + u3_noun a, b; + + if ( (u3_none == (a = u3r_at(u3x_sam_2, cor))) || + (u3_none == (b = u3r_at(u3x_sam_3, cor))) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqe_shay(a, b); + } + } + + u3_noun + u3we_shal(u3_noun cor) + { + u3_noun a, b; + + if ( (u3_none == (a = u3r_at(u3x_sam_2, cor))) || + (u3_none == (b = u3r_at(u3x_sam_3, cor))) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqe_shal(a, b); + } + } + + u3_noun + u3we_shas(u3_noun cor) + { + u3_noun sal, ruz; + + if ( (u3_none == (sal = u3r_at(u3x_sam_2, cor))) || + (u3_none == (ruz = u3r_at(u3x_sam_3, cor))) || + (c3n == u3ud(sal)) || + (c3n == u3ud(ruz)) ) + { + return u3m_bail(c3__exit); + } else { + return _cqe_shas(sal, ruz); + } + } + + static u3_noun + _og_list(u3_noun a, + u3_noun b, + u3_noun c) + { + u3_noun l = u3_nul; + + if ( !_(u3a_is_cat(b)) ) { + return u3m_bail(c3__fail); + } + while ( 0 != b ) { + u3_noun x = u3qc_mix(a, c); + u3_noun y = u3qc_mix(b, x); + u3_noun d = _cqe_shas(c3_s4('o','g','-','b'), y); + u3_noun m; + + u3z(x); u3z(y); + + if ( b < 256 ) { + u3_noun e = u3qc_end(0, b, d); + + u3z(d); + m = u3nc(b, e); + b = 0; + } else { + m = u3nc(256, d); + c = d; + + b -= 256; + } + l = u3nc(m, l); + } + return u3kb_flop(l); + } + + u3_noun + u3qeo_raw(u3_atom a, + u3_atom b) + { + u3_noun x = u3qc_mix(b, a); + u3_noun c = _cqe_shas(c3_s4('o','g','-','a'), x); + u3_noun l = _og_list(a, b, c); + u3_noun r = u3qc_can(0, l); + + u3z(l); + u3z(c); + u3z(x); + + return r; + } + + u3_noun + u3weo_raw(u3_noun cor) + { + u3_noun a, b; + + if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ) { + return u3m_bail(c3__exit); + } else { + return u3qeo_raw(a, b); + } + } diff --git a/vere/pkg/noun/jets/e/slaw.c b/vere/pkg/noun/jets/e/slaw.c new file mode 100644 index 0000000..906b0d7 --- /dev/null +++ b/vere/pkg/noun/jets/e/slaw.c @@ -0,0 +1,477 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +#include <ctype.h> + +static inline u3_noun +_parse_ud(u3_noun a) +{ + u3_weak pro; + + if ( u3_none == (pro = u3s_sift_ud(u3x_atom(a))) ) { + return u3_nul; + } + + return u3nc(u3_nul, pro); +} + +static +u3_noun get_syllable(c3_c** cur_ptr, c3_c* one, c3_c* two, c3_c* three) { + if (islower((*cur_ptr)[0]) && islower((*cur_ptr)[1]) && + islower((*cur_ptr)[2])) { + *one = (*cur_ptr)[0]; + *two = (*cur_ptr)[1]; + *three = (*cur_ptr)[2]; + (*cur_ptr) += 3; + return c3y; + } else { + return c3n; + } +} + +static u3_noun +combine(u3_noun p, u3_noun q) +{ + if ( (c3y == u3a_is_atom(p)) || (c3y == u3a_is_atom(q)) ) { + return 0; + } + + u3_noun lef = u3qa_mul(256, u3t(q)); + u3_noun ret = u3nc(0, u3qa_add(u3t(p), lef)); + u3z(lef); + u3z(p); u3z(q); + + return ret; +} + +#define ENSURE_NOT_END() do { \ + if (*cur == 0) { \ + u3a_free(c); \ + return u3_none; \ + } \ + } while (0) + +#define CONSUME(x) do { \ + if (*cur != x) { \ + u3a_free(c); \ + return u3_none; \ + } \ + cur++; \ + } while (0) + +#define TRY_GET_SYLLABLE(prefix) \ + c3_c prefix##_one, prefix##_two, prefix##_three; \ + if (c3n == get_syllable(&cur, & prefix##_one, & prefix##_two, & prefix##_three)) { \ + u3a_free(c); \ + return u3_none; \ + } + +u3_noun +_parse_p(u3_noun cor, u3_noun txt) { + c3_c* c = u3a_string(txt); + + c3_c* cur = c; + CONSUME('~'); + + // We at least have a sig prefix. We're now going to parse tuples of three + // lowercase letters. Our naming pattern for the pieces we read is [a b c d + // ...] as we read them. + TRY_GET_SYLLABLE(a); + + // There was only one syllable. If it's a valid suffix syllable, then + // it's a galaxy. We don't even have to run this through the scrambler or + // check for validity since its already a (unit @). + if (*cur == 0) { + u3a_free(c); + return u3_po_find_suffix(a_one, a_two, a_three); + } + + TRY_GET_SYLLABLE(b); + + // There were only two syllables. If they are a valid prefix and suffix, then + // it's a star. + if (*cur == 0) { + u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); + u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); + u3_atom combined = combine(b_part, a_part); + u3a_free(c); + return combined; + } + + // There must now be a - or it is invalid + CONSUME('-'); + + TRY_GET_SYLLABLE(c); + + ENSURE_NOT_END(); + + TRY_GET_SYLLABLE(d); + + if (*cur == 0) { + u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); + u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); + u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three); + u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three); + + u3_noun m = combine(d_part, combine(c_part, combine(b_part, a_part))); + u3a_free(c); + + if (_(u3a_is_atom(m))) { + return 0; + } + + u3_atom raw = u3k(u3t(m)); + u3z(m); + + u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob"); + u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd"); + return u3nc(0, u3n_slam_on(hok, raw)); + } + + // There must now be a - or it is invalid. + CONSUME('-'); + + // The next possible case is a "short" moon. (~ab-cd-ef) + TRY_GET_SYLLABLE(e); + + ENSURE_NOT_END(); + + TRY_GET_SYLLABLE(f); + + if (*cur == 0) { + u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); + u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); + u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three); + u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three); + u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three); + u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three); + + u3_noun m = combine(f_part, combine(e_part, combine(d_part, + combine(c_part, combine(b_part, a_part))))); + u3a_free(c); + + if (_(u3a_is_atom(m))) { + return 0; + } + + u3_atom raw = u3k(u3t(m)); + u3z(m); + u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob"); + u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd"); + return u3nc(0, u3n_slam_on(hok, raw)); + } + + // There must now be a - or it is invalid. + CONSUME('-'); + + // The next possible case is a "long" moon. (~ab-cd-ef-gh) + TRY_GET_SYLLABLE(g); + + ENSURE_NOT_END(); + + TRY_GET_SYLLABLE(h); + + if (*cur == 0) { + u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); + u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); + u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three); + u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three); + u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three); + u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three); + u3_noun g_part = u3_po_find_prefix(g_one, g_two, g_three); + u3_noun h_part = u3_po_find_suffix(h_one, h_two, h_three); + + u3_noun m = combine(h_part, combine(g_part, combine(f_part, + combine(e_part, combine(d_part, combine(c_part, + combine(b_part, a_part))))))); + u3a_free(c); + + if (_(u3a_is_atom(m))) { + return 0; + } + + u3_atom raw = u3k(u3t(m)); + u3z(m); + u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob"); + u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd"); + return u3nc(0, u3n_slam_on(hok, raw)); + } + + // At this point, the only thing it could be is a long comet, of the form + // ~ab-cd-ef-gh--ij-kl-mn-op + + CONSUME('-'); + CONSUME('-'); + + TRY_GET_SYLLABLE(i); + ENSURE_NOT_END(); + TRY_GET_SYLLABLE(j); + CONSUME('-'); + TRY_GET_SYLLABLE(k); + ENSURE_NOT_END(); + TRY_GET_SYLLABLE(l); + CONSUME('-'); + TRY_GET_SYLLABLE(m); + ENSURE_NOT_END(); + TRY_GET_SYLLABLE(n); + CONSUME('-'); + TRY_GET_SYLLABLE(o); + ENSURE_NOT_END(); + TRY_GET_SYLLABLE(p); + + if (*cur != 0) { + // We've parsed all of a comet shape, and there's still more in the + // string. Bail back to the interpreter. + u3a_free(c); + return u3_none; + } + + // We have a long comet. Time to jam it all together. We rely on combine() + // for the error checking and we don't have to scramble comet names. + u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); + u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); + u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three); + u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three); + u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three); + u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three); + u3_noun g_part = u3_po_find_prefix(g_one, g_two, g_three); + u3_noun h_part = u3_po_find_suffix(h_one, h_two, h_three); + u3_noun i_part = u3_po_find_prefix(i_one, i_two, i_three); + u3_noun j_part = u3_po_find_suffix(j_one, j_two, j_three); + u3_noun k_part = u3_po_find_prefix(k_one, k_two, k_three); + u3_noun l_part = u3_po_find_suffix(l_one, l_two, l_three); + u3_noun m_part = u3_po_find_prefix(m_one, m_two, m_three); + u3_noun n_part = u3_po_find_suffix(n_one, n_two, n_three); + u3_noun o_part = u3_po_find_prefix(o_one, o_two, o_three); + u3_noun p_part = u3_po_find_suffix(p_one, p_two, p_three); + + u3a_free(c); + + return combine(p_part, combine(o_part, combine(n_part, combine(m_part, + combine(l_part, combine(k_part, combine(j_part, combine(i_part, + combine(h_part, combine(g_part, combine(f_part, combine(e_part, + combine(d_part, combine(c_part, combine(b_part, a_part))))))))))))))); +} + +#define PARSE_NONZERO_NUMBER(numname) \ + c3_w numname = 0; \ + do { \ + if (cur[0] > '9' || cur[0] < '1') { \ + u3a_free(c); \ + return u3_none; \ + } \ + numname = cur[0] - '0'; \ + cur++; \ + while (isdigit(cur[0])) { \ + numname = u3ka_mul(numname, 10); \ + numname = u3ka_add(numname, cur[0] - '0'); \ + cur++; \ + } \ + } while (0) + +#define PARSE_INCLUDING_ZERO_NUMBER(numname) \ + c3_w numname = 0; \ + do { \ + if (cur[0] > '9' || cur[0] < '0') { \ + u3a_free(c); \ + return u3_none; \ + } \ + numname = cur[0] - '0'; \ + cur++; \ + while (isdigit(cur[0])) { \ + numname = u3ka_mul(numname, 10); \ + numname = u3ka_add(numname, cur[0] - '0'); \ + cur++; \ + } \ + } while (0) + +#define PARSE_HEX_DIGIT(out) \ + do { \ + if (cur[0] >= '0' && cur[0] <= '9') { \ + out = cur[0] - '0'; \ + } else if (cur[0] >= 'a' && cur[0] <= 'f') { \ + out = 10 + cur[0] - 'a'; \ + } else { \ + u3a_free(c); \ + return u3_none; \ + } \ + cur++; \ + } while(0) + + +u3_noun +_parse_da(u3_noun cor, u3_noun txt) { + c3_c* c = u3a_string(txt); + + c3_c* cur = c; + CONSUME('~'); + + // Parse out an arbitrary year number. Starts with a nonzero digit followed + // by a series of any digits. + PARSE_NONZERO_NUMBER(year); + + // Parse the optional negative sign for BC dates. + u3_noun bc = c3y; + if (cur[0] == '-') { + bc = c3n; + cur++; + } + + CONSUME('.'); + + // Parse out a two digit month (mot:ag). Either a single digit 1-9 or 1[012]. + c3_y month; + if (cur[0] == '1') { + if (cur[1] <= '2' && cur[1] >= '0') { + // This is a two number month. + month = 10 + cur[1] - '0'; + cur += 2; + } else { + // This is January. + month = 1; + cur++; + } + } else if (cur[0] <= '9' && cur[0] >= '2') { + month = cur[0] - '0'; + cur++; + } else { + u3a_free(c); + return u3_none; + } + + CONSUME('.'); + + // Parse out a two digit day (dip:ag). This number can be really big, so we + // can track number of days since September 1993. + PARSE_NONZERO_NUMBER(day); + + if (cur[0] == 0) { + u3a_free(c); + u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year"); + u3_noun res = u3n_slam_on(hok, + u3nt(u3nc(bc, year), month, + u3nc(day, u3nq(0, 0, 0, 0)))); + return u3nc(0, res); + } + + CONSUME('.'); + CONSUME('.'); + + PARSE_INCLUDING_ZERO_NUMBER(hour); + CONSUME('.'); + PARSE_INCLUDING_ZERO_NUMBER(minute); + CONSUME('.'); + PARSE_INCLUDING_ZERO_NUMBER(second); + + if (cur[0] == 0) { + u3a_free(c); + u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year"); + u3_noun res = u3n_slam_on(hok, + u3nt(u3nc(bc, year), month, + u3nc(day, u3nq(hour, minute, second, 0)))); + return u3nc(0, res); + } + + CONSUME('.'); + CONSUME('.'); + + // Now we have to parse a list of hexidecimal numbers 0-f of length 4 only + // (zero padded otherwise) separated by dots. + u3_noun list = 0; + while (1) { + // Parse 4 hex digits + c3_y one, two, three, four; + PARSE_HEX_DIGIT(one); + PARSE_HEX_DIGIT(two); + PARSE_HEX_DIGIT(three); + PARSE_HEX_DIGIT(four); + + c3_w current = (one << 12) + (two << 8) + (three << 4) + four; + list = u3nc(u3i_words(1, ¤t), list); + + if (cur[0] == 0) { + u3a_free(c); + + u3_noun flopped = u3qb_flop(list); + u3z(list); + + u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year"); + u3_noun res = u3n_slam_on(hok, + u3nt(u3nc(bc, year), month, + u3nc(day, + u3nq(hour, minute, second, flopped)))); + return u3nc(0, res); + } + + CONSUME('.'); + } +} + +#undef ENSURE_NOT_END +#undef CONSUME +#undef TRY_GET_SYLLABLE +#undef PARSE_NONZERO_NUMBER +#undef PARSE_HEX_DIGIT + +u3_noun +_parse_tas(u3_noun txt) { + // For any symbol which matches, txt will return itself as a + // value. Therefore, this is mostly checking validity. + c3_c* c = u3a_string(txt); + + // First character must represent a lowercase letter + c3_c* cur = c; + if (!islower(cur[0])) { + u3a_free(c); + return 0; + } + cur++; + + while (cur[0] != 0) { + if (!(islower(cur[0]) || isdigit(cur[0]) || cur[0] == '-')) { + u3a_free(c); + return 0; + } + + cur++; + } + + u3a_free(c); + return u3nc(0, u3k(txt)); +} + +u3_noun +u3we_slaw(u3_noun cor) +{ + u3_noun mod; + u3_noun txt; + + if (c3n == u3r_mean(cor, u3x_sam_2, &mod, + u3x_sam_3, &txt, 0)) { + return u3m_bail(c3__exit); + } + + switch (mod) { + case c3__da: + return _parse_da(cor, txt); + + case 'p': + return _parse_p(cor, txt); + + case c3__ud: + return _parse_ud(txt); + + // %ta is used once in link.hoon. don't bother. + + case c3__tas: + return _parse_tas(txt); + + default: + return u3_none; + } +} diff --git a/vere/pkg/noun/jets/e/tape.c b/vere/pkg/noun/jets/e/tape.c new file mode 100644 index 0000000..4d251b6 --- /dev/null +++ b/vere/pkg/noun/jets/e/tape.c @@ -0,0 +1,53 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + static u3_noun + _norm(u3_noun a) + { + if ( c3n == u3du(a) ) { + return u3_nul; + } else { + return u3nc(((c3y == u3du(u3h(a))) ? u3_nul : u3k(u3h(a))), + _norm(u3t(a))); + } + } + + static u3_noun + _good(u3_noun a) + { + while ( 1 ) { + if ( u3_nul == a ) { + return c3y; + } + if ( c3n == u3ud(u3h(a)) ) { + return c3n; + } + a = u3t(a); + } + } + + u3_noun + u3qe_tape(u3_noun a) + { + if ( c3y == _good(a) ) { + return u3k(a); + } else { + return _norm(a); + } + } + u3_noun + u3we_tape(u3_noun cor) + { + u3_noun a; + + if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ) { + return u3m_bail(c3__fail); + } else { + return u3qe_tape(a); + } + } diff --git a/vere/pkg/noun/jets/e/trip.c b/vere/pkg/noun/jets/e/trip.c new file mode 100644 index 0000000..519a852 --- /dev/null +++ b/vere/pkg/noun/jets/e/trip.c @@ -0,0 +1,33 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3qe_trip(u3_atom a) +{ + return u3qc_rip(3, 1, a); +} + +u3_noun +u3we_trip(u3_noun cor) +{ + u3_noun a = u3x_at(u3x_sam, cor); + + if ( c3n == u3ud(a) ) { + return u3m_bail(c3__exit); + } + + return u3qe_trip(a); +} + +u3_atom +u3ke_trip(u3_noun a) +{ + u3_atom pro = u3qe_trip(a); + u3z(a); + return pro; +} diff --git a/vere/pkg/noun/jets/e/urwasm.c b/vere/pkg/noun/jets/e/urwasm.c new file mode 100644 index 0000000..626aef3 --- /dev/null +++ b/vere/pkg/noun/jets/e/urwasm.c @@ -0,0 +1,3086 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +#include "wasm3.h" +#include "m3_env.h" + +// #define URWASM_SUBROAD +#define URWASM_STATEFUL + +#define ONCE_CTX 63 +#define RUN_CTX 7 + +#define AX_RUNNABLE 374 +#define AX_ARROWS 1502 + +#define AX_CALL 20 +#define AX_MEMREAD 383 +#define AX_MEMWRITE 94 +#define AX_CALL_EXT 375 +#define AX_GLOBAL_SET 4 +#define AX_GLOBAL_GET 22 +#define AX_MEM_SIZE 186 +#define AX_MEM_GROW 381 +#define AX_GET_ACC 374 +#define AX_SET_ACC 92 +#define AX_GET_ALL_GLOB 43 +#define AX_SET_ALL_GLOB 380 + +#define AX_TRY 43 +#define AX_CATCH 4 +#define AX_RETURN 20 +#define AX_FAIL 47 + +#define ARROW_CTX 511 +#define MONAD_CTX 127 + +#define arr_sam 62 +#define arr_sam_2 124 +#define arr_sam_3 125 +#define arr_sam_6 250 +#define arr_sam_7 251 + +#define seed_module 2 +#define seed_past 6 +#define seed_shop 14 +#define seed_import 15 + +#define uw__lia c3_s3('l', 'i', 'a') + +#define uw_lia_run_version 1 + +#define ERR(string) ("\r\n\033[31m>>> " string "\033[0m\r\n") +#define WUT(string) ("\r\n\033[33m>> " string "\033[0m\r\n") +#define DBG(string) ("\r\n" string "\r\n") + +#define KICK1(TRAP) uw_kick_nock(TRAP, 2) +#define KICK2(TRAP) KICK1(KICK1(TRAP)) + +// [a b c d e f g h] +static inline u3_noun +uw_octo(u3_noun a, + u3_noun b, + u3_noun c, + u3_noun d, + u3_noun e, + u3_noun f, + u3_noun g, + u3_noun h) +{ + return u3nc(a, u3nq(b, c, d, u3nq(e, f, g, h))); +} + +// kick by nock. axe RETAINED (ignore if direct) +static u3_noun +uw_kick_nock(u3_noun cor, u3_noun axe) +{ + u3_noun fol = u3x_at(axe, cor); + return u3n_nock_on(cor, u3k(fol)); +} + +// slam by nock +static u3_noun +uw_slam_nock(u3_noun gat, u3_noun sam) +{ + u3_noun cor = u3nc(u3k(u3h(gat)), u3nc(sam, u3k(u3t(u3t(gat))))); + u3z(gat); + return uw_kick_nock(cor, 2); +} + +static u3_noun +uw_slam_check(u3_noun gat, u3_noun sam, c3_t is_stateful) +{ + u3_noun bat = u3k(u3h(gat)); + u3_noun cor = u3nc(u3k(bat), u3nc(sam, u3k(u3t(u3t(gat))))); + u3z(gat); + + if (!is_stateful) + { + return u3n_nock_on(cor, bat); + } + else + { + u3_noun ton = u3n_nock_an(cor, bat); + + u3_noun tag, pro; + if (c3n == u3r_cell(ton, &tag, &pro)) + { + return u3m_bail(c3__fail); + } + if (0 == tag) + { + u3k(pro); + u3z(ton); + return pro; + } + else if (2 == tag) + { + return u3m_bail(c3__exit); + } + else + { + return u3m_bail(c3__fail); + } + } +} + +static inline void +_push_list(u3_noun som, u3_noun *lit) +{ + if (u3_none == *lit) + { + u3z(som); + } + else + { + *lit = u3nc(som, *lit); + } +} + +static inline u3_weak +_pop_list(u3_weak *lit) +{ + if (u3_none == *lit) + { + return u3_none; + } + u3_noun hed, tel; + if (c3n == u3r_cell(*lit, &hed, &tel)) + { + return u3m_bail(c3__fail); + } + u3k(hed); + u3k(tel); + u3z(*lit); + *lit = tel; + return hed; +} + +static const M3Result UrwasmArrowExit = "An imported arrow returned %2"; + +static const c3_m uw_run_m = uw__lia + c3__run + uw_lia_run_version; + +static_assert( + (c3y == u3a_is_cat(uw_run_m)), + "u3we_run key tag must be a direct atom" +); + +typedef struct { + u3_noun call_bat; + u3_noun memread_bat; + u3_noun memwrite_bat; + u3_noun call_ext_bat; + u3_noun try_bat; + u3_noun catch_bat; + u3_noun return_bat; + u3_noun fail_bat; + u3_noun global_set_bat; + u3_noun global_get_bat; + u3_noun mem_grow_bat; + u3_noun mem_size_bat; + u3_noun get_acc_bat; + u3_noun set_acc_bat; + u3_noun get_all_glob_bat; + u3_noun set_all_glob_bat; +// + u3_noun call_ctx; + u3_noun memread_ctx; + u3_noun memwrite_ctx; + u3_noun global_set_ctx; + u3_noun global_get_ctx; + u3_noun mem_grow_ctx; + u3_noun mem_size_ctx; + u3_noun get_all_glob_ctx; + u3_noun set_all_glob_ctx; +} match_data_struct; + +// memory arena with exponential growth +typedef struct { + c3_w siz_w; // size in bytes + c3_y pad_y; // alignment padding + c3_t ini_t; // already initialized + u3i_slab sab_u; // associated slab + c3_y* buf_y; // allocated buffer + c3_y* nex_y; // next allocation + c3_y* end_y; // end of arena + jmp_buf* esc_u; // escape buffer +} uw_arena; + +typedef struct { + IM3Module wasm_module; // p + u3_noun lia_shop; // q, transferred + u3_noun acc; // p.r, transferred + u3_noun map; // q.r, retained + match_data_struct* match; + u3_noun arrow_yil; // transferred + u3_noun susp_list; // transferred + u3_noun resolution; // resolved %1 block, transferred + uw_arena box_arena; + uw_arena code_arena; + u3_noun yil_previous; // transferred + u3_noun queue; // transferred + c3_t is_stateful; +} lia_state; + +typedef enum { + west_call, + west_call_ext, + west_try, + west_catch_try, + west_catch_err, + west_link_wasm, +} wasm3_ext_suspend_tag; + +typedef enum { + lst_call = 0, + // lst_call_ext = 1, // not necessary + lst_try = 2, + lst_catch_try = 3, + lst_catch_err = 4, + lst_link_wasm = 5, +} lia_suspend_tag; + +static void +_uw_arena_init_size(uw_arena* ren_u, c3_w siz_w) +{ + ren_u->siz_w = siz_w; + u3i_slab_init(&ren_u->sab_u, 3, siz_w + 12); // size + max padding + ren_u->buf_y = ren_u->nex_y = c3_align(ren_u->sab_u.buf_y, 16, C3_ALGHI); + ren_u->end_y = ren_u->buf_y + ren_u->siz_w; + c3_y pad_y = ren_u->buf_y - ren_u->sab_u.buf_y; + if (pad_y > 12) + { + u3m_bail(c3__fail); + } + ren_u->pad_y = pad_y; + ren_u->ini_t = 1; +} + +static void +_uw_arena_init(uw_arena* ren_u) +{ + _uw_arena_init_size(ren_u, (c3_w)1 << 23); +} + +static void +_uw_arena_grow(uw_arena* ren_u) +{ + if (!ren_u->ini_t) + { + u3m_bail(c3__fail); + } + c3_w new_w = ren_u->siz_w * 2; + if (new_w / 2 != ren_u->siz_w) + { + u3m_bail(c3__fail); + } + ren_u->siz_w = new_w; + + u3i_slab_free(&ren_u->sab_u); + + u3i_slab_init(&ren_u->sab_u, 3, new_w + 12); // size + max padding + ren_u->buf_y = ren_u->nex_y = c3_align(ren_u->sab_u.buf_y, 16, C3_ALGHI); + ren_u->end_y = ren_u->nex_y + new_w; + c3_y pad_y = ren_u->nex_y - ren_u->sab_u.buf_y; + if (pad_y > 12) + { + u3m_bail(c3__fail); + } + ren_u->pad_y = pad_y; +} + +static void +_uw_arena_reset(uw_arena* ren_u) +{ + if (!ren_u->ini_t) + { + u3m_bail(c3__fail); + } + ren_u->nex_y = ren_u->buf_y; + memset(ren_u->buf_y, 0, (size_t)ren_u->siz_w); +} + +static void +_uw_arena_free(uw_arena* ren_u) +{ + if (!ren_u->ini_t) + { + u3m_bail(c3__fail); + } + u3i_slab_free(&ren_u->sab_u); + ren_u->ini_t = 0; +} + +// Code page allocation: simple bump allocator for non-growing objects, +// i.e. code pages +// save allocation length for realloc +// CodeArena->esc_u MUST be initialized by the caller to handle OOM +// +static uw_arena* CodeArena; + +static void* +_calloc_code(size_t num_i, size_t len_i) +{ + if (!CodeArena->ini_t) + { + u3m_bail(c3__fail); + } + + void* lag_v = CodeArena->nex_y; + + size_t byt_i = num_i * len_i; + if (byt_i / len_i != num_i) + { + u3m_bail(c3__fail); + } + + if (byt_i >= UINT64_MAX - 16) + { + u3m_bail(c3__fail); + } + c3_d byt_d = byt_i + 16; // c3_d for length + alignment padding + + c3_y* nex_y = CodeArena->nex_y + byt_d; + nex_y = c3_align(nex_y, 16, C3_ALGHI); + + if (nex_y >= CodeArena->end_y) + { // OOM, jump out to increase the arena size and try again + _longjmp(*CodeArena->esc_u, c3__code); + } + + *((c3_d*)lag_v) = byt_d - 16; // corruption check + *((c3_d*)lag_v + 1) = byt_d - 16; + + CodeArena->nex_y = nex_y; + return ((c3_d*)lag_v + 2); +} + +static void* +_realloc_code(void* lag_v, size_t len_i) +{ + if (!CodeArena->ini_t) + { + u3m_bail(c3__fail); + } + if (!lag_v) + { + return _calloc_code(len_i, 1); + } + c3_d old1_d = *((c3_d*)lag_v - 1); + c3_d old2_d = *((c3_d*)lag_v - 2); + if (old1_d != old2_d) + { + u3m_bail(c3__fail); + } + if (len_i >= UINT64_MAX) + { + u3m_bail(c3__fail); + } + c3_d len_d = len_i; + void* new_v = _calloc_code(len_d, 1); + memcpy(new_v, lag_v, c3_min(len_d, old1_d)); + + return new_v; +} + +static void +_free_code(void* lag_v) +{ + if (!CodeArena->ini_t) + { + u3m_bail(c3__fail); + } + // noop +} + +// Struct/array allocation: [len_d cap_d data] +// BoxArena->esc_u MUST be initialized by the caller to handle OOM +// +static uw_arena* BoxArena; + +// allocate with capacity +// the allocated buffer +static void* +_malloc_box_cap(c3_d len_d, c3_d cap_d) +{ + if (!BoxArena->ini_t) + { + u3m_bail(c3__fail); + } + + void* lag_v = BoxArena->nex_y; + + if (cap_d >= UINT64_MAX - 16) + { + u3m_bail(c3__fail); + } + c3_d pac_d = cap_d + 16; // c3_d for length + capacity + + c3_y* nex_y = BoxArena->nex_y + pac_d; + nex_y = c3_align(nex_y, 16, C3_ALGHI); + + if (nex_y >= BoxArena->end_y) + { // OOM, jump out to increase the arena size and try again + _longjmp(*BoxArena->esc_u, c3__box); + } + + *((c3_d*)lag_v) = len_d; + *((c3_d*)lag_v + 1) = cap_d; + + BoxArena->nex_y = nex_y; + return ((c3_d*)lag_v + 2); +} + +static void* +_calloc_box(size_t num_i, size_t len_i) +{ + size_t byt_i = num_i * len_i; + if (byt_i / len_i != num_i) + { + u3m_bail(c3__fail); + } + if (byt_i > UINT64_MAX - 16) + { + u3m_bail(c3__fail); + } + c3_d byt_d = byt_i; + return _malloc_box_cap(byt_d, byt_d); +} + +static void* +_realloc_box(void* lag_v, size_t len_i) +{ + if (!BoxArena->ini_t) + { + u3m_bail(c3__fail); + } + if (!lag_v) + { + return _calloc_box(len_i, 1); + } + c3_d old_d = *((c3_d*)lag_v - 2); + c3_d cap_d = *((c3_d*)lag_v - 1); + if (len_i >= UINT64_MAX) + { + u3m_bail(c3__fail); + } + c3_d len_d = len_i; + if (len_d <= cap_d) + { + *((c3_d*)lag_v - 2) = len_d; + return lag_v; + } + + // while (cap_d <= len_d) + // { + // cap_d *= 2; + // } + cap_d <<= c3_bits_dabl(len_d) - c3_bits_dabl(cap_d); + cap_d <<= (cap_d <= len_d); + + // overflow check + if (cap_d <= len_d) + u3m_bail(c3__fail); + + void* new_v = _malloc_box_cap(len_d, cap_d); + memcpy(new_v, lag_v, old_d); + + return new_v; +} + +static void +_free_box(void* lag_v) +{ + if (!BoxArena->ini_t) + { + u3m_bail(c3__fail); + } + // noop +} + +// bailing allocator to prevent wasm3 from touching the arenas + +static void* +_calloc_bail(size_t num_i, size_t len_i) +{ + u3m_bail(c3__fail); +} + +static void* +_realloc_bail(void* lag_v, size_t len_i) +{ + u3m_bail(c3__fail); +} + +static void +_free_bail(void* lag_v) +{ + u3m_bail(c3__fail); +} + + +static u3_noun +_atoms_from_stack(void** valptrs, c3_w n, c3_y* types) +{ + u3_noun out = u3_nul; + while (n--) + { + switch (types[n]) + { // TODO 64 bit vere + case c_m3Type_i32: + case c_m3Type_f32: + { + out = u3nc(u3i_word(*(c3_w*)valptrs[n]), out); + break; + } + case c_m3Type_i64: + case c_m3Type_f64: + { + out = u3nc(u3i_chub(*(c3_d*)valptrs[n]), out); + break; + } + default: + { + return u3m_bail(c3__fail); + } + } + } + return out; +} + +// RETAIN argument +static c3_o +_atoms_to_stack(u3_noun atoms, void** valptrs, c3_w n, c3_y* types) +{ + for (c3_w i = 0; i < n; i++) + { + if (c3y == u3ud(atoms)) + { + return c3n; + } + u3_noun atom; + u3x_cell(atoms, &atom, &atoms); + if (c3n == u3ud(atom)) + { + return u3m_bail(c3__fail); + } + switch (types[i]) + { + case c_m3Type_i32: + case c_m3Type_f32: + { + *(c3_w*)valptrs[i] = u3r_word(0, atom); + break; + } + case c_m3Type_i64: + case c_m3Type_f64: + { + *(c3_d*)valptrs[i] = u3r_chub(0, atom); + break; + } + default: + { + return u3m_bail(c3__fail); + } + } + } + return __(u3_nul == atoms); +} + +static u3_noun +_coins_from_stack(void** valptrs, c3_w n, c3_y* types) +{ + u3_noun out = u3_nul; + while (n--) + { + switch (types[n]) + { // TODO 64 bit vere + case c_m3Type_i32: + { + out = u3nc(u3nc(c3__i32, u3i_word(*(c3_w*)valptrs[n])), out); + break; + } + case c_m3Type_i64: + { + out = u3nc(u3nc(c3__i64, u3i_chub(*(c3_d*)valptrs[n])), out); + break; + } + case c_m3Type_f32: + { + out = u3nc(u3nc(c3__f32, u3i_word(*(c3_w*)valptrs[n])), out); + break; + } + case c_m3Type_f64: + { + out = u3nc(u3nc(c3__f64, u3i_chub(*(c3_d*)valptrs[n])), out); + break; + } + default: + { + return u3m_bail(c3__fail); + } + } + } + return out; +} + +// RETAIN argument +static c3_o +_coins_to_stack(u3_noun coins, void** valptrs, c3_w n, c3_y* types) +{ + for (c3_w i = 0; i < n; i++) + { + if (c3y == u3ud(coins)) + { + return c3n; + } + u3_noun coin; + u3x_cell(coins, &coin, &coins); + if (c3y == u3ud(coin)) + { + return u3m_bail(c3__fail); + } + u3_noun tag, value; + u3x_cell(coin, &tag, &value); + if (c3n == u3ud(value)) + { + return u3m_bail(c3__fail); + } + switch (types[i]) + { + case c_m3Type_i32: + { + if (c3__i32 != tag) + { + return c3n; + } + *(c3_w*)valptrs[i] = u3r_word(0, value); + break; + } + case c_m3Type_i64: + { + if (c3__i64 != tag) + { + return c3n; + } + *(c3_d*)valptrs[i] = u3r_chub(0, value); + break; + } + case c_m3Type_f32: + { + if (c3__f32 != tag) + { + return c3n; + } + *(c3_w*)valptrs[i] = u3r_word(0, value); + break; + } + case c_m3Type_f64: + { + if (c3__f64 != tag) + { + return c3n; + } + *(c3_d*)valptrs[i] = u3r_chub(0, value); + break; + } + default: + { + return u3m_bail(c3__fail); + } + } + } + return __(u3_nul == coins); +} + +static c3_t +_deterministic_trap(M3Result result) +{ + return ( result == m3Err_trapOutOfBoundsMemoryAccess + || result == m3Err_trapDivisionByZero + || result == m3Err_trapIntegerOverflow + || result == m3Err_trapIntegerConversion + || result == m3Err_trapIndirectCallTypeMismatch + || result == m3Err_trapTableIndexOutOfRange + || result == m3Err_trapTableElementIsNull + || result == UrwasmArrowExit + ); +} + +static u3_noun +_reduce_monad(u3_noun monad, lia_state* sat_u) +{ + u3_noun monad_bat = u3h(monad); + if (c3y == u3r_sing(monad_bat, sat_u->match->call_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->call_ctx)) + { + return u3m_bail(c3__fail); + } + // call + u3_atom name = u3x_atom(u3at(arr_sam_2, monad)); + u3_noun args = u3at(arr_sam_3, monad); + + c3_w met_w = u3r_met(3, name); + c3_c* name_c = u3a_malloc(met_w + 1); + u3r_bytes(0, met_w, (c3_y*)name_c, name); + name_c[met_w] = 0; + + M3Result result; + + IM3Function f; + result = m3_FindFunction(&f, sat_u->wasm_module->runtime, name_c); + + if (result) + { + fprintf(stderr, ERR("function %s search error: %s"), name_c, result); + return u3m_bail(c3__fail); + } + + c3_w n_in = f->funcType->numArgs; + c3_w n_out = f->funcType->numRets; + c3_y* types = f->funcType->types; + + c3_d *vals_in = u3a_calloc(n_in, sizeof(c3_d)); + void **valptrs_in = u3a_calloc(n_in, sizeof(void*)); + for (c3_w i = 0; i < n_in; i++) + { + valptrs_in[i] = &vals_in[i]; + } + + c3_d *vals_out = u3a_calloc(n_out, sizeof(c3_d)); + void **valptrs_out = u3a_calloc(n_out, sizeof(void*)); + for (c3_w i = 0; i < n_out; i++) + { + valptrs_out[i] = &vals_out[i]; + } + + if (c3n == _atoms_to_stack(args, valptrs_in, n_in, (types+n_out))) + { + fprintf(stderr, ERR("function %s wrong number of args"), name_c); + return u3m_bail(c3__fail); + } + + c3_w edge_1 = sat_u->wasm_module->runtime->edge_suspend; + + // printf("\r\n\r\n invoke %s\r\n\r\n", name_c); + + { // push on suspend stacks + c3_d f_idx_d = f - sat_u->wasm_module->functions; + m3_SuspendStackPush64(sat_u->wasm_module->runtime, f_idx_d); + m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_call); + m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime); + _push_list( + u3nc(lst_call, u3k(name)), + &sat_u->susp_list + ); + } + + M3Result result_call = m3_Call(f, n_in, (const void**)valptrs_in); + // printf("\r\n done %s\r\n", name_c); + + if (result_call != m3Err_ComputationBlock + && result_call != m3Err_SuspensionError) + { // pop suspend stacks + m3_SuspendStackPopExtTag(sat_u->wasm_module->runtime); + c3_d tag; + m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag); + if (tag != -1 && tag != west_call) + { + printf(ERR("call tag mismatch: %"PRIc3_d), tag); + return u3m_bail(c3__fail); + } + m3_SuspendStackPop64(sat_u->wasm_module->runtime, NULL); + u3_noun frame = _pop_list(&sat_u->susp_list); + if (u3_none != frame && lst_call != u3h(frame)) + { + printf(ERR("wrong frame: call")); + return u3m_bail(c3__fail); + } + u3z(frame); + } + + u3_noun yil; + if (result_call == m3Err_ComputationBlock) + { + yil = sat_u->arrow_yil; + sat_u->arrow_yil = u3_none; + if (yil == u3_none) + { + return u3m_bail(c3__fail); + } + } + else if (_deterministic_trap(result_call)) + { + fprintf(stderr, WUT("%s call trapped: %s"), name_c, result_call); + yil = u3nc(2, 0); + } + else if (result_call == m3Err_functionImportMissing) + { + return u3m_bail(c3__exit); + } + else if (result_call) + { + fprintf(stderr, ERR("%s call failed: %s"), name_c, result_call); + return u3m_bail(c3__fail); + } + else + { + result = m3_GetResults(f, n_out, (const void**)valptrs_out); + if (result) + { + fprintf(stderr, ERR("function %s failed to get results"), name_c); + return u3m_bail(c3__fail); + } + yil = u3nc(0, _atoms_from_stack(valptrs_out, n_out, types)); + } + + c3_w edge_2 = sat_u->wasm_module->runtime->edge_suspend; + if (edge_1 != edge_2 && !result_call) + { + fprintf(stderr, ERR("imbalanced suspension stack on succesfull return: %d vs %d"), edge_1, edge_2); + return u3m_bail(c3__fail); + } + + u3a_free(name_c); + u3a_free(vals_in); + u3a_free(valptrs_in); + u3a_free(vals_out); + u3a_free(valptrs_out); + u3z(monad); + + return yil; + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->memread_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->memread_ctx)) + { + return u3m_bail(c3__fail); + } + // memread + u3_atom ptr = u3x_atom(u3at(arr_sam_2, monad)); + u3_noun len = u3at(arr_sam_3, monad); + + c3_w ptr_w = u3r_word(0, ptr); + c3_l len_l = (c3y == u3a_is_cat(len)) ? len : u3m_bail(c3__fail); + c3_w len_buf_w; + c3_y* buf_y = m3_GetMemory(sat_u->wasm_module->runtime, &len_buf_w, 0); + + if (buf_y == NULL) + { + fprintf(stderr, ERR("memread failed to get memory")); + return u3m_bail(c3__fail); + } + + if (ptr_w + len_l > len_buf_w) + { + fprintf(stderr, ERR("memread out of bounds")); + return u3m_bail(c3__fail); + } + + u3z(monad); + return u3nt(0, len_l, u3i_bytes(len_l, (buf_y + ptr_w))); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->memwrite_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->memwrite_ctx)) + { + return u3m_bail(c3__fail); + } + // memwrite + u3_atom ptr = u3x_atom(u3at(arr_sam_2, monad)); + u3_noun len = u3at(arr_sam_6, monad); + u3_noun src = u3at(arr_sam_7, monad); + + c3_w ptr_w = u3r_word(0, ptr); + c3_l len_l = (c3y == u3a_is_cat(len)) ? len : u3m_bail(c3__fail); + + c3_w len_buf_w; + c3_y* buf_y = m3_GetMemory(sat_u->wasm_module->runtime, &len_buf_w, 0); + + if (buf_y == NULL) + { + fprintf(stderr, ERR("memwrite failed to get memory")); + return u3m_bail(c3__fail); + } + + if (ptr_w + len_l > len_buf_w) + { + fprintf(stderr, ERR("memwrite out of bounds")); + return u3m_bail(c3__fail); + } + + u3r_bytes(0, len_l, (buf_y + ptr_w), u3x_atom(src)); + + u3z(monad); + return u3nc(0, 0); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->call_ext_bat)) + { + // call-ext + if (u3_nul == sat_u->lia_shop) + { + // Suspended computation will have exactly one blocking point, which + // must be at the top of the stack. You are at this point. + // There is no useful info to be saved here, name/args are not enough + // to qualify the external call, which can and will be nondeterministic + // (like all IO in urbit) + // + // On wasm3 side op_CallRaw will store the information about the + // called function. It shall be the top frame of the suspension stack, + // since only Lia can block, so wasm3 has to call Lia to get blocked. + // + // A frame is pushed in wasm3 to trigger the callback and signal to + // _apply_diff that the computation is blocked + // + m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_call_ext); + m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime); + + u3_noun name = u3at(arr_sam_2, monad); + u3_noun args = u3at(arr_sam_3, monad); + + u3_noun yil = u3nt(1, u3k(name), u3k(args)); + u3z(monad); + return yil; + } + else + { + u3z(monad); + + u3_noun lia_buy, tel; + u3x_cell(sat_u->lia_shop, &lia_buy, &tel); + u3_noun yil = u3nc(0, u3k(lia_buy)); + u3k(tel); + u3z(sat_u->lia_shop); + sat_u->lia_shop = tel; + return yil; + } + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->try_bat)) + { + // try + u3_noun monad_b = u3at(60, monad); + u3_noun cont = u3at(61, monad); + u3_weak yil; + u3_noun monad_cont; + { // push on suspend stacks + m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_try); + m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime); + _push_list(u3nc(lst_try, u3k(cont)), &sat_u->susp_list); + } + { + yil = _reduce_monad(u3k(monad_b), sat_u); + + if (1 != u3h(yil)) + { // pop suspend stacks + m3_SuspendStackPopExtTag(sat_u->wasm_module->runtime); + c3_d tag; + m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag); + if (tag != -1 && tag != west_try) + { + printf(ERR("try tag mismatch: %"PRIc3_d), tag); + return u3m_bail(c3__fail); + } + u3_noun frame = _pop_list(&sat_u->susp_list); + if (u3_none != frame && lst_try != u3h(frame)) + { + printf(ERR("wrong frame: try")); + return u3m_bail(c3__fail); + } + u3z(frame); + } + + if (0 == u3h(yil)) + { + // any unconstrained nock computation is a potential urwasm reentry: + // save the pointers before that, restore after + uw_arena* box_arena_frame = BoxArena; + uw_arena* code_arena_frame = CodeArena; + monad_cont = uw_slam_check( + u3k(cont), + u3k(u3t(yil)), + sat_u->is_stateful + ); + BoxArena = box_arena_frame; + CodeArena = code_arena_frame; + u3z(yil); + yil = u3_none; + } + } + + u3z(monad); + if (u3_none == yil) + { + return _reduce_monad(monad_cont, sat_u); + } + else + { + return yil; + } + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->catch_bat)) + { + // catch + u3_noun monad_try = u3at(120, monad); + u3_noun monad_catch = u3at(121, monad); + u3_noun cont = u3at(61, monad); + u3_weak yil; + u3_noun monad_cont; + + { + { // push on suspend stacks + m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_catch_try); + m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime); + _push_list( + u3nt(lst_catch_try, u3k(monad_catch), u3k(cont)), + &sat_u->susp_list + ); + } + yil = _reduce_monad(u3k(monad_try), sat_u); + + if (1 != u3h(yil)) + { // pop suspend stacks + m3_SuspendStackPopExtTag(sat_u->wasm_module->runtime); + c3_d tag; + m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag); + if (tag != -1 && tag != west_catch_try) + { + printf(ERR("catch-try tag mismatch: %"PRIc3_d), tag); + return u3m_bail(c3__fail); + } + u3_noun frame = _pop_list(&sat_u->susp_list); + if (u3_none != frame && lst_catch_try != u3h(frame)) + { + printf(ERR("wrong frame: catch-try")); + return u3m_bail(c3__fail); + } + u3z(frame); + } + + if (0 == u3h(yil)) + { + uw_arena* box_arena_frame = BoxArena; + uw_arena* code_arena_frame = CodeArena; + monad_cont = uw_slam_check( + u3k(cont), + u3k(u3t(yil)), + sat_u->is_stateful + ); + BoxArena = box_arena_frame; + CodeArena = code_arena_frame; + u3z(yil); + yil = u3_none; + } + else if (2 == u3h(yil)) + { + u3z(yil); + + { // push on suspend stacks + m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_catch_err); + m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime); + _push_list( + u3nc(lst_catch_err, u3k(cont)), + &sat_u->susp_list + ); + } + + yil = _reduce_monad(u3k(monad_catch), sat_u); + + if (1 != u3h(yil)) + { // pop suspend stacks + m3_SuspendStackPopExtTag(sat_u->wasm_module->runtime); + c3_d tag; + m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag); + if (tag != -1 && tag != west_catch_err) + { + printf(ERR("catch-err tag mismatch: %"PRIc3_d), tag); + return u3m_bail(c3__fail); + } + u3_noun frame = _pop_list(&sat_u->susp_list); + if (u3_none != frame && lst_catch_err != u3h(frame)) + { + printf(ERR("wrong frame: catch-err")); + return u3m_bail(c3__fail); + } + u3z(frame); + } + + if (0 == u3h(yil)) + { + uw_arena* box_arena_frame = BoxArena; + uw_arena* code_arena_frame = CodeArena; + monad_cont = uw_slam_check( + u3k(cont), + u3k(u3t(yil)), + sat_u->is_stateful + ); + BoxArena = box_arena_frame; + CodeArena = code_arena_frame; + u3z(yil); + yil = u3_none; + } + } + } + + u3z(monad); + if (u3_none == yil) + { + return _reduce_monad(monad_cont, sat_u); + } + else + { + return yil; + } + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->return_bat)) + { + // return + u3_noun yil = u3nc(0, u3k(u3at(30, monad))); + u3z(monad); + return yil; + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->global_set_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->global_set_ctx)) + { + return u3m_bail(c3__fail); + } + // global-set + u3_atom name = u3x_atom(u3at(arr_sam_2, monad)); + u3_atom value = u3x_atom(u3at(arr_sam_3, monad)); + + c3_w met_w = u3r_met(3, name); + c3_c* name_c = u3a_malloc(met_w + 1); + u3r_bytes(0, met_w, (c3_y*)name_c, name); + name_c[met_w] = 0; + + IM3Global glob = m3_FindGlobal(sat_u->wasm_module, name_c); + + if (!glob) + { + fprintf(stderr, ERR("global %s not found"), name_c); + return u3m_bail(c3__fail); + } + + if (!glob->isMutable) + { + fprintf(stderr, ERR("global %s not mutable"), name_c); + return u3m_bail(c3__fail); + } + + M3TaggedValue glob_value; + M3Result result = m3_GetGlobal(glob, &glob_value); + if (result) + { + fprintf(stderr, ERR("couldn't get global %s: %s"), name_c, result); + return u3m_bail(c3__fail); + } + switch (glob_value.type) + { + default: + { + return u3m_bail(c3__fail); + } + case c_m3Type_i32: + { + glob_value.value.i32 = u3r_word(0, value); + break; + } + case c_m3Type_i64: + { + glob_value.value.i64 = u3r_chub(0, value); + break; + } + case c_m3Type_f32: + { + glob_value.value.f32 = u3r_word(0, value); + break; + } + case c_m3Type_f64: + { + glob_value.value.f64 = u3r_chub(0, value); + break; + } + } + result = m3_SetGlobal(glob, &glob_value); + if (result) + { + fprintf(stderr, ERR("couldn't set global %s: %s"), name_c, result); + return u3m_bail(c3__fail); + } + u3z(monad); + u3a_free(name_c); + return u3nc(0, 0); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->global_get_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->global_get_ctx)) + { + return u3m_bail(c3__fail); + } + // global-get + u3_atom name = u3x_atom(u3at(arr_sam, monad)); + + c3_w met_w = u3r_met(3, name); + c3_c* name_c = u3a_malloc(met_w + 1); + u3r_bytes(0, met_w, (c3_y*)name_c, name); + name_c[met_w] = 0; + + IM3Global glob = m3_FindGlobal(sat_u->wasm_module, name_c); + if (!glob) + { + fprintf(stderr, ERR("global %s not found"), name_c); + return u3m_bail(c3__fail); + } + + M3TaggedValue glob_value; + M3Result result = m3_GetGlobal(glob, &glob_value); + if (result) + { + fprintf(stderr, ERR("couldn't get global %s: %s"), name_c, result); + return u3m_bail(c3__fail); + } + + u3_noun out; + switch (glob_value.type) + { + default: + { + return u3m_bail(c3__fail); + } + case c_m3Type_i32: + { + out = u3i_word(glob_value.value.i32); + break; + } + case c_m3Type_i64: + { + out = u3i_chub(glob_value.value.i64); + break; + } + case c_m3Type_f32: + { + out = u3i_word(glob_value.value.f32); + break; + } + case c_m3Type_f64: + { + out = u3i_chub(glob_value.value.f64); + break; + } + } + + u3z(monad); + u3a_free(name_c); + return u3nc(0, out); + + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->mem_size_bat)) + { + if (c3n == u3r_sing(u3at(MONAD_CTX, monad), sat_u->match->mem_size_ctx)) + { + return u3m_bail(c3__fail); + } + // memory-size + if (!sat_u->wasm_module->memoryInfo.hasMemory) + { + fprintf(stderr, ERR("memsize no memory")); + return u3m_bail(c3__fail); + } + c3_w num_pages = sat_u->wasm_module->runtime->memory.numPages; + + u3z(monad); + return u3nc(0, u3i_word(num_pages)); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->mem_grow_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->mem_grow_ctx)) + { + return u3m_bail(c3__fail); + } + // memory-grow + if (!sat_u->wasm_module->memoryInfo.hasMemory) + { + fprintf(stderr, ERR("memgrow no memory")); + return u3m_bail(c3__fail); + } + + u3_noun delta = u3at(arr_sam, monad); + + c3_l delta_l = (c3y == u3a_is_cat(delta)) ? delta : u3m_bail(c3__fail); + + c3_w n_pages = sat_u->wasm_module->runtime->memory.numPages; + c3_w required_pages = n_pages + delta_l; + + M3Result result = ResizeMemory(sat_u->wasm_module->runtime, required_pages); + + if (result) + { + fprintf(stderr, ERR("failed to resize memory: %s"), result); + return u3m_bail(c3__fail); + } + + u3z(monad); + return u3nc(0, u3i_word(n_pages)); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->get_acc_bat)) + { + u3z(monad); + return u3nc(0, u3k(sat_u->acc)); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->set_acc_bat)) + { + u3_noun new = u3k(u3at(arr_sam, monad)); + u3z(monad); + u3z(sat_u->acc); + sat_u->acc = new; + return u3nc(0, 0); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->get_all_glob_bat)) + { + if (c3n == u3r_sing(u3at(MONAD_CTX, monad), sat_u->match->get_all_glob_ctx)) + { + return u3m_bail(c3__fail); + } + u3z(monad); + u3_noun atoms = u3_nul; + c3_w n_globals = sat_u->wasm_module->numGlobals; + c3_w n_globals_import = sat_u->wasm_module->numGlobImports; + while (n_globals-- > n_globals_import) + { + M3Global glob = sat_u->wasm_module->globals[n_globals]; + switch (glob.type) + { + default: + { + return u3m_bail(c3__fail); + } + case c_m3Type_i32: + { + atoms = u3nc(u3i_word(glob.intValue), atoms); + break; + } + case c_m3Type_i64: + { + atoms = u3nc(u3i_chub(glob.intValue), atoms); + break; + } + case c_m3Type_f32: + { + atoms = u3nc(u3i_word(glob.f32Value), atoms); + break; + } + case c_m3Type_f64: + { + atoms = u3nc(u3i_chub(glob.f64Value), atoms); + break; + } + } + } + return u3nc(0, atoms); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->set_all_glob_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->set_all_glob_ctx)) + { + return u3m_bail(c3__fail); + } + u3_noun atoms = u3at(arr_sam, monad); + c3_w n_globals = sat_u->wasm_module->numGlobals; + c3_w n_globals_import = sat_u->wasm_module->numGlobImports; + for (c3_w i = n_globals_import; i < n_globals; i++) + { + IM3Global glob = &sat_u->wasm_module->globals[i]; + u3_noun atom; + u3x_cell(atoms, &atom, &atoms); + u3x_atom(atom); + switch (glob->type) + { + default: + { + return u3m_bail(c3__fail); + } + case c_m3Type_i32: + { + glob->intValue = u3r_word(0, atom); + break; + } + case c_m3Type_i64: + { + glob->intValue = u3r_chub(0, atom); + break; + } + case c_m3Type_f32: + { + glob->f32Value = u3r_word(0, atom); + break; + } + case c_m3Type_f64: + { + glob->f64Value = u3r_chub(0, atom); + break; + } + } + } + if (u3_nul != atoms) + { + fprintf(stderr, WUT("glob list too long")); + return u3m_bail(c3__exit); + } + u3z(monad); + return u3nc(0, 0); + } + else if (c3y == u3r_sing(monad_bat, sat_u->match->fail_bat)) + { + u3z(monad); + return u3nc(2, 0); + } + else + { + return u3m_bail(c3__fail); + } +} + +static const M3Result +_resume_callback(M3Result result_m3, IM3Runtime runtime) +{ + if (result_m3 == m3Err_ComputationBlock + || result_m3 == m3Err_SuspensionError) + { + return result_m3; + } + M3Result result = m3Err_none; + lia_state* sat_u = runtime->userdata_resume; + m3_SuspendStackPopExtTag(runtime); + c3_d tag_d; + m3_SuspendStackPop64(runtime, &tag_d); + switch (tag_d) + { + default: + { + u3m_bail(c3__fail); + } + case west_call: + { + c3_d f_idx_d; + m3_SuspendStackPop64(sat_u->wasm_module->runtime, &f_idx_d); + u3_noun frame = _pop_list(&sat_u->susp_list); + if (lst_call != u3h(frame)) + { + printf(ERR("wrong frame: call")); + u3m_bail(c3__fail); + } + u3_noun name = u3t(frame); + c3_w met_w = u3r_met(3, name); + c3_c* name_c = u3a_malloc(met_w + 1); + u3r_bytes(0, met_w, (c3_y*)name_c, name); + u3z(frame); + name_c[met_w] = 0; + + u3_noun yil; + if (_deterministic_trap(result_m3)) + { + fprintf(stderr, WUT("%s call trapped: %s"), name_c, result_m3); + yil = u3nc(2, 0); + } + else if (result_m3) + { + fprintf(stderr, ERR("%s call failed: %s"), name_c, result_m3); + u3m_bail(c3__fail); + } + else + { + IM3Function f = runtime->modules->functions + f_idx_d; + c3_w n_out_w = f->funcType->numRets; + c3_d *vals_out = u3a_calloc(n_out_w, sizeof(c3_d)); + void **valptrs_out = u3a_calloc(n_out_w, sizeof(void*)); + for (c3_w i = 0; i < n_out_w; i++) + { + valptrs_out[i] = &vals_out[i]; + } + M3Result result_tmp = m3_GetResults(f, + n_out_w, + (const void**)valptrs_out + ); + if (result_tmp) + { + fprintf(stderr, + ERR("function %s failed to get results: %s"), name_c, result_tmp + ); + u3m_bail(c3__fail); + } + yil = u3nc(0, + _atoms_from_stack(valptrs_out, n_out_w, f->funcType->types) + ); + u3a_free(valptrs_out); + u3a_free(vals_out); + } + if (u3_none != sat_u->resolution) + { + u3m_bail(c3__fail); + } + sat_u->resolution = yil; + u3a_free(name_c); + break; + } + + case west_call_ext: + { + if (1 == u3h(sat_u->resolution)) + { + // it's a new block, it's not yet resolved + // restore the frame + // + m3_SuspendStackPush64(runtime, tag_d); + m3_SuspendStackPushExtTag(runtime); + result = m3Err_ComputationBlock; + } + // else the block is resolved and sat_u->resolution holds the result + // + break; + } + + case west_try: + { + if (1 != u3h(sat_u->resolution)) + { + u3_noun frame = _pop_list(&sat_u->susp_list); + if (lst_try != u3h(frame)) + { + printf(ERR("wrong frame: try")); + u3m_bail(c3__fail); + } + if (0 == u3h(sat_u->resolution)) + { + u3_noun cont = u3t(frame); + u3_noun p_res = u3t(sat_u->resolution); + uw_arena* box_arena_frame = BoxArena; + uw_arena* code_arena_frame = CodeArena; + u3_noun monad_cont = uw_slam_check( + u3k(cont), + u3k(p_res), + sat_u->is_stateful + ); + BoxArena = box_arena_frame; + CodeArena = code_arena_frame; + u3z(sat_u->resolution); + sat_u->resolution = _reduce_monad(monad_cont, sat_u); + } + // if %2 then nothing to do, sat_u->resolution already holds %2 result + // + u3z(frame); + } + else + { + // we shouldn't be here + // + u3m_bail(c3__fail); + } + break; + } + + case west_catch_try: + { + if (1 != u3h(sat_u->resolution)) + { + u3_noun frame = _pop_list(&sat_u->susp_list); + if (lst_catch_try != u3h(frame)) + { + printf(ERR("wrong frame: catch-try")); + u3m_bail(c3__fail); + } + if (0 == u3h(sat_u->resolution)) + { + u3_noun cont = u3t(u3t(frame)); + u3_noun p_res = u3t(sat_u->resolution); + uw_arena* box_arena_frame = BoxArena; + uw_arena* code_arena_frame = CodeArena; + u3_noun monad_cont = uw_slam_check( + u3k(cont), + u3k(p_res), + sat_u->is_stateful + ); + BoxArena = box_arena_frame; + CodeArena = code_arena_frame; + u3z(sat_u->resolution); + sat_u->resolution = _reduce_monad(monad_cont, sat_u); + } + // %2 + // + else + { + u3_noun cont = u3t(u3t(frame)); + u3_noun monad_catch = u3h(u3t(frame)); + { // push on suspend stacks + m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_catch_err); + m3_SuspendStackPushExtTag(runtime); + _push_list( + u3nc(lst_catch_err, u3k(cont)), + &sat_u->susp_list + ); + } + + u3_noun yil = _reduce_monad(u3k(monad_catch), sat_u); + + if (1 != u3h(yil)) + { // pop suspend stacks + m3_SuspendStackPopExtTag(runtime); + c3_d tag; + m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag); + if (tag != -1 && tag != west_catch_err) + { + printf(ERR("catch-err tag mismatch: %"PRIc3_d), tag); + u3m_bail(c3__fail); + } + u3_noun frame1 = _pop_list(&sat_u->susp_list); + if (lst_catch_err != u3h(frame1)) + { + printf(ERR("wrong frame: catch-err")); + u3m_bail(c3__fail); + } + u3z(frame1); + } + + if (2 == u3h(yil)) + { + // sat_u->resolution already has %2, do nothing + u3z(yil); + } + else if (1 == u3h(yil)) + { + u3z(sat_u->resolution); + sat_u->resolution = yil; + } + else // %0 + { + u3_noun p_res = u3t(yil); + uw_arena* box_arena_frame = BoxArena; + uw_arena* code_arena_frame = CodeArena; + u3_noun monad_cont = uw_slam_check( + u3k(cont), + u3k(p_res), + sat_u->is_stateful + ); + BoxArena = box_arena_frame; + CodeArena = code_arena_frame; + u3z(sat_u->resolution); + u3z(yil); + sat_u->resolution = _reduce_monad(monad_cont, sat_u); + } + } + u3z(frame); + } + else + { + // we shouldn't be here + // + u3m_bail(c3__fail); + } + break; + } + case west_catch_err: + { + if (1 != u3h(sat_u->resolution)) + { + u3_noun frame = _pop_list(&sat_u->susp_list); + if (lst_catch_err != u3h(frame)) + { + printf(ERR("wrong frame: catch-err")); + u3m_bail(c3__fail); + } + if (0 == u3h(sat_u->resolution)) + { + u3_noun cont = u3t(frame); + u3_noun p_res = u3t(sat_u->resolution); + uw_arena* box_arena_frame = BoxArena; + uw_arena* code_arena_frame = CodeArena; + u3_noun monad_cont = uw_slam_check( + u3k(cont), + u3k(p_res), + sat_u->is_stateful + ); + BoxArena = box_arena_frame; + CodeArena = code_arena_frame; + u3z(sat_u->resolution); + sat_u->resolution = _reduce_monad(monad_cont, sat_u); + } + // if %2 then nothing to do, sat_u->resolution already holds %2 result + // + u3z(frame); + } + else + { + // we shouldn't be here + // + u3m_bail(c3__fail); + } + break; + } + case west_link_wasm: + { + if (1 != u3h(sat_u->resolution)) + { + c3_d _sp_offset_d, func_idx_d; + m3_SuspendStackPop64(runtime, &func_idx_d); + m3_SuspendStackPop64(runtime, &_sp_offset_d); + if (2 == u3h(sat_u->resolution)) + { + u3z(sat_u->resolution); + sat_u->resolution = u3_none; + result = UrwasmArrowExit; + } + else // %0 + { + IM3Function f = runtime->modules->functions + func_idx_d; + uint64_t * _sp = (uint64_t *)(runtime->base + _sp_offset_d); + c3_w n_out = f->funcType->numRets; + c3_y* types = f->funcType->types; + void **valptrs_out = u3a_calloc(n_out, sizeof(void*)); + const char *mod = f->import.moduleUtf8; + const char *name = f->import.fieldUtf8; + for (c3_w i = 0; i < n_out; i++) + { + valptrs_out[i] = &_sp[i]; + } + c3_o pushed = _coins_to_stack( + u3t(sat_u->resolution), + valptrs_out, + n_out, + types + ); + + if (c3n == pushed) + { + printf(ERR("import result type mismatch: %s/%s"), mod, name); + result = "import result type mismatch"; + } + + u3z(sat_u->resolution); + sat_u->resolution = u3_none; + u3a_free(valptrs_out); + } + } + else + { + // we shouldn't be here + // + u3m_bail(c3__fail); + } + break; + } + } + + return result; +} + +// TRANSFERS sat->arrow_yil if m3Err_ComputationBlock is thrown +static const void * +_link_wasm_with_arrow_map( + IM3Runtime runtime, + IM3ImportContext _ctx, + uint64_t * _sp, + void * _mem +) +{ + const char *mod = _ctx->function->import.moduleUtf8; + const char *name = _ctx->function->import.fieldUtf8; + lia_state* sat_u = _ctx->userdata; + + u3_noun key = u3nc(u3i_string(mod), u3i_string(name)); + u3_weak arrow = u3kdb_get(u3k(sat_u->map), key); + if (u3_none == arrow) + { + fprintf(stderr, ERR("import not found: %s/%s"), mod, name); + return m3Err_functionImportMissing; + } + c3_w n_in = _ctx->function->funcType->numArgs; + c3_w n_out = _ctx->function->funcType->numRets; + c3_y* types = _ctx->function->funcType->types; + void **valptrs_in = u3a_calloc(n_in, sizeof(void*)); + for (c3_w i = 0; i < n_in; i++) + { + valptrs_in[i] = &_sp[i+n_out]; + } + void **valptrs_out = u3a_calloc(n_out, sizeof(void*)); + for (c3_w i = 0; i < n_out; i++) + { + valptrs_out[i] = &_sp[i]; + } + + u3_noun coin_wasm_list = _coins_from_stack(valptrs_in, n_in, (types+n_out)); + + { // push on suspend stacks + m3_SuspendStackPush64(runtime, (c3_d)((c3_y*)_sp - (c3_y*)runtime->base)); + c3_d func_idx_d = _ctx->function - runtime->modules->functions; + m3_SuspendStackPush64(runtime, func_idx_d); + m3_SuspendStackPush64(runtime, west_link_wasm); + m3_SuspendStackPushExtTag(runtime); + } + + uw_arena* box_arena_frame = BoxArena; + uw_arena* code_arena_frame = CodeArena; + u3_noun script = uw_slam_check(arrow, coin_wasm_list, sat_u->is_stateful); + BoxArena = box_arena_frame; + CodeArena = code_arena_frame; + u3_noun yil = _reduce_monad(script, sat_u); + + M3Result result = m3Err_none; + + if (1 != u3h(yil)) + { // pop suspend stacks + m3_SuspendStackPopExtTag(runtime); + c3_d tag; + m3_SuspendStackPop64(runtime, &tag); + if (tag != -1 && tag != west_link_wasm) + { + printf(ERR("west_link tag mismatch: %"PRIc3_d), tag); + u3m_bail(c3__fail); + } + m3_SuspendStackPop64(runtime, NULL); + m3_SuspendStackPop64(runtime, NULL); + + } + + if (1 == u3h(yil)) + { + if (sat_u->arrow_yil != u3_none) + { + u3z(yil); + result = "non-empty sat_u->arrow_yil on block"; + } + else + { + sat_u->arrow_yil = yil; + result = m3Err_ComputationBlock; // start suspending if not yet suspending + } + } + else if (2 == u3h(yil)) + { + u3z(yil); + result = UrwasmArrowExit; + } + else + { + c3_o pushed = _coins_to_stack(u3t(yil), valptrs_out, n_out, types); + u3z(yil); + if (c3n == pushed) + { + fprintf(stderr, ERR("import result type mismatch: %s/%s"), mod, name); + result = "import result type mismatch"; + } + } + u3a_free(valptrs_in); + u3a_free(valptrs_out); + return result; +} + +// key: [uw_run_m seed] +// stored nouns: +// $@ ~ :: tombstone value +// $: yield=* :: +2 +// queue=(list script) :: +6 +// box_arena=[buffer=octs padding=@] :: [[+56 +57] +29] +// memory=[buffer=octs max_stack_offset=@] :: [[+120 +121] +61] +// runtime_offset=@ :: +62 +// lia_shop=(list) :: +126 +// acc=* :: +254 +// susp_list=(list) :: +255 +// == +// arguments RETAINED +// on success allocates sat_u->wasm_module->runtime->memory.mallocated +// and initializes the arenas +static c3_t +_get_state(u3_noun hint, u3_noun seed, lia_state* sat_u) +{ + // u3_weak get = u3z_find_m(u3z_memo_keep, uw_run_m, seed); + // XX order of search matters (sentinel value ~ + // from previous invocation is closer to the home road) + // and u3z_find_m searches from home road down, which is the opposite + // of what we want + // + u3_noun key = u3z_key(uw_run_m, seed); + u3_weak get = u3z_find_up(key); + u3z(key); + + if (u3_none == get || u3_nul == get) + { + return 0; + } + else + { + u3_noun yil_previous; + u3_noun queue; + u3_noun p_box_buffer, q_box_buffer, pad_box; + u3_noun p_mem_buffer, q_mem_buffer, stack_offset; + u3_noun runtime_offset; + u3_noun lia_shop; + u3_noun acc; + u3_noun susp_list; + + if ( c3n == u3r_mean(get, + 2, &yil_previous, + 6, &queue, + 56, &p_box_buffer, + 57, &q_box_buffer, + 29, &pad_box, + 120, &p_mem_buffer, + 121, &q_mem_buffer, + 61, &stack_offset, + 62, &runtime_offset, + 126, &lia_shop, + 254, &acc, + 255, &susp_list, + 0) + ) + { + return u3m_bail(c3__fail); + } + c3_w box_len_w = (c3y == u3a_is_cat(p_box_buffer)) + ? p_box_buffer + : u3m_bail(c3__fail); + + c3_w pad_w = (c3y == u3a_is_cat(pad_box)) + ? pad_box + : u3m_bail(c3__fail); + + c3_w run_off_w = (c3y == u3a_is_cat(runtime_offset)) + ? runtime_offset + : u3m_bail(c3__fail); + + c3_w len_buf_w = (c3y == u3a_is_cat(p_mem_buffer)) + ? p_mem_buffer + : u3m_bail(c3__fail); + + c3_w stk_off_w = (c3y == u3a_is_cat(stack_offset)) + ? stack_offset + : u3m_bail(c3__fail); + + _uw_arena_init_size(BoxArena, box_len_w); + u3r_bytes(pad_w, box_len_w, BoxArena->buf_y, q_box_buffer); + _uw_arena_init(CodeArena); + + M3Result result; + IM3Runtime wasm3_runtime = (IM3Runtime)(BoxArena->buf_y + run_off_w); + wasm3_runtime->base = BoxArena->buf_y; + wasm3_runtime->base_transient = CodeArena->buf_y; + m3_RewritePointersRuntime(wasm3_runtime, BoxArena->buf_y, 0 /*is_store*/); + IM3Module wasm3_module = wasm3_runtime->modules; + c3_w n_imports = wasm3_module->numFuncImports; + + // make sure to not touch BoxArena + m3_SetAllocators(_calloc_bail, _free_bail, _realloc_bail); + m3_SetTransientAllocators(_calloc_code, _free_code, _realloc_code); + m3_SetMemoryAllocators(_calloc_bail, _free_bail, _realloc_bail); + + jmp_buf esc; + CodeArena->esc_u = &esc; + c3_i jmp_i; + + while (1) + { + wasm3_runtime->base_transient = CodeArena->buf_y; + + if (0 == (jmp_i = setjmp(esc))) + { + for (c3_w i = 0; i < n_imports; i++) + { + M3Function f = wasm3_module->functions[i]; + const char* mod = f.import.moduleUtf8; + const char* name = f.import.fieldUtf8; + + result = m3_LinkRawFunctionEx( + wasm3_module, mod, name, + NULL, &_link_wasm_with_arrow_map, + sat_u + ); + + if (result) + { + fprintf(stderr, ERR("link error: %s"), result); + return u3m_bail(c3__fail); + } + } + + result = m3_CompileModule(wasm3_module); + if (result) + { + fprintf(stderr, ERR("compilation error: %s"), result); + return u3m_bail(c3__fail); + } + + break; + } + else + { + if (jmp_i == c3__code) + { + _uw_arena_grow(CodeArena); + } + else + { + return u3m_bail(c3__fail); + } + continue; + } + } + + { + sat_u->yil_previous = u3k(yil_previous); + sat_u->queue = u3k(queue); + sat_u->wasm_module = wasm3_module; + sat_u->lia_shop = u3k(lia_shop); + sat_u->acc = u3k(acc); + // sat_u->map to be filled afterwards + // sat_u->match same + // sat_u->resolution same + sat_u->arrow_yil = u3_none; + sat_u->susp_list = u3k(susp_list); + M3MemoryHeader* mem = u3a_malloc(len_buf_w + sizeof(M3MemoryHeader)); + mem->runtime = wasm3_runtime; + mem->maxStack = BoxArena->buf_y + stk_off_w; + mem->length = len_buf_w; + u3r_bytes(0, len_buf_w, (u8*)(mem + 1), q_mem_buffer); + wasm3_runtime->memory.mallocated = mem; + } + + u3z(get); + + return 1; + } +} + +// arguments RETAINED, returned yield transfered. +// transfers sat_u->yil_previous if it is returned, and replaces +// the struct value with u3_none +static u3_noun +_apply_diff(u3_noun input_tag, u3_noun p_input, lia_state* sat_u) +{ + m3_SetAllocators(_calloc_bail, _free_bail, _realloc_bail); + m3_SetTransientAllocators(_calloc_bail, _free_bail, _realloc_bail); + m3_SetMemoryAllocators(u3a_calloc, u3a_free, u3a_realloc); + + if (input_tag == c3y) + { + if (sat_u->wasm_module->runtime->edge_suspend) + { + // appended new script but the computation is still suspended: + // add script to queue, return previous yield + if (sat_u->yil_previous == u3_none) + { + return u3m_bail(c3__fail); + } + sat_u->queue = u3kb_weld(sat_u->queue, u3nc(u3k(p_input), u3_nul)); // snoc + u3_noun yil = sat_u->yil_previous; + sat_u->yil_previous = u3_none; + return yil; + } + else + { + return _reduce_monad(u3k(p_input), sat_u); + } + } + else + { + if (!sat_u->wasm_module->runtime->edge_suspend) + { + // appended external call resolution but no block to resolve: + // snoc result to shop, return previous yield + if (sat_u->yil_previous == u3_none) + { + return u3m_bail(c3__fail); + } + sat_u->lia_shop = u3kb_weld(sat_u->lia_shop, u3nc(u3k(p_input), u3_nul)); // snoc + u3_noun yil = sat_u->yil_previous; + sat_u->yil_previous = u3_none; + return yil; + } + // else resume + IM3Runtime run_u = sat_u->wasm_module->runtime; + run_u->resume_external = _resume_callback; + run_u->userdata_resume = sat_u; + if (sat_u->resolution != u3_none) + { + return u3m_bail(c3__fail); + } + sat_u->resolution = u3nc(0, u3k(p_input)); + M3Result result = m3_Resume(run_u); + u3_noun yil; + if (result == m3Err_ComputationBlock) + { + yil = sat_u->resolution; + sat_u->resolution = u3_none; + if (yil == u3_none) + { + yil = sat_u->arrow_yil; + sat_u->arrow_yil = u3_none; + if (yil == u3_none) + { + return u3m_bail(c3__fail); + } + } + } + else if (_deterministic_trap(result)) + { + fprintf(stderr, WUT("function call trapped: %s"), result); // XX get name of entry function? + yil = u3nc(2, 0); + } + else if (result == m3Err_functionImportMissing) + { + return u3m_bail(c3__exit); + } + else if (result) + { + fprintf(stderr, ERR("resumption failed: %s"), result); + return u3m_bail(c3__fail); + } + else + { + yil = sat_u->resolution; + sat_u->resolution = u3_none; + if (yil == u3_none) + { + return u3m_bail(c3__fail); + } + + if (sat_u->queue != u3_none) + { + while (u3h(yil) == 0 && sat_u->queue != u3_nul) + { + u3z(yil); + u3_noun deferred_script = _pop_list(&sat_u->queue); + yil = _reduce_monad(deferred_script, sat_u); + } + } + } + + return yil; + } +} + +// try to save new state, replacing old state with a tombstone value +// frees wasm3 memory buffer, releases arenas +// RETAINS arguments, transfers sat_u->lia_shop/susp_list/queue and +// replaces them with u3_none if save is succesful +static void +_move_state( + lia_state* sat_u, + u3_noun seed_old, + u3_noun seed_new, + u3_noun hint, + u3_noun yil) +{ + if ( (c3__oust == hint) + || (2 == u3h(yil)) + || (c3__rand == hint && 0 == u3h(yil)) + ) + { + u3z_save_m(u3z_memo_keep, uw_run_m, seed_old, u3_nul); + IM3Runtime run_u = sat_u->wasm_module->runtime; + M3MemoryHeader* mem_u = run_u->memory.mallocated; + u3a_free(mem_u); + _uw_arena_free(CodeArena); + _uw_arena_free(BoxArena); + return; + } + + IM3Runtime run_u = sat_u->wasm_module->runtime; + M3MemoryHeader* mem_u = run_u->memory.mallocated; + c3_w stk_off_w = (u8*)mem_u->maxStack - BoxArena->buf_y; + if (c3n == u3a_is_cat(stk_off_w)) + { + u3m_bail(c3__fail); + } + + c3_w len_buf_w = mem_u->length; + if (c3n == u3a_is_cat(len_buf_w)) + { + u3m_bail(c3__fail); + } + + u3_atom q_buf = u3i_bytes(len_buf_w, (c3_y*)(mem_u + 1)); + + u3a_free(mem_u); + + m3_RewritePointersRuntime(run_u, BoxArena->buf_y, 1 /*is_store*/); + c3_w run_off_w = (c3_y*)run_u - BoxArena->buf_y; + if (c3n == u3a_is_cat(run_off_w)) + { + u3m_bail(c3__fail); + } + + _uw_arena_free(CodeArena); + + c3_w box_len_w = BoxArena->siz_w; + if (c3n == u3a_is_cat(box_len_w)) + { + u3m_bail(c3__fail); + } + + c3_y pad_y = BoxArena->pad_y; + + u3_atom q_box = u3i_slab_mint(&BoxArena->sab_u); + BoxArena->ini_t = 0; + + u3_noun stash = uw_octo( + u3k(yil), + sat_u->queue, + u3nc(u3nc(box_len_w, q_box), pad_y), + u3nc(u3nc(len_buf_w, q_buf), stk_off_w), + run_off_w, + sat_u->lia_shop, + u3k(sat_u->acc), // accumulator will be returned + sat_u->susp_list + ); + sat_u->lia_shop = u3_none; + sat_u->susp_list = u3_none; + sat_u->queue = u3_none; + + u3z_save_m(u3z_memo_keep, uw_run_m, seed_old, u3_nul); + + u3z_save_m(u3z_memo_keep, uw_run_m, seed_new, stash); + + u3z(stash); +} + +u3_weak +u3we_lia_run_v1(u3_noun cor) +{ +#ifndef URWASM_STATEFUL + return u3_none; +#else + + u3_noun hint = u3at(u3x_sam_7, cor); + if (c3__none == hint) + { + return u3_none; + } + + // strand: save %1, delete in other cases + c3_t rand_t = (c3__rand == hint); + + // agent: always save + c3_t gent_t = (c3__gent == hint); + + // oust: don't save + c3_t oust_t = (c3__oust == hint); + + // omit: run statelessly + c3_t omit_t = !(rand_t || gent_t || oust_t); + + #ifdef URWASM_SUBROAD + + // enter subroad, 4MB safety buffer + u3m_hate(1 << 20); + + #endif + + u3_noun ctx = u3at(RUN_CTX, cor); + u3r_mug(ctx); + + u3_noun input = u3at(u3x_sam_2, cor); + u3_noun seed = u3at(u3x_sam_6, cor); + + u3_noun runnable = uw_kick_nock(u3k(ctx), AX_RUNNABLE); + u3_noun arrows = KICK1(uw_kick_nock(u3k(ctx), AX_ARROWS)); + + u3_noun try_gate = uw_kick_nock(u3k(runnable), AX_TRY); + u3_noun try_gate_inner = KICK1(try_gate); + + u3_noun seed_new; + u3_noun input_tag, p_input; + u3x_cell(input, &input_tag, &p_input); + + if (input_tag == c3y) + { + u3_noun p_input_gate = u3nt(u3nc(0, 7), 0, u3k(p_input)); // =>(p.input |=(* +>)) + u3_noun past_new = uw_slam_nock( + u3k(try_gate_inner), + u3nc( + u3k(u3at(seed_past, seed)), + p_input_gate + ) + ); + seed_new = u3nq( + u3k(u3at(seed_module, seed)), + past_new, + u3k(u3at(seed_shop, seed)), + u3k(u3at(seed_import, seed)) + ); + } + else if (input_tag == c3n) + { + seed_new = u3nq( + u3k(u3at(seed_module, seed)), + u3k(u3at(seed_past, seed)), + u3nc(u3k(p_input), u3k(u3at(seed_shop, seed))), + u3k(u3at(seed_import, seed)) + ); + } + else + { + return u3m_bail(c3__fail); + } + + u3_noun call_script = KICK1(uw_kick_nock(u3k(arrows), AX_CALL)); + u3_noun memread_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEMREAD)); + u3_noun memwrite_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEMWRITE)); + u3_noun call_ext_script = KICK1(uw_kick_nock(u3k(arrows), AX_CALL_EXT)); + u3_noun global_set_script = KICK1(uw_kick_nock(u3k(arrows), AX_GLOBAL_SET)); + u3_noun global_get_script = KICK1(uw_kick_nock(u3k(arrows), AX_GLOBAL_GET)); + u3_noun mem_grow_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEM_GROW)); + u3_noun mem_size_script = uw_kick_nock(u3k(arrows), AX_MEM_SIZE); + u3_noun get_acc_script = uw_kick_nock(u3k(arrows), AX_GET_ACC); + u3_noun set_acc_script = KICK1(uw_kick_nock(u3k(arrows), AX_SET_ACC)); + u3_noun get_all_glob_script = uw_kick_nock(u3k(arrows), AX_GET_ALL_GLOB); + u3_noun set_all_glob_script = KICK1(uw_kick_nock( arrows, AX_SET_ALL_GLOB)); + + u3_noun try_script = KICK1(try_gate_inner); + u3_noun catch_script = KICK2(uw_kick_nock(u3k(runnable), AX_CATCH)); + u3_noun return_script = KICK1(uw_kick_nock(u3k(runnable), AX_RETURN)); + u3_noun fail_script = uw_kick_nock( runnable, AX_FAIL); + + u3_noun call_bat = u3k(u3h(call_script)); + u3_noun memread_bat = u3k(u3h(memread_script)); + u3_noun memwrite_bat = u3k(u3h(memwrite_script)); + u3_noun call_ext_bat = u3k(u3h(call_ext_script)); + u3_noun try_bat = u3k(u3h(try_script)); + u3_noun catch_bat = u3k(u3h(catch_script)); + u3_noun return_bat = u3k(u3h(return_script)); + u3_noun fail_bat = u3k(u3h(fail_script)); + u3_noun global_set_bat = u3k(u3h(global_set_script)); + u3_noun global_get_bat = u3k(u3h(global_get_script)); + u3_noun mem_grow_bat = u3k(u3h(mem_grow_script)); + u3_noun mem_size_bat = u3k(u3h(mem_size_script)); + u3_noun get_acc_bat = u3k(u3h(get_acc_script)); + u3_noun set_acc_bat = u3k(u3h(set_acc_script)); + u3_noun get_all_glob_bat = u3k(u3h(get_all_glob_script)); + u3_noun set_all_glob_bat = u3k(u3h(set_all_glob_script)); + + u3_noun call_ctx = u3k(u3at(ARROW_CTX, call_script)); + u3_noun memread_ctx = u3k(u3at(ARROW_CTX, memread_script)); + u3_noun memwrite_ctx = u3k(u3at(ARROW_CTX, memwrite_script)); + u3_noun global_set_ctx = u3k(u3at(ARROW_CTX, global_set_script)); + u3_noun global_get_ctx = u3k(u3at(ARROW_CTX, global_get_script)); + u3_noun mem_grow_ctx = u3k(u3at(ARROW_CTX, mem_grow_script)); + u3_noun mem_size_ctx = u3k(u3at(MONAD_CTX, mem_size_script)); + u3_noun get_all_glob_ctx = u3k(u3at(MONAD_CTX, get_all_glob_script)); + u3_noun set_all_glob_ctx = u3k(u3at(ARROW_CTX, set_all_glob_script)); + + u3z(call_script); + u3z(memread_script); + u3z(memwrite_script); + u3z(call_ext_script); + u3z(try_script); + u3z(catch_script); + u3z(return_script); + u3z(fail_script); + u3z(global_set_script); + u3z(global_get_script); + u3z(mem_grow_script); + u3z(mem_size_script); + u3z(get_acc_script); + u3z(set_acc_script); + u3z(get_all_glob_script); + u3z(set_all_glob_script); + + match_data_struct match = { + call_bat, + memread_bat, + memwrite_bat, + call_ext_bat, + try_bat, + catch_bat, + return_bat, + fail_bat, + global_set_bat, + global_get_bat, + mem_grow_bat, + mem_size_bat, + get_acc_bat, + set_acc_bat, + get_all_glob_bat, + set_all_glob_bat, + // + call_ctx, + memread_ctx, + memwrite_ctx, + global_set_ctx, + global_get_ctx, + mem_grow_ctx, + mem_size_ctx, + get_all_glob_ctx, + set_all_glob_ctx, + }; + + lia_state sat; + + BoxArena = &sat.box_arena; + CodeArena = &sat.code_arena; + + u3_noun yil; + if (!omit_t) + { + sat.is_stateful = 1; + if (_get_state(hint, seed, &sat)) + { + sat.map = u3t(u3at(seed_import, seed)); + sat.match = &match; + sat.resolution = u3_none; + yil = _apply_diff(input_tag, p_input, &sat); + } + else + { // instantiate state with retries + u3_noun octs = u3at(seed_module, seed_new); + u3_noun p_octs, q_octs; + u3x_cell(octs, &p_octs, &q_octs); + c3_w bin_len_w = (c3y == u3a_is_cat(p_octs)) ? p_octs + : u3m_bail(c3__fail); + c3_y* bin_y; + M3Result result; + IM3Environment wasm3_env; + IM3Runtime wasm3_runtime = NULL; + IM3Module wasm3_module; + + _uw_arena_init(CodeArena); + _uw_arena_init(BoxArena); + + m3_SetAllocators(_calloc_box, _free_box, _realloc_box); + m3_SetTransientAllocators(_calloc_code, _free_code, _realloc_code); + m3_SetMemoryAllocators(u3a_calloc, u3a_free, u3a_realloc); + jmp_buf esc; + CodeArena->esc_u = BoxArena->esc_u = &esc; + c3_i jmp_i; + + while (1) + { + if (0 == (jmp_i = setjmp(esc))) + { + bin_y = _calloc_box(bin_len_w, 1); + u3r_bytes(0, bin_len_w, bin_y, u3x_atom(q_octs)); + + wasm3_env = m3_NewEnvironment(); + if (!wasm3_env) + { + fprintf(stderr, ERR("env is null")); + return u3m_bail(c3__fail); + } + + wasm3_runtime = m3_NewRuntime( + wasm3_env, + 1 << 21, + NULL, + 1 /* suspend */ + ); + if (!wasm3_runtime) + { + fprintf(stderr, ERR("runtime is null")); + return u3m_bail(c3__fail); + } + + result = m3_ParseModule(wasm3_env, &wasm3_module, bin_y, bin_len_w); + if (result) + { + fprintf(stderr, ERR("parse binary error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_LoadModule(wasm3_runtime, wasm3_module); + if (result) + { + fprintf(stderr, ERR("load module error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_ValidateModule(wasm3_module); + if (result) + { + fprintf(stderr, ERR("validation error: %s"), result); + return u3m_bail(c3__fail); + } + + c3_w n_imports = wasm3_module->numFuncImports; + u3_noun lia_shop = u3at(seed_shop, seed_new); + u3_noun import = u3at(seed_import, seed_new); + + u3_noun acc, map; + u3x_cell(import, &acc, &map); + { + sat.yil_previous = u3_none; + sat.queue = u3_nul; + sat.wasm_module = wasm3_module; + sat.lia_shop = u3qb_flop(lia_shop); + sat.acc = u3k(acc); + sat.map = map; + sat.match = &match; + sat.arrow_yil = u3_none; + sat.susp_list = u3_nul; + sat.resolution = u3_none; + } + + for (c3_w i = 0; i < n_imports; i++) + { + M3Function f = wasm3_module->functions[i]; + const char* mod = f.import.moduleUtf8; + const char* name = f.import.fieldUtf8; + + result = m3_LinkRawFunctionEx( + wasm3_module, mod, name, + NULL, &_link_wasm_with_arrow_map, + &sat + ); + + if (result) + { + fprintf(stderr, ERR("link error: %s"), result); + return u3m_bail(c3__fail); + } + } + + result = m3_CompileModule(wasm3_module); + if (result) + { + fprintf(stderr, ERR("compilation error: %s"), result); + return u3m_bail(c3__fail); + } + + break; + } + else + { + // escaped, grow arena and retry + if (wasm3_runtime) + { + u3a_free(wasm3_runtime->memory.mallocated); + } + + if (jmp_i == c3__box) + { + _uw_arena_grow(BoxArena); + _uw_arena_reset(CodeArena); + } + else if (jmp_i == c3__code) + { + _uw_arena_grow(CodeArena); + _uw_arena_reset(BoxArena); + } + else + { + return u3m_bail(c3__fail); + } + + continue; + } + } + + wasm3_runtime->base = BoxArena->buf_y; + wasm3_runtime->base_transient = CodeArena->buf_y; + // sanity check: struct and code allocators should not be used + // when running wasm + m3_SetAllocators(_calloc_bail, _free_bail, _realloc_bail); + m3_SetTransientAllocators(_calloc_bail, _free_bail, _realloc_bail); + + result = m3_RunStart(wasm3_module); + + if (result == m3Err_ComputationBlock) + { + yil = sat.arrow_yil; + sat.arrow_yil = u3_none; + if (yil == u3_none) + { + return u3m_bail(c3__fail); + } + } + else if (_deterministic_trap(result)) + { + fprintf(stderr, WUT("start function call trapped: %s"), result); + yil = u3nc(2, 0); + } + else if (result == m3Err_functionImportMissing) + { + return u3m_bail(c3__exit); + } + else if (result) + { + fprintf(stderr, ERR("start function failed: %s"), result); + return u3m_bail(c3__fail); + } + else + { + u3_noun monad = u3at(seed_past, seed_new); + yil = _reduce_monad(u3k(monad), &sat); + } + } + + _move_state(&sat, seed, seed_new, hint, yil); + } + else + { + sat.is_stateful = 0; + M3Result result; + IM3Environment wasm3_env; + IM3Runtime wasm3_runtime = NULL; + IM3Module wasm3_module; + u3_noun p_octs, q_octs; + + u3_noun octs = u3at(seed_module, seed_new); + u3x_cell(octs, &p_octs, &q_octs); + c3_w bin_len_w = (c3y == u3a_is_cat(p_octs)) ? p_octs + : u3m_bail(c3__fail); + c3_y* bin_y = u3r_bytes_alloc(0, bin_len_w, u3x_atom(q_octs)); + + m3_SetAllocators(u3a_calloc, u3a_free, u3a_realloc); + m3_SetTransientAllocators(u3a_calloc, u3a_free, u3a_realloc); + m3_SetMemoryAllocators(u3a_calloc, u3a_free, u3a_realloc); + + wasm3_env = m3_NewEnvironment(); + if (!wasm3_env) + { + fprintf(stderr, ERR("env is null")); + return u3m_bail(c3__fail); + } + + // 2MB stack + wasm3_runtime = m3_NewRuntime(wasm3_env, 1 << 21, NULL, 0 /* suspend */); + if (!wasm3_runtime) + { + fprintf(stderr, ERR("runtime is null")); + return u3m_bail(c3__fail); + } + + // save the stack to restore it later before calling m3_FreeRuntime + // since it is allocated and freed seperately; no need to do it in + // stateful code branch since there we will allocate and free + // whole arena + + void* stk_u = wasm3_runtime->stack; + + result = m3_ParseModule(wasm3_env, &wasm3_module, bin_y, bin_len_w); + if (result) + { + fprintf(stderr, ERR("parse binary error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_LoadModule(wasm3_runtime, wasm3_module); + if (result) + { + fprintf(stderr, ERR("load module error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_ValidateModule(wasm3_module); + if (result) + { + fprintf(stderr, ERR("validation error: %s"), result); + return u3m_bail(c3__fail); + } + + c3_w n_imports = wasm3_module->numFuncImports; + u3_noun lia_shop = u3at(seed_shop, seed_new); + u3_noun import = u3at(seed_import, seed_new); + + u3_noun acc, map; + u3x_cell(import, &acc, &map); + { + sat.yil_previous = u3_none; + sat.queue = u3_none; + sat.wasm_module = wasm3_module; + sat.lia_shop = u3qb_flop(lia_shop); + sat.acc = u3k(acc); + sat.map = map; + sat.match = &match; + sat.arrow_yil = u3_none; + sat.susp_list = u3_none; + sat.resolution = u3_none; + } + + for (c3_w i = 0; i < n_imports; i++) + { + M3Function f = wasm3_module->functions[i]; + const char* mod = f.import.moduleUtf8; + const char* name = f.import.fieldUtf8; + + result = m3_LinkRawFunctionEx( + wasm3_module, mod, name, + NULL, &_link_wasm_with_arrow_map, + &sat + ); + + if (result) + { + fprintf(stderr, ERR("link error: %s"), result); + return u3m_bail(c3__fail); + } + } + + // don't compile module since here we don't care about the ordering + // of code pages when we don't suspend, the functions will + // get compiled on call + // + + result = m3_RunStart(wasm3_module); + + if (result == m3Err_ComputationBlock) + { + yil = sat.arrow_yil; + sat.arrow_yil = u3_none; + if (yil == u3_none) + { + return u3m_bail(c3__fail); + } + } + else if (_deterministic_trap(result)) + { + fprintf(stderr, WUT("start function call trapped: %s"), result); + yil = u3nc(2, 0); + } + else if (result == m3Err_functionImportMissing) + { + return u3m_bail(c3__exit); + } + else if (result) + { + fprintf(stderr, ERR("start function failed: %s"), result); + return u3m_bail(c3__fail); + } + else + { + u3_noun monad = u3at(seed_past, seed_new); + yil = _reduce_monad(u3k(monad), &sat); + } + + wasm3_runtime->stack = stk_u; + m3_FreeRuntime(wasm3_runtime); + m3_FreeEnvironment(wasm3_env); + u3a_free(bin_y); + } + + // any of these could be u3_none + // + { + u3z(sat.lia_shop); + u3z(sat.susp_list); + u3z(sat.yil_previous); + u3z(sat.queue); + } + + u3z(match.call_bat); + u3z(match.memread_bat); + u3z(match.memwrite_bat); + u3z(match.call_ext_bat); + u3z(match.try_bat); + u3z(match.catch_bat); + u3z(match.return_bat); + u3z(match.fail_bat); + u3z(match.global_set_bat); + u3z(match.global_get_bat); + u3z(match.mem_grow_bat); + u3z(match.mem_size_bat); + + u3z(match.call_ctx); + u3z(match.memread_ctx); + u3z(match.memwrite_ctx); + u3z(global_set_ctx); + u3z(global_get_ctx); + u3z(mem_grow_ctx); + u3z(mem_size_ctx); + + #ifdef URWASM_SUBROAD + // exit subroad, copying the result + u3_noun pro = u3m_love(u3nc(u3nc(yil, sat.acc), seed_new)); + #else + u3_noun pro = u3nc(u3nc(yil, sat.acc), seed_new); + #endif + + return pro; + +#endif // URWASM_STATEFUL +} + + +u3_weak +u3we_lia_run_once(u3_noun cor) +{ + if (c3__none == u3at(u3x_sam_6, cor)) + { + return u3_none; + } + + #ifdef URWASM_SUBROAD + // enter subroad, 4MB safety buffer + u3m_hate(1 << 20); + #endif + + u3_noun ctx = u3at(ONCE_CTX, cor); + u3r_mug(ctx); + + u3_noun runnable = uw_kick_nock(u3k(ctx), AX_RUNNABLE); + u3_noun arrows = KICK1(uw_kick_nock(u3k(ctx), AX_ARROWS)); + + u3_noun call_script = KICK1(uw_kick_nock(u3k(arrows), AX_CALL)); + u3_noun memread_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEMREAD)); + u3_noun memwrite_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEMWRITE)); + u3_noun call_ext_script = KICK1(uw_kick_nock(u3k(arrows), AX_CALL_EXT)); + u3_noun global_set_script = KICK1(uw_kick_nock(u3k(arrows), AX_GLOBAL_SET)); + u3_noun global_get_script = KICK1(uw_kick_nock(u3k(arrows), AX_GLOBAL_GET)); + u3_noun mem_grow_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEM_GROW)); + u3_noun mem_size_script = uw_kick_nock(u3k(arrows), AX_MEM_SIZE); + u3_noun get_acc_script = uw_kick_nock(u3k(arrows), AX_GET_ACC); + u3_noun set_acc_script = KICK1(uw_kick_nock(u3k(arrows), AX_SET_ACC)); + u3_noun get_all_glob_script = uw_kick_nock(u3k(arrows), AX_GET_ALL_GLOB); + u3_noun set_all_glob_script = KICK1(uw_kick_nock( arrows, AX_SET_ALL_GLOB)); + + u3_noun try_script = KICK2(uw_kick_nock(u3k(runnable), AX_TRY)); + u3_noun catch_script = KICK2(uw_kick_nock(u3k(runnable), AX_CATCH)); + u3_noun return_script = KICK1(uw_kick_nock(u3k(runnable), AX_RETURN)); + u3_noun fail_script = uw_kick_nock( runnable, AX_FAIL); + + u3_noun call_bat = u3k(u3h(call_script)); + u3_noun memread_bat = u3k(u3h(memread_script)); + u3_noun memwrite_bat = u3k(u3h(memwrite_script)); + u3_noun call_ext_bat = u3k(u3h(call_ext_script)); + u3_noun try_bat = u3k(u3h(try_script)); + u3_noun catch_bat = u3k(u3h(catch_script)); + u3_noun return_bat = u3k(u3h(return_script)); + u3_noun fail_bat = u3k(u3h(fail_script)); + u3_noun global_set_bat = u3k(u3h(global_set_script)); + u3_noun global_get_bat = u3k(u3h(global_get_script)); + u3_noun mem_grow_bat = u3k(u3h(mem_grow_script)); + u3_noun mem_size_bat = u3k(u3h(mem_size_script)); + u3_noun get_acc_bat = u3k(u3h(get_acc_script)); + u3_noun set_acc_bat = u3k(u3h(set_acc_script)); + u3_noun get_all_glob_bat = u3k(u3h(get_all_glob_script)); + u3_noun set_all_glob_bat = u3k(u3h(set_all_glob_script)); + + u3_noun call_ctx = u3k(u3at(ARROW_CTX, call_script)); + u3_noun memread_ctx = u3k(u3at(ARROW_CTX, memread_script)); + u3_noun memwrite_ctx = u3k(u3at(ARROW_CTX, memwrite_script)); + u3_noun global_set_ctx = u3k(u3at(ARROW_CTX, global_set_script)); + u3_noun global_get_ctx = u3k(u3at(ARROW_CTX, global_get_script)); + u3_noun mem_grow_ctx = u3k(u3at(ARROW_CTX, mem_grow_script)); + u3_noun mem_size_ctx = u3k(u3at(MONAD_CTX, mem_size_script)); + u3_noun get_all_glob_ctx = u3k(u3at(MONAD_CTX, get_all_glob_script)); + u3_noun set_all_glob_ctx = u3k(u3at(ARROW_CTX, set_all_glob_script)); + + u3z(call_script); + u3z(memread_script); + u3z(memwrite_script); + u3z(call_ext_script); + u3z(try_script); + u3z(catch_script); + u3z(return_script); + u3z(fail_script); + u3z(global_set_script); + u3z(global_get_script); + u3z(mem_grow_script); + u3z(mem_size_script); + u3z(get_acc_script); + u3z(set_acc_script); + u3z(get_all_glob_script); + u3z(set_all_glob_script); + + + match_data_struct match = { + call_bat, + memread_bat, + memwrite_bat, + call_ext_bat, + try_bat, + catch_bat, + return_bat, + fail_bat, + global_set_bat, + global_get_bat, + mem_grow_bat, + mem_size_bat, + get_acc_bat, + set_acc_bat, + get_all_glob_bat, + set_all_glob_bat, + // + call_ctx, + memread_ctx, + memwrite_ctx, + global_set_ctx, + global_get_ctx, + mem_grow_ctx, + mem_size_ctx, + get_all_glob_ctx, + set_all_glob_ctx, + }; + + u3_noun octs = u3at(u3x_sam_4, cor); + u3_noun p_octs, q_octs; + u3x_cell(octs, &p_octs, &q_octs); + + c3_w bin_len_w = (c3y == u3a_is_cat(p_octs)) ? p_octs : u3m_bail(c3__fail); + c3_y* bin_y = u3r_bytes_alloc(0, bin_len_w, u3x_atom(q_octs)); + + M3Result result; + + m3_SetAllocators(u3a_calloc, u3a_free, u3a_realloc); + m3_SetTransientAllocators(u3a_calloc, u3a_free, u3a_realloc); + m3_SetMemoryAllocators(u3a_calloc, u3a_free, u3a_realloc); + + IM3Environment wasm3_env = m3_NewEnvironment(); + if (!wasm3_env) + { + fprintf(stderr, ERR("env is null")); + return u3m_bail(c3__fail); + } + + // 2MB stack + IM3Runtime wasm3_runtime = m3_NewRuntime( + wasm3_env, + 1 << 21, + NULL, + 0 /* suspend */ + ); + if (!wasm3_runtime) + { + fprintf(stderr, ERR("runtime is null")); + return u3m_bail(c3__fail); + } + + void* stk_u = wasm3_runtime->stack; + + IM3Module wasm3_module; + result = m3_ParseModule(wasm3_env, &wasm3_module, bin_y, bin_len_w); + if (result) + { + fprintf(stderr, ERR("parse binary error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_LoadModule(wasm3_runtime, wasm3_module); + if (result) + { + fprintf(stderr, ERR("load module error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_ValidateModule(wasm3_module); + if (result) + { + fprintf(stderr, ERR("validation error: %s"), result); + return u3m_bail(c3__fail); + } + + c3_w n_imports = wasm3_module->numFuncImports; + u3_noun monad = u3at(u3x_sam_7, cor); + u3_noun import = u3at(u3x_sam_5, cor); + + u3_noun acc, map; + u3x_cell(import, &acc, &map); + + lia_state sat = { + wasm3_module, + u3_nul, + u3k(acc), + map, + &match, + u3_none, + u3_none, + u3_none + }; + + sat.is_stateful = 0; + + for (c3_w i = 0; i < n_imports; i++) + { + M3Function f = wasm3_module->functions[i]; + const char * mod = f.import.moduleUtf8; + const char * name = f.import.fieldUtf8; + + result = m3_LinkRawFunctionEx( + wasm3_module, mod, name, + NULL, &_link_wasm_with_arrow_map, + (void *)&sat + ); + + if (result) + { + fprintf(stderr, ERR("link error: %s"), result); + return u3m_bail(c3__fail); + } + } + + u3_noun yil; + + result = m3_RunStart(wasm3_module); + + if (result == m3Err_ComputationBlock) + { + yil = sat.arrow_yil; + sat.arrow_yil = u3_none; + if (yil == u3_none) + { + return u3m_bail(c3__fail); + } + } + else if (_deterministic_trap(result)) + { + fprintf(stderr, WUT("start function call trapped: %s"), result); + yil = u3nc(2, 0); + } + else if (result == m3Err_functionImportMissing) + { + return u3m_bail(c3__exit); + } + else if (result) + { + fprintf(stderr, ERR("start function failed: %s"), result); + return u3m_bail(c3__fail); + } + else + { + yil = _reduce_monad(u3k(monad), &sat); + } + + wasm3_runtime->stack = stk_u; + m3_FreeRuntime(wasm3_runtime); + m3_FreeEnvironment(wasm3_env); + + u3a_free(bin_y); + + u3z(match.call_bat); + u3z(match.memread_bat); + u3z(match.memwrite_bat); + u3z(match.call_ext_bat); + u3z(match.try_bat); + u3z(match.catch_bat); + u3z(match.return_bat); + u3z(match.fail_bat); + u3z(match.global_set_bat); + u3z(match.global_get_bat); + u3z(match.mem_grow_bat); + u3z(match.mem_size_bat); + u3z(match.get_acc_bat); + u3z(match.set_acc_bat); + u3z(match.get_all_glob_bat); + u3z(match.set_all_glob_bat); + + u3z(match.call_ctx); + u3z(match.memread_ctx); + u3z(match.memwrite_ctx); + u3z(global_set_ctx); + u3z(global_get_ctx); + u3z(mem_grow_ctx); + u3z(mem_size_ctx); + u3z(get_all_glob_ctx); + u3z(set_all_glob_ctx); + + #ifdef URWASM_SUBROAD + // exit subroad, copying the result + u3_noun pro = u3m_love(u3nc(yil, sat.acc)); + #else + u3_noun pro = u3nc(yil, sat.acc); + #endif + + return pro; +} diff --git a/vere/pkg/noun/jets/e/zlib.c b/vere/pkg/noun/jets/e/zlib.c new file mode 100644 index 0000000..89937df --- /dev/null +++ b/vere/pkg/noun/jets/e/zlib.c @@ -0,0 +1,225 @@ +/// @file + +#include <allocate.h> +#include <stdio.h> +#include "zlib.h" + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static void* +zlib_malloc(voidpf opaque, uInt items, uInt size) +{ + size_t len = items * size; + void* result = u3a_malloc(len); + return result; +} + +static void +zlib_free(voidpf opaque, voidpf address) +{ + u3a_free(address); +} + +u3_noun +_decompress(u3_atom pos, u3_noun octs, int window_bits) +{ + u3_atom p_octs = u3h(octs); + u3_atom q_octs = u3t(octs); + + c3_w p_octs_w, pos_w; + + if ( c3n == u3r_safe_word(p_octs, &p_octs_w) ) { + return u3_none; + } + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; + } + + c3_w len_w = u3r_met(3, q_octs); + + int leading_zeros = 0; + + if (p_octs_w > len_w) { + leading_zeros = p_octs_w - len_w; + } + else { + len_w = p_octs_w; + } + + // Bytestream exhausted + // + if (pos_w >= len_w) { + return u3_none; + } + + c3_y* input; + + if (c3y == u3a_is_cat(q_octs)) { + input = (c3_y*)&q_octs + pos_w; + } + else { + u3a_atom* vat_u = u3a_to_ptr(q_octs); + input = (c3_y*)vat_u->buf_w + pos_w; + } + + int ret; + z_stream strm; + + if (pos_w < len_w) { + strm.avail_in = (len_w - pos_w); + } + else { + strm.avail_in = 0; + } + + strm.zalloc = zlib_malloc; + strm.zfree = zlib_free; + strm.opaque = Z_NULL; + strm.next_in = input; + + ret = inflateInit2(&strm, window_bits); + + if (ret != Z_OK) { + u3l_log("%i", ret); + u3l_log("%s", strm.msg); + return u3m_bail(c3__exit); + } + + c3_w chunk_w = len_w / 10; + u3i_slab sab_u; + +#define INIT_SZ 16384 + strm.avail_out = INIT_SZ; + u3i_slab_init(&sab_u, 3, INIT_SZ); + strm.next_out = sab_u.buf_y; + + void* this_address = strm.next_out; + +#define ZEROS_SZ 256 + c3_y zeros[ZEROS_SZ]; + + if (leading_zeros) { + memset(zeros, 0, ZEROS_SZ); + } + + while ((ret = inflate(&strm, Z_FINISH)) == Z_BUF_ERROR) { + + // Output exhausted: reallocate + // + if (strm.avail_out == 0) { + strm.avail_out = chunk_w; + + u3i_slab_grow(&sab_u, 3, strm.total_out + chunk_w); + strm.next_out = sab_u.buf_y + strm.total_out; + } + + // Input exhausted: input leading zeros? + // + if (strm.avail_in == 0) { + + if (leading_zeros) { + // Position in the stream exceeded atom bytes, + // but is still below stream length + // + if (strm.total_in + pos_w >= len_w + && strm.total_in + pos_w < p_octs_w) { + + c3_w rem_w = p_octs_w - (strm.total_in + pos_w); + strm.next_in = zeros; + + if (rem_w > ZEROS_SZ) { + strm.avail_in = ZEROS_SZ; + } + else { + strm.avail_in = rem_w; + } + } + else { + u3l_log("%i", ret); + u3l_log("%s", strm.msg); + inflateEnd(&strm); + u3i_slab_free(&sab_u); + return u3m_bail(c3__exit); + } + } + else { + u3l_log("%i", ret); + u3l_log("%s", strm.msg); + inflateEnd(&strm); + u3i_slab_free(&sab_u); + return u3m_bail(c3__exit); + } + } + } + if (ret != Z_STREAM_END) { + u3l_log("%i", ret); + u3l_log("%s", strm.msg); + inflateEnd(&strm); + u3i_slab_free(&sab_u); + return u3m_bail(c3__exit); + } + ret = inflateEnd(&strm); + + if (ret != Z_OK) { + u3l_log("%i", ret); + u3l_log("%s", strm.msg); + u3i_slab_free(&sab_u); + return u3m_bail(c3__exit); + } + + u3_noun decompressed_octs = u3nc(strm.total_out, u3i_slab_mint(&sab_u)); + u3_noun new_pos = pos_w + strm.total_in; + u3_noun new_stream = u3nc(u3i_word(new_pos), u3k(octs)); + + return u3nc(decompressed_octs, new_stream); +} + +u3_noun +u3qe_decompress_gzip(u3_atom pos, u3_noun octs) +{ + return _decompress(pos, octs, 31); +} +u3_noun +u3qe_decompress_zlib(u3_atom pos, u3_noun octs) +{ + return _decompress(pos, octs, 15); +} + +u3_noun +u3we_decompress_gzip(u3_noun cor) +{ + u3_atom pos; + u3_noun octs; + + u3_noun a = u3r_at(u3x_sam, cor); + u3x_cell(a, &pos, &octs); + + if(_(u3a_is_atom(pos)) && _(u3a_is_cell(octs))) { + return u3qe_decompress_gzip(pos, octs); + } + + else { + return u3m_bail(c3__exit); + } +} + +u3_noun +u3we_decompress_zlib(u3_noun cor) +{ + u3_atom pos; + u3_noun octs; + + u3_noun a = u3r_at(u3x_sam, cor); + u3x_cell(a, &pos, &octs); + + if(_(u3a_is_atom(pos)) && _(u3a_is_cell(octs))) { + return u3qe_decompress_zlib(pos, octs); + } + + else { + return u3m_bail(c3__exit); + } +} diff --git a/vere/pkg/noun/jets/f/cell.c b/vere/pkg/noun/jets/f/cell.c new file mode 100644 index 0000000..0a818f2 --- /dev/null +++ b/vere/pkg/noun/jets/f/cell.c @@ -0,0 +1,29 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_cell(u3_noun hed, + u3_noun tal) + { + if ( (c3__void == hed) || (c3__void == tal) ) { + return c3__void; + } else { + return u3nt(c3__cell, u3k(hed), u3k(tal)); + } + } + u3_noun + u3wf_cell(u3_noun cor) + { + u3_noun hed, tal; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &hed, u3x_sam_3, &tal, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_cell(hed, tal); + } + } diff --git a/vere/pkg/noun/jets/f/comb.c b/vere/pkg/noun/jets/f/comb.c new file mode 100644 index 0000000..1dfe794 --- /dev/null +++ b/vere/pkg/noun/jets/f/comb.c @@ -0,0 +1,70 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_comb(u3_noun mal, + u3_noun buz) + { + if ( (u3_none == mal) || (u3_none == buz) ) { + return u3_none; + } + else { + u3_noun p_mal, q_mal, p_buz, q_buz, pp_buz, pq_buz; + + if ( (c3y == u3r_p(mal, 0, &p_mal)) && (0 != p_mal) ) { + if ( (c3y == u3r_p(buz, 0, &p_buz)) && (0 != p_buz) ) { + return u3nc(0, + u3qc_peg(p_mal, p_buz)); + } + else if ( c3y == u3r_pq(buz, 2, &p_buz, &q_buz) && + c3y == u3r_p(p_buz, 0, &pp_buz) && + c3y == u3r_p(q_buz, 0, &pq_buz) ) + { + return u3nt(2, + u3nc(0, + u3qc_peg(p_mal, pp_buz)), + u3nc(0, + u3qc_peg(p_mal, pq_buz))); + } + else return u3nt(7, + u3k(mal), + u3k(buz)); + } +#if 1 + else if ( (c3y == u3r_bush(mal, &p_mal, &q_mal)) && + (c3y == u3du(p_mal)) && + (c3y == u3du(q_mal)) && + (0 == u3h(q_mal)) && + (1 == u3t(q_mal)) ) + { + return u3nt(8, + u3k(p_mal), + u3k(buz)); + } +#endif + else if ( (c3y == u3r_p(buz, 0, &p_buz)) && + (c3y == u3r_sing(1, p_buz)) ) + { + return u3k(mal); + } + else return u3nt(7, + u3k(mal), + u3k(buz)); + } + } + u3_noun + u3wf_comb(u3_noun cor) + { + u3_noun mal, buz; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &mal, u3x_sam_3, &buz, 0) ) { + return u3_none; + } else { + return u3qf_comb(mal, buz); + } + } diff --git a/vere/pkg/noun/jets/f/cons.c b/vere/pkg/noun/jets/f/cons.c new file mode 100644 index 0000000..45719c1 --- /dev/null +++ b/vere/pkg/noun/jets/f/cons.c @@ -0,0 +1,54 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_cons(u3_noun vur, + u3_noun sed) + { + u3_noun p_vur, p_sed; + + if ( c3y == u3r_p(vur, 1, &p_vur) && + c3y == u3r_p(sed, 1, &p_sed) ) { + return u3nt(1, + u3k(p_vur), + u3k(p_sed)); + } +#if 0 + else if ( c3y == u3r_p(vur, 0, &p_vur) && + c3y == u3r_p(sed, 0, &p_sed) && + !(c3y == u3r_sing(1, p_vur)) && + !(c3y == u3r_sing(p_vur, p_sed)) && + (0 == u3r_nord(p_vur, p_sed)) ) + { + u3_atom fub = u3qa_div(p_vur, 2); + u3_atom nof = u3qa_div(p_sed, 2); + + if ( c3y == u3r_sing(fub, nof) ) { + u3z(nof); + + return u3nc(0, fub); + } + else { + u3z(fub); + u3z(nof); + } + } +#endif + return u3nc(u3k(vur), u3k(sed)); + } + u3_noun + u3wf_cons(u3_noun cor) + { + u3_noun vur, sed; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &vur, u3x_sam_3, &sed, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_cons(vur, sed); + } + } diff --git a/vere/pkg/noun/jets/f/core.c b/vere/pkg/noun/jets/f/core.c new file mode 100644 index 0000000..ca7e93d --- /dev/null +++ b/vere/pkg/noun/jets/f/core.c @@ -0,0 +1,118 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_core(u3_noun pac, + u3_noun con) + { + if ( (c3__void == pac) ) { + return c3__void; + } else { + { + u3_noun p_con, q_con, r_con, hr_con, tr_con; + + u3r_trel(con, &p_con, &q_con, &r_con); + u3r_cell(r_con, &hr_con, &tr_con); + if ( (c3y == u3du(hr_con)) && + (u3_nul == u3h(hr_con)) && + (u3_nul == u3t(hr_con)) ) + { + u3l_log("old core"); + abort(); + } + } + return u3nt(c3__core, u3k(pac), u3k(con)); + } + } + u3_noun + u3wf_core(u3_noun cor) + { + u3_noun pac, con; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &pac, u3x_sam_3, &con, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_core(pac, con); + } + } + +#if 0 + static void + _fork_test(const c3_c *lab_c, u3_noun set) + { + if ( u3_nul == set ) { + return; + } else { + u3_noun n_set, l_set, r_set; + + u3x_trel(set, &n_set, &l_set, &r_set); + + u3qf_test(lab_c, n_set); + _fork_test(lab_c, l_set); + _fork_test(lab_c, r_set); + } + } + void + u3qf_test(const c3_c* lab_c, u3_noun sut) + { + u3_noun p_sut, q_sut; + + if ( c3n == u3du(sut) ) switch ( sut ) { + default: u3m_bail(c3__fail); return; + + case c3__noun: + { + return; + } + case c3__void: + { + return; + } + } + else switch ( u3h(sut) ) { + default: u3m_bail(c3__fail); return; + + case c3__atom: u3x_cell(u3t(sut), &p_sut, &q_sut); + { + return; + } + case c3__cell: u3x_cell(u3t(sut), &p_sut, &q_sut); + { + u3qf_test(lab_c, p_sut); + u3qf_test(lab_c, q_sut); + return; + } + case c3__core: u3x_cell(u3t(sut), &p_sut, &q_sut); + { + u3qf_test(lab_c, p_sut); + return; + } + case c3__face: u3x_cell(u3t(sut), &p_sut, &q_sut); + { + u3qf_test(lab_c, q_sut); + return; + } + case c3__fork: p_sut = u3t(sut); + { + _fork_test(lab_c, p_sut); + return; + } + case c3__hint: u3x_cell(u3t(sut), &p_sut, &q_sut); + { + u3qf_test(lab_c, q_sut); + u3qf_test(lab_c, u3h(p_sut)); + return; + } + case c3__hold: u3x_cell(u3t(sut), &p_sut, &q_sut); + { + u3qf_test(lab_c, p_sut); + return; + } + } + } +#endif diff --git a/vere/pkg/noun/jets/f/face.c b/vere/pkg/noun/jets/f/face.c new file mode 100644 index 0000000..7e689e7 --- /dev/null +++ b/vere/pkg/noun/jets/f/face.c @@ -0,0 +1,31 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_face(u3_noun sag, + u3_noun tip) + { + if ( c3__void == tip ) { + return c3__void; + } + else return u3nt(c3__face, + u3k(sag), + u3k(tip)); + } + u3_noun + u3wf_face(u3_noun cor) + { + u3_noun sag, tip; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_face(sag, tip); + } + } + diff --git a/vere/pkg/noun/jets/f/fine.c b/vere/pkg/noun/jets/f/fine.c new file mode 100644 index 0000000..2c5a85c --- /dev/null +++ b/vere/pkg/noun/jets/f/fine.c @@ -0,0 +1,35 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_fine(u3_noun fuv, + u3_noun lup, + u3_noun mar) + { + if ( (c3__void == lup) || (c3__void == mar) ) { + return c3__void; + } else { + return u3nq(c3__fine, + u3k(fuv), + u3k(lup), + u3k(mar)); + } + } + u3_noun + u3wf_fine(u3_noun cor) + { + u3_noun fuv, lup, mar; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &fuv, + u3x_sam_6, &lup, + u3x_sam_7, &mar, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_fine(fuv, lup, mar); + } + } diff --git a/vere/pkg/noun/jets/f/fitz.c b/vere/pkg/noun/jets/f/fitz.c new file mode 100644 index 0000000..b1c2a5d --- /dev/null +++ b/vere/pkg/noun/jets/f/fitz.c @@ -0,0 +1,75 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +static u3_noun +_fitz_fiz(u3_noun yaz, + u3_noun wix) +{ + c3_w yaz_w = u3r_met(3, yaz); + c3_w wix_w = u3r_met(3, wix); + c3_y yaz_y, wix_y; + + yaz_y = (0 == yaz_w) ? 0 : u3r_byte((yaz_w - 1), yaz); + if ( (yaz_y < 'A') || (yaz_y > 'Z') ) yaz_y = 0; + + wix_y = (0 == wix_w) ? 0 : u3r_byte((wix_w - 1), wix); + if ( (wix_y < 'A') || (wix_y > 'Z') ) wix_y = 0; + + if ( yaz_y && wix_y ) { + if ( wix_y > yaz_y ) { + return c3n; + } + } + + return c3y; +} + +u3_noun +u3qf_fitz(u3_noun yaz, + u3_noun wix) +{ + c3_w yet_w = u3r_met(3, yaz); + c3_w wet_w = u3r_met(3, wix); + + c3_w i_w, met_w = c3_min(yet_w, wet_w); + + if ( c3n == _fitz_fiz(yaz, wix) ) { + return c3n; + } + for ( i_w = 0; i_w < met_w; i_w++ ) { + c3_y yaz_y = u3r_byte(i_w, yaz); + c3_y wix_y = u3r_byte(i_w, wix); + + if ( (i_w == (yet_w - 1)) && (yaz_y >= 'A') && (yaz_y <= 'Z')) { + return c3y; + } + + if ( (i_w == (wet_w - 1)) && (wix_y >= 'A') && (wix_y <= 'Z')) { + return c3y; + } + + if ( yaz_y != wix_y ) { + return c3n; + } + } + return c3y; +} + +u3_noun +u3wf_fitz(u3_noun cor) +{ + u3_noun yaz, wix; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &yaz, u3x_sam_3, &wix, 0)) || + (c3n == u3ud(yaz)) || + (c3n == u3ud(wix)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qf_fitz(yaz, wix); + } +} diff --git a/vere/pkg/noun/jets/f/flan.c b/vere/pkg/noun/jets/f/flan.c new file mode 100644 index 0000000..319e1f0 --- /dev/null +++ b/vere/pkg/noun/jets/f/flan.c @@ -0,0 +1,47 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_flan(u3_noun bos, + u3_noun nif) + { + if ( c3y == u3r_sing(bos, nif) ) { + return u3k(bos); + } + if ( c3y == u3r_sing(1, u3h(bos)) ) { + if ( (u3_nul == u3t(bos)) ) { + return u3k(nif); + } + else return u3k(bos); + } + else { + if ( c3y == u3r_sing(1, u3h(nif)) ) { + if ( (u3_nul == u3t(nif)) ) { + return u3k(bos); + } + else return u3k(nif); + } + else { + return u3nq(6, + u3k(bos), + u3k(nif), + u3nc(1, c3n)); + } + } + } + u3_noun + u3wf_flan_139(u3_noun cor) + { + u3_noun bos, nif; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &bos, u3x_sam_3, &nif, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_flan(bos, nif); + } + } diff --git a/vere/pkg/noun/jets/f/flip.c b/vere/pkg/noun/jets/f/flip.c new file mode 100644 index 0000000..9eb922e --- /dev/null +++ b/vere/pkg/noun/jets/f/flip.c @@ -0,0 +1,39 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_flip(u3_noun hel) + { + if ( c3y == u3r_sing(1, u3h(hel)) ) { + if ( (c3y == u3t(hel)) ) { + return u3nc(1, c3n); + } + else { + u3_assert((c3n == u3t(hel))); + + return u3nc(1, c3y); + } + } + else { + return u3nq(6, + u3k(hel), + u3nc(1, c3n), + u3nc(1, c3y)); + } + } + u3_noun + u3wf_flip_139(u3_noun cor) + { + u3_noun hel; + + if ( u3_none == (hel = u3r_at(u3x_sam, cor)) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_flip(hel); + } + } diff --git a/vere/pkg/noun/jets/f/flor.c b/vere/pkg/noun/jets/f/flor.c new file mode 100644 index 0000000..031168e --- /dev/null +++ b/vere/pkg/noun/jets/f/flor.c @@ -0,0 +1,47 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_flor(u3_noun bos, + u3_noun nif) + { + if ( c3y == u3r_sing(bos, nif) ) { + return u3k(bos); + } + if ( c3y == u3r_sing(1, u3h(bos)) ) { + if ( (u3_nul == u3t(bos)) ) { + return u3k(bos); + } + else return u3k(nif); + } + else { + if ( c3y == u3r_sing(1, u3h(nif)) ) { + if ( (u3_nul == u3t(nif)) ) { + return u3k(nif); + } + else return u3k(bos); + } + else { + return u3nq(6, + u3k(bos), + u3nc(1, c3y), + u3k(nif)); + } + } + } + u3_noun + u3wf_flor_139(u3_noun cor) + { + u3_noun bos, nif; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &bos, u3x_sam_3, &nif, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_flor(bos, nif); + } + } diff --git a/vere/pkg/noun/jets/f/fork.c b/vere/pkg/noun/jets/f/fork.c new file mode 100644 index 0000000..b2a68eb --- /dev/null +++ b/vere/pkg/noun/jets/f/fork.c @@ -0,0 +1,79 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_forq(u3_noun hoz, + u3_noun bur) + { + if ( c3y == u3r_sing(hoz, bur) ) { + return u3k(hoz); + } + else if ( c3__void == bur ) { + return u3k(hoz); + } + else if ( c3__void == hoz ) { + return u3k(bur); + } + else return u3kf_fork(u3nt(u3k(hoz), u3k(bur), u3_nul)); + } + + u3_noun + u3qf_fork(u3_noun yed) + { + u3_noun lez = u3_nul; + + while ( u3_nul != yed ) { + u3_noun i_yed = u3h(yed); + + if ( c3__void != i_yed ) { + if ( (c3y == u3du(i_yed)) && (c3__fork == u3h(i_yed)) ) { + lez = u3kdi_uni(lez, u3k(u3t(i_yed))); + } + else { + lez = u3kdi_put(lez, u3k(i_yed)); + } + } + + yed = u3t(yed); + } + + if ( u3_nul == lez ) { + return c3__void; + } + else if ( (u3_nul == u3h(u3t(lez))) && (u3_nul == u3t(u3t(lez))) ) { + u3_noun ret = u3k(u3h(lez)); + + u3z(lez); + return ret; + } + else { + return u3nc(c3__fork, lez); + } + } + + u3_noun + u3wf_fork(u3_noun cor) + { + u3_noun yed; + + if ( c3n == u3r_mean(cor, u3x_sam, &yed, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_fork(yed); + } + } + + u3_noun + u3kf_fork(u3_noun yed) + { + u3_noun ret = u3qf_fork(yed); + + u3z(yed); + return ret; + } diff --git a/vere/pkg/noun/jets/f/help.c b/vere/pkg/noun/jets/f/help.c new file mode 100644 index 0000000..41fe7fb --- /dev/null +++ b/vere/pkg/noun/jets/f/help.c @@ -0,0 +1,31 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_help(u3_noun sag, + u3_noun tip) + { + if ( c3__void == tip ) { + return c3__void; + } + else return u3nt(c3__help, + u3k(sag), + u3k(tip)); + } + u3_noun + u3wf_help(u3_noun cor) + { + u3_noun sag, tip; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_help(sag, tip); + } + } + diff --git a/vere/pkg/noun/jets/f/hint.c b/vere/pkg/noun/jets/f/hint.c new file mode 100644 index 0000000..175c3fb --- /dev/null +++ b/vere/pkg/noun/jets/f/hint.c @@ -0,0 +1,32 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + + u3_noun + u3qf_hint(u3_noun sag, + u3_noun tip) + { + if ( c3__void == tip ) { + return c3__void; + } + if ( c3__noun == tip ) { + return c3__noun; + } + else return u3nt(c3__hint, u3k(sag), u3k(tip)); + } + u3_noun + u3wf_hint(u3_noun cor) + { + u3_noun sag, tip; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_hint(sag, tip); + } + } + diff --git a/vere/pkg/noun/jets/f/look.c b/vere/pkg/noun/jets/f/look.c new file mode 100644 index 0000000..e50e914 --- /dev/null +++ b/vere/pkg/noun/jets/f/look.c @@ -0,0 +1,134 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + +/* internals +*/ + static u3_noun + _look_in(u3_noun cog, + u3_noun dab, + u3_atom axe) + { + if ( u3_nul == dab ) { + return u3_nul; + } + else { + u3_noun n_dab, l_dab, r_dab; + + u3r_trel(dab, &n_dab, &l_dab, &r_dab); + if ( c3n == u3du(n_dab) ) { + // return u3m_bail(c3__fail); + u3l_log("bad look"); + return u3m_bail(c3__exit) ; + } + else { + u3_noun pn_dab = u3h(n_dab); + u3_noun qn_dab = u3t(n_dab); + + if ( (u3_nul == l_dab) && (u3_nul == r_dab) ) { + if ( (c3y == u3du(qn_dab)) && + (c3y == u3r_sing(cog, pn_dab)) ) { + return u3nt(u3_nul, + u3k(axe), + u3k(qn_dab)); + } + else { + return u3_nul; + } + } + else if ( (u3_nul == l_dab) ) { + if ( (c3y == u3du(qn_dab)) && + (c3y == u3r_sing(cog, pn_dab)) ) { + return u3nt(u3_nul, + u3qc_peg(axe, 2), + u3k(qn_dab)); + } + else { + if ( c3y == u3qc_gor(cog, pn_dab) ) { + return u3_nul; + } + else { + u3_noun pro; + + axe = u3qc_peg(axe, 3); + pro = _look_in(cog, r_dab, axe); + u3z(axe); + return pro; + } + } + } + else if ( (u3_nul == r_dab) ) { + if ( (c3y == u3du(qn_dab)) && + (c3y == u3r_sing(cog, pn_dab)) ) { + return u3nt(u3_nul, + u3qc_peg(axe, 2), + u3k(qn_dab)); + } + else { + if ( c3y == u3qc_gor(cog, pn_dab) ) { + u3_noun pro; + + axe = u3qc_peg(axe, 3); + pro = _look_in(cog, l_dab, axe); + u3z(axe); + return pro; + } + else { + return u3_nul; + } + } + } + else { + if ( (c3y == u3du(qn_dab)) && + (c3y == u3r_sing(cog, pn_dab)) ) { + return u3nt(u3_nul, + u3qc_peg(axe, 2), + u3k(qn_dab)); + } + else { + if ( c3y == u3qc_gor(cog, pn_dab) ) { + u3_noun pro; + + axe = u3qc_peg(axe, 6); + pro = _look_in(cog, l_dab, axe); + u3z(axe); + return pro; + } + else { + u3_noun pro; + + axe = u3qc_peg(axe, 7); + pro = _look_in(cog, r_dab, axe); + u3z(axe); + return pro; + } + } + } + } + } + } + + + + + u3_noun + u3qf_look(u3_noun cog, + u3_noun dab) + { + return _look_in(cog, dab, 1); + } + u3_noun + u3wf_look(u3_noun cor) + { + u3_noun cog, dab; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &cog, u3x_sam_3, &dab, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_look(cog, dab); + } + } diff --git a/vere/pkg/noun/jets/f/loot.c b/vere/pkg/noun/jets/f/loot.c new file mode 100644 index 0000000..d1a7bef --- /dev/null +++ b/vere/pkg/noun/jets/f/loot.c @@ -0,0 +1,133 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + + +/* internals +*/ + static u3_noun + _loot_in(u3_noun cog, + u3_noun dom, + u3_atom axe) + { + if ( u3_nul == dom ) { + return u3_nul; + } + else { + u3_noun n_dom, l_dom, r_dom; + + u3r_trel(dom, &n_dom, &l_dom, &r_dom); + if ( c3n == u3du(n_dom) ) { + return u3m_bail(c3__fail); + } + else { + u3_noun qqn_dom = u3t(u3t(n_dom)); + u3_noun yep = u3qf_look(cog, qqn_dom); + + if ( (u3_nul == l_dom) && (u3_nul == r_dom) ) { + if ( u3_nul == yep ) { + return u3_nul; + } else { + u3_noun u_yep = u3t(yep); + u3_noun pro; + + pro = u3nt(u3_nul, u3qc_peg(axe, u3h(u_yep)), u3k(u3t(u_yep))); + u3z(yep); + return pro; + } + } + else if ( (u3_nul == l_dom) ) { + if ( u3_nul == yep ) { + u3_noun nax = u3qc_peg(axe, 3); + u3_noun pro; + + pro = _loot_in(cog, r_dom, nax); + u3z(nax); + return pro; + } + else { + u3_noun u_yep = u3t(yep); + u3_noun nax = u3qc_peg(axe, 2); + u3_noun pro; + + pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep))); + u3z(nax); + u3z(yep); + return pro; + } + } + else if ( (u3_nul == r_dom) ) { + if ( u3_nul == yep ) { + u3_noun nax = u3qc_peg(axe, 3); + u3_noun pro; + + pro = _loot_in(cog, l_dom, nax); + u3z(nax); + return pro; + } + else { + u3_noun u_yep = u3t(yep); + u3_noun nax = u3qc_peg(axe, 2); + u3_noun pro; + + pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep))); + u3z(nax); + u3z(yep); + return pro; + } + } + else { + if ( u3_nul == yep ) { + u3_noun nax = u3qc_peg(axe, 6); + u3_noun pey; + + pey = _loot_in(cog, l_dom, nax); + u3z(nax); + + if ( u3_nul != pey ) { + return pey; + } + else { + u3_noun nax = u3qc_peg(axe, 7); + u3_noun pro; + + pro = _loot_in(cog, r_dom, nax); + u3z(nax); + return pro; + } + } + else { + u3_noun u_yep = u3t(yep); + u3_noun nax = u3qc_peg(axe, 2); + u3_noun pro; + + pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep))); + u3z(nax); + u3z(yep); + return pro; + } + } + } + } + } + + u3_noun + u3qf_loot(u3_noun cog, + u3_noun dom) + { + return _loot_in(cog, dom, 1); + } + u3_noun + u3wf_loot(u3_noun cor) + { + u3_noun cog, dom; + + if ( c3n == u3r_mean(cor, u3x_sam_2, &cog, u3x_sam_3, &dom, 0) ) { + return u3m_bail(c3__fail); + } else { + return u3qf_loot(cog, dom); + } + } diff --git a/vere/pkg/noun/jets/f/ut_crop.c b/vere/pkg/noun/jets/f/ut_crop.c new file mode 100644 index 0000000..189564d --- /dev/null +++ b/vere/pkg/noun/jets/f/ut_crop.c @@ -0,0 +1,34 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3wfu_crop(u3_noun cor) +{ + u3_noun bat, sut, ref, van; + + if ( (c3n == u3r_mean(cor, u3x_sam, &ref, u3x_con, &van, 0)) + || (u3_none == (bat = u3r_at(u3x_bat, van))) + || (u3_none == (sut = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } + else { + u3_weak vet = u3r_at(u3qfu_van_vet, van); + c3_m fun_m = 141 + c3__crop + ((!!vet) << 8); + u3_noun key = u3z_key_3(fun_m, sut, ref, bat); + u3_weak pro = u3z_find(u3z_memo_toss, key); + + if ( u3_none != pro ) { + u3z(key); + return pro; + } + else { + pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); + return u3z_save(u3z_memo_toss, key, pro); + } + } +} diff --git a/vere/pkg/noun/jets/f/ut_fish.c b/vere/pkg/noun/jets/f/ut_fish.c new file mode 100644 index 0000000..e8acbd4 --- /dev/null +++ b/vere/pkg/noun/jets/f/ut_fish.c @@ -0,0 +1,35 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3wfu_fish(u3_noun cor) +{ + u3_noun bat, sut, axe, van; + + if ( (c3n == u3r_mean(cor, u3x_sam, &axe, u3x_con, &van, 0)) + || (c3n == u3ud(axe)) + || (u3_none == (bat = u3r_at(u3x_bat, van))) + || (u3_none == (sut = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } + else { + u3_weak vet = u3r_at(u3qfu_van_vet, van); + c3_m fun_m = 141 + c3__fish + ((!!vet) << 8); + u3_noun key = u3z_key_3(fun_m, sut, axe, bat); + u3_weak pro = u3z_find(u3z_memo_toss, key); + + if ( u3_none != pro ) { + u3z(key); + return pro; + } + else { + pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); + return u3z_save(u3z_memo_toss, key, pro); + } + } +} diff --git a/vere/pkg/noun/jets/f/ut_fuse.c b/vere/pkg/noun/jets/f/ut_fuse.c new file mode 100644 index 0000000..8e4e1a6 --- /dev/null +++ b/vere/pkg/noun/jets/f/ut_fuse.c @@ -0,0 +1,34 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3wfu_fuse(u3_noun cor) +{ + u3_noun bat, sut, ref, van; + + if ( (c3n == u3r_mean(cor, u3x_sam, &ref, u3x_con, &van, 0)) + || (u3_none == (bat = u3r_at(u3x_bat, van))) + || (u3_none == (sut = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } + else { + u3_weak vet = u3r_at(u3qfu_van_vet, van); + c3_m fun_m = 141 + c3__fuse + ((!!vet) << 8); + u3_noun key = u3z_key_3(fun_m, sut, ref, bat); + u3_weak pro = u3z_find(u3z_memo_toss, key); + + if ( u3_none != pro ) { + u3z(key); + return pro; + } + else { + pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); + return u3z_save(u3z_memo_toss, key, pro); + } + } +} diff --git a/vere/pkg/noun/jets/f/ut_mint.c b/vere/pkg/noun/jets/f/ut_mint.c new file mode 100644 index 0000000..618e729 --- /dev/null +++ b/vere/pkg/noun/jets/f/ut_mint.c @@ -0,0 +1,36 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3wfu_mint(u3_noun cor) +{ + u3_noun bat, sut, gol, gen, van; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &gol, + u3x_sam_3, &gen, + u3x_con, &van, 0)) + || (u3_none == (bat = u3r_at(u3x_bat, van))) + || (u3_none == (sut = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } + else { + c3_m fun_m = 141 + c3__mint; + u3_noun vet = u3r_at(u3qfu_van_vet, van); + u3_noun key = u3z_key_5(fun_m, vet, sut, gol, gen, bat); + u3_weak pro = u3z_find(u3z_memo_toss, key); + + if ( u3_none != pro ) { + u3z(key); + return pro; + } + else { + pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); + return u3z_save(u3z_memo_toss, key, pro); + } + } +} diff --git a/vere/pkg/noun/jets/f/ut_mull.c b/vere/pkg/noun/jets/f/ut_mull.c new file mode 100644 index 0000000..767ab3c --- /dev/null +++ b/vere/pkg/noun/jets/f/ut_mull.c @@ -0,0 +1,37 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3wfu_mull(u3_noun cor) +{ + u3_noun bat, sut, gol, dox, gen, van; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &gol, + u3x_sam_6, &dox, + u3x_sam_7, &gen, + u3x_con, &van, 0)) + || (u3_none == (bat = u3r_at(u3x_bat, van))) + || (u3_none == (sut = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } + else { + u3_weak vet = u3r_at(u3qfu_van_vet, van); + c3_m fun_m = 141 + c3__mull + ((!!vet) << 8); + u3_noun key = u3z_key_5(fun_m, sut, gol, dox, gen, bat); + u3_weak pro = u3z_find(u3z_memo_toss, key); + + if ( u3_none != pro ) { + u3z(key); + return pro; + } + else { + pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); + return u3z_save(u3z_memo_toss, key, pro); + } + } +} diff --git a/vere/pkg/noun/jets/f/ut_nest.c b/vere/pkg/noun/jets/f/ut_nest.c new file mode 100644 index 0000000..9bc53bf --- /dev/null +++ b/vere/pkg/noun/jets/f/ut_nest.c @@ -0,0 +1,50 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3wfu_nest_dext(u3_noun dext_core) +{ + u3_noun nest_in_core, nest_core; + u3_noun bat, sut, ref, van, seg, reg, gil; + + if ( (u3_none == (nest_in_core = u3r_at(3, dext_core))) + || (c3n == u3r_mean(nest_in_core, u3x_sam_2, &seg, + u3x_sam_6, ®, + u3x_sam_7, &gil, + u3x_con, &nest_core, 0)) + || (c3n == u3r_mean(nest_core, u3x_sam_3, &ref, + u3x_con, &van, 0)) + || (u3_none == (bat = u3r_at(u3x_bat, van))) + || (u3_none == (sut = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } + else { + u3_weak vet = u3r_at(u3qfu_van_vet, van); + c3_m fun_m = 141 + c3__dext + ((!!vet) << 8); + u3_noun key = u3z_key_3(fun_m, sut, ref, bat); + u3_weak pro = u3z_find(u3z_memo_toss, key); + + if ( u3_none != pro ) { + u3z(key); + return pro; + } + else { + pro = u3n_nock_on(u3k(dext_core), u3k(u3x_at(u3x_bat, dext_core))); + + if ( ((c3y == pro) && (u3_nul == reg)) || + ((c3n == pro) && (u3_nul == seg)) ) + { + return u3z_save(u3z_memo_toss, key, pro); + } + else { + u3z(key); + return pro; + } + } + } +} diff --git a/vere/pkg/noun/jets/f/ut_redo.c b/vere/pkg/noun/jets/f/ut_redo.c new file mode 100644 index 0000000..43fb06c --- /dev/null +++ b/vere/pkg/noun/jets/f/ut_redo.c @@ -0,0 +1,34 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3wfu_redo(u3_noun cor) +{ + u3_noun bat, sut, ref, van; + + if ( (c3n == u3r_mean(cor, u3x_sam, &ref, u3x_con, &van, 0)) + || (u3_none == (bat = u3r_at(u3x_bat, van))) + || (u3_none == (sut = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } + else { + u3_weak vet = u3r_at(u3qfu_van_vet, van); + c3_m fun_m = 141 + c3__redo + ((!!vet) << 8); + u3_noun key = u3z_key_3(fun_m, sut, ref, bat); + u3_weak pro = u3z_find(u3z_memo_toss, key); + + if ( u3_none != pro ) { + u3z(key); + return pro; + } + else { + pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); + return u3z_save(u3z_memo_toss, key, pro); + } + } +} diff --git a/vere/pkg/noun/jets/f/ut_rest.c b/vere/pkg/noun/jets/f/ut_rest.c new file mode 100644 index 0000000..87ff60f --- /dev/null +++ b/vere/pkg/noun/jets/f/ut_rest.c @@ -0,0 +1,34 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_noun +u3wfu_rest(u3_noun cor) +{ + u3_noun bat, sut, leg, van; + + if ( (c3n == u3r_mean(cor, u3x_sam, &leg, u3x_con, &van, 0)) + || (u3_none == (bat = u3r_at(u3x_bat, van))) + || (u3_none == (sut = u3r_at(u3x_sam, van))) ) + { + return u3m_bail(c3__fail); + } + else { + u3_weak vet = u3r_at(u3qfu_van_vet, van); + c3_m fun_m = 141 + c3__rest + ((!!vet) << 8); + u3_noun key = u3z_key_3(fun_m, sut, leg, bat); + u3_weak pro = u3z_find(u3z_memo_toss, key); + + if ( u3_none != pro ) { + u3z(key); + return pro; + } + else { + pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); + return u3z_save(u3z_memo_toss, key, pro); + } + } +} diff --git a/vere/pkg/noun/jets/g/plot.c b/vere/pkg/noun/jets/g/plot.c new file mode 100644 index 0000000..18c8ab0 --- /dev/null +++ b/vere/pkg/noun/jets/g/plot.c @@ -0,0 +1,364 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +// XX optimize +// +static c3_w +_met_plat_m(c3_g a_g, c3_w fum_w, c3_w met_w, u3_atom vat) +{ + c3_w len_w, wor_w; + + { + u3i_slab sab_u; + u3i_slab_init(&sab_u, a_g, met_w); + u3r_chop(a_g, fum_w, met_w, 0, sab_u.buf_w, vat); + + len_w = sab_u.len_w; + + while ( len_w && !sab_u.buf_w[len_w - 1] ) { + len_w--; + } + + wor_w = !len_w ? 0 : sab_u.buf_w[len_w - 1]; + + u3i_slab_free(&sab_u); + } + + + if ( !len_w ) { + return 0; + } + + { + c3_w gal_w = len_w - 1; + c3_w daz_w = wor_w; + c3_y a_y = a_g; + + // inlined from u3r_met + if (a_y < 5) { + c3_y max_y = (1 << a_y) - 1; + c3_y gow_y = 5 - a_y; + + if (gal_w > ((UINT32_MAX - (32 + max_y)) >> gow_y)) { + return u3m_bail(c3__fail); + } + + return (gal_w << gow_y) + + ((c3_bits_word(daz_w) + max_y) + >> a_y); + } + + { + c3_y gow_y = (a_y - 5); + return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y; + } + } +} + +static c3_w +_met_list(c3_g a_g, + c3_w sep_w, + u3_noun b_p); + +static c3_w +_met_pair(c3_g* las_g, + c3_w sep_w, + u3_noun a_p, + u3_noun b_p, + c3_g* new_g) +{ + c3_g res_g, a_g; + + while ( c3y == u3a_is_cell(a_p) ) { + sep_w = _met_pair(las_g, sep_w, u3h(a_p), u3t(a_p), &res_g); + las_g = &res_g; + a_p = u3h(b_p); + b_p = u3t(b_p); + } + + if ( !_(u3a_is_cat(a_p)) || (a_p >= 32) ) { + return u3m_bail(c3__fail); + } + + a_g = (c3_g)a_p; + + if ( las_g && (a_g != *las_g) ) { + sep_w = u3qc_rig_s(*las_g, sep_w, a_g); // XX overflow + } + + *new_g = a_g; + return _met_list(a_g, sep_w, b_p); +} + +static c3_w +_met_list(c3_g a_g, + c3_w sep_w, + u3_noun b_p) +{ + if ( u3_nul != b_p ) { + c3_w met_w; + u3_noun i, t = b_p; + + do { + u3x_cell(t, &i, &t); + + // ?@ i.b.p + if ( c3y == u3a_is_atom(i) ) { + met_w = u3r_met(a_g, i); + sep_w += met_w; // XX overflow + } + else { + u3_noun i_i, t_i; + u3x_cell(i, &i_i, &t_i); + + // ?=(@ -.i.b.p) + if ( c3y == u3a_is_atom(i_i) ) { + if ( !_(u3a_is_cat(i_i)) ) { + return u3m_bail(c3__fail); + } + + met_w = (c3_w)i_i; + sep_w += met_w; // XX overflow + } + else { + u3_noun l, r; + c3_o cel_o = u3r_cell(i_i, &l, &r); + + // ?=([%c ~] -.i.b.p) + if ( (c3y == cel_o) && ('c' == l) && (u3_nul == r) ) { + u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i))); + u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i))); + u3_atom q_t_i = u3x_atom(u3t(t_i)); + + if ( !_(u3a_is_cat(p_p_t_i)) + || !_(u3a_is_cat(q_p_t_i)) + || !_(u3a_is_cat(q_t_i)) ) + { + return u3m_bail(c3__fail); + } + + met_w = (c3_w)q_p_t_i; + sep_w += met_w; // XX overflow + } + // ?=([%m ~] -.i.b.p) + else if ( (c3y == cel_o) && ('m' == l) && (u3_nul == r) ) { + u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i))); + u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i))); + u3_atom q_t_i = u3x_atom(u3t(t_i)); + + if ( !_(u3a_is_cat(p_p_t_i)) + || !_(u3a_is_cat(q_p_t_i)) + || !_(u3a_is_cat(q_t_i)) ) + { + return u3m_bail(c3__fail); + } + + met_w = _met_plat_m(a_g, (c3_w)p_p_t_i, (c3_w)q_p_t_i, q_t_i); + sep_w += met_w; // XX overflow + } + // ?=([%s ~] -.i.b.p) (assumed) + else { + c3_g new_g; + u3x_cell(t_i, &l, &r); + + sep_w = _met_pair(&a_g, sep_w, l, r, &new_g); + + if ( new_g != a_g ) { + sep_w = u3qc_rig_s(new_g, sep_w, a_g); // XX overflow + } + } + } + } + } + while ( u3_nul != t ); + } + + return sep_w; +} + +static c3_w +_fax_list(u3i_slab* sab_u, + c3_g a_g, + c3_w sep_w, + u3_noun b_p); + +static c3_w +_fax_pair(u3i_slab* sab_u, + c3_g* las_g, + c3_w sep_w, + u3_noun a_p, + u3_noun b_p, + c3_g* new_g) +{ + c3_g res_g, a_g; + + while ( c3y == u3a_is_cell(a_p) ) { + sep_w = _fax_pair(sab_u, las_g, sep_w, u3h(a_p), u3t(a_p), &res_g); + las_g = &res_g; + a_p = u3h(b_p); + b_p = u3t(b_p); + } + + if ( !_(u3a_is_cat(a_p)) || (a_p >= 32) ) { + return u3m_bail(c3__fail); + } + + a_g = (c3_g)a_p; + + if ( las_g && (a_g != *las_g) ) { + sep_w = u3qc_rig_s(*las_g, sep_w, a_g); // XX overflow + } + + *new_g = a_g; + return _fax_list(sab_u, a_g, sep_w, b_p); +} + +static c3_w +_fax_list(u3i_slab* sab_u, + c3_g a_g, + c3_w sep_w, + u3_noun b_p) +{ + if ( u3_nul != b_p ) { + c3_w met_w; + u3_noun i, t = b_p; + + do { + u3x_cell(t, &i, &t); + + // ?@ i.b.p + if ( c3y == u3a_is_atom(i) ) { + met_w = u3r_met(a_g, i); + + u3r_chop(a_g, 0, met_w, sep_w, sab_u->buf_w, i); + + sep_w += met_w; // XX overflow + } + else { + u3_noun i_i, t_i; + u3x_cell(i, &i_i, &t_i); + + // ?=(@ -.i.b.p) + if ( c3y == u3a_is_atom(i_i) ) { + if ( !_(u3a_is_cat(i_i)) ) { + return u3m_bail(c3__fail); + } + + met_w = (c3_w)i_i; + + u3r_chop(a_g, 0, met_w, sep_w, sab_u->buf_w, u3x_atom(t_i)); + + sep_w += met_w; // XX overflow + } + else { + u3_noun l, r; + c3_o cel_o = u3r_cell(i_i, &l, &r); + + // ?=([%c ~] -.i.b.p) + if ( (c3y == cel_o) && ('c' == l) && (u3_nul == r) ) { + u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i))); + u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i))); + u3_atom q_t_i = u3x_atom(u3t(t_i)); + + if ( !_(u3a_is_cat(p_p_t_i)) + || !_(u3a_is_cat(q_p_t_i)) + || !_(u3a_is_cat(q_t_i)) ) + { + return u3m_bail(c3__fail); + } + + met_w = (c3_w)q_p_t_i; + + u3r_chop(a_g, (c3_w)p_p_t_i, met_w, sep_w, sab_u->buf_w, q_t_i); + + sep_w += met_w; // XX overflow + } + // ?=([%m ~] -.i.b.p) + else if ( (c3y == cel_o) && ('m' == l) && (u3_nul == r) ) { + u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i))); + u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i))); + u3_atom q_t_i = u3x_atom(u3t(t_i)); + + if ( !_(u3a_is_cat(p_p_t_i)) + || !_(u3a_is_cat(q_p_t_i)) + || !_(u3a_is_cat(q_t_i)) ) + { + return u3m_bail(c3__fail); + } + + met_w = _met_plat_m(a_g, (c3_w)p_p_t_i, (c3_w)q_p_t_i, q_t_i); + + u3r_chop(a_g, (c3_w)p_p_t_i, met_w, sep_w, sab_u->buf_w, q_t_i); + + sep_w += met_w; // XX overflow + } + // ?=([%s ~] -.i.b.p) (assumed) + else { + c3_g new_g; + u3x_cell(t_i, &l, &r); + + sep_w = _fax_pair(sab_u, &a_g, sep_w, l, r, &new_g); + + if ( new_g != a_g ) { + sep_w = u3qc_rig_s(new_g, sep_w, a_g); // XX overflow + } + } + } + } + } + while ( u3_nul != t ); + } + + return sep_w; +} + +u3_noun +u3qg_plot_met(u3_noun a_p, u3_noun b_p) +{ + c3_g out_g; + c3_w sep_w = _met_pair(NULL, 0, a_p, b_p, &out_g); + + return u3nc(out_g, u3i_word(sep_w)); +} + +u3_noun +u3wg_plot_met(u3_noun cor) +{ + u3_noun a_p, b_p; + { + u3_noun sam = u3h(u3t(cor)); + a_p = u3h(sam); + b_p = u3t(sam); + } + return u3qg_plot_met(a_p, b_p); +} + +u3_noun +u3qg_plot_fax(u3_noun a_p, u3_noun b_p) +{ + c3_g out_g; + c3_w sep_w = _met_pair(NULL, 0, a_p, b_p, &out_g); + u3i_slab sab_u; + + u3i_slab_init(&sab_u, out_g, sep_w); + + _fax_pair(&sab_u, NULL, 0, a_p, b_p, &out_g); + + return u3nt(u3i_slab_mint(&sab_u), out_g, u3i_word(sep_w)); +} + +u3_noun +u3wg_plot_fax(u3_noun cor) +{ + u3_noun a_p, b_p; + { + u3_noun sam = u3h(u3t(cor)); + a_p = u3h(sam); + b_p = u3t(sam); + } + return u3qg_plot_fax(a_p, b_p); +} diff --git a/vere/pkg/noun/jets/i/lagoon.c b/vere/pkg/noun/jets/i/lagoon.c new file mode 100644 index 0000000..db7088b --- /dev/null +++ b/vere/pkg/noun/jets/i/lagoon.c @@ -0,0 +1,3315 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "c3/motes.h" + +#include "noun.h" +#include "softfloat.h" +#include "softblas.h" + +#include <math.h> // for pow() +#include <stdio.h> + +#define f16_ceil(a) f16_roundToInt( a, softfloat_round_max, false ) +#define f32_ceil(a) f32_roundToInt( a, softfloat_round_max, false ) +#define f64_ceil(a) f64_roundToInt( a, softfloat_round_max, false ) +#define f128M_ceil(a, b) f128M_roundToInt( a, softfloat_round_max, false, b ) + + union half { + float16_t h; + c3_w c; + }; + + union sing { + float32_t s; + c3_w c; + }; + + union doub { + float64_t d; + c3_d c; + }; + + union quad { + float128_t q; + c3_d c[2]; + }; + + // $?(%n %u %d %z %a) + static inline void + _set_rounding(c3_w a) + { + // We could use SoftBLAS set_rounding() to set the SoftFloat + // mode as well, but it's more explicit to do it here since + // we may use SoftFloat in any given Lagoon jet and we want + // you, dear developer, to see it set here. + switch ( a ) + { + default: + u3m_bail(c3__fail); + break; + // %n - near + case c3__n: + softfloat_roundingMode = softfloat_round_near_even; + softblas_roundingMode = 'n'; + break; + // %z - zero + case c3__z: + softfloat_roundingMode = softfloat_round_minMag; + softblas_roundingMode = 'z'; + break; + // %u - up + case c3__u: + softfloat_roundingMode = softfloat_round_max; + softblas_roundingMode = 'u'; + break; + // %d - down + case c3__d: + softfloat_roundingMode = softfloat_round_min; + softblas_roundingMode = 'd'; + break; + // %a - away + case c3__a: + softfloat_roundingMode = softfloat_round_near_maxMag; + softblas_roundingMode = 'a'; + break; + } + } + +/* length of shape = x * y * z * w * ... +*/ + static inline c3_d _get_length(u3_noun shape) + { + c3_d len = 1; + while (u3_nul != shape) { + len = len * u3x_atom(u3h(shape)); + shape = u3t(shape); + } + return len; + } + +/* get dims from shape as array [x y z w ...] +*/ + static inline c3_d* _get_dims(u3_noun shape) + { + u3_atom len = u3qb_lent(shape); + c3_d len_d = u3r_chub(0, len); + c3_d* dims = (c3_d*)u3a_malloc(len_d*sizeof(c3_d)); + for (c3_d i = 0; i < len_d; i++) { + dims[i] = u3r_chub(0, u3x_atom(u3h(shape))); + shape = u3t(shape); + } + u3z(len); + return dims; + } + +/* check consistency of array shape and bloq size + |= =ray + ^- ? + .= (roll shape.meta.ray ^mul) + (dec (met bloq.meta.ray data.ray)) +*/ + static inline c3_o _check(u3_noun ray) + { + // Calculate expected size. + u3_atom shp = u3h(u3h(ray)); // (reported) shape of ray, +4 + u3_atom blq = u3h(u3t(u3h(ray))); // block size of ray, +10 + u3_atom sin = _get_length(shp); // calculated length of ray + + // Calculate actual size. + u3_atom len = u3r_met(blq, u3t(ray)); // length of ray + u3_atom dex = u3qa_dec(len); // decrement length b/c of pinned 1 + + return __(sin == dex); + } + +/* add - axpy = 1*x+y +*/ + u3_noun + u3qi_la_add_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq + ) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + haxpy(len_x, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1); + break; + + case 5: + saxpy(len_x, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1); + break; + + case 6: + daxpy(len_x, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1); + break; + + case 7: + qaxpy(len_x, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1); + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* sub - axpy = -1*y+x +*/ + u3_noun + u3qi_la_sub_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq + ) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + haxpy(len_x, (float16_t){SB_REAL16_NEGONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1); + break; + + case 5: + saxpy(len_x, (float32_t){SB_REAL32_NEGONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1); + break; + + case 6: + daxpy(len_x, (float64_t){SB_REAL64_NEGONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1); + break; + + case 7: + qaxpy(len_x, (float128_t){SB_REAL128L_NEGONE,SB_REAL128U_NEGONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1); + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + + +/* mul - x.*y + elementwise multiplication +*/ + u3_noun + u3qi_la_mul_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)y_bytes)[i] = f16_mul(((float16_t*)x_bytes)[i], ((float16_t*)y_bytes)[i]); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)y_bytes)[i] = f32_mul(((float32_t*)x_bytes)[i], ((float32_t*)y_bytes)[i]); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)y_bytes)[i] = f64_mul(((float64_t*)x_bytes)[i], ((float64_t*)y_bytes)[i]); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + f128M_mul(&(((float128_t*)y_bytes)[i]), &(((float128_t*)x_bytes)[i]), &(((float128_t*)y_bytes)[i])); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* div - x/y + elementwise division +*/ + u3_noun + u3qi_la_div_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)y_bytes)[i] = f16_div(((float16_t*)x_bytes)[i], ((float16_t*)y_bytes)[i]); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)y_bytes)[i] = f32_div(((float32_t*)x_bytes)[i], ((float32_t*)y_bytes)[i]); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)y_bytes)[i] = f64_div(((float64_t*)x_bytes)[i], ((float64_t*)y_bytes)[i]); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + f128M_div(&(((float128_t*)y_bytes)[i]), &(((float128_t*)x_bytes)[i]), &(((float128_t*)y_bytes)[i])); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* mod - x % y = x - r*floor(x/r) + remainder after division +*/ + u3_noun + u3qi_la_mod_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + // Perform division x/n + float16_t div_result16 = f16_div(x_val16, y_val16); + // Compute floor of the division result + c3_ds floor_result16 = f16_to_i64(div_result16, softfloat_round_minMag, false); + float16_t floor_float16 = i64_to_f16(floor_result16); + // Multiply n by floor(x/n) + float16_t mult_result16 = f16_mul(y_val16, floor_float16); + // Compute remainder: x - n * floor(x/n) + ((float16_t*)y_bytes)[i] = f16_sub(x_val16, mult_result16); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + // Perform division x/n + float32_t div_result32 = f32_div(x_val32, y_val32); + // Compute floor of the division result + c3_ds floor_result32 = f32_to_i64(div_result32, softfloat_round_minMag, false); + float32_t floor_float32 = i64_to_f32(floor_result32); + // Multiply n by floor(x/n) + float32_t mult_result32 = f32_mul(y_val32, floor_float32); + // Compute remainder: x - n * floor(x/n) + ((float32_t*)y_bytes)[i] = f32_sub(x_val32, mult_result32); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + // Perform division x/n + float64_t div_result64 = f64_div(x_val64, y_val64); + // Compute floor of the division result + c3_ds floor_result64 = f64_to_i64(div_result64, softfloat_round_minMag, false); + float64_t floor_float64 = i64_to_f64(floor_result64); + // Multiply n by floor(x/n) + float64_t mult_result64 = f64_mul(y_val64, floor_float64); + // Compute remainder: x - n * floor(x/n) + ((float64_t*)y_bytes)[i] = f64_sub(x_val64, mult_result64); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + // Perform division x/n + float128_t div_result128; + f128M_div((float128_t*)&x_val128, (float128_t*)&y_val128, (float128_t*)&div_result128); + // Compute floor of the division result + c3_ds floor_result128 = f128M_to_i64(&div_result128, softfloat_round_minMag, false); + float128_t floor_float128; + i64_to_f128M(floor_result128, &floor_float128); + // Multiply n by floor(x/n) + float128_t mult_result128; + f128M_mul(((float128_t*)&y_val128), ((float128_t*)&floor_float128), ((float128_t*)&mult_result128)); + // Compute remainder: x - n * floor(x/n) + f128M_sub(((float128_t*)&x_val128), ((float128_t*)&mult_result128), &(((float128_t*)y_bytes)[i])); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* cumsum - x[0] + x[1] + ... x[n] +*/ + u3_noun + u3qi_la_cumsum_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // y_bytes is the data array (w/ leading 0x1, skipped by for range) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + u3_noun r_data; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t sum16[2]; + sum16[0] = (float16_t){SB_REAL16_ZERO}; + for (c3_d i = len_x; i > 0; i--) { + sum16[0] = f16_add(sum16[0], ((float16_t*)x_bytes)[i-1]); + } + sum16[1].v = 0x1; + r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)sum16); + break;} + + case 5: { + float32_t sum32[2]; + sum32[0] = (float32_t){SB_REAL32_ZERO}; + for (c3_d i = len_x; i > 0; i--) { + sum32[0] = f32_add(sum32[0], ((float32_t*)x_bytes)[i-1]); + } + sum32[1].v = 0x1; + r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)sum32); + break;} + + case 6: { + float64_t sum64[2]; + sum64[0] = (float64_t){SB_REAL64_ZERO}; + for (c3_d i = len_x; i > 0; i--) { + sum64[0] = f64_add(sum64[0], ((float64_t*)x_bytes)[i-1]); + } + sum64[1].v = 0x1; + r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)sum64); + break;} + + case 7: { + float128_t sum128[2]; + sum128[0] = (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + for (c3_d i = len_x; i > 0; i--) { + f128M_add(&(sum128[0]), &(((float128_t*)x_bytes)[i-1]), &(sum128[0])); + } + sum128[1] = (float128_t){0x1, 0x0}; + r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)sum128); + break;} + } + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* argmin - argmin(x) +*/ + u3_noun + u3qi_la_argmin_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1, which doesn't matter here) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + c3_w min_idx = 0; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t min_val16 = ((float16_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f16_lt(((float16_t*)x_bytes)[i], min_val16)) { + min_val16 = ((float16_t*)x_bytes)[i]; + min_idx = (len_x - i - 1); + } + } + break;} + + case 5: { + float32_t min_val32 = ((float32_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f32_lt(((float32_t*)x_bytes)[i], min_val32)) { + min_val32 = ((float32_t*)x_bytes)[i]; + min_idx = (len_x - i - 1); + } + } + break;} + + case 6: { + float64_t min_val64 = ((float64_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f64_lt(((float64_t*)x_bytes)[i], min_val64)) { + min_val64 = ((float64_t*)x_bytes)[i]; + min_idx = (len_x - i - 1); + } + } + break;} + + case 7: { + float128_t min_val128 = ((float128_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f128M_lt(&(((float128_t*)x_bytes)[i]), &min_val128)) { + min_val128 = *f128M_min(&min_val128, &((float128_t*)x_bytes)[i]); + min_idx = (len_x - i - 1); + } + } + break;} + } + + u3_noun r_data = u3i_chub(min_idx); + + return r_data; + } + +/* argmax - argmax(x) +*/ + u3_noun + u3qi_la_argmax_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1, which doesn't matter here) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + c3_w max_idx = 0; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t max_val16 = ((float16_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f16_gt(((float16_t*)x_bytes)[i], max_val16)) { + max_val16 = ((float16_t*)x_bytes)[i]; + max_idx = (len_x - i - 1); + } + } + break;} + + case 5: { + float32_t max_val32 = ((float32_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f32_gt(((float32_t*)x_bytes)[i], max_val32)) { + max_val32 = ((float32_t*)x_bytes)[i]; + max_idx = (len_x - i - 1); + } + } + break;} + + case 6: { + float64_t max_val64 = ((float64_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f64_gt(((float64_t*)x_bytes)[i], max_val64)) { + max_val64 = ((float64_t*)x_bytes)[i]; + max_idx = (len_x - i - 1); + } + } + break;} + + case 7: { + float128_t max_val128 = ((float128_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + if(f128M_gt(&(((float128_t*)x_bytes)[i]), &max_val128)) { + max_val128 = *f128M_max(&max_val128, &((float128_t*)x_bytes)[i]); + max_idx = (len_x - i - 1); + } + } + break;} + } + + u3_noun r_data = u3i_chub(max_idx); + + return r_data; + } + +/* ravel - x -> ~[x[0], x[1], ... x[n]] + entire nd-array busted out as a linear list +*/ + u3_noun + u3qi_la_ravel_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // r_data is the result noun of [data] + u3_noun r_data = u3_nul; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + r_data = u3nc(u3i_word(x_val16.v), r_data); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + r_data = u3nc(u3i_word(x_val32.v), r_data); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + r_data = u3nc(u3i_chub(x_val64.v), r_data); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + r_data = u3nc(u3i_chubs(2, (c3_d*)&(x_val128.v)), r_data); + } + break; + } + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* min - min(x,y) +*/ + u3_noun + u3qi_la_min_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by for range) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + u3_noun r_data; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t min_val16 = ((float16_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + min_val16 = f16_min(min_val16, ((float16_t*)x_bytes)[i]); + } + float16_t r16[2]; + r16[0] = min_val16; + r16[1].v = 0x1; + r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16); + break;} + + case 5: { + float32_t min_val32 = ((float32_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + min_val32 = f32_min(min_val32, ((float32_t*)x_bytes)[i]); + } + float32_t r32[2]; + r32[0] = min_val32; + r32[1].v = 0x1; + r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32); + break;} + + case 6: { + float64_t min_val64 = ((float64_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + min_val64 = f64_min(min_val64, ((float64_t*)x_bytes)[i]); + } + float64_t r64[2]; + r64[0] = min_val64; + r64[1].v = 0x1; + r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64); + break;} + + case 7: { + float128_t min_val128 = ((float128_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + min_val128 = *f128M_min(&min_val128, &((float128_t*)x_bytes)[i]); + } + float128_t r128[2]; + r128[0] = min_val128; + r128[1] = (float128_t){0x1, 0x0}; + r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128); + break;} + } + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* max - max(x,y) +*/ + u3_noun + u3qi_la_max_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by for range) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + u3_noun r_data; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t max_val16 = ((float16_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + max_val16 = f16_max(max_val16, ((float16_t*)x_bytes)[i]); + } + float16_t r16[2]; + r16[0] = max_val16; + r16[1].v = 0x1; + r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16); + break;} + + case 5: { + float32_t max_val32 = ((float32_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + max_val32 = f32_max(max_val32, ((float32_t*)x_bytes)[i]); + } + float32_t r32[2]; + r32[0] = max_val32; + r32[1].v = 0x1; + r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32); + break;} + + case 6: { + float64_t max_val64 = ((float64_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + max_val64 = f64_max(max_val64, ((float64_t*)x_bytes)[i]); + } + float64_t r64[2]; + r64[0] = max_val64; + r64[1].v = 0x1; + r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64); + break;} + + case 7: { + float128_t max_val128 = ((float128_t*)x_bytes)[0]; + for (c3_d i = 0; i < len_x; i++) { + max_val128 = *f128M_max(&max_val128, &((float128_t*)x_bytes)[i]); + } + float128_t r128[2]; + r128[0] = max_val128; + r128[1] = (float128_t){0x1, 0x0}; + r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128); + break;} + } + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* abs - |x| +*/ + u3_noun + u3qi_la_abs_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by for range) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)x_bytes)[i] = f16_abs(((float16_t*)x_bytes)[i]); + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)x_bytes)[i] = f32_abs(((float32_t*)x_bytes)[i]); + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)x_bytes)[i] = f64_abs(((float64_t*)x_bytes)[i]); + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + ((float128_t*)x_bytes)[i] = f128_abs(((float128_t*)x_bytes)[i]); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* gth - x > y +*/ + u3_noun + u3qi_la_gth_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + ((float16_t*)y_bytes)[i] = f16_gt(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO}; + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + ((float32_t*)y_bytes)[i] = f32_gt(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO}; + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + ((float64_t*)y_bytes)[i] = f64_gt(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO}; + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + ((float128_t*)y_bytes)[i] = f128M_gt(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* gte - x > y +*/ + u3_noun + u3qi_la_gte_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + ((float16_t*)y_bytes)[i] = f16_ge(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO}; + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + ((float32_t*)y_bytes)[i] = f32_ge(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO}; + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + ((float64_t*)y_bytes)[i] = f64_ge(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO}; + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + ((float128_t*)y_bytes)[i] = f128M_ge(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* lth - x > y +*/ + u3_noun + u3qi_la_lth_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + ((float16_t*)y_bytes)[i] = f16_lt(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO}; + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + ((float32_t*)y_bytes)[i] = f32_lt(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO}; + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + ((float64_t*)y_bytes)[i] = f64_lt(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO}; + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + ((float128_t*)y_bytes)[i] = f128M_lt(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* lte - x > y +*/ + u3_noun + u3qi_la_lte_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + float16_t y_val16 = ((float16_t*)y_bytes)[i]; + ((float16_t*)y_bytes)[i] = f16_le(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO}; + } + break; + + case 5: + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + float32_t y_val32 = ((float32_t*)y_bytes)[i]; + ((float32_t*)y_bytes)[i] = f32_le(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO}; + } + break; + + case 6: + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + float64_t y_val64 = ((float64_t*)y_bytes)[i]; + ((float64_t*)y_bytes)[i] = f64_le(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO}; + } + break; + + case 7: + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + float128_t y_val128 = ((float128_t*)y_bytes)[i]; + ((float128_t*)y_bytes)[i] = f128M_le(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO}; + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* adds - axpy = 1*x+[n] +*/ + u3_noun + u3qi_la_adds_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + + float16_t n16; + float32_t n32; + float64_t n64; + float128_t n128; + + // Switch on the block size. We assume that n fits in the target block size; Hoon typecheck should prevent. + switch (u3x_atom(bloq)) { + case 4: + u3r_bytes(0, 2, (c3_y*)&(n16.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)y_bytes)[i] = n16; + } + haxpy(len_x, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1); + break; + + case 5: + u3r_bytes(0, 4, (c3_y*)&(n32.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)y_bytes)[i] = n32; + } + saxpy(len_x, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1); + break; + + case 6: + u3r_bytes(0, 8, (c3_y*)&(n64.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)y_bytes)[i] = n64; + } + daxpy(len_x, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1); + break; + + case 7: + u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float128_t*)y_bytes)[i] = (float128_t){n128.v[0], n128.v[1]}; + } + qaxpy(len_x, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1); + break; + } + + // r_data is the result noun of [data] + y_bytes[syz_x] = 0x1; // pin head + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* subs - axpy = -1*[n]+x +*/ + u3_noun + u3qi_la_subs_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/o leading 0x1) + c3_y* y_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + + float16_t n16; + float32_t n32; + float64_t n64; + float128_t n128; + + // Switch on the block size. We assume that n fits in the target block size; Hoon typecheck should prevent. + switch (u3x_atom(bloq)) { + case 4: + u3r_bytes(0, 2, (c3_y*)&(n16.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float16_t*)y_bytes)[i] = n16; + } + haxpy(len_x, (float16_t){SB_REAL16_NEGONE}, (float16_t*)y_bytes, 1, (float16_t*)x_bytes, 1); + break; + + case 5: + u3r_bytes(0, 4, (c3_y*)&(n32.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float32_t*)y_bytes)[i] = n32; + } + saxpy(len_x, (float32_t){SB_REAL32_NEGONE}, (float32_t*)y_bytes, 1, (float32_t*)x_bytes, 1); + break; + + case 6: + u3r_bytes(0, 8, (c3_y*)&(n64.v), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float64_t*)y_bytes)[i] = n64; + } + daxpy(len_x, (float64_t){SB_REAL64_NEGONE}, (float64_t*)y_bytes, 1, (float64_t*)x_bytes, 1); + break; + + case 7: + u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n); + // set y to [n] + for (c3_d i = 0; i < len_x; i++) { + ((float128_t*)y_bytes)[i] = (float128_t){n128.v[0], n128.v[1]}; + } + qaxpy(len_x, (float128_t){SB_REAL128L_NEGONE,SB_REAL128U_NEGONE}, (float128_t*)y_bytes, 1, (float128_t*)x_bytes, 1); + break; + } + + // r_data is the result noun of [data] + x_bytes[syz_x] = 0x1; // pin head + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* muls - ?scal n * x + elementwise multiplication +*/ + u3_noun + u3qi_la_muls_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + x_bytes[syz_x] = 0x1; // pin head + + float16_t n16; + float32_t n32; + float64_t n64; + float128_t n128; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + u3r_bytes(0, 2, (c3_y*)&(n16.v), n); + hscal(len_x, n16, (float16_t*)x_bytes, 1); + break; + + case 5: + u3r_bytes(0, 4, (c3_y*)&(n32.v), n); + sscal(len_x, n32, (float32_t*)x_bytes, 1); + break; + + case 6: + u3r_bytes(0, 8, (c3_y*)&(n64.v), n); + dscal(len_x, n64, (float64_t*)x_bytes, 1); + break; + + case 7: + u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n); + qscal(len_x, n128, (float128_t*)x_bytes, 1); + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* divs - ?scal 1/n * x + elementwise division +*/ + u3_noun + u3qi_la_divs_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + x_bytes[syz_x] = 0x1; // pin head + + float16_t in16; + float32_t in32; + float64_t in64; + float128_t in128; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + // XX note that in16 is doing double duty here + u3r_bytes(0, 2, (c3_y*)&(in16.v), n); + in16 = f16_div((float16_t){SB_REAL16_ONE}, in16); + hscal(len_x, in16, (float16_t*)x_bytes, 1); + break; + + case 5: + // XX note that in32 is doing double duty here + u3r_bytes(0, 4, (c3_y*)&(in32.v), n); + in32 = f32_div((float32_t){SB_REAL32_ONE}, in32); + sscal(len_x, in32, (float32_t*)x_bytes, 1); + break; + + case 6: + // XX note that in64 is doing double duty here + u3r_bytes(0, 8, (c3_y*)&(in64.v), n); + in64 = f64_div((float64_t){SB_REAL64_ONE}, in64); + dscal(len_x, in64, (float64_t*)x_bytes, 1); + break; + + case 7: + // XX note that in128 is doing double duty here + u3r_bytes(0, 16, (c3_y*)&(in128.v[0]), n); + f128M_div(&((float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}), &in128, &in128); + qscal(len_x, in128, (float128_t*)x_bytes, 1); + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* mods - x % [n] = x - r*floor(x/r) + remainder after scalar division +*/ + u3_noun + u3qi_la_mods_i754(u3_noun x_data, + u3_noun n, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + // we reuse it for results for parsimony + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + + float16_t n16, in16; + float32_t n32, in32; + float64_t n64, in64; + float128_t n128, in128; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + u3r_bytes(0, 2, (c3_y*)&(n16.v), n); + in16 = f16_div((float16_t){SB_REAL16_ONE}, n16); + + for (c3_d i = 0; i < len_x; i++) { + float16_t x_val16 = ((float16_t*)x_bytes)[i]; + // Perform division x/n + float16_t div_result16 = f16_mul(in16, x_val16); + // Compute floor of the division result + c3_ds floor_result16 = f16_to_i64(div_result16, softfloat_round_minMag, false); + float16_t floor_float16 = i64_to_f16(floor_result16); + // Multiply n by floor(x/n) + float16_t mult_result16 = f16_mul(n16, floor_float16); + // Compute remainder: x - n * floor(x/n) + ((float16_t*)x_bytes)[i] = f16_sub(x_val16, mult_result16); + } + break; + + case 5: + u3r_bytes(0, 4, (c3_y*)&(n32.v), n); + in32 = f32_div((float32_t){SB_REAL32_ONE}, n32); + + for (c3_d i = 0; i < len_x; i++) { + float32_t x_val32 = ((float32_t*)x_bytes)[i]; + // Perform division x/n + float32_t div_result32 = f32_mul(in32, x_val32); + // Compute floor of the division result + c3_ds floor_result32 = f32_to_i64(div_result32, softfloat_round_minMag, false); + float32_t floor_float32 = i64_to_f32(floor_result32); + // Multiply n by floor(x/n) + float32_t mult_result32 = f32_mul(n32, floor_float32); + // Compute remainder: x - n * floor(x/n) + ((float32_t*)x_bytes)[i] = f32_sub(x_val32, mult_result32); + } + break; + + case 6: + u3r_bytes(0, 8, (c3_y*)&(n64.v), n); + in64 = f64_div((float64_t){SB_REAL64_ONE}, n64); + + for (c3_d i = 0; i < len_x; i++) { + float64_t x_val64 = ((float64_t*)x_bytes)[i]; + // Perform division x/n + float64_t div_result64 = f64_mul(in64, x_val64); + // Compute floor of the division result + c3_ds floor_result64 = f64_to_i64(div_result64, softfloat_round_minMag, false); + float64_t floor_float64 = i64_to_f64(floor_result64); + // Multiply n by floor(x/n) + float64_t mult_result64 = f64_mul(n64, floor_float64); + // Compute remainder: x - n * floor(x/n) + ((float64_t*)x_bytes)[i] = f64_sub(x_val64, mult_result64); + } + break; + + case 7: + u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n); + f128M_div(&((float128_t){SB_REAL128L_ONE,SB_REAL128U_ZERO}), &n128, &in128); + + for (c3_d i = 0; i < len_x; i++) { + float128_t x_val128 = ((float128_t*)x_bytes)[i]; + // Perform division x/n + float128_t div_result128; + f128M_mul((float128_t*)&in128, (float128_t*)&x_val128, (float128_t*)&div_result128); + // Compute floor of the division result + c3_ds floor_result128 = f128M_to_i64(&div_result128, softfloat_round_minMag, false); + float128_t floor_float128; + i64_to_f128M(floor_result128, &floor_float128); + // Multiply n by floor(x/n) + float128_t mult_result128; + f128M_mul(((float128_t*)&n128), ((float128_t*)&floor_float128), ((float128_t*)&mult_result128)); + // Compute remainder: x - n * floor(x/n) + f128M_sub(((float128_t*)&x_val128), ((float128_t*)&mult_result128), &(((float128_t*)x_bytes)[i])); + } + break; + } + + // r_data is the result noun of [data] + u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes); + + // Clean up and return. + u3a_free(x_bytes); + + return r_data; + } + +/* dot - ?dot = x · y +*/ + u3_noun + u3qi_la_dot_i754(u3_noun x_data, + u3_noun y_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(shape); + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy) + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, y_bytes, y_data); + + u3_noun r_data; + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: { + float16_t r16[2]; + r16[0] = hdot(len_x, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1); + r16[1].v = 0x1; + r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16); + break;} + + case 5: { + float32_t r32[2]; + r32[0] = sdot(len_x, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1); + r32[1].v = 0x1; + r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32); + break;} + + case 6: { + float64_t r64[2]; + r64[0] = ddot(len_x, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1); + r64[1].v = 0x1; + r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64); + break;} + + case 7: { + float128_t r128[2]; + r128[0] = qdot(len_x, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1); + r128[1] = (float128_t){0x1, 0x0}; + r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128); + break;} + } + + // Clean up and return. + u3a_free(x_bytes); + u3a_free(y_bytes); + + return r_data; + } + +/* diag - diag(x) +*/ + u3_noun + u3qi_la_diag(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + // Assert length of dims is 2. + if (u3qb_lent(shape) != 2) { + return u3m_bail(c3__exit); + } + // Unpack shape into an array of dimensions. + c3_d *dims = _get_dims(shape); + if (dims[0] != dims[1]) { + return u3m_bail(c3__exit); + } + + // Unpack the data as a byte array. We assume total length < 2**64. + c3_d len_x = _get_length(shape); + c3_d syz_x = len_x * pow(2, bloq - 3); + c3_d wyd = pow(2, bloq - 3); + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + c3_d syz_y = wyd * dims[1]; + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_y+1)*sizeof(c3_y)); + + u3_noun r_data; + + // Grab the index at i*n_x+j in bytes; put it at j. + for (c3_d i = 0; i < dims[1]; i++) { + // Scan across whole field width. + for (c3_y k = 0; k < wyd; k++) { + y_bytes[i*wyd+k] = x_bytes[(i*dims[0]+i)*wyd+k]; + } + } + y_bytes[syz_y] = 0x1; // pin head + + // Unpack the result back into a noun. + r_data = u3i_bytes((syz_y+1)*sizeof(c3_y), y_bytes); + + u3a_free(x_bytes); + u3a_free(y_bytes); + u3a_free(dims); + + return r_data; + } + +/* transpose - x' +*/ + u3_noun + u3qi_la_transpose(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + // Assert length of dims is 2. + if (u3qb_lent(shape) != 2) { + return u3m_bail(c3__exit); + } + // Unpack shape into an array of dimensions. + c3_d *dims = _get_dims(shape); + + // Unpack the data as a byte array. We assume total length < 2**64. + c3_d len_x = _get_length(shape); + c3_d syz_x = len_x * pow(2, bloq - 3); + c3_d wyd = pow(2, bloq - 3); + c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + u3r_bytes(0, syz_x+1, x_bytes, x_data); + c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y)); + + u3_noun r_data; + + // Grab the index at i*n_x+j in bytes; put it at j. + for (c3_d i = 0; i < dims[1]; i++) { + for (c3_d j = 0; j < dims[0]; j++) { + // Scan across whole field width. + for (c3_y k = 0; k < wyd; k++) { + y_bytes[(j*dims[1]+i)*wyd+k] = x_bytes[(i*dims[0]+j)*wyd+k]; + } + } + } + y_bytes[syz_x] = 0x1; // pin head + + // Unpack the result back into a noun. + r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes); + + u3a_free(x_bytes); + u3a_free(y_bytes); + u3a_free(dims); + + return r_data; + } + +/* linspace - [a a+(b-a)/n ... b] +*/ + u3_noun + u3qi_la_linspace_i754(u3_noun a, + u3_noun b, + u3_noun n, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + u3_noun r_data; + + switch (u3x_atom(bloq)) { + case 4: { + float16_t a16, b16; + u3r_bytes(0, 2, (c3_y*)&(a16.v), a); + u3r_bytes(0, 2, (c3_y*)&(b16.v), b); + float16_t span16 = f16_sub(b16, a16); + float16_t interval16 = f16_div(span16, i32_to_f16(n-1)); + c3_y* x_bytes16 = (c3_y*)u3a_malloc((n*2+1)*sizeof(c3_y)); + for (c3_d i = 1; i < n-1; i++) { + ((float16_t*)x_bytes16)[i] = f16_add(a16, f16_mul(i32_to_f16(i), interval16)); + } + // Assign in reverse order so that n=1 case is correctly left-hand bound. + ((float16_t*)x_bytes16)[n-1] = b16; + ((float16_t*)x_bytes16)[0] = a16; + x_bytes16[n*2] = 0x1; // pin head + r_data = u3i_bytes((n*2+1)*sizeof(c3_y), x_bytes16); + u3a_free(x_bytes16); + break;} + + case 5: { + float32_t a32, b32; + u3r_bytes(0, 4, (c3_y*)&(a32.v), a); + u3r_bytes(0, 4, (c3_y*)&(b32.v), b); + float32_t span32 = f32_sub(b32, a32); + float32_t interval32 = f32_div(span32, i32_to_f32(n-1)); + c3_y* x_bytes32 = (c3_y*)u3a_malloc((n*4+1)*sizeof(c3_y)); + for (c3_d i = 1; i < n-1; i++) { + ((float32_t*)x_bytes32)[i] = f32_add(a32, f32_mul(i32_to_f32(i), interval32)); + } + ((float32_t*)x_bytes32)[n-1] = b32; + ((float32_t*)x_bytes32)[0] = a32; + x_bytes32[n*4] = 0x1; // pin head + r_data = u3i_bytes((n*4+1)*sizeof(c3_y), x_bytes32); + u3a_free(x_bytes32); + break;} + + case 6: { + float64_t a64, b64; + u3r_bytes(0, 8, (c3_y*)&(a64.v), a); + u3r_bytes(0, 8, (c3_y*)&(b64.v), b); + float64_t span64 = f64_sub(b64, a64); + float64_t interval64 = f64_div(span64, i32_to_f64(n-1)); + c3_y* x_bytes64 = (c3_y*)u3a_malloc((n*8+1)*sizeof(c3_y)); + for (c3_d i = 1; i < n-1; i++) { + ((float64_t*)x_bytes64)[i] = f64_add(a64, f64_mul(i32_to_f64(i), interval64)); + } + ((float64_t*)x_bytes64)[n-1] = b64; + ((float64_t*)x_bytes64)[0] = a64; + x_bytes64[n*8] = 0x1; // pin head + r_data = u3i_bytes((n*8+1)*sizeof(c3_y), x_bytes64); + u3a_free(x_bytes64); + break;} + + case 7: { + float128_t a128, b128; + u3r_bytes(0, 16, (c3_y*)&(a128.v[0]), a); + u3r_bytes(0, 16, (c3_y*)&(b128.v[0]), b); + float128_t span128; + f128M_sub(&b128, &a128, &span128); + float128_t interval128; + float128_t n128; + i32_to_f128M(n-1, &n128); + f128M_div(&span128, &n128, &interval128); + c3_y* x_bytes128 = (c3_y*)u3a_malloc((n*16+1)*sizeof(c3_y)); + float128_t i128; + for (c3_d i = 1; i < n-1; i++) { + i32_to_f128M(i, &i128); + f128M_mul(&i128, &interval128, &((float128_t*)x_bytes128)[i]); + f128M_add(&a128, &((float128_t*)x_bytes128)[i], &((float128_t*)x_bytes128)[i]); + } + ((float128_t*)x_bytes128)[n-1] = b128; + ((float128_t*)x_bytes128)[0] = a128; + x_bytes128[n*16] = 0x1; // pin head + r_data = u3i_bytes((n*16+1)*sizeof(c3_y), x_bytes128); + u3a_free(x_bytes128); + break;} + } + + return r_data; + } + +/* range - [a a+d ... b] +*/ + u3_noun + u3qi_la_range_i754(u3_noun a, + u3_noun b, + u3_noun d, + u3_noun bloq) + { + // Fence on valid bloq size. + if (bloq < 4 || bloq > 7) { + return u3_none; + } + + u3_noun r_data; + + switch (u3x_atom(bloq)) { + case 4: { + float16_t a16, b16, interval16; + u3r_bytes(0, 2, (c3_y*)&(a16.v), a); + u3r_bytes(0, 2, (c3_y*)&(b16.v), b); + u3r_bytes(0, 2, (c3_y*)&(interval16.v), d); + c3_d n16 = f16_to_i64(f16_ceil(f16_div(f16_sub(b16, a16), interval16)), softfloat_round_minMag, false); + c3_y* x_bytes16 = (c3_y*)u3a_malloc(((n16+1)*2)*sizeof(c3_y)); + ((float16_t*)x_bytes16)[0] = a16; + for (c3_d i = 1; i < n16; i++) { + ((float16_t*)x_bytes16)[i] = f16_add(a16, f16_mul(i32_to_f16(i), interval16)); + } + ((float16_t*)x_bytes16)[n16].v = 0x1; // pin head + r_data = u3i_bytes(((n16+1)*2)*sizeof(c3_y), x_bytes16); + u3a_free(x_bytes16); + break;} + + case 5: { + float32_t a32, b32, interval32; + u3r_bytes(0, 4, (c3_y*)&(a32.v), a); + u3r_bytes(0, 4, (c3_y*)&(b32.v), b); + u3r_bytes(0, 4, (c3_y*)&(interval32.v), d); + c3_d n32 = f32_to_i64(f32_ceil(f32_div(f32_sub(b32, a32), interval32)), softfloat_round_minMag, false); + c3_y* x_bytes32 = (c3_y*)u3a_malloc(((n32+1)*4)*sizeof(c3_y)); + ((float32_t*)x_bytes32)[0] = a32; + for (c3_d i = 1; i < n32; i++) { + ((float32_t*)x_bytes32)[i] = f32_add(a32, f32_mul(i32_to_f32(i), interval32)); + } + ((float32_t*)x_bytes32)[n32].v = 0x1; // pin head + r_data = u3i_bytes(((n32+1)*4)*sizeof(c3_y), x_bytes32); + u3a_free(x_bytes32); + break;} + + case 6: { + float64_t a64, b64, interval64; + u3r_bytes(0, 8, (c3_y*)&(a64.v), a); + u3r_bytes(0, 8, (c3_y*)&(b64.v), b); + u3r_bytes(0, 8, (c3_y*)&(interval64.v), d); + c3_d n64 = f64_to_i64(f64_ceil(f64_div(f64_sub(b64, a64), interval64)), softfloat_round_minMag, false); + c3_y* x_bytes64 = (c3_y*)u3a_malloc(((n64+1)*8)*sizeof(c3_y)); + ((float64_t*)x_bytes64)[0] = a64; + for (c3_d i = 1; i < n64; i++) { + ((float64_t*)x_bytes64)[i] = f64_add(a64, f64_mul(i32_to_f64(i), interval64)); + } + ((float64_t*)x_bytes64)[n64].v = 0x1; // pin head + r_data = u3i_bytes(((n64+1)*8)*sizeof(c3_y), x_bytes64); + u3a_free(x_bytes64); + break;} + + case 7: { + float128_t a128, b128, interval128; + u3r_bytes(0, 16, (c3_y*)&(a128.v[0]), a); + u3r_bytes(0, 16, (c3_y*)&(b128.v[0]), b); + u3r_bytes(0, 16, (c3_y*)&(interval128.v[0]), d); + float128_t tmp; + f128M_sub(&b128, &a128, &tmp); + f128M_div(&tmp, &interval128, &tmp); + f128M_ceil(&tmp, &tmp); + c3_d n128 = f128M_to_i64(&tmp, softfloat_round_minMag, false); + c3_y* x_bytes128 = (c3_y*)u3a_malloc(((n128+1)*16)*sizeof(c3_y)); + float128_t i128; + ((float128_t*)x_bytes128)[0] = a128; + for (c3_d i = 1; i < n128; i++) { + i32_to_f128M(i, &i128); + f128M_mul(&i128, &interval128, &((float128_t*)x_bytes128)[i]); + f128M_add(&a128, &((float128_t*)x_bytes128)[i], &((float128_t*)x_bytes128)[i]); + } + ((float128_t*)x_bytes128)[n128].v[0] = 0x1; // pin head + ((float128_t*)x_bytes128)[n128].v[1] = 0x0; // pin head + r_data = u3i_bytes(((n128+1)*16)*sizeof(c3_y), x_bytes128); + u3a_free(x_bytes128); + break;} + } + + return r_data; + } + +/* trace - tr(x) +*/ + u3_noun + u3qi_la_trace_i754(u3_noun x_data, + u3_noun shape, + u3_noun bloq) + { + u3_noun d_data = u3qi_la_diag(x_data, shape, bloq); + c3_d len_x0 = _get_dims(shape)[0]; + u3_noun r_data = u3qi_la_dot_i754(d_data, d_data, u3nt(len_x0, 0x1, u3_nul), u3k(bloq)); + return r_data; + } + +/* mmul +*/ + u3_noun + u3qi_la_mmul_i754(u3_noun x_data, + u3_noun y_data, + u3_noun x_shape, + u3_noun y_shape, + u3_noun bloq) + { + // Unpack the data as a byte array. We assume total length < 2**64. + c3_d M = u3x_atom(u3h(x_shape)); + c3_d Na= u3x_atom(u3h(u3t(x_shape))); + c3_d Nb= u3x_atom(u3h(y_shape)); + c3_d P = u3x_atom(u3h(u3t(y_shape))); + + if ((u3_nul != u3t(u3t(x_shape))) || + (u3_nul != u3t(u3t(y_shape))) || + (Na != Nb)) { + return u3m_bail(c3__exit); + } + c3_d N = Na; + + // Unpack the data as a byte array. We assume total length < 2**64. + // len_x is length in base units + c3_d len_x = _get_length(x_shape); // M*N + + // syz_x is length in bytes + c3_d syz_x = len_x * pow(2, bloq-3); // M*N + + // x_bytes is the data array (w/o leading 0x1) + c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y)); + u3r_bytes(0, syz_x, x_bytes, x_data); + + // len_x is length in base units + c3_d len_y = _get_length(y_shape); // N*P + + // syz_x is length in bytes + c3_d syz_y = len_y * pow(2, bloq-3); // N*P + + // y_bytes is the data array (w/o leading 0x1) + c3_y* y_bytes = (c3_y*)u3a_malloc(syz_y*sizeof(c3_y)); + u3r_bytes(0, syz_y, y_bytes, y_data); + + // len_r is length in base units + c3_d len_r = M*P; // M*P + + // syz_r is length in bytes + c3_d syz_r = len_r * pow(2, bloq-3); // M*P + + // r_bytes is the result array + c3_y* r_bytes = (c3_y*)u3a_malloc((syz_r+1)*sizeof(c3_y)); + r_bytes[syz_r] = 0x1; // pin head + // initialize with 0x0s + for (c3_d i = 0; i < syz_r; i++) { + r_bytes[i] = 0x0; + } + + // Switch on the block size. + switch (u3x_atom(bloq)) { + case 4: + hgemm('N', 'N', M, N, P, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, N, (float16_t*)y_bytes, P, (float16_t){SB_REAL16_ZERO}, (float16_t*)r_bytes, P); + break; + + case 5: + sgemm('N', 'N', M, N, P, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, N, (float32_t*)y_bytes, P, (float32_t){SB_REAL32_ZERO}, (float32_t*)r_bytes, P); + break; + + case 6: + dgemm('N', 'N', M, N, P, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, N, (float64_t*)y_bytes, P, (float64_t){SB_REAL64_ZERO}, (float64_t*)r_bytes, P); + break; + + case 7: + qgemm('N', 'N', M, N, P, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, N, (float128_t*)y_bytes, P, (float128_t){SB_REAL128L_ZERO,SB_REAL128U_ZERO}, (float128_t*)r_bytes, P); + break; + } + + // Unpack the result back into a noun. + u3_noun r_data = u3i_bytes(syz_r+1, r_bytes); + u3_noun M_ = u3i_chub(M); + u3_noun P_ = u3i_chub(P); + + u3a_free(x_bytes); + u3a_free(y_bytes); + u3a_free(r_bytes); + + return u3nc(u3nq(u3nt(M_, P_, u3_nul), u3k(bloq), c3__i754, u3_nul), r_data); + } + + u3_noun + u3wi_la_add(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_add_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_sub(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_sub_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_mul(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_mul_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_div(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_div_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_mod(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(rnd) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_mod_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_cumsum(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_cumsum_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nc(0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_argmin(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_argmin_i754(x_data, x_shape, x_bloq); + // bare atom (@ index) + return r_data;} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_ravel(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_ravel_i754(x_data, x_shape, x_bloq); + // (list @) + return r_data;} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_argmax(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_argmax_i754(x_data, x_shape, x_bloq); + // bare atom (@ index) + return r_data;} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_min(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_min_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_max(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(u3nc(x_meta, x_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_max_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_abs(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_abs_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_gth(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_gth_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3k(x_meta), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_gte(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_gte_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3k(x_meta), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_lth(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_lth_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3k(x_meta), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_lte(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_lte_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3k(x_meta), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_adds(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_adds_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_subs(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_subs_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_muls(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_muls_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_divs(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_divs_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_mods(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, n; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_3, &n, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(n) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_mods_i754(x_data, n, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + + u3_noun + u3wi_la_dot(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3r_sing(x_meta, y_meta) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_dot_i754(x_data, y_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + c3_d len_x0 = _get_dims(x_shape)[0]; + return u3nc(u3nq(u3nt(len_x0, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_transpose(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(cor) + ) + { + return u3m_bail(c3__exit); + } else { + u3_noun r_data = u3qi_la_transpose(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nt(u3k(u3h(x_shape)), u3k(u3h(u3t(x_shape))), u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + } + } + } + + u3_noun + u3wi_la_linspace(u3_noun cor) + { + u3_noun x_meta, a, b, n, rnd; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_12, &a, + u3x_sam_13, &b, + u3x_sam_7, &n, + 0)) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == u3ud(n) || + (n < 1) // crash on zero size + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_linspace_i754(a, b, n, x_bloq); + if (r_data == u3_none) { return u3_none; } + x_shape = u3nc(u3x_atom(n), u3_nul); + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_range(u3_noun cor) + { + u3_noun x_meta, a, b, d, rnd; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_12, &a, + u3x_sam_13, &b, + u3x_sam_7, &d, + 0)) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_range_i754(a, b, d, x_bloq); + if (r_data == u3_none) { return u3_none; } + c3_d a_, b_, d_; + c3_ds n_; + switch (x_bloq) { + case 4: + u3r_bytes(0, 2, (c3_y*)&a_, a); + u3r_bytes(0, 2, (c3_y*)&b_, b); + u3r_bytes(0, 2, (c3_y*)&d_, d); + n_ = f16_to_i64(f16_ceil(f16_div(f16_sub((float16_t){b_}, (float16_t){a_}), (float16_t){d_})), softfloat_round_minMag, false) - 1; + break; + case 5: + u3r_bytes(0, 4, (c3_y*)&a_, a); + u3r_bytes(0, 4, (c3_y*)&b_, b); + u3r_bytes(0, 4, (c3_y*)&d_, d); + n_ = f32_to_i64(f32_ceil(f32_div(f32_sub((float32_t){b_}, (float32_t){a_}), (float32_t){d_})), softfloat_round_minMag, false) - 1; + break; + case 6: + u3r_bytes(0, 8, (c3_y*)&a_, a); + u3r_bytes(0, 8, (c3_y*)&b_, b); + u3r_bytes(0, 8, (c3_y*)&d_, d); + n_ = f64_to_i64(f64_ceil(f64_div(f64_sub((float64_t){b_}, (float64_t){a_}), (float64_t){d_})), softfloat_round_minMag, false) - 1; + break; + case 7: { + c3_d a__[2], b__[2], d__[2]; + u3r_bytes(0, 16, (c3_y*)&a__, a); + u3r_bytes(0, 16, (c3_y*)&b__, b); + u3r_bytes(0, 16, (c3_y*)&d__, d); + float128_t tmp; + f128M_sub((float128_t*)&b__, (float128_t*)&a__, &tmp); + f128M_div(&tmp, (float128_t*)&d__, &tmp); + f128M_ceil(&tmp, &tmp); + n_ = f128M_to_i64(&tmp, softfloat_round_minMag, false) - 1; + break;} + } + u3_noun n = u3i_chub(n_+1); + x_shape = u3nc(u3k(n), u3_nul); + return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_diag(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + x_tail = u3t(u3t(u3t(x_meta))); // 15 + if ( c3n == u3ud(x_bloq) || + c3n == u3ud(x_kind) || + c3n == _check(cor) + ) + { + return u3m_bail(c3__exit); + } else { + u3_noun r_data = u3qi_la_diag(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + c3_d len_x0 = _get_dims(x_shape)[0]; + return u3nc(u3nq(u3nt(len_x0, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data); + } + } + } + + u3_noun + u3wi_la_trace(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_2, &x_meta, + u3x_sam_3, &x_data, + 0) || + c3n == u3ud(x_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, x_tail; + if ( c3n == u3r_mean(x_meta, + 2, &x_shape, + 6, &x_bloq, + 14, &x_kind, + 15, &x_tail, + 0) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: { + u3_noun r_data = u3qi_la_trace_i754(x_data, x_shape, x_bloq); + if (r_data == u3_none) { return u3_none; } + return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);} + + default: + return u3_none; + } + } + } + } + + u3_noun + u3wi_la_mmul(u3_noun cor) + { + // Each argument is a ray, [=meta data=@ux] + u3_noun x_meta, x_data, + y_meta, y_data; + + if ( c3n == u3r_mean(cor, + u3x_sam_4, &x_meta, + u3x_sam_5, &x_data, + u3x_sam_6, &y_meta, + u3x_sam_7, &y_data, + 0) || + c3n == u3ud(x_data) || + c3n == u3ud(y_data) ) + { + return u3m_bail(c3__exit); + } else { + u3_noun x_shape, x_bloq, x_kind, + y_shape, + rnd; + x_shape = u3h(x_meta); // 2 + x_bloq = u3h(u3t(x_meta)); // 6 + x_kind = u3h(u3t(u3t(x_meta))); // 14 + y_shape = u3h(y_meta); // 2 + rnd = u3h(u3t(u3t(u3t(cor)))); // 30 + if ( c3n == _check(u3nc(x_meta, x_data)) || + c3n == _check(u3nc(y_meta, y_data)) + ) + { + return u3m_bail(c3__exit); + } else { + switch (x_kind) { + case c3__i754: + _set_rounding(rnd); + u3_noun r_data = u3qi_la_mmul_i754(x_data, y_data, x_shape, y_shape, x_bloq); + // result is already [meta data] + return r_data; + + default: + return u3_none; + } + } + } + } diff --git a/vere/pkg/noun/jets/k.h b/vere/pkg/noun/jets/k.h new file mode 100644 index 0000000..27733fb --- /dev/null +++ b/vere/pkg/noun/jets/k.h @@ -0,0 +1,185 @@ +/// @file + +#ifndef U3_JETS_K_H +#define U3_JETS_K_H + +#include "types.h" + + /** Tier 1. + **/ + u3_noun u3ka_add(u3_noun a, u3_noun b); + u3_noun u3ka_dec(u3_atom a); + u3_noun u3ka_div(u3_noun a, u3_noun b); + u3_noun u3ka_sub(u3_noun a, u3_noun b); + u3_noun u3ka_max(u3_noun a, u3_noun b); + u3_noun u3ka_min(u3_noun a, u3_noun b); + u3_noun u3ka_mod(u3_noun a, u3_noun b); + u3_noun u3ka_mul(u3_noun a, u3_noun b); + u3_noun u3ka_gth(u3_noun a, u3_noun b); + u3_noun u3ka_lte(u3_noun a, u3_noun b); + + /** Tier 2. + **/ + u3_noun u3kb_lent(u3_noun a); + u3_noun u3kb_weld(u3_noun a, u3_noun b); + u3_noun u3kb_flop(u3_noun a); + +/* u3kc: tier 3 functions +*/ + /* u3kc_bex(): binary exponent. + */ + u3_noun + u3kc_bex(u3_atom); + + /* u3kc_con(): binary loobean conjunction. + */ + u3_noun + u3kc_con(u3_noun a, + u3_noun b); + + /* u3kc_mix(): binary xor. + */ + u3_noun + u3kc_mix(u3_atom a, u3_atom b); + + /* u3kc_lsh(): left shift. + */ + u3_noun + u3kc_lsh(u3_noun a, u3_noun b, u3_noun c); + + /* u3kc_rsh(): right shift. + */ + u3_noun + u3kc_rsh(u3_noun a, u3_noun b, u3_noun c); + + /* u3kc_rep(): assemble single. + */ + u3_noun + u3kc_rep(u3_atom a, + u3_atom b, + u3_noun c); + + /* u3kc_rip(): disassemble. + */ + u3_noun + u3kc_rip(u3_atom a, + u3_atom b, + u3_atom c); + + /* u3kc_rev(): reverse block order, accounting for leading zeroes. + */ + u3_noun + u3kc_rev(u3_atom boz, u3_atom len, u3_atom dat); + + /* u3kc_swp(): reverse block order. + */ + u3_noun + u3kc_swp(u3_atom a, u3_atom b); + +/* u3kd: tier 4 functions +*/ + /* u3kdb_get(): map get for key `b` in map `a` with u3_none. + */ + u3_weak + u3kdb_get(u3_noun a, u3_noun b); + + /* u3kdb_got(): map get for key `b` in map `a` with bail. + */ + u3_noun + u3kdb_got(u3_noun a, u3_noun b); + + /* u3kdb_put(): map put for key `b`, value `c` in map `a`. + */ + u3_weak + u3kdb_put(u3_noun a, u3_noun b, u3_noun c); + + /* u3kdb_del(): map del for key `b` + */ + u3_weak + u3kdb_del(u3_noun a, u3_noun b); + + /* u3kdb_has(): test for get. + */ + u3_noun + u3kdb_has(u3_noun a, u3_noun b); + + /* u3kdb_gas(): list to map. + */ + u3_noun + u3kdb_gas(u3_noun a, u3_noun b); + + /* u3kdb_uni(): map union. + */ + u3_noun + u3kdb_uni(u3_noun a, u3_noun b); + + /* u3kdi_gas(): list to map. + */ + u3_noun + u3kdi_gas(u3_noun a, u3_noun b); + + /* u3kdi_has(): test for presence. + */ + u3_noun + u3kdi_has(u3_noun a, u3_noun b); + + /* u3kdi_tap(): map/set convert to list. (solves by_tap also.) + */ + u3_noun + u3kdi_tap(u3_noun a); + + /* u3kdi_put(): put in set. + */ + u3_weak + u3kdi_put(u3_noun a, u3_noun b); + + /* u3kdi_uni(): set union. + */ + u3_noun + u3kdi_uni(u3_noun a, u3_noun b); + +# define u3kdb_tap(a) u3kdi_tap(a) + +/* u3ke: tier 5 functions +*/ + /* u3ke_cue(): expand saved pill. + */ + u3_noun + u3ke_cue(u3_atom a); + + /* u3ke_jam(): pack noun as atom. + */ + u3_atom + u3ke_jam(u3_noun a); + + /* u3ke_trip(): atom to tape. + */ + u3_noun + u3ke_trip(u3_noun a); + + /* u3ke_json_de(): parse JSON from cord. + */ + u3_noun + u3ke_json_de(u3_atom); + + /* u3ke_json_en(): serialize JSON to cord. + */ + u3_atom + u3ke_json_en(u3_noun); + + /* u3kf_fork(): build %fork span. + */ + u3_noun + u3kf_fork(u3_noun yed); + + /* u3kz_fork(): build %fork span. + */ + u3_noun + u3kz_fork(u3_noun yed); + + /* u3kfu_repo(): + */ + u3_noun + u3kfu_repo(u3_noun, u3_noun); + +#endif /* ifndef U3_JETS_K_H */ diff --git a/vere/pkg/noun/jets/q.h b/vere/pkg/noun/jets/q.h new file mode 100644 index 0000000..db1cfe1 --- /dev/null +++ b/vere/pkg/noun/jets/q.h @@ -0,0 +1,306 @@ +/// @file + +#ifndef U3_JETS_Q_H +#define U3_JETS_Q_H + +#include "types.h" + + /** Tier 1. + **/ + u3_noun u3qa_add(u3_atom, u3_atom); + u3_noun u3qa_dec(u3_atom); + u3_noun u3qa_div(u3_atom, u3_atom); + u3_noun u3qa_gte(u3_atom, u3_atom); + u3_noun u3qa_gth(u3_atom, u3_atom); + u3_noun u3qa_inc(u3_atom); + u3_noun u3qa_lte(u3_atom, u3_atom); + u3_noun u3qa_lth(u3_atom, u3_atom); + u3_noun u3qa_max(u3_atom, u3_atom); + u3_noun u3qa_min(u3_atom, u3_atom); + u3_noun u3qa_mod(u3_atom, u3_atom); + u3_noun u3qa_mul(u3_atom, u3_atom); + u3_noun u3qa_sub(u3_atom, u3_atom); + + /** Tier 2. + **/ + u3_noun u3qb_bind(u3_noun, u3_noun); + u3_noun u3qb_clap(u3_noun, u3_noun, u3_noun); + u3_noun u3qb_drop(u3_noun); + u3_noun u3qb_flop(u3_noun); + u3_noun u3qb_lent(u3_noun); + u3_noun u3qb_levy(u3_noun, u3_noun); + u3_noun u3qb_lien(u3_noun, u3_noun); + u3_noun u3qb_murn(u3_noun, u3_noun); + u3_noun u3qb_need(u3_noun); + u3_noun u3qb_mate(u3_noun, u3_noun); + u3_noun u3qb_reap(u3_atom, u3_noun); + u3_noun u3qb_reel(u3_noun, u3_noun); + u3_noun u3qb_roll(u3_noun, u3_noun); + u3_noun u3qb_skid(u3_noun, u3_noun); + u3_noun u3qb_skim(u3_noun, u3_noun); + u3_noun u3qb_skip(u3_noun, u3_noun); + u3_noun u3qb_scag(u3_atom, u3_noun); + u3_noun u3qb_slag(u3_atom, u3_noun); + u3_noun u3qb_snag(u3_atom, u3_noun); + u3_noun u3qb_sort(u3_noun, u3_noun); + u3_noun u3qb_turn(u3_noun, u3_noun); + u3_noun u3qb_weld(u3_noun, u3_noun); + + /** Tier 3. + **/ + u3_noun u3qc_aor(u3_atom, u3_atom); + u3_noun u3qc_bex(u3_atom); + u3_noun u3qc_xeb(u3_atom); + u3_noun u3qc_can(u3_atom, u3_noun); + u3_noun u3qc_cap(u3_atom); + u3_noun u3qc_cat(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_clz(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_con(u3_atom, u3_atom); + u3_noun u3qc_ctz(u3_atom); + u3_noun u3qc_cut(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qc_dis(u3_atom, u3_atom); + u3_noun u3qc_dor(u3_atom, u3_atom); + u3_noun u3qc_dvr(u3_atom, u3_atom); + u3_noun u3qc_end(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_gor(u3_atom, u3_atom); + u3_noun u3qc_ham(u3_atom); + u3_noun u3qc_hew(u3_atom, u3_atom, u3_atom, u3_noun); + u3_noun u3qc_lsh(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_mas(u3_atom); + u3_noun u3qc_met(u3_atom, u3_atom); + u3_noun u3qc_mix(u3_atom, u3_atom); + u3_noun u3qc_mor(u3_atom, u3_atom); + u3_noun u3qc_muk(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_peg(u3_atom, u3_atom); + u3_noun u3qc_pow(u3_atom, u3_atom); + u3_noun u3qc_rap(u3_atom, u3_noun); + u3_noun u3qc_rep(u3_atom, u3_atom, u3_noun); + u3_noun u3qc_rev(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rig(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rip(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rsh(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_sew(u3_atom, u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qc_swp(u3_atom, u3_atom); + u3_noun u3qc_sqt(u3_atom); + + c3_d u3qc_rig_s(c3_g, c3_w, c3_g); + + u3_noun u3_po_find_prefix(c3_y one, c3_y two, c3_y three); + u3_noun u3_po_find_suffix(c3_y one, c3_y two, c3_y three); + void u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); + void u3_po_to_suffix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); + + /** Tier 4. + **/ + u3_noun u3qdb_all(u3_noun, u3_noun); + u3_noun u3qdb_any(u3_noun, u3_noun); + u3_noun u3qdb_apt(u3_noun); + u3_noun u3qdb_bif(u3_noun, u3_noun); + u3_noun u3qdb_del(u3_noun, u3_noun); + u3_noun u3qdb_dif(u3_noun, u3_noun); + u3_noun u3qdb_gas(u3_noun, u3_noun); + u3_noun u3qdb_get(u3_noun, u3_noun); + u3_noun u3qdb_has(u3_noun, u3_noun); + u3_noun u3qdb_int(u3_noun, u3_noun); + u3_noun u3qdb_key(u3_noun); + u3_noun u3qdb_put(u3_noun, u3_noun, u3_noun); + u3_noun u3qdb_run(u3_noun, u3_noun); +# define u3qdb_tap u3qdi_tap + u3_noun u3qdb_uni(u3_noun, u3_noun); + u3_noun u3qdb_urn(u3_noun, u3_noun); +# define u3qdb_wyt u3qdi_wyt + + u3_noun u3qdi_apt(u3_noun); + u3_noun u3qdi_bif(u3_noun, u3_noun); + u3_noun u3qdi_del(u3_noun, u3_noun); + u3_noun u3qdi_dif(u3_noun, u3_noun); + u3_noun u3qdi_gas(u3_noun, u3_noun); + u3_noun u3qdi_has(u3_noun, u3_noun); + u3_noun u3qdi_int(u3_noun, u3_noun); + u3_noun u3qdi_put(u3_noun, u3_noun); + u3_noun u3qdi_rep(u3_noun, u3_noun); + u3_noun u3qdi_run(u3_noun, u3_noun); + u3_noun u3qdi_tap(u3_noun); + u3_noun u3qdi_uni(u3_noun, u3_noun); + u3_noun u3qdi_wyt(u3_noun); + + /** Tier 5. + **/ + u3_noun u3qe_cue(u3_atom); + u3_noun u3qe_jam(u3_atom); + u3_noun u3qe_mat(u3_atom); + u3_noun u3qe_rub(u3_atom, u3_atom); + u3_noun u3qe_leer(u3_atom); + u3_noun u3qe_lore(u3_atom); + u3_noun u3qe_loss(u3_noun, u3_noun); + u3_noun u3qe_lune(u3_atom); + u3_noun u3qe_repg(u3_noun, u3_noun, u3_noun); + u3_noun u3qe_rexp(u3_noun, u3_noun); + u3_noun u3qe_trip(u3_atom); + + u3_atom u3qe_scot(u3_atom, u3_atom); + u3_atom u3qe_scow(u3_atom, u3_atom); + + u3_noun u3qea_ecba_en(u3_atom, u3_atom); + u3_noun u3qea_ecba_de(u3_atom, u3_atom); + u3_noun u3qea_ecbb_en(u3_atom, u3_atom); + u3_noun u3qea_ecbb_de(u3_atom, u3_atom); + u3_noun u3qea_ecbc_en(u3_atom, u3_atom); + u3_noun u3qea_ecbc_de(u3_atom, u3_atom); + + u3_noun u3qea_cbca_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbca_de(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcb_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcb_de(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcc_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcc_de(u3_atom, u3_atom, u3_atom); + + u3_noun u3qea_de(u3_atom, u3_atom); + u3_noun u3qea_en(u3_atom, u3_atom); + + u3_noun u3qee_recs(u3_atom); + + u3_atom u3qe_fein_ob(u3_atom pyn); + u3_atom u3qe_fynd_ob(u3_atom pyn); + + u3_noun u3qe_hmac(u3_noun, u3_atom, u3_atom, + u3_atom, u3_atom, u3_atom, u3_atom); + + u3_noun u3qe_en_base16(u3_atom len, u3_atom dat); + u3_noun u3qe_de_base16(u3_atom inp); + + u3_noun u3qe_json_de(u3_atom); + u3_atom u3qe_json_en(u3_noun); + + u3_noun u3qeo_raw(u3_atom, u3_atom); + + u3_noun u3qef_drg(u3_noun, u3_atom); + u3_noun u3qef_lug(u3_noun, u3_noun, u3_atom, u3_atom); + + u3_noun u3qer_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_sqt(u3_atom, u3_atom); + u3_noun u3qer_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qer_lth(u3_atom, u3_atom); + u3_noun u3qer_lte(u3_atom, u3_atom); + u3_noun u3qer_equ(u3_atom, u3_atom); + u3_noun u3qer_gte(u3_atom, u3_atom); + u3_noun u3qer_gth(u3_atom, u3_atom); + + u3_noun u3qet_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_sqt(u3_atom, u3_atom); + u3_noun u3qet_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qet_lth(u3_atom, u3_atom); + u3_noun u3qet_lte(u3_atom, u3_atom); + u3_noun u3qet_equ(u3_atom, u3_atom); + u3_noun u3qet_gte(u3_atom, u3_atom); + u3_noun u3qet_gth(u3_atom, u3_atom); + + u3_noun u3qeq_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_sqt(u3_atom, u3_atom); + u3_noun u3qeq_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_lth(u3_atom, u3_atom); + u3_noun u3qeq_lte(u3_atom, u3_atom); + u3_noun u3qeq_equ(u3_atom, u3_atom); + u3_noun u3qeq_gte(u3_atom, u3_atom); + u3_noun u3qeq_gth(u3_atom, u3_atom); + + u3_noun u3qes_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_sqt(u3_atom, u3_atom); + u3_noun u3qes_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qes_lth(u3_atom, u3_atom); + u3_noun u3qes_lte(u3_atom, u3_atom); + u3_noun u3qes_equ(u3_atom, u3_atom); + u3_noun u3qes_gte(u3_atom, u3_atom); + u3_noun u3qes_gth(u3_atom, u3_atom); + + u3_noun u3qe_decompress_zlib(u3_atom, u3_noun); + u3_noun u3qe_decompress_gzip(u3_atom, u3_noun); + + /** Tier 6. + **/ + u3_noun u3qf_bull(u3_noun, u3_noun); + u3_noun u3qf_cell(u3_noun, u3_noun); + u3_noun u3qf_comb(u3_noun, u3_noun); + u3_noun u3qf_cons(u3_noun, u3_noun); + u3_noun u3qf_core(u3_noun, u3_noun); + u3_noun u3qf_cube(u3_noun, u3_noun); + u3_noun u3qf_face(u3_noun, u3_noun); + u3_noun u3qf_fine(u3_noun, u3_noun, u3_noun); + u3_noun u3qf_fitz(u3_noun, u3_noun); + u3_noun u3qf_flay(u3_noun); + u3_noun u3qf_forq(u3_noun, u3_noun); + u3_noun u3qf_fork(u3_noun); + u3_noun u3qf_grof(u3_noun); + u3_noun u3qf_hint(u3_noun, u3_noun); + u3_noun u3qf_hike(u3_noun, u3_noun); + u3_noun u3qf_look(u3_noun, u3_noun); + u3_noun u3qf_loot(u3_noun, u3_noun); + u3_noun u3qf_slot(u3_atom, u3_noun); + u3_noun u3qf_type(u3_noun); + + u3_noun u3qfl_bunt(u3_noun, u3_noun); + u3_noun u3qfl_whip(u3_noun, u3_noun, u3_noun); + + u3_noun u3qfr_fish(u3_noun, u3_noun, u3_noun, u3_noun); + + u3_noun u3qfp_hack(u3_noun, u3_noun); + u3_noun u3qfp_late(u3_noun); + u3_noun u3qfp_open(u3_noun, u3_noun, u3_noun); + u3_noun u3qfp_nepo(u3_noun, u3_noun); + u3_noun u3qfp_rake(u3_noun); + + u3_noun u3qi_la_add_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_sub_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mul_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_div_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mod_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_adds_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_subs_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_muls_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_divs_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mods_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_dot_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_diag(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_transpose(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_cumsum_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_argmin_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_argmax_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_ravel_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_min_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_max_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_linspace_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_range_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_abs_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_gth_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_gte_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_lth_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_lte_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_trace_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mmul_i754(u3_noun, u3_noun, u3_noun, u3_noun, u3_noun); + +# define u3qfu_van_fan 28 +# define u3qfu_van_rib 58 +# define u3qfu_van_vet 59 + + void u3qf_test(const c3_c*, u3_noun); + + + /** Tier 6. + **/ + u3_noun u3qg_plot_fax(u3_noun, u3_noun); + u3_noun u3qg_plot_met(u3_noun, u3_noun); + +#endif /* ifndef U3_JETS_Q_H */ + diff --git a/vere/pkg/noun/jets/tree.c b/vere/pkg/noun/jets/tree.c new file mode 100644 index 0000000..1735f22 --- /dev/null +++ b/vere/pkg/noun/jets/tree.c @@ -0,0 +1,2658 @@ +/// @file + +/* + These hashes are deprecated, you should instead use no_hashes. + + To generate the hashes, take the sha256 of the jammed battery. For example: + + ``` + > `@ux`(shax (jam -:rip)) + 0x2759.a693.1e9e.f9a5.2c8e.ee43.1088.43d9.4d39.32a6.b04f.86cb.6ba1.5553.4329.3a28 + ``` + + Becomes: + + ``` + 2759a6931e9ef9a52c8eee43108843d94d3932a6b04f86cb6ba1555343293a28 + ``` +*/ + +#include "c3/c3.h" +#include "jets.h" +#include "jets/w.h" + +static c3_c* no_hashes[] = { 0 }; + + + static u3j_harm _140_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}}; + static c3_c* _140_hex_mimes_base16_en_ha[] = { + "669807766b6802719769fcbfe149d77fb352fcf0922afaf35dc4ab8c201d84e5", + 0 + }; + static u3j_harm _140_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}}; + static c3_c* _140_hex_mimes_base16_de_ha[] = { + "f1e04d0f452f2783e17b3bd5bbbcf95a651624fe7a2aca28dd9a7feae1319734", + 0 + }; + static u3j_core _140_hex_mimes_base16_d[] = + { { "en", 7, _140_hex_mimes_base16_en_a, 0, _140_hex_mimes_base16_en_ha }, + { "de", 7, _140_hex_mimes_base16_de_a, 0, _140_hex_mimes_base16_de_ha }, + {} + }; + static c3_c* _140_hex_mimes_base16_ha[] = { + "c71bdcc8542fd49aa307f296ac097e300a714fb3b3d1e475426f0916fa61f12c", + 0 + }; +static u3j_core _140_hex_mimes_d[] = + { { "base16", 3, 0, _140_hex_mimes_base16_d, _140_hex_mimes_base16_ha }, + {} + }; +static c3_c* _140_hex_mimes_ha[] = { + "bca2510fd7172643812f9d224deb95ddd69400c990db3d8cfb517a7292e8f06e", + 0 +}; + + static u3j_harm _140_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}}; + static c3_c* _140_hex_aes_ecba_en_ha[] = { + "d7674ad72666a787580c52785c5d4d37ca462ba05e904efbeded5d1bd8b02b4b", + 0 + }; + static u3j_harm _140_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}}; + static c3_c* _140_hex_aes_ecba_de_ha[] = { + "6e6599e93bea2e4297b621814bfb17a9b10849f920d50b14e808ef2e4fe62383", + 0 + }; + static u3j_core _140_hex_aes_ecba_d[] = + { { "en", 7, _140_hex_aes_ecba_en_a, 0, _140_hex_aes_ecba_en_ha }, + { "de", 7, _140_hex_aes_ecba_de_a, 0, _140_hex_aes_ecba_de_ha }, + {} + }; + static c3_c* _140_hex_aes_ecba_ha[] = { + "693409d27b777f73ce92cebd38e9ebceebe1e9c27ad8c9de9afc091e31bd7d9f", + 0 + }; + + static u3j_harm _140_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}}; + static c3_c* _140_hex_aes_ecbb_en_ha[] = { + "2c0e3c8f4d741b37324563ecd0ab8fbf87721d1e017f1eeeaf8b6a60515c483b", + 0 + }; + static u3j_harm _140_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}}; + static c3_c* _140_hex_aes_ecbb_de_ha[] = { + "cf78f314a1dbbc53b28d6405b98c66a4451350757872d8f7cf0477411e731acc", + 0 + }; + static u3j_core _140_hex_aes_ecbb_d[] = + { { "en", 7, _140_hex_aes_ecbb_en_a, 0, _140_hex_aes_ecbb_en_ha }, + { "de", 7, _140_hex_aes_ecbb_de_a, 0, _140_hex_aes_ecbb_de_ha }, + {} + }; + static c3_c* _140_hex_aes_ecbb_ha[] = { + "7255c39f10e068007d0d64dd40e4f6e83492ed2e3222919440be0d28fd42a5e3", + 0 + }; + + static u3j_harm _140_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}}; + static c3_c* _140_hex_aes_ecbc_en_ha[] = { + "f56450f2662082e27ba1aecd2fe04c66aa8641d6eb155f8d3707e242a1e1cf1c", + 0 + }; + static u3j_harm _140_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}}; + static c3_c* _140_hex_aes_ecbc_de_ha[] = { + "28c8c44002799fbe94d4aa07922f2b74dbbf234c84684cd8c3187622b4be6a5f", + 0 + }; + static u3j_core _140_hex_aes_ecbc_d[] = + { { "en", 7, _140_hex_aes_ecbc_en_a, 0, _140_hex_aes_ecbc_en_ha }, + { "de", 7, _140_hex_aes_ecbc_de_a, 0, _140_hex_aes_ecbc_de_ha }, + {} + }; + static c3_c* _140_hex_aes_ecbc_ha[] = { + "65da73b8de06a6660ca2d36be881b708362e1f8bc12c01290aed90fdb2977667", + 0 + }; + + static u3j_harm _140_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}}; + static c3_c* _140_hex_aes_cbca_en_ha[] = { + "f85366d520b3179c5dabfb58ee1fa0554f5044f676340439db875841cd4058de", + 0 + }; + static u3j_harm _140_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}}; + static c3_c* _140_hex_aes_cbca_de_ha[] = { + "8b876fbdb1849d8fbabba5e143aea0532a0e5dfff1c784d7ad15fd497ea376b1", + 0 + }; + static u3j_core _140_hex_aes_cbca_d[] = + { { "en", 7, _140_hex_aes_cbca_en_a, 0, _140_hex_aes_cbca_en_ha }, + { "de", 7, _140_hex_aes_cbca_de_a, 0, _140_hex_aes_cbca_de_ha }, + {} + }; + static c3_c* _140_hex_aes_cbca_ha[] = { + "420d04c03b7816b656fe4e8d9fce04f7e6d51d3d274c6511e89cfdb43ebf107e", + 0 + }; + + static u3j_harm _140_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}}; + static c3_c* _140_hex_aes_cbcb_en_ha[] = { + "6f961e0629c5efce47793e6a352220d355bb8fba6656c6941a68efb3ba10999d", + 0 + }; + static u3j_harm _140_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}}; + static c3_c* _140_hex_aes_cbcb_de_ha[] = { + "7ee2f33f80612e91fda1fd84201266dea6cab596a4e23a535d1a14fb0763f1a3", + 0 + }; + static u3j_core _140_hex_aes_cbcb_d[] = + { { "en", 7, _140_hex_aes_cbcb_en_a, 0, _140_hex_aes_cbcb_en_ha }, + { "de", 7, _140_hex_aes_cbcb_de_a, 0, _140_hex_aes_cbcb_de_ha }, + {} + }; + static c3_c* _140_hex_aes_cbcb_ha[] = { + "1b84daab497795f2afd7238a6a6090be68b78eb6051b0ffa076b2ed9fedeebe5", + 0 + }; + + static u3j_harm _140_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}}; + static c3_c* _140_hex_aes_cbcc_en_ha[] = { + "b2578cf17a3095f48cc96cf7690dd7ab4f4e0b76b2578eadc1dce31a075f5b12", + 0 + }; + static u3j_harm _140_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}}; + static c3_c* _140_hex_aes_cbcc_de_ha[] = { + "36586f89d702bedb8c2a01ea3614f61627e762488e373106cbb1b27c46e3493c", + 0 + }; + static u3j_core _140_hex_aes_cbcc_d[] = + { { "en", 7, _140_hex_aes_cbcc_en_a, 0, _140_hex_aes_cbcc_en_ha }, + { "de", 7, _140_hex_aes_cbcc_de_a, 0, _140_hex_aes_cbcc_de_ha }, + {} + }; + static c3_c* _140_hex_aes_cbcc_ha[] = { + "3bab1a59c7673afeb659821d54754e8e5e281243e79624fdbe4d7f85cae192c5", + 0 + }; + + static u3j_harm _140_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}}; + static c3_c* _140_hex_aes_siva_en_ha[] = { + "2a137039301788b8540ed81cbfafe450c9306348d02a6576f5c14f6d6f20ba81", + 0 + }; + static u3j_harm _140_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}}; + static c3_c* _140_hex_aes_siva_de_ha[] = { + "d0130e9229e71c589429dd87843dc104bc4ee5b426400a547081d8c91a548eaa", + 0 + }; + static u3j_core _140_hex_aes_siva_d[] = + { { "en", 7, _140_hex_aes_siva_en_a, 0, _140_hex_aes_siva_en_ha }, + { "de", 7, _140_hex_aes_siva_de_a, 0, _140_hex_aes_siva_de_ha }, + {} + }; + static c3_c* _140_hex_aes_siva_ha[] = { + "435c5c769d2522d71ab60332bb57440d69c6803d5ca9a5faae88c825cb55d72e", + 0 + }; + + static u3j_harm _140_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}}; + static c3_c* _140_hex_aes_sivb_en_ha[] = { + "1638f56e8728f285e4175c7b514c5a4e1a24205acf33e105f0513cad7ae843cf", + 0 + }; + static u3j_harm _140_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}}; + static c3_c* _140_hex_aes_sivb_de_ha[] = { + "64c9b199fffd6d31baf7457bf27d5a510121be45201b2ae5cc1d9565c0bdd0ff", + 0 + }; + static u3j_core _140_hex_aes_sivb_d[] = + { { "en", 7, _140_hex_aes_sivb_en_a, 0, _140_hex_aes_sivb_en_ha }, + { "de", 7, _140_hex_aes_sivb_de_a, 0, _140_hex_aes_sivb_de_ha }, + {} + }; + static c3_c* _140_hex_aes_sivb_ha[] = { + "0683f3f9067c2a16f68805c778c404179dc5df9019bbbe0f8d680a99a69e61fc", + 0 + }; + + static u3j_harm _140_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}}; + static c3_c* _140_hex_aes_sivc_en_ha[] = { + "d721486dea943efd52d9e6450f4f48dd191c89637a2f842d3ff6edfd3beecbb9", + 0 + }; + static u3j_harm _140_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}}; + static c3_c* _140_hex_aes_sivc_de_ha[] = { + "3ded831b992ea100582229a4d1d9b5c80380128ae6b59b5bb36403ed13dc5d55", + 0 + }; + static u3j_core _140_hex_aes_sivc_d[] = + { { "en", 7, _140_hex_aes_sivc_en_a, 0, _140_hex_aes_sivc_en_ha }, + { "de", 7, _140_hex_aes_sivc_de_a, 0, _140_hex_aes_sivc_de_ha }, + {} + }; + static c3_c* _140_hex_aes_sivc_ha[] = { + "23ef582f110d28aff82b0795305b02e5a718d667bcae97091c08bc26790e7176", + 0 + }; +static u3j_core _140_hex_aes_d[] = + { { "ecba", 7, 0, _140_hex_aes_ecba_d, _140_hex_aes_ecba_ha }, + { "ecbb", 7, 0, _140_hex_aes_ecbb_d, _140_hex_aes_ecbb_ha }, + { "ecbc", 7, 0, _140_hex_aes_ecbc_d, _140_hex_aes_ecbc_ha }, + { "cbca", 7, 0, _140_hex_aes_cbca_d, _140_hex_aes_cbca_ha }, + { "cbcb", 7, 0, _140_hex_aes_cbcb_d, _140_hex_aes_cbcb_ha }, + { "cbcc", 7, 0, _140_hex_aes_cbcc_d, _140_hex_aes_cbcc_ha }, + { "siva", 7, 0, _140_hex_aes_siva_d, _140_hex_aes_siva_ha }, + { "sivb", 7, 0, _140_hex_aes_sivb_d, _140_hex_aes_sivb_ha }, + { "sivc", 7, 0, _140_hex_aes_sivc_d, _140_hex_aes_sivc_ha }, + {} + }; +static c3_c* _140_hex_aes_ha[] = { + "ca4c1b0cff03db74ceca1b844f0223d669aa42934152a784d431469f0eb71527", + 0 +}; + +static u3j_harm _140_hex_leer_a[] = {{".2", u3we_leer}, {}}; +static c3_c* _140_hex_leer_ha[] = { + "8a4486bb09639f6b8cf7631f9bf883256529c6d7d9aa320ab6dfa5517611f0d7", + 0 +}; +static u3j_harm _140_hex_lore_a[] = {{".2", u3we_lore}, {}}; +static c3_c* _140_hex_lore_ha[] = { + "19b13cfea49fd14aafbb20b8b888ba454f809c3f50a7cfeebd43f87336fe052d", + 0 +}; +static u3j_harm _140_hex_loss_a[] = {{".2", u3we_loss}, {}}; +static c3_c* _140_hex_loss_ha[] = { + "67aacd21484078828ad4342297d44c38d9213b8809f83f695c2996378a92dc2a", + 0 +}; +static u3j_harm _140_hex_lune_a[] = {{".2", u3we_lune}, {}}; +static c3_c* _140_hex_lune_ha[] = { + "417472f35b885fe6dd0715e78fd0920cb59f68b738aadc9768e73bc5efa0e570", + 0 +}; + +static u3j_harm _140_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}}; +static c3_c* _140_hex_coed__ed_puck_ha[] = { + "1bc694675842345c50b0e20a2193bb5bcbb42f163fc832431a3d1822a81e4c98", + 0 +}; + +static u3j_harm _140_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}}; + +static u3j_harm _140_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}}; +static c3_c* _140_hex_coed__ed_sign_octs_ha[] = { + "34ad749bf8443611cbf1f7de90a066318bd12be36f2f7f6f55281f6f7ed79754", + 0 +}; + +static u3j_harm _140_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}}; + +static u3j_harm _140_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}}; +static c3_c* _140_hex_coed__ed_veri_octs_ha[] = { + "047a7eeccb2e68aeeee631b6db86e11a5a3aa9e179660553eca6304327612dcf", + 0 +}; +static u3j_harm _140_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}}; +static c3_c* _140_hex_coed__ed_shar_ha[] = { + "52d3b0a2f51f2b0a9dd72bb33db38c73dc873029c365d871d0559a1472a80e72", + 0 +}; + + static u3j_harm _140_hex_coed__ed_point_add_a[] = + {{".2", u3wee_point_add}, {}}; + + static u3j_harm _140_hex_coed__ed_scalarmult_a[] = + {{".2", u3wee_scalarmult}, {}}; + static c3_c* _140_hex_coed__ed_scalarmult_ha[] = { + "72e71cd3aa3af429cd65baa78632500c60edd1d4c82a39d3ba7f231ef97e6316", + 0 + }; + + static u3j_harm _140_hex_coed__ed_scalarmult_base_a[] = + {{".2", u3wee_scalarmult_base}, {}}; + static c3_c* _140_hex_coed__ed_scalarmult_base_ha[] = { + "976fdb8251f9b767af689a0d2c41b88941921bf53777c1ceeb5297511021f9d8", + 0 + }; + + static u3j_harm _140_hex_coed__ed_add_scalarmult_scalarmult_base_a[] = + {{".2", u3wee_add_scalarmult_scalarmult_base}, {}}; + static c3_c* _140_hex_coed__ed_add_scalarmult_scalarmult_base_ha[] = { + "11819071c24a2d7b36daea6e16c78b2e05f9ca3e857cf4815ffe652ce677a61a", + 0 + }; + + static u3j_harm _140_hex_coed__ed_add_double_scalarmult_a[] = + {{".2", u3wee_add_double_scalarmult}, {}}; + static c3_c* _140_hex_coed__ed_add_double_scalarmult_ha[] = { + "0fab78a1e890e53cecade1c22b95813db77e066044e33417a0919695b6cde9ba", + 0 + }; + +static u3j_core _140_hex_coed__ed_d[] = + { { "sign", 7, _140_hex_coed__ed_sign_a, 0, no_hashes }, + { "sign-octs", 7, _140_hex_coed__ed_sign_octs_a, 0, _140_hex_coed__ed_sign_octs_ha }, + { "puck", 7, _140_hex_coed__ed_puck_a, 0, _140_hex_coed__ed_puck_ha }, + { "veri", 7, _140_hex_coed__ed_veri_a, 0, no_hashes }, + { "veri-octs", 7, _140_hex_coed__ed_veri_octs_a, 0, _140_hex_coed__ed_veri_octs_ha }, + { "shar", 7, _140_hex_coed__ed_shar_a, 0, _140_hex_coed__ed_shar_ha }, + { "point-add", 7, _140_hex_coed__ed_point_add_a, 0, 0 }, + { "scalarmult", 7, _140_hex_coed__ed_scalarmult_a, 0, + _140_hex_coed__ed_scalarmult_ha }, + { "scalarmult-base", 7, _140_hex_coed__ed_scalarmult_base_a, 0, + _140_hex_coed__ed_scalarmult_base_ha }, + { "add-scalarmult-scalarmult-base", 7, + _140_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0, + _140_hex_coed__ed_add_scalarmult_scalarmult_base_ha }, + { "add-double-scalarmult", 7, + _140_hex_coed__ed_add_double_scalarmult_a, 0, + _140_hex_coed__ed_add_double_scalarmult_ha }, + {} + }; +static c3_c* _140_hex_coed__ed_ha[] = { + "7a44a962aa72933588b5c99a8b68ebac21ce3c4710c081cb66b3599b45af9ced", + 0 +}; + +static u3j_core _140_hex_coed_d[] = +{ { "ed", 3, 0, _140_hex_coed__ed_d, _140_hex_coed__ed_ha }, + {} +}; +static c3_c* _140_hex_coed_ha[] = { + "4be0254f06d953b69509eb15550595ffad8767d3c3dc2dafcd7c22f92f7704c4", + 0 +}; + + static u3j_harm _140_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}}; + static c3_c* _140_hex_hmac_hmac_ha[] = { + "d0dbd778156aef21d18f44a8cffd87296826120af5a4af020dd7aff0f95f03b1", + 0 + }; +static u3j_core _140_hex_hmac_d[] = + { { "hmac", 7, _140_hex_hmac_hmac_a, 0, _140_hex_hmac_hmac_ha }, + {} + }; +static c3_c* _140_hex_hmac_ha[] = { + "976bb4508dbe659eb12aa32d4a481dbd885e40f8a15c505762f1acf43b744234", + 0 +}; + + static u3j_harm _140_hex_argon2_a[] = {{".2", u3we_argon2}, {}}; + static c3_c* _140_hex_argon2_ha[] = { + "4df7cec141ffa2cc76b058846474ca42cc9840666ee3e7e80e565803e83ea98b", + 0 + }; +static u3j_core _140_hex_argon_d[] = + { { "argon2", 511, _140_hex_argon2_a, 0, _140_hex_argon2_ha }, + {} + }; +static c3_c* _140_hex_argon_ha[] = { + "dc704c786192ecd09d4c206a8f28db3202b6e0eb03e3ce63a95987510ac312d6", + 0 +}; + + static u3j_harm _140_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}}; + static c3_c* _140_hex_scr_pbk_ha[] = { 0 }; + static u3j_harm _140_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}}; + static c3_c* _140_hex_scr_pbl_ha[] = { 0 }; + static u3j_harm _140_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}}; + static c3_c* _140_hex_scr_hsh_ha[] = { 0 }; + static u3j_harm _140_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}}; + static c3_c* _140_hex_scr_hsl_ha[] = { 0 }; +static u3j_core _140_hex_scr_d[] = + { { "pbk", 7, _140_hex_scr_pbk_a, 0, _140_hex_scr_pbk_ha }, + { "pbl", 7, _140_hex_scr_pbl_a, 0, _140_hex_scr_pbl_ha }, + { "hsh", 7, _140_hex_scr_hsh_a, 0, _140_hex_scr_hsh_ha }, + { "hsl", 7, _140_hex_scr_hsl_a, 0, _140_hex_scr_hsl_ha }, + {} + }; +static c3_c* _140_hex_scr_ha[] = { 0 }; + + static u3j_harm _140_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}}; + static c3_c* _140_hex_secp_secp256k1_make_ha[] = { 0 }; + static u3j_harm _140_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}}; + static c3_c* _140_hex_secp_secp256k1_sign_ha[] = { 0 }; + static u3j_harm _140_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}}; + static c3_c* _140_hex_secp_secp256k1_reco_ha[] = { 0 }; + + static u3j_harm _140_hex_secp_secp256k1_schnorr_sosi_a[] = + {{".2", u3we_sosi}, {}}; + static c3_c* _140_hex_secp_secp256k1_schnorr_sosi_ha[] = { 0 }; + static u3j_harm _140_hex_secp_secp256k1_schnorr_sove_a[] = + {{".2", u3we_sove}, {}}; + static c3_c* _140_hex_secp_secp256k1_schnorr_sove_ha[] = { 0 }; + static u3j_core _140_hex_secp_secp256k1_schnorr_d[] = + { { "sosi", 7, + _140_hex_secp_secp256k1_schnorr_sosi_a, 0, + _140_hex_secp_secp256k1_schnorr_sosi_ha }, + { "sove", 7, + _140_hex_secp_secp256k1_schnorr_sove_a, 0, + _140_hex_secp_secp256k1_schnorr_sove_ha }, + {} + }; + static c3_c* _140_hex_secp_secp256k1_schnorr_ha[] = { 0 }; + + static u3j_core _140_hex_secp_secp256k1_d[] = + { { "make", 7, _140_hex_secp_secp256k1_make_a, 0, _140_hex_secp_secp256k1_make_ha }, + { "sign", 7, _140_hex_secp_secp256k1_sign_a, 0, _140_hex_secp_secp256k1_sign_ha }, + { "reco", 7, _140_hex_secp_secp256k1_reco_a, 0, _140_hex_secp_secp256k1_reco_ha }, + { "schnorr", 7, 0, + _140_hex_secp_secp256k1_schnorr_d, + _140_hex_secp_secp256k1_schnorr_ha }, + {} + }; + static c3_c* _140_hex_secp_secp256k1_ha[] = { + "e7fc0971a970aba7ded43bd89e9c82623eb2f346c9c720c63b22f2a646927861", + 0 + }; +static u3j_core _140_hex_secp_d[] = + { { "secp256k1", 3, 0, _140_hex_secp_secp256k1_d, _140_hex_secp_secp256k1_ha }, + {} + }; +static c3_c* _140_hex_secp_ha[] = { + "9f5c23f0e7923b6cf1603388ba52401b6e43881be3560b3acfaab20b25071792", + 0 +}; + + static u3j_harm _140_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}}; + +static u3j_core _140_hex_blake_d[] = + { { "blake2b", 7, _140_hex_blake2b_a, 0, no_hashes }, + {} + }; +static c3_c* _140_hex_blake_ha[] = { + "ff30d99ffb3e13d8aa50b2b8461c8edfabf0e76de22312d16d1d6daaf3636b5f", + 0 +}; + + static u3j_harm _140_hex_kecc_k224_a[] = + {{".2", u3we_kecc224, c3y, c3y, c3y}, {}}; + static u3j_harm _140_hex_kecc_k256_a[] = + {{".2", u3we_kecc256, c3y, c3y, c3y}, {}}; + static u3j_harm _140_hex_kecc_k384_a[] = + {{".2", u3we_kecc384, c3y, c3y, c3y}, {}}; + static u3j_harm _140_hex_kecc_k512_a[] = + {{".2", u3we_kecc512, c3y, c3y, c3y}, {}}; +static u3j_core _140_hex_kecc_d[] = + { { "k224", 7, _140_hex_kecc_k224_a, 0, no_hashes }, + { "k256", 7, _140_hex_kecc_k256_a, 0, no_hashes }, + { "k384", 7, _140_hex_kecc_k384_a, 0, no_hashes }, + { "k512", 7, _140_hex_kecc_k512_a, 0, no_hashes }, + {} + }; + + static u3j_harm _140_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}}; + static c3_c* _140_hex_ripemd_160_ha[] = { + "176684b29926a01f5c60fa584e4691b0cbdc9b93608dcbe7d0cf3585683fa42f", + 0 + }; +static u3j_core _140_hex_ripe_d[] = + { { "ripemd160", 7, _140_hex_ripemd_160_a, 0, _140_hex_ripemd_160_ha }, + {} + }; +static c3_c* _140_hex_ripe_ha[] = { + "b0cb16bf206c0496bb480e5759ea1afa7dee1748b64e5243c23fddb09720ebd0", + 0 +}; + +static u3j_core _140_hex_d[] = +{ { "lore", 63, _140_hex_lore_a, 0, _140_hex_lore_ha }, + { "leer", 63, _140_hex_leer_a, 0, _140_hex_leer_ha }, + { "loss", 63, _140_hex_loss_a, 0, _140_hex_loss_ha }, + { "lune", 127, _140_hex_lune_a, 0, _140_hex_lune_ha }, + + { "coed", 63, 0, _140_hex_coed_d, _140_hex_coed_ha }, + { "aes", 31, 0, _140_hex_aes_d, _140_hex_aes_ha }, + + { "hmac", 63, 0, _140_hex_hmac_d, _140_hex_hmac_ha }, + { "argon", 31, 0, _140_hex_argon_d, _140_hex_argon_ha }, + { "blake", 31, 0, _140_hex_blake_d, _140_hex_blake_ha }, + { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _140_hex_ripe_d, _140_hex_ripe_ha }, + { "scr", 31, 0, _140_hex_scr_d, _140_hex_scr_ha }, + { "secp", 6, 0, _140_hex_secp_d, _140_hex_secp_ha }, + { "mimes", 31, 0, _140_hex_mimes_d, _140_hex_mimes_ha }, + {} +}; +static c3_c* _140_hex_ha[] = { + "7e393356dd7ac64eed5cd9f5cf0e320d401ca36a0a0ce0f954e7538824114844", + 0 +}; + + +/* layer five +*/ +static u3j_harm _140_pen_cell_a[] = {{".2", u3wf_cell}, {}}; +static c3_c* _140_pen_cell_ha[] = { + "411649e69ff5c5d4a2976b300d213b99af3de724cec0e95f48404b808fc4f428", + 0 +}; +static u3j_harm _140_pen_comb_a[] = {{".2", u3wf_comb}, {}}; +static c3_c* _140_pen_comb_ha[] = { + "f9e37c3b3d5036c31af60f7047391594068638b54db7cf94bfea9dabbdffa547", + 0 +}; +static u3j_harm _140_pen_cons_a[] = {{".2", u3wf_cons}, {}}; +static c3_c* _140_pen_cons_ha[] = { + "b698cc6bc49ea0473e344c784075e99a433b4c5738f90fc58ab17c3eaa44b2e9", + 0 +}; +static u3j_harm _140_pen_core_a[] = {{".2", u3wf_core}, {}}; +static c3_c* _140_pen_core_ha[] = { + "1180e9371cf3465783ef192f9a7f580cd90533f5b52b77b456287f1d580a3535", + 0 +}; +static u3j_harm _140_pen_face_a[] = {{".2", u3wf_face}, {}}; +static c3_c* _140_pen_face_ha[] = { + "a184c44d57f5c94b84a3258b05bf891f3c96a4a4bbff3a8934d11cad0efa81d8", + 0 +}; +static u3j_harm _140_pen_fitz_a[] = {{".2", u3wf_fitz}, {}}; +static c3_c* _140_pen_fitz_ha[] = { + "469abe976ec15eeff9a87bce385f2c87c9bd89814ce2858aa9fee094beea1e5d", + 0 +}; +static u3j_harm _140_pen_flan_a[] = {{".2", u3wf_flan_139}, {}}; +static c3_c* _140_pen_flan_ha[] = { + "cc00cb9373b0274af4e17d7acd77f65d8a2fa886e422c949c12d9d9e7cb3525b", + 0 +}; +static u3j_harm _140_pen_flip_a[] = {{".2", u3wf_flip_139}, {}}; +static c3_c* _140_pen_flip_ha[] = { + "6e97fab9d039e715a30af5da93ef97389babfdcae7ef87655d278e77a1af0f0c", + 0 +}; +static u3j_harm _140_pen_flor_a[] = {{".2", u3wf_flor_139}, {}}; +static c3_c* _140_pen_flor_ha[] = { + "ab5360aacf0c9a325727e90e1caea9c42f5d94ccc248c9e1f253b0922b4c4e63", + 0 +}; +static u3j_harm _140_pen_fork_a[] = {{".2", u3wf_fork}, {}}; +static c3_c* _140_pen_fork_ha[] = { + "36f0ea0e2eb30328b8b83ed43a81c8c9a1f5b4c5a03fd68fd25701991a40b9dd", + 0 +}; + +static u3j_harm _140_pen_look_a[] = {{".2", u3wf_look}, {}}; +static c3_c* _140_pen_look_ha[] = { + "fdda2166a2b9e1a9bda6ab375dd6fb6c610e18f54636a5e89896b45fd0a7169b", + 0 +}; +static u3j_harm _140_pen_loot_a[] = {{".2", u3wf_loot}, {}}; +static c3_c* _140_pen_loot_ha[] = { + "e275da4562ae6da9bd333aeae6b9829e886874c8b891898c0ef5306268eb45c1", + 0 +}; + + static u3j_harm _140_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}}; + static c3_c* _140_pen__ut_crop_ha[] = { + "e2c6fc3e714a3a98ccd28423dcb9f2c6480935e26b54dd0581eb2ad7e5b16d6f", + 0 + }; + static u3j_harm _140_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}}; + static c3_c* _140_pen__ut_fish_ha[] = { + "080caee60b5ee4616bf9568bdbceabbf044379c47466e0ae3968cb0146049a84", + 0 + }; + static u3j_harm _140_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}}; + static c3_c* _140_pen__ut_fuse_ha[] = { + "519aac7b40b7018d5df00ddf3977c2ebe0c2e05bcee34796d56a1d54c15e0c84", + 0 + }; + static u3j_harm _140_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}}; + static c3_c* _140_pen__ut_mint_ha[] = { + "7d980f7425b51bb10fbbd8b465b5d83f5dd4cb6e66d88758a9f7490b812a765e", + 0 + }; + static u3j_harm _140_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}}; + static c3_c* _140_pen__ut_mull_ha[] = { + "c806329aefd920501ea0faa0cfb0ce3280a74408782efe6d82878ec43ec44fb7", + 0 + }; + + static u3j_harm _140_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}}; + static c3_c* _140_pen__ut_nest_dext_ha[] = { + "72f33df96800034fc63531293f9b110e6505027195bf8a10ff94b9a1f1ef719b", + 0 + }; + static u3j_core _140_pen__ut_nest_in_d[] = + { + { "nest-dext", 3, _140_pen__ut_nest_dext_a, 0, _140_pen__ut_nest_dext_ha }, + {} + }; + static c3_c* _140_pen__ut_nest_in_ha[] = { + "68378dfa1d1fee0b1cd9593fb561234cec2ae9371a5ffa287c3d2ab9620e198c", + 0 + }; + static u3j_core _140_pen__ut_nest_d[] = + { + { "nest-in", 7, 0, _140_pen__ut_nest_in_d, _140_pen__ut_nest_in_ha }, + {} + }; + static c3_c* _140_pen__ut_nest_ha[] = { + "1e8de5d1225facc1158c92c2ea5e0dc84129cbb317fde3691e224b8c2550d950", + 0 + }; + + static u3j_harm _140_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}}; + static c3_c* _140_pen__ut_rest_ha[] = { + "b4a83073f4cb03898ef099fab5722a046122dc96a5332ffc82f988df6c186e74", + 0 + }; + +static u3j_core _140_pen__ut_d[] = + { + { "crop", 7, _140_pen__ut_crop_a, 0, _140_pen__ut_crop_ha }, + { "fish", 7, _140_pen__ut_fish_a, 0, _140_pen__ut_fish_ha }, + { "fuse", 7, _140_pen__ut_fuse_a, 0, _140_pen__ut_fuse_ha }, + { "mint", 7, _140_pen__ut_mint_a, 0, _140_pen__ut_mint_ha }, + { "mull", 7, _140_pen__ut_mull_a, 0, _140_pen__ut_mull_ha }, + { "nest", 7, 0, _140_pen__ut_nest_d, _140_pen__ut_nest_ha }, + { "rest", 7, _140_pen__ut_rest_a, 0, _140_pen__ut_rest_ha }, + {} + }; +static c3_c* _140_pen__ut_ha[] = { + "50c79204c82a3ba8f01e085a2e27e7716e5c7ab1929f94423ef1da92cf5ac631", + 0 +}; + +static u3j_hood _140_pen__ut_ho[] = + { { "ar", 12282 }, + { "fan", 28, c3n }, + { "rib", 58, c3n }, + { "vet", 59, c3n }, + + { "blow", 6015 }, + { "burp", 342 }, + { "busk", 1373 }, + { "buss", 374 }, + { "crop", 1494 }, + { "duck", 1524 }, + { "dune", 2991 }, + { "dunk", 3066 }, + { "epla", 12206 }, + { "emin", 1534 }, + { "emul", 6134 }, + { "feel", 1502 }, + { "felt", 94 }, + { "fine", 49086 }, + { "fire", 4 }, + { "fish", 6006 }, + { "fond", 12283 }, + { "fund", 6014 }, + // XX +funk is not part of +ut, and this hook appears to be unused + // remove from here and the +ut hint + // + { "funk", 0xbefafa, c3y, 31 }, + { "fuse", 24021 }, + { "gain", 380 }, + { "lose", 0x2fefe }, + { "mile", 382 }, + { "mine", 372 }, + { "mint", 49083 }, + { "moot", 0x2feff }, + { "mull", 24020 }, + { "nest", 92 }, + { "peel", 1526 }, + { "play", 3006 }, + { "peek", 1532 }, + { "repo", 22 }, + { "rest", 6102 }, + { "tack", 6007 }, + { "toss", 24540 }, + { "wrap", 6140 }, + {}, + }; + +static u3j_core _140_pen_d[] = +{ { "hex", 7, 0, _140_hex_d, _140_hex_ha }, + + { "cell", 7, _140_pen_cell_a, 0, _140_pen_cell_ha }, + { "comb", 7, _140_pen_comb_a, 0, _140_pen_comb_ha }, + { "cons", 7, _140_pen_cons_a, 0, _140_pen_cons_ha }, + { "core", 7, _140_pen_core_a, 0, _140_pen_core_ha }, + { "face", 7, _140_pen_face_a, 0, _140_pen_face_ha }, + { "fitz", 7, _140_pen_fitz_a, 0, _140_pen_fitz_ha }, + { "flan", 7, _140_pen_flan_a, 0, _140_pen_flan_ha }, + { "flip", 7, _140_pen_flip_a, 0, _140_pen_flip_ha }, + { "flor", 7, _140_pen_flor_a, 0, _140_pen_flor_ha }, + { "fork", 7, _140_pen_fork_a, 0, _140_pen_fork_ha }, + { "look", 7, _140_pen_look_a, 0, _140_pen_look_ha }, + { "loot", 7, _140_pen_loot_a, 0, _140_pen_loot_ha }, + { "ut", 15, 0, _140_pen__ut_d, _140_pen__ut_ha, _140_pen__ut_ho }, + {} +}; +static c3_c* _140_pen_ha[] = { + "e6c9e2362bdf2d1f9a2837a0efa154c0b8b9d51aea03a86b5aece573ff423cb1", + 0 +}; + +static u3j_hood _140_pen_ho[] = { + { "ap", 22 }, + { "ut", 86 }, + {}, +}; + + +/* layer four +*/ +static u3j_harm _140_qua_trip_a[] = {{".2", u3we_trip}, {}}; +static c3_c* _140_qua_trip_ha[] = { + "05423b940d10d03891cc23f36eea14b233e5884ef539de3d985d6818dd427b05", + 0 +}; + +static u3j_harm _140_qua_slaw_a[] = {{".2", u3we_slaw}, {}}; +static c3_c* _140_qua_slaw_ha[] = { + "306c9692f48e2700675ed6581e9df4feaee951e1bed3cad7f89aab392e80000f", + 0 +}; +static u3j_harm _140_qua_scot_a[] = {{".2", u3we_scot}, {}}; +static c3_c* _140_qua_scot_ha[] = { + 0 +}; +static u3j_harm _140_qua_scow_a[] = {{".2", u3we_scow}, {}}; +static c3_c* _140_qua_scow_ha[] = { + 0 +}; + + static u3j_harm _140_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}}; + static c3_c* _140_qua__po_ind_ha[] = { + "95bbe9867dbbd1b9ce12671d64cf7b1dee8d987c6770955a83c73291c4537a61", + 0 + }; + static u3j_harm _140_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}}; + static c3_c* _140_qua__po_ins_ha[] = { + "aae783fb258dff7f8ade49756e01f96a2d2100411a88a886732270dcf9f174f0", + 0 + }; + static u3j_harm _140_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}}; + static c3_c* _140_qua__po_tod_ha[] = { + "153aeba45ca2a87aa918e9cea1b26e8104a6e4395979257b075546c1e2654a17", + 0 + }; + static u3j_harm _140_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}}; + static c3_c* _140_qua__po_tos_ha[] = { + "7c5ffad03bcf8b4ea9bdf0c7f7500351923bc0431f3d62d6ce0472790f668fb4", + 0 + }; +static u3j_core _140_qua__po_d[] = + { { "ind", 7, _140_qua__po_ind_a, 0, _140_qua__po_ind_ha }, + { "ins", 7, _140_qua__po_ins_a, 0, _140_qua__po_ins_ha }, + { "tod", 7, _140_qua__po_tod_a, 0, _140_qua__po_tod_ha }, + { "tos", 7, _140_qua__po_tos_a, 0, _140_qua__po_tos_ha }, + {} + }; +static c3_c* _140_qua__po_ha[] = { + "efc5fa7c0efedd490e9a270bb5cf9f90809e6b224f8a381a6b8a481253b237a1", + 0 +}; + + static u3j_harm _140_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}}; + static c3_c* _140_qua__bend_fun_ha[] = { + "e6ea05e3d765a005fccde9eb88fb93e06f0b6ea198afa8ed599b056ba179396a", + 0 + }; +static u3j_core _140_qua__bend_d[] = + { { "fun", 7, _140_qua__bend_fun_a, 0, _140_qua__bend_fun_ha }, + {} + }; +static c3_c* _140_qua__bend_ha[] = { + "adc59c6db6d5b26122bc6c04e25c3efe830c9eef68ecf81c492a59ee5e9e20a2", + 0 +}; + + static u3j_harm _140_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}}; + static c3_c* _140_qua__cold_fun_ha[] = { + "ad5a0ab7405be9ffda0a9dd34580c6039f6bbb0301920fb2df0c31be3c72c58e", + 0 + }; +static u3j_core _140_qua__cold_d[] = + { { "fun", 7, _140_qua__cold_fun_a, 0, _140_qua__cold_fun_ha }, + {} + }; +static c3_c* _140_qua__cold_ha[] = { + "06c49d8dab6cb057e3ae1d1164e96950944ea48e54ad72347239ea434f1d4b9c", + 0 +}; + + static u3j_harm _140_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}}; + static c3_c* _140_qua__cook_fun_ha[] = { + "f2a45612ad9c279b723334ab0915d3ed3ece7727309968c2555f45e0668eeb27", + 0 + }; +static u3j_core _140_qua__cook_d[] = + { { "fun", 7, _140_qua__cook_fun_a, 0, _140_qua__cook_fun_ha }, + {} + }; +static c3_c* _140_qua__cook_ha[] = { + "3ccd46dd21828d7be11f8c093536e305b1df982393a69c40ea73f63a574b3bb1", + 0 +}; + + static u3j_harm _140_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}}; + static c3_c* _140_qua__comp_fun_ha[] = { + "bd7fdba84b05b00a63c24d19a03b882578ee9a3b922a3a688f7827c6e64daf96", + 0 + }; +static u3j_core _140_qua__comp_d[] = + { { "fun", 7, _140_qua__comp_fun_a, 0, _140_qua__comp_fun_ha }, + {} + }; +static c3_c* _140_qua__comp_ha[] = { + "7baad25ba87bcbba8ce4fe328280a799765dcf62a8bb761ffd87b939dd8734f2", + 0 +}; + + static u3j_harm _140_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}}; + static c3_c* _140_qua__easy_fun_ha[] = { + "4bbbc43ece463d961e572301d0824d3e3cab3ba09ec2756cbefae63ee106044b", + 0 + }; +static u3j_core _140_qua__easy_d[] = + { { "fun", 7, _140_qua__easy_fun_a, 0, _140_qua__easy_fun_ha }, + {} + }; +static c3_c* _140_qua__easy_ha[] = { + "fdcf833943e24323deb6b071497498933ce6c4ba7d4742f2752b6ddb7fb9634e", + 0 +}; + + static u3j_harm _140_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}}; + static c3_c* _140_qua__glue_fun_ha[] = { + "ffe0fe8815a2298c51a58e963efbbb7af90830abf11ce50bf9a47f479ce452fb", + 0 + }; +static u3j_core _140_qua__glue_d[] = + { { "fun", 7, _140_qua__glue_fun_a, 0, _140_qua__glue_fun_ha }, + {} + }; +static c3_c* _140_qua__glue_ha[] = { + "079c8a395428c2921b266a84bcf271fbe62f3d873b26680661e13a78df1a3989", + 0 +}; + + static u3j_harm _140_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}}; + static c3_c* _140_qua__here_fun_ha[] = { + "47ec445fcfa89d266dae3c3590ed041d1b05f92d1bce360f232da5d496e4f2eb", + 0 + }; +static u3j_core _140_qua__here_d[] = + { { "fun", 7, _140_qua__here_fun_a, 0, _140_qua__here_fun_ha }, + {} + }; +static c3_c* _140_qua__here_ha[] = { + "4600093be5becba9a65a14b67624e3d9e4c66e0c97ba57b2bc271907eea32ffe", + 0 +}; + + static u3j_harm _140_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}}; + static c3_c* _140_qua__just_fun_ha[] = { + "38bf1fb843bc29837868f2828f32d7e2bbb419b0cb9a1236adea28dfc6ce1040", + 0 + }; +static u3j_core _140_qua__just_d[] = + { { "fun", 7, _140_qua__just_fun_a, 0, _140_qua__just_fun_ha }, + {} + }; +static c3_c* _140_qua__just_ha[] = { + "7d6b2165e52dec478d96cf72478a35b7a92b014e6a15f046f026c0c8cb07679b", + 0 +}; + + static u3j_harm _140_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}}; + static c3_c* _140_qua__mask_fun_ha[] = { + "892dfcd5f3d90981fa6e7608e93f0517000d316e7d9c07b3bd390c4966c97f5f", + 0 + }; +static u3j_core _140_qua__mask_d[] = + { { "fun", 7, _140_qua__mask_fun_a, 0, _140_qua__mask_fun_ha }, + {} + }; +static c3_c* _140_qua__mask_ha[] = { + "48e11fc12d7c453cda6ca42577d68e968446aa4d0ad3b99cc674affc7f4507b4", + 0 +}; + + static u3j_harm _140_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}}; + static c3_c* _140_qua__shim_fun_ha[] = { + "4e26a0e98adb13ee6718fd68d90910c630df9bb7023b3e3ef40cda6710075fc9", + 0 + }; +static u3j_core _140_qua__shim_d[] = + { { "fun", 7, _140_qua__shim_fun_a, 0, _140_qua__shim_fun_ha }, + {} + }; +static c3_c* _140_qua__shim_ha[] = { + "226b96d1a59daada23a1ea80227c2dbf32ddd748d4c6363f316147ab7f292ced", + 0 +}; + + static u3j_harm _140_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}}; + static c3_c* _140_qua__stag_fun_ha[] = { + "f76c7205c23e77809af793bc506f4727071fd029d234317fe78a7f65e2b7d6ea", + 0 + }; +static u3j_core _140_qua__stag_d[] = + { { "fun", 7, _140_qua__stag_fun_a, 0, _140_qua__stag_fun_ha }, + {} + }; +static c3_c* _140_qua__stag_ha[] = { + "fc978af18fb13dc0d77501b6f3eeb538b079b4345eb9195c3dd44c516e69424a", + 0 +}; + + static u3j_harm _140_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}}; + static c3_c* _140_qua__stew_fun_ha[] = { + "a700f6bdfdb83ba33b2a3fe92fda3cb1bbfe95e595401538c8371b55fcc61447", + 0 + }; +static u3j_core _140_qua__stew_d[] = + { { "fun", 31, _140_qua__stew_fun_a, 0, _140_qua__stew_fun_ha }, + {} + }; +static c3_c* _140_qua__stew_ha[] = { + "29303fd6ab78cbbccdfc5bcf23d0bff126a0ef2bf4fa11ce70fcf4e6aa5fe60b", + 0 +}; + + static u3j_harm _140_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}}; + static c3_c* _140_qua__stir_fun_ha[] = { + "6251308ea3c741e76ef9cb2dc5a71c9d8706d6cce6fdb420fef12915e0c032d6", + 0 + }; +static u3j_core _140_qua__stir_d[] = + { { "fun", 7, _140_qua__stir_fun_a, 0, _140_qua__stir_fun_ha }, + {} + }; +static c3_c* _140_qua__stir_ha[] = { + "4e466aef4d91f0ced008c00e8a4330afb3a43ef81dc1a6d93f1853685f69b9ca", + 0 +}; + +static u3j_harm _140_qua_pfix_a[] = {{".2", u3we_pfix}, {}}; +static c3_c* _140_qua_pfix_ha[] = { + "f7019bccc8b3b04a969878ffed84c9eba4dfa60ee32f984119cacb0c2381656b", + 0 +}; + +static u3j_harm _140_qua_plug_a[] = {{".2", u3we_plug}, {}}; +static c3_c* _140_qua_plug_ha[] = { + "5f5a9824e0952fd565748cc0a20f96cf883a41e2f5707c8a7797e6edd617b79c", + 0 +}; +static u3j_harm _140_qua_pose_a[] = {{".2", u3we_pose}, {}}; +static c3_c* _140_qua_pose_ha[] = { + "5c77203f288ef0f7bcd87871c69673db7fc804b647ecc42992707dc32f0f4611", + 0 +}; + +static u3j_harm _140_qua_sfix_a[] = {{".2", u3we_sfix}, {}}; +static c3_c* _140_qua_sfix_ha[] = { + "00987ed37104b902c5264d4d013826d762bfa80a6b29cfe4b7fa61b1ddd9cfac", + 0 +}; + +static u3j_harm _140_qua_mink_a[] = {{".2", u3we_mink}, {}}; +static c3_c* _140_qua_mink_ha[] = { + "99b653da6a21fa3375424811af288f59164592ece4a072abc460df03e81abcaf", + 0 +}; +static u3j_harm _140_qua_mole_a[] = {{".2", u3we_mole}, {}}; +static c3_c* _140_qua_mole_ha[] = { + "029c1acaff1911c54ce31a3693397394604ea970bf076078c1a1cfa23d2fa74e", + 0 +}; +static u3j_harm _140_qua_mule_a[] = {{".2", u3we_mule}, {}}; +static c3_c* _140_qua_mule_ha[] = { + "d54688d726565ddade7f2636741cad7209ea40fab28d3335555d8a02ff6001c4", + 0 +}; + +static u3j_core _140_qua_d[] = +{ { "pen", 3, 0, _140_pen_d, _140_pen_ha, _140_pen_ho }, + + { "po", 7, 0, _140_qua__po_d, _140_qua__po_ha }, + + { "trip", 7, _140_qua_trip_a, 0, _140_qua_trip_ha }, + + { "bend", 7, 0, _140_qua__bend_d, _140_qua__bend_ha }, + { "cold", 7, 0, _140_qua__cold_d, _140_qua__cold_ha }, + { "comp", 7, 0, _140_qua__comp_d, _140_qua__comp_ha }, + { "cook", 7, 0, _140_qua__cook_d, _140_qua__cook_ha }, + { "easy", 7, 0, _140_qua__easy_d, _140_qua__easy_ha }, + { "glue", 7, 0, _140_qua__glue_d, _140_qua__glue_ha }, + { "here", 7, 0, _140_qua__here_d, _140_qua__here_ha }, + { "just", 7, 0, _140_qua__just_d, _140_qua__just_ha }, + { "mask", 7, 0, _140_qua__mask_d, _140_qua__mask_ha }, + { "shim", 7, 0, _140_qua__shim_d, _140_qua__shim_ha }, + { "stag", 7, 0, _140_qua__stag_d, _140_qua__stag_ha }, + { "stew", 7, 0, _140_qua__stew_d, _140_qua__stew_ha }, + { "stir", 7, 0, _140_qua__stir_d, _140_qua__stir_ha }, + + { "pfix", 7, _140_qua_pfix_a, 0, _140_qua_pfix_ha }, + { "plug", 7, _140_qua_plug_a, 0, _140_qua_plug_ha }, + { "pose", 7, _140_qua_pose_a, 0, _140_qua_pose_ha }, + { "sfix", 7, _140_qua_sfix_a, 0, _140_qua_sfix_ha }, + + { "mink", 7, _140_qua_mink_a, 0, _140_qua_mink_ha }, + { "mole", 7, _140_qua_mole_a, 0, _140_qua_mole_ha }, + { "mule", 7, _140_qua_mule_a, 0, _140_qua_mule_ha }, + + { "scot", 7, _140_qua_scot_a, 0, _140_qua_scot_ha }, + { "scow", 7, _140_qua_scow_a, 0, _140_qua_scow_ha }, + { "slaw", 7, _140_qua_slaw_a, 0, _140_qua_slaw_ha }, + {} +}; +static c3_c* _140_qua_ha[] = { + "db9b4b21c0a8a8324105cbccc1421ef2a715ef0562c280b943fe1d96651cd9cc", + 0 +}; + +static u3j_hood _140_qua_ho[] = { + { "mute", 0x2fbabe }, + { "show", 24406 }, + { "mure", 1404 }, + {}, +}; + + +/* layer three +*/ + static u3j_harm _140_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}}; + static c3_c* _140_tri__cofl__drg_ha[] = { + "6063adb8cac639f7b20d5e7700c8108266be04f99cce4434f906240b424bf36d", + 0 + }; + static u3j_harm _140_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}}; + static c3_c* _140_tri__cofl__lug_ha[] = { + "f146a84731447e5c4b1e7b6e9331b33d1babed09bb0618e134c9535062154a87", + 0 + }; +static u3j_core _140_tri__cofl_d[] = + { { "drg", 7, _140_tri__cofl__drg_a, 0, _140_tri__cofl__drg_ha }, + { "lug", 7, _140_tri__cofl__lug_a, 0, _140_tri__cofl__lug_ha }, + {} + }; +static c3_c* _140_tri__cofl_ha[] = { + "f320c5bf51db85f55b900f4160f7e0ab9ef267f43ddb698900de034c6e2600d5", + 0 +}; + + static u3j_harm _140_tri__rd_add_a[] = {{".2", u3wer_add}, {}}; + static c3_c* _140_tri__rd_add_ha[] = { + "90dfaaadb2878d6d89a808ce4199e5bb239fa981e1c2edf24dc54aa3fcab55a5", + 0 + }; + static u3j_harm _140_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}}; + static c3_c* _140_tri__rd_sub_ha[] = { + "5898a2424ba815d66d83917953f01860e63207f4200a447f632d9a5cc77a8a9c", + 0 + }; + static u3j_harm _140_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}}; + static c3_c* _140_tri__rd_mul_ha[] = { + "a3af44ef4cd89afe78f1088bddb7d56dfa7fc209153256557c98ff34b67976bc", + 0 + }; + static u3j_harm _140_tri__rd_div_a[] = {{".2", u3wer_div}, {}}; + static c3_c* _140_tri__rd_div_ha[] = { + "9be3b38b9b4b0b0cd0bb060529c8f439cb0589aa9c3528efc519fbcc6845e98d", + 0 + }; + static u3j_harm _140_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}}; + static c3_c* _140_tri__rd_sqt_ha[] = { + "0413678ac8ec89c3425ba762cd24b2a8a455543ec9b5dd719524e6b834e0c99c", + 0 + }; + static u3j_harm _140_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}}; + static c3_c* _140_tri__rd_fma_ha[] = { + "7c920238dd42fb645c057cc950ed7ece775d5f502a0faf6ef5d17d348e0fc3e3", + 0 + }; + static u3j_harm _140_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}}; + static c3_c* _140_tri__rd_lth_ha[] = { + "a108f1ac15c1d4e2c86457c9afc97a97a5954003c709c3c19c722b37255bcba9", + 0 + }; + static u3j_harm _140_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}}; + static c3_c* _140_tri__rd_lte_ha[] = { + "ef9a6b2c5cdd0d4de550a32679d242693131cdc3cf40ac914eadfa7d6d9f1bac", + 0 + }; + static u3j_harm _140_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}}; + static c3_c* _140_tri__rd_equ_ha[] = { + "c93cdb951dca3b0ac61070780f95e1baa3718fe519d0268305c032cf14a21e39", + 0 + }; + static u3j_harm _140_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}}; + static c3_c* _140_tri__rd_gte_ha[] = { + "6857077d97e2fc203b555dc20748c33d34b694d33c48f628543bea6491e722a6", + 0 + }; + static u3j_harm _140_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}}; + static c3_c* _140_tri__rd_gth_ha[] = { + "87fd815913fa590c715d3a96ada5bae6298f3e7823af90ffcdf235f493c56330", + 0 + }; +static u3j_core _140_tri__rd_d[] = + { { "add", 7, _140_tri__rd_add_a, 0, _140_tri__rd_add_ha }, + { "sub", 7, _140_tri__rd_sub_a, 0, _140_tri__rd_sub_ha }, + { "mul", 7, _140_tri__rd_mul_a, 0, _140_tri__rd_mul_ha }, + { "div", 7, _140_tri__rd_div_a, 0, _140_tri__rd_div_ha }, + { "sqt", 7, _140_tri__rd_sqt_a, 0, _140_tri__rd_sqt_ha }, + { "fma", 7, _140_tri__rd_fma_a, 0, _140_tri__rd_fma_ha }, + { "lth", 7, _140_tri__rd_lth_a, 0, _140_tri__rd_lth_ha }, + { "lte", 7, _140_tri__rd_lte_a, 0, _140_tri__rd_lte_ha }, + { "equ", 7, _140_tri__rd_equ_a, 0, _140_tri__rd_equ_ha }, + { "gte", 7, _140_tri__rd_gte_a, 0, _140_tri__rd_gte_ha }, + { "gth", 7, _140_tri__rd_gth_a, 0, _140_tri__rd_gth_ha }, + {} + }; +static c3_c* _140_tri__rd_ha[] = { + "0afab285837f9c88faff3ac8f3f49b5e259da253e0505cd823a53d4e826261f7", + 0 +}; + + static u3j_harm _140_tri__rs_add_a[] = {{".2", u3wet_add}, {}}; + static c3_c* _140_tri__rs_add_ha[] = { + "b89a1e348628fd9b4fd520aabbf6c53e12be5bbf661b9094f7a9841be3f51de9", + 0 + }; + static u3j_harm _140_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}}; + static c3_c* _140_tri__rs_sub_ha[] = { + "9d13b86d17908830f93b920e80e1a985105583597f6fb640f175c98052e357f1", + 0 + }; + static u3j_harm _140_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}}; + static c3_c* _140_tri__rs_mul_ha[] = { + "5c61a9e335f6c139332523d871ca5773ab476365b623444370474fde08639061", + 0 + }; + static u3j_harm _140_tri__rs_div_a[] = {{".2", u3wet_div}, {}}; + static c3_c* _140_tri__rs_div_ha[] = { + "a7147a81be3ef5a1c0de6587edb2990e30057d7871d73632eabc8dc567e751c8", + 0 + }; + static u3j_harm _140_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}}; + static c3_c* _140_tri__rs_sqt_ha[] = { + "c403bb48d78bcfa9cd4128b7f9eb362e71e5269ab6578fb0bb5e70b4244c5781", + 0 + }; + static u3j_harm _140_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}}; + static c3_c* _140_tri__rs_fma_ha[] = { + "afc14914eb8f579a0c6620db69bc951329325747a8ef01c2d0e5feb29e9a9ddd", + 0 + }; + static u3j_harm _140_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}}; + static c3_c* _140_tri__rs_lth_ha[] = { + "e7efa422def6b6dbd25b5f664462adb3895b8b45f9531877c9dbfe40a96612bf", + 0 + }; + static u3j_harm _140_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}}; + static c3_c* _140_tri__rs_lte_ha[] = { + "b45e1ef16c47dc9b99865c7e75d4c2094c0e206ed538818a38da0adb7fbe2ce3", + 0 + }; + static u3j_harm _140_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}}; + static c3_c* _140_tri__rs_equ_ha[] = { + "8c1178311ded837292c297380e48cf7e0bc4d83962dadcafda0c9ef9f20e39f2", + 0 + }; + static u3j_harm _140_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}}; + static c3_c* _140_tri__rs_gte_ha[] = { + "50f5eb237b74e772eb6a3257441078461450cd4a25cf9bd97cb1a5e00f4ff4d2", + 0 + }; + static u3j_harm _140_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}}; + static c3_c* _140_tri__rs_gth_ha[] = { + "505842ff486f0bb8fa63f04d2fd6f806dc760f9b4a12a3bf2d57da92f560785b", + 0 + }; +static u3j_core _140_tri__rs_d[] = + { { "add", 7, _140_tri__rs_add_a, 0, _140_tri__rs_add_ha }, + { "sub", 7, _140_tri__rs_sub_a, 0, _140_tri__rs_sub_ha }, + { "mul", 7, _140_tri__rs_mul_a, 0, _140_tri__rs_mul_ha }, + { "div", 7, _140_tri__rs_div_a, 0, _140_tri__rs_div_ha }, + { "sqt", 7, _140_tri__rs_sqt_a, 0, _140_tri__rs_sqt_ha }, + { "fma", 7, _140_tri__rs_fma_a, 0, _140_tri__rs_fma_ha }, + { "lth", 7, _140_tri__rs_lth_a, 0, _140_tri__rs_lth_ha }, + { "lte", 7, _140_tri__rs_lte_a, 0, _140_tri__rs_lte_ha }, + { "equ", 7, _140_tri__rs_equ_a, 0, _140_tri__rs_equ_ha }, + { "gte", 7, _140_tri__rs_gte_a, 0, _140_tri__rs_gte_ha }, + { "gth", 7, _140_tri__rs_gth_a, 0, _140_tri__rs_gth_ha }, + {} + }; +static c3_c* _140_tri__rs_ha[] = { + "6c7027c5de34540a4b1548039e5423fb44727079af054b7135a3e961ec8dede8", + 0 +}; + + static u3j_harm _140_tri__rq_add_a[] = {{".2", u3weq_add}, {}}; + static c3_c* _140_tri__rq_add_ha[] = { + "9c4c2a37550930605495401886d41fb9fbc2eba487e0ba845130fe88e4c52a01", + 0 + }; + static u3j_harm _140_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}}; + static c3_c* _140_tri__rq_sub_ha[] = { + "f3b027090a1bb5af74234301facfbf64503b3e0599501ade12cb05aa158a79a3", + 0 + }; + static u3j_harm _140_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}}; + static c3_c* _140_tri__rq_mul_ha[] = { + "15c03b1f3081514c4767d86297aaebf1d62af7f3437f30821f011b17ed769f3a", + 0 + }; + static u3j_harm _140_tri__rq_div_a[] = {{".2", u3weq_div}, {}}; + static c3_c* _140_tri__rq_div_ha[] = { + "094105c77e37e548ea1b8d49a132ab97d90a0ab5f329340400c381bcd44de347", + 0 + }; + static u3j_harm _140_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}}; + static c3_c* _140_tri__rq_sqt_ha[] = { + "a031cd5b8e05f997323b0ca1ca9d2419401d7d2acc2da6fc6387fe57701b84b0", + 0 + }; + static u3j_harm _140_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}}; + static c3_c* _140_tri__rq_fma_ha[] = { + "871664a9305808a671aacf1de0e83f8e951611033170d86370352afb363b79bc", + 0 + }; + static u3j_harm _140_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}}; + static c3_c* _140_tri__rq_lth_ha[] = { + "b10822caa442c8e9f6b9eb52aac5796a42bed5ae0eef7fe49d4075b38bf78ddd", + 0 + }; + static u3j_harm _140_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}}; + static c3_c* _140_tri__rq_lte_ha[] = { + "3316346be3e9464fbb5b0feff16cd2252086004229d08f8eaa320f9509d6a029", + 0 + }; + static u3j_harm _140_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}}; + static c3_c* _140_tri__rq_equ_ha[] = { + "154be82a7b8ecf4571015d9ef6c0e90ffd8c3e8803441d9c2df5a4ea484ccf3b", + 0 + }; + static u3j_harm _140_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}}; + static c3_c* _140_tri__rq_gte_ha[] = { + "edbe94f9cfefa89deef7f6c11f4ce8240fd93970dbd6130e632d0447452a612a", + 0 + }; + static u3j_harm _140_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}}; + static c3_c* _140_tri__rq_gth_ha[] = { + "50e85936cfad61659ed1bfdab26fda2b2696571b9aa4b4c55dc5c0d919edc296", + 0 + }; +static u3j_core _140_tri__rq_d[] = + { { "add", 7, _140_tri__rq_add_a, 0, _140_tri__rq_add_ha }, + { "sub", 7, _140_tri__rq_sub_a, 0, _140_tri__rq_sub_ha }, + { "mul", 7, _140_tri__rq_mul_a, 0, _140_tri__rq_mul_ha }, + { "div", 7, _140_tri__rq_div_a, 0, _140_tri__rq_div_ha }, + { "sqt", 7, _140_tri__rq_sqt_a, 0, _140_tri__rq_sqt_ha }, + { "fma", 7, _140_tri__rq_fma_a, 0, _140_tri__rq_fma_ha }, + { "lth", 7, _140_tri__rq_lth_a, 0, _140_tri__rq_lth_ha }, + { "lte", 7, _140_tri__rq_lte_a, 0, _140_tri__rq_lte_ha }, + { "equ", 7, _140_tri__rq_equ_a, 0, _140_tri__rq_equ_ha }, + { "gte", 7, _140_tri__rq_gte_a, 0, _140_tri__rq_gte_ha }, + { "gth", 7, _140_tri__rq_gth_a, 0, _140_tri__rq_gth_ha }, + {} + }; +static c3_c* _140_tri__rq_ha[] = { + "b772cd5901a18dc91852fada74c2a1e4b1bbf4e7465451b0d8bdcc86d2288c22", + 0 +}; + + static u3j_harm _140_tri__rh_add_a[] = {{".2", u3wes_add}, {}}; + static c3_c* _140_tri__rh_add_ha[] = { + "7e2b600eced08d774800a6a3d82e18189db85010b870c26905ee38008d3d301e", + 0 + }; + static u3j_harm _140_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}}; + static c3_c* _140_tri__rh_sub_ha[] = { + "827dfb41660cb4743a88d921b4185bd2000ee6f0708ec36ac8aba2e4e19c0875", + 0 + }; + static u3j_harm _140_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}}; + static c3_c* _140_tri__rh_mul_ha[] = { + "ec2a010128aca0a6f74196f3de4fe7b6617fd810d3b19f7bf5878afb787e8b86", + 0 + }; + static u3j_harm _140_tri__rh_div_a[] = {{".2", u3wes_div}, {}}; + static c3_c* _140_tri__rh_div_ha[] = { + "067a3dafb0158bc2441729beb2c0934c6c6ccf0a9b5193db9c16f22b490b27c6", + 0 + }; + static u3j_harm _140_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}}; + static c3_c* _140_tri__rh_sqt_ha[] = { + "3fdbba47626d91d41fcdf460ad38018c78b0233d7ec4d0fac406a8c5357a2384", + 0 + }; + static u3j_harm _140_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}}; + static c3_c* _140_tri__rh_fma_ha[] = { + "ada2adf5a88ba61759219926aef950e72ae6926c6e10c30ecd0f9c99e79beca0", + 0 + }; + static u3j_harm _140_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}}; + static c3_c* _140_tri__rh_lth_ha[] = { + "70c9bc0073d23371d8155c28795f5acbff1a9504a5a3881c8693aa7c1f3d35d4", + 0 + }; + static u3j_harm _140_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}}; + static c3_c* _140_tri__rh_lte_ha[] = { + "6157e766050f9697c05b111ad2a582459a63a98b3b1ec70881f9ad943f951a0d", + 0 + }; + static u3j_harm _140_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}}; + static c3_c* _140_tri__rh_equ_ha[] = { + "72664392e2a00137383aa5a55e947c5e95c7b3172f71a7238dc0d55050196884", + 0 + }; + static u3j_harm _140_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}}; + static c3_c* _140_tri__rh_gte_ha[] = { + "145355b13712b9471031e755d0ab271907efdb9a287b1bacb2f1d0338d28dbf6", + 0 + }; + static u3j_harm _140_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}}; + static c3_c* _140_tri__rh_gth_ha[] = { + "d53219ee10acdd291a1e2b34fa5f543c780a0301357e93cfebd466e556f9824e", + 0 + }; +static u3j_core _140_tri__rh_d[] = + { { "add", 7, _140_tri__rh_add_a, 0, _140_tri__rh_add_ha }, + { "sub", 7, _140_tri__rh_sub_a, 0, _140_tri__rh_sub_ha }, + { "mul", 7, _140_tri__rh_mul_a, 0, _140_tri__rh_mul_ha }, + { "div", 7, _140_tri__rh_div_a, 0, _140_tri__rh_div_ha }, + { "sqt", 7, _140_tri__rh_sqt_a, 0, _140_tri__rh_sqt_ha }, + { "fma", 7, _140_tri__rh_fma_a, 0, _140_tri__rh_fma_ha }, + { "lth", 7, _140_tri__rh_lth_a, 0, _140_tri__rh_lth_ha }, + { "lte", 7, _140_tri__rh_lte_a, 0, _140_tri__rh_lte_ha }, + { "equ", 7, _140_tri__rh_equ_a, 0, _140_tri__rh_equ_ha }, + { "gte", 7, _140_tri__rh_gte_a, 0, _140_tri__rh_gte_ha }, + { "gth", 7, _140_tri__rh_gth_a, 0, _140_tri__rh_gth_ha }, + {} + }; +static c3_c* _140_tri__rh_ha[] = { + "c38f8c0a7e2f1fccb52c459f60a30ec5d21635cafaf1aa120b70c1fa91cf7da5", + 0 +}; + + static u3j_harm _140_tri__og_raw_a[] = {{".2", u3weo_raw}, {}}; + static c3_c* _140_tri__og_raw_ha[] = { + "bbcbefc237dbebf6c141ba14fd9e0464a836127fd123d10da5f121e82d49ebdb", + 0 + }; +static u3j_core _140_tri__og_d[] = + { { "raw", 7, _140_tri__og_raw_a, 0, _140_tri__og_raw_ha }, + {} + }; +static c3_c* _140_tri__og_ha[] = { + "74b9ae67eeabbffcff969ac7fdc7f4f0f4f67af64931e969bcac50d084e15fc0", + 0 +}; + + static u3j_harm _140_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}}; + static c3_c* _140_tri__sha_sha1_ha[] = { + "75aababa0688619d9df36238269119302a64ad2e3c69c53bd0057fe6b1abaf0c", + 0 + }; +static u3j_core _140_tri__sha_d[] = + { { "sha1", 7, _140_tri__sha_sha1_a, 0, _140_tri__sha_sha1_ha }, + {} + }; +static c3_c* _140_tri__sha_ha[] = { + "3c22d2f8719cb626e8dfe1a4206bcbc14b678c1422c48322054b40f84416d557", + 0 +}; + +static u3j_harm _140_tri_shax_a[] = {{".2", u3we_shax}, {}}; +static c3_c* _140_tri_shax_ha[] = { + "0fc53de3ddc8b8f84a46136f1728fa3ed66a5113888d14907589d16bf5927ad8", + 0 +}; +static u3j_harm _140_tri_shay_a[] = {{".2", u3we_shay}, {}}; +static c3_c* _140_tri_shay_ha[] = { + "b6dbc72e15c2204f83f902619b7a60328f29c9d302ddb35c435111dea28c5470", + 0 +}; +static u3j_harm _140_tri_shas_a[] = {{".2", u3we_shas}, {}}; +static c3_c* _140_tri_shas_ha[] = { + "5230583767b7625b3496248ed03b6b94c1d4ee9b26342f9390bf999ec9b6cfdb", + 0 +}; +static u3j_harm _140_tri_shal_a[] = {{".2", u3we_shal}, {}}; +static c3_c* _140_tri_shal_ha[] = { + "3242912e29e3e1ed8d1a395cc860a82d78961b4278ed79bbdeb37cb5615bbf20", + 0 +}; + + static u3j_harm _140_ob_fein_a[] = {{".2", u3we_fein_ob}, {}}; + static c3_c* _140_ob_fein_ha[] = { + 0 + }; + static u3j_harm _140_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}}; + static c3_c* _140_ob_fynd_ha[] = { + 0 + }; +static u3j_core _140_ob_d[] = { + { "fein", 7, _140_ob_fein_a, 0, _140_ob_fein_ha }, + { "fynd", 7, _140_ob_fynd_a, 0, _140_ob_fynd_ha }, + {} +}; +static c3_c* _140_ob_ha[] = { + "13ebfbdee69396bc1d980fc4dcbcdaa9cc3fb9c011e6cf188e71311a8bffc8e6", + 0 +}; +static u3j_hood _140_ob_ho[] = { + { "fein", 42 }, + { "fynd", 20 }, + {}, +}; + +static u3j_core _140_tri_d[] = +{ { "qua", 3, 0, _140_qua_d, _140_qua_ha, _140_qua_ho }, + + { "cofl", 7, 0, _140_tri__cofl_d, _140_tri__cofl_ha }, + { "rd", 7, 0, _140_tri__rd_d, _140_tri__rd_ha }, + { "rs", 7, 0, _140_tri__rs_d, _140_tri__rs_ha }, + { "rq", 7, 0, _140_tri__rq_d, _140_tri__rq_ha }, + { "rh", 7, 0, _140_tri__rh_d, _140_tri__rh_ha }, + { "og", 7, 0, _140_tri__og_d, _140_tri__og_ha }, + + { "sha", 7, 0, _140_tri__sha_d, _140_tri__sha_ha }, + { "shax", 7, _140_tri_shax_a, 0, _140_tri_shax_ha }, + { "shay", 7, _140_tri_shay_a, 0, _140_tri_shay_ha }, + { "shas", 7, _140_tri_shas_a, 0, _140_tri_shas_ha }, + { "shal", 7, _140_tri_shal_a, 0, _140_tri_shal_ha }, + + { "ob", 3, 0, _140_ob_d, _140_ob_ha, _140_ob_ho }, + {} +}; +static c3_c* _140_tri_ha[] = { + "e7339eb317038f64555717c5624e4571fe9654d471c1a78454129afdbcad9b53", + 0 +}; + +static u3j_hood _140_tri_ho[] = { + { "ob", 20 }, + { "yore", 5462 }, + { "year", 44975 }, + {}, +}; + + +/* layer two +*/ +static u3j_harm _140_two_find_a[] = {{".2", u3wb_find, c3y}, {}}; +static c3_c* _140_two_find_ha[] = { + "cab18d537962b48d38fa061844f44c4635ee11c74fdf403aa80d3a6d1b15c177", + 0 +}; +static u3j_harm _140_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}}; +static c3_c* _140_two_flop_ha[] = { + "73d496aac2ce6fd9475645c76f949ae0228f8f5ae6738529b08ed9aeb58255fe", + 0 +}; +static u3j_harm _140_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}}; +static c3_c* _140_two_lent_ha[] = { + "1b98ab19350f6a6753ea4bd6daf4509a7c5681b7ac20c83204fe62846d46c2c3", + 0 +}; +static u3j_harm _140_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}}; +static c3_c* _140_two_levy_ha[] = { + "634f1f506b17b4b50e6902f6e21b290ffc5305d1546075cba745c9e195fcc56b", + 0 +}; +static u3j_harm _140_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}}; +static c3_c* _140_two_lien_ha[] = { + "2ffb70864f2be120b48869b27c614aadeed1390bde497d8940fe85b7861093ea", + 0 +}; +static u3j_harm _140_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}}; +static c3_c* _140_two_murn_ha[] = { + "53257aaee131c2a892529c2ee75271160811814086456e8fdf249eebdf31b990", + 0 +}; +static u3j_harm _140_two_need_a[] = {{".2", u3wb_need, c3y}, {}}; +static c3_c* _140_two_need_ha[] = { + "bfdd39af478811efe816e69e8c9202d10c41f646c0d27f39c23e4fe1aec807dd", + 0 +}; +static u3j_harm _140_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}}; +static c3_c* _140_two_reap_ha[] = { + "cf6bd10b97b418b67c645374712c768d9e7e9809c14ecf36a5c507e5fc4b4039", + 0 +}; +static u3j_harm _140_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}}; +static c3_c* _140_two_reel_ha[] = { + "36108d1ba09617cf62e739e0ff2dcf9286f322ca0e8faa3521ef127e9840eebf", + 0 +}; +static u3j_harm _140_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}}; +static c3_c* _140_two_roll_ha[] = { + "42abc6b3defd7c5eb8f6d14d57a14ba2a02d559907c03141c70a65e0803c01e5", + 0 +}; +static u3j_harm _140_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}}; +static c3_c* _140_two_skid_ha[] = { + "832366432a85005f9a9849d6de9a9045c8f9a591050519b06aec6a9a1a54c360", + 0 +}; +static u3j_harm _140_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}}; +static c3_c* _140_two_skim_ha[] = { + "ccbecb459b90d05ed6c1073859a58987bf9a479820b5550fa75f37b95f98a279", + 0 +}; +static u3j_harm _140_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}}; +static c3_c* _140_two_skip_ha[] = { + "873e3e4d6b8f16212911aa982065dd0d36b1f6e8834828d5eb5d59afa9da2384", + 0 +}; +static u3j_harm _140_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}}; +static c3_c* _140_two_scag_ha[] = { + "ddba868a28eb9655c9f6e06cfecb4ec9e9ff78277290579b9bb9b25339bb4ab9", + 0 +}; +static u3j_harm _140_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}}; +static c3_c* _140_two_slag_ha[] = { + "811f7f67de7ab3f33b85198a69b1bf344498cd4922b0273d918a48b803b7877d", + 0 +}; +static u3j_harm _140_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}}; +static c3_c* _140_two_snag_ha[] = { + "12a1d53541d4df9be60bda45f2dae6c6e6381f85edd4de062af23c6654860591", + 0 +}; +static u3j_harm _140_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}}; +static c3_c* _140_two_sort_ha[] = { + "dc14f91fdedacd3b77bdf241d22555fe2bf0a231e9cab58b4ae779791e54c4e7", + 0 +}; +static u3j_harm _140_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}}; +static c3_c* _140_two_turn_ha[] = { + "e13d9f52434ba810e182017f50a73d4d44eaa298a833231e90353f2a32ea6a78", + 0 +}; +static u3j_harm _140_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}}; +static c3_c* _140_two_weld_ha[] = { + "d855628821d57392f575c5da000c7326eaaa19e08cda967a4772859269669df2", + 0 +}; +static u3j_harm _140_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}}; +static c3_c* _140_two_welp_ha[] = { + "0bccae6625e62ce622c62f9e828a2a6469e2fbf42342d95e23c3b926f340140d", + 0 +}; +static u3j_harm _140_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}}; +static c3_c* _140_two_zing_ha[] = { + "113bdea043e9e05cf4a63dac793caf34634bc58414d00250af87139405521b9d", + 0 +}; + +static u3j_harm _140_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}}; +static c3_c* _140_two_bex_ha[] = { + "ee7a095ea21b6438ec19ab235e73877b96108f0a14cae02cecbd8a48c44e70e3", + 0 +}; +static u3j_harm _140_two_can_a[] = {{".2", u3wc_can, c3y}, {}}; +static c3_c* _140_two_can_ha[] = { + "c49ee52487369ba17a0105a61aa658df60e7a537e3e8737ab582644fe00b3938", + 0 +}; +static u3j_harm _140_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}}; +static c3_c* _140_two_cat_ha[] = { + "467f007931110ac0755dcd44c5aaee65785a63b9042b8eea6a7838fa86cc5d8f", + 0 +}; +static u3j_harm _140_two_con_a[] = {{".2", u3wc_con, c3y}, {}}; +static c3_c* _140_two_con_ha[] = { + "d20f091bd4f28d37c1a78373df939f3d3a41e025129e9a2bb5e2b9a710358965", + 0 +}; +static u3j_harm _140_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}}; +static c3_c* _140_two_cut_ha[] = { + "96bb4e9a259d6a1ede5461956b6a6fb73f05cb8e745c4803c2bae4ec0b7f0800", + 0 +}; +static u3j_harm _140_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}}; +static c3_c* _140_two_dis_ha[] = { + "4b3987314451e20a45d2c7baff51d5d39be57e5970f23f86df4dd6569826ddff", + 0 +}; +static u3j_harm _140_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}}; +static c3_c* _140_two_dor_ha[] = { + "277927a2e49e4d942e81ffc7740a71e68a7b732df886a9f84dc7d914be911879", + 0 +}; +static u3j_harm _140_two_end_a[] = {{".2", u3wc_end, c3y}, {}}; +static c3_c* _140_two_end_ha[] = { + "403c9f12f2481966ffb07842006713149960c67c6bcad8edd78cdf837bc0d854", + 0 +}; +static u3j_harm _140_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}}; +static c3_c* _140_two_gor_ha[] = { + "8a1e3ed1de749ff2ff61d489466df618e4e0773498cb9693ec2e612e9733385c", + 0 +}; +static u3j_harm _140_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}}; +static c3_c* _140_two_lsh_ha[] = { + "3db89b02bc596a57c7fb72a991c9fbf3197de501c56b3d1df26911b664c45f3d", + 0 +}; +static u3j_harm _140_two_met_a[] = {{".2", u3wc_met, c3y}, {}}; +static c3_c* _140_two_met_ha[] = { + "39dc9b1d10d9e93414b43f315f9a375596c99b4e8172d71d26759996bb7bab08", + 0 +}; +static u3j_harm _140_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}}; +static c3_c* _140_two_mix_ha[] = { + "c84b3e487850d73dd5e4af18fb54b623028be3c45ae9b712718754233057fbc3", + 0 +}; +static u3j_harm _140_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}}; +static c3_c* _140_two_mor_ha[] = { + "7c2d86e952606e571e5bcd988e70ded072c0eaa45d1fd958849d76360a763ddf", + 0 +}; +static u3j_harm _140_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}}; +static c3_c* _140_two_mug_ha[] = { + "6da3f3aa1e951ef2d00e5131945d140fb52728558867237891e029160b7f5010", + 0 +}; +static u3j_harm _140_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}}; +static c3_c* _140_two_muk_ha[] = { + "5a04a09bf7d22c8ef048ba2cc86be8f3a02066eab84cf4a45bbdf2bf534ff9f6", + 0 +}; +static u3j_harm _140_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}}; +static c3_c* _140_two_pow_ha[] = { + "6cfcb9da6ad812eb72788e22e1370b4ab1b6ab64ab0628dfdff78ccead325406", + 0 +}; +static u3j_harm _140_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}}; +static c3_c* _140_two_rap_ha[] = { + "f694f96bcbf97b339285d6c73ed5d33d112b911f7a991acefdef223ff01d8834", + 0 +}; +static u3j_harm _140_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}}; +static c3_c* _140_two_rep_ha[] = { + "25aa2f1746e1cf2235117f22a3db152fa86e003d9bf9f9cfcda79e76e51f382f", + 0 +}; +static u3j_harm _140_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}}; +static c3_c* _140_two_rev_ha[] = { + "15e20592ac1d9c0c80d99589e67cadb4ed7566be1d21844bbe7ef936e0db4524", + 0 +}; +static u3j_harm _140_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}}; +static c3_c* _140_two_rip_ha[] = { + "16026c27499953978f69dbf81c1530b2dec8d5a2403c5561f7a5afcc180e129e", + 0 +}; +static u3j_harm _140_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}}; +static c3_c* _140_two_rsh_ha[] = { + "55bd777f239a2a7c849e0c7a35bb967b79279c79bbd985f31ba272761f97928f", + 0 +}; +static u3j_harm _140_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}}; +static c3_c* _140_two_swp_ha[] = { + "2c4583c36d73c9c2857052b893b87e1170a794e0edbbdba9d767ba7639e7c1ec", + 0 +}; +static u3j_harm _140_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}}; +static c3_c* _140_two_sqt_ha[] = { + "fc28ff327ae69f55ccf257b69a1477b845552ef9e615e85718902c249bdeca6f", + 0 +}; +static u3j_harm _140_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}}; +static c3_c* _140_two_xeb_ha[] = { + "41403aafe1e2ccb1a02edde96fe742085feffe028d02529eb2b13f925884a499", + 0 +}; + + static u3j_harm _140_two__in_apt_a[] = {{".2", u3wdi_apt_140}, {}}; + static c3_c* _140_two__in_apt_ha[] = { + "a40812fa255f13afdaf196bff38d2d9bfcb38f09c48ace9139a2701a555a0c9a", + 0 + }; + static u3j_harm _140_two__in_bif_a[] = {{".2", u3wdi_bif}, {}}; + static c3_c* _140_two__in_bif_ha[] = { + "edd0d727b9099e75c3e5b73b3025ad9737136eacedc2f8088b6edb02dbe06cb3", + 0 + }; + static u3j_harm _140_two__in_del_a[] = {{".2", u3wdi_del}, {}}; + static c3_c* _140_two__in_del_ha[] = { + "33a21e7aaf71105e2d48e1af61ff463fb8a0b7e04f8a8c30a6f6a2d1f967795f", + 0 + }; + static u3j_harm _140_two__in_dif_a[] = {{".2", u3wdi_dif}, {}}; + static c3_c* _140_two__in_dif_ha[] = { + "a488f0be5adbb1c04e2038a2315ac065591e7daadcafc1d47aea272979680468", + 0 + }; + static u3j_harm _140_two__in_gas_a[] = {{".2", u3wdi_gas}, {}}; + static c3_c* _140_two__in_gas_ha[] = { + "223a60a43a10f1f90a3b205ecfce8e17af1adfcf9dbf3cff9b8b1362656b1af1", + 0 + }; + static u3j_harm _140_two__in_has_a[] = {{".2", u3wdi_has}, {}}; + static c3_c* _140_two__in_has_ha[] = { + "a65e666e92176401040a883801e4f05bd650fe6c094a6c8d7f4afcaee9cf55ad", + 0 + }; + static u3j_harm _140_two__in_int_a[] = {{".2", u3wdi_int}, {}}; + static c3_c* _140_two__in_int_ha[] = { + "a71b0e355fa02d18447c02922f69096f42043da451e8c79e7a9270460c3a44e6", + 0 + }; + static u3j_harm _140_two__in_put_a[] = {{".2", u3wdi_put}, {}}; + static c3_c* _140_two__in_put_ha[] = { + "19b27267e18ef156d85d84d37e02692a17fec0b7a2a0fe4120a3ae02b841c8f4", + 0 + }; + static u3j_harm _140_two__in_rep_a[] = {{".2", u3wdi_rep}, {}}; + static c3_c* _140_two__in_rep_ha[] = { + "05bfb84a52ed8ccc330a96faca29a49afd28300960ac089d00dba32212b971a7", + 0 + }; + static u3j_harm _140_two__in_run_a[] = {{".2", u3wdi_run}, {}}; + static c3_c* _140_two__in_run_ha[] = { + "7f2061dbee19fa20925bd5a80cc41ed71e462e0f49ee6e845fd750c219734864", + 0 + }; + static u3j_harm _140_two__in_tap_a[] = {{".2", u3wdi_tap}, {}}; + static c3_c* _140_two__in_tap_ha[] = { + "7dde59e2bd7684e785ce9787bc394571bd1216d7a62398c703447fc951c6b352", + 0 + }; + static u3j_harm _140_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}}; + static c3_c* _140_two__in_wyt_ha[] = { + "fac9248ebd1defade9df695cd81f94355bebb271f85b164ff34658a5f45c71a0", + 0 + }; + static u3j_harm _140_two__in_uni_a[] = {{".2", u3wdi_uni}, {}}; + static c3_c* _140_two__in_uni_ha[] = { + "6bd72ef1fb12482a839f4435a2b163ace1b56036297a3cec6968be33d6863096", + 0 + }; +static u3j_core _140_two__in_d[] = + { { "apt", 7, _140_two__in_apt_a, 0, _140_two__in_apt_ha }, + { "bif", 7, _140_two__in_bif_a, 0, _140_two__in_bif_ha }, + { "del", 7, _140_two__in_del_a, 0, _140_two__in_del_ha }, + { "dif", 7, _140_two__in_dif_a, 0, _140_two__in_dif_ha }, + { "gas", 7, _140_two__in_gas_a, 0, _140_two__in_gas_ha }, + { "has", 7, _140_two__in_has_a, 0, _140_two__in_has_ha }, + { "int", 7, _140_two__in_int_a, 0, _140_two__in_int_ha }, + { "put", 7, _140_two__in_put_a, 0, _140_two__in_put_ha }, + { "rep", 7, _140_two__in_rep_a, 0, _140_two__in_rep_ha }, + { "run", 7, _140_two__in_run_a, 0, _140_two__in_run_ha }, + { "tap", 7, _140_two__in_tap_a, 0, _140_two__in_tap_ha }, + { "uni", 7, _140_two__in_uni_a, 0, _140_two__in_uni_ha }, + { "wyt", 3, _140_two__in_wyt_a, 0, _140_two__in_wyt_ha }, + {} + }; +static c3_c* _140_two__in_ha[] = { + "8bbb90ce0a49d627194aa267f6cf1fd78df677111b553ce03119fea19f9d763c", + 0 +}; + + static u3j_harm _140_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}}; + static c3_c* _140_two__by_all_ha[] = { + "c2e87d0047c14b4488d03aad98fa43080c736d86d2ff723a037aaf1843aa9285", + 0 + }; + static u3j_harm _140_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}}; + static c3_c* _140_two__by_any_ha[] = { + "96b95c942dcbc97f5291fa6f7342c3e19a87d69cc254965b0f75d95133a19301", + 0 + }; + static u3j_harm _140_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}}; + static c3_c* _140_two__by_apt_ha[] = { + "1f0a6f8b945b243520b77069060589938d9e651e34b24924db9528d02a98014f", + 0 + }; + + static u3j_harm _140_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}}; + static c3_c* _140_two__by_del_ha[] = { + "09f78d6235d3fce8303c7bc663988349b7d4592abdacfb09b833d2f43629b6b6", + 0 + }; + static u3j_harm _140_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}}; + static c3_c* _140_two__by_dif_ha[] = { + "0334e6df6fd0bd5013b94a1b22c29e4c436da0a2d5573f1992faad1c8a059cc7", + 0 + }; + static u3j_harm _140_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}}; + static c3_c* _140_two__by_gas_ha[] = { + "43046602e0b9e568b09448cfe18527e2331f3393a2f32e485d9707a14c346698", + 0 + }; + static u3j_harm _140_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}}; + static c3_c* _140_two__by_get_ha[] = { + "4de4cea8fa98ef48e9faae10c90ba5bd77971670030ffb00483d0608af4c466f", + 0 + }; + static u3j_harm _140_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}}; + static c3_c* _140_two__by_has_ha[] = { + "04ecc67ab25961bee1b7c9dbcf42965d16f32474b9bbdd2b286983f998e3957a", + 0 + }; + static u3j_harm _140_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}}; + static c3_c* _140_two__by_int_ha[] = { + "a2345429482c271a1668f3c0675a559452bb7b13cb7393c3acb7de44c603aef9", + 0 + }; + static u3j_harm _140_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}}; + static c3_c* _140_two__by_jab_ha[] = { + "48930133d9b26e912dce54d1bc486cfe9dcb32bb3c2b1ad76143382799aec156", + 0 + }; + static u3j_harm _140_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}}; + static c3_c* _140_two__by_key_ha[] = { + "0096c77b93e9fe36b98d9f433eb73300f024283b93b3d73a4001afb9f9804d1b", + 0 + }; + static u3j_harm _140_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}}; + static c3_c* _140_two__by_put_ha[] = { + "b7307589fed604bfb92e8ad5ffad611c82d835baf02a86c6911b279930f4e8d7", + 0 + }; + static u3j_harm _140_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}}; + static c3_c* _140_two__by_rep_ha[] = { + "05bfb84a52ed8ccc330a96faca29a49afd28300960ac089d00dba32212b971a7", + 0 + }; + static u3j_harm _140_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}}; + static c3_c* _140_two__by_run_ha[] = { + "adea01e9036e0b40e4969814d4eed935d7d69a52e4a55de5520df2fa5204d8e7", + 0 + }; + static u3j_harm _140_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}}; + static c3_c* _140_two__by_tap_ha[] = { + "7dde59e2bd7684e785ce9787bc394571bd1216d7a62398c703447fc951c6b352", + 0 + }; + static u3j_harm _140_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}}; + static c3_c* _140_two__by_uni_ha[] = { + "f18bc4dac19abe14a6f56afc15d838b7394d48969156f4b37c3c84edd5d46752", + 0 + }; + static u3j_harm _140_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}}; + static c3_c* _140_two__by_urn_ha[] = { + "a409cf78e7f1c2ce8440115730f74367839b658cde2d6a1daa8af067b790eb83", + 0 + }; + static u3j_harm _140_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}}; + static c3_c* _140_two__by_wyt_ha[] = { + "fac9248ebd1defade9df695cd81f94355bebb271f85b164ff34658a5f45c71a0", + 0 + }; +static u3j_core _140_two__by_d[] = + { { "all", 7, _140_two__by_all_a, 0, _140_two__by_all_ha }, + { "any", 7, _140_two__by_any_a, 0, _140_two__by_any_ha }, + { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha }, + // disabled due to interface change in %138 + // + // { "bif", 7, _140_two__by_bif_a, 0, _140_two__by_bif_ha }, + { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha }, + { "dif", 7, _140_two__by_dif_a, 0, _140_two__by_dif_ha }, + { "gas", 7, _140_two__by_gas_a, 0, _140_two__by_gas_ha }, + { "get", 7, _140_two__by_get_a, 0, _140_two__by_get_ha }, + { "has", 7, _140_two__by_has_a, 0, _140_two__by_has_ha }, + { "int", 7, _140_two__by_int_a, 0, _140_two__by_int_ha }, + { "jab", 7, _140_two__by_jab_a, 0, _140_two__by_jab_ha }, + { "key", 7, _140_two__by_key_a, 0, _140_two__by_key_ha }, + { "put", 7, _140_two__by_put_a, 0, _140_two__by_put_ha }, + { "rep", 7, _140_two__by_rep_a, 0, _140_two__by_rep_ha }, + { "run", 7, _140_two__by_run_a, 0, _140_two__by_run_ha }, + { "tap", 7, _140_two__by_tap_a, 0, _140_two__by_tap_ha }, + { "uni", 7, _140_two__by_uni_a, 0, _140_two__by_uni_ha }, + { "urn", 7, _140_two__by_urn_a, 0, _140_two__by_urn_ha }, + { "wyt", 3, _140_two__by_wyt_a, 0, _140_two__by_wyt_ha }, + {} + }; +static c3_c* _140_two__by_ha[] = { + "9c70e973de46335405a7ff932d4742743f54db579f2584758ef2b02afd4fbfe8", + 0 +}; + +static u3j_harm _140_two_cue_a[] = {{".2", u3we_cue}, {}}; +static c3_c* _140_two_cue_ha[] = { + "a52b584c5a92fc653e47f50c3389caf3427e13d20ddb8bd701a2d7bca12cb742", + 0 +}; +static u3j_harm _140_two_jam_a[] = {{".2", u3we_jam}, {}}; +static c3_c* _140_two_jam_ha[] = { + "61f86be74cb1fd5a1d7f531cc9588f8f34a972be8de487c93d25c8e026592ed2", + 0 +}; +static u3j_harm _140_two_mat_a[] = {{".2", u3we_mat}, {}}; +static c3_c* _140_two_mat_ha[] = { + "b5cd9fd1eded54fcb9bfd06af3c34460c1aa4cfc46f1ee9bd3f6476aa8fbb8c8", + 0 +}; +static u3j_harm _140_two_rub_a[] = {{".2", u3we_rub}, {}}; +static c3_c* _140_two_rub_ha[] = { + "87fcf40fb6fce8c3cb778373670d0682785ae650f785531db8ff69d431bc14c6", + 0 +}; + +static u3j_core _140_two_d[] = +{ { "tri", 3, 0, _140_tri_d, _140_tri_ha, _140_tri_ho }, + + { "find", 7, _140_two_find_a, 0, _140_two_find_ha }, + { "flop", 7, _140_two_flop_a, 0, _140_two_flop_ha }, + { "lent", 7, _140_two_lent_a, 0, _140_two_lent_ha }, + { "levy", 7, _140_two_levy_a, 0, _140_two_levy_ha }, + { "lien", 7, _140_two_lien_a, 0, _140_two_lien_ha }, + { "murn", 7, _140_two_murn_a, 0, _140_two_murn_ha }, + { "need", 7, _140_two_need_a, 0, _140_two_need_ha }, + { "reap", 7, _140_two_reap_a, 0, _140_two_reap_ha }, + { "reel", 7, _140_two_reel_a, 0, _140_two_reel_ha }, + { "roll", 7, _140_two_roll_a, 0, _140_two_roll_ha }, + { "skid", 7, _140_two_skid_a, 0, _140_two_skid_ha }, + { "skim", 7, _140_two_skim_a, 0, _140_two_skim_ha }, + { "skip", 7, _140_two_skip_a, 0, _140_two_skip_ha }, + { "scag", 7, _140_two_scag_a, 0, _140_two_scag_ha }, + { "slag", 7, _140_two_slag_a, 0, _140_two_slag_ha }, + { "snag", 7, _140_two_snag_a, 0, _140_two_snag_ha }, + { "sort", 7, _140_two_sort_a, 0, _140_two_sort_ha }, + { "turn", 7, _140_two_turn_a, 0, _140_two_turn_ha }, + { "weld", 7, _140_two_weld_a, 0, _140_two_weld_ha }, + { "welp", 7, _140_two_welp_a, 0, _140_two_welp_ha }, + { "zing", 7, _140_two_zing_a, 0, _140_two_zing_ha }, + + { "bex", 7, _140_two_bex_a, 0, _140_two_bex_ha }, + { "cat", 7, _140_two_cat_a, 0, _140_two_cat_ha }, + { "can", 7, _140_two_can_a, 0, _140_two_can_ha }, + { "con", 7, _140_two_con_a, 0, _140_two_con_ha }, + { "cue", 7, _140_two_cue_a, 0, _140_two_cue_ha }, + { "cut", 7, _140_two_cut_a, 0, _140_two_cut_ha }, + { "dis", 7, _140_two_dis_a, 0, _140_two_dis_ha }, + { "dor", 7, _140_two_dor_a, 0, _140_two_dor_ha }, + { "end", 7, _140_two_end_a, 0, _140_two_end_ha }, + { "gor", 7, _140_two_gor_a, 0, _140_two_gor_ha }, + { "jam", 7, _140_two_jam_a, 0, _140_two_jam_ha }, + { "lsh", 7, _140_two_lsh_a, 0, _140_two_lsh_ha }, + { "mat", 7, _140_two_mat_a, 0, _140_two_mat_ha }, + { "met", 7, _140_two_met_a, 0, _140_two_met_ha }, + { "mix", 7, _140_two_mix_a, 0, _140_two_mix_ha }, + { "mor", 7, _140_two_mor_a, 0, _140_two_mor_ha }, + { "mug", 7, _140_two_mug_a, 0, _140_two_mug_ha }, + { "muk", 59, _140_two_muk_a, 0, _140_two_muk_ha }, + { "rap", 7, _140_two_rap_a, 0, _140_two_rap_ha }, + { "rep", 7, _140_two_rep_a, 0, _140_two_rep_ha }, + { "rev", 7, _140_two_rev_a, 0, _140_two_rev_ha }, + { "rip", 7, _140_two_rip_a, 0, _140_two_rip_ha }, + { "rsh", 7, _140_two_rsh_a, 0, _140_two_rsh_ha }, + { "swp", 7, _140_two_swp_a, 0, _140_two_swp_ha }, + { "rub", 7, _140_two_rub_a, 0, _140_two_rub_ha }, + { "pow", 7, _140_two_pow_a, 0, _140_two_pow_ha }, + { "sqt", 7, _140_two_sqt_a, 0, _140_two_sqt_ha }, + { "xeb", 7, _140_two_xeb_a, 0, _140_two_xeb_ha }, + + { "by", 7, 0, _140_two__by_d, _140_two__by_ha }, + { "in", 7, 0, _140_two__in_d, _140_two__in_ha }, + {} +}; +static c3_c* _140_two_ha[] = { + "f693e1f5ff57ec741fe28a48a18252b3e12dead2bfe3bcd4ea8e904a36905c0b", + 0 +}; + + +/* layer one +*/ +static u3j_harm _140_one_add_a[] = {{".2", u3wa_add, c3y}, {}}; +static c3_c* _140_one_add_ha[] = { + "46407e27fe5d7c20b3ba25c02657c227b37217ddab8501b2d3b70b818aca7a44", + 0 +}; +static u3j_harm _140_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}}; +static c3_c* _140_one_dec_ha[] = { + "6345d28d34c62c4b4f9da98828574bc9060ff0869789968d9045d90faeb3580c", + 0 +}; +static u3j_harm _140_one_div_a[] = {{".2", u3wa_div, c3y}, {}}; +static c3_c* _140_one_div_ha[] = { + "e3292e76feb274b9314e7693827de11e96677629c556b3a6c72cc15ebad45113", + 0 +}; +static u3j_harm _140_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}}; +static c3_c* _140_one_dvr_ha[] = { + "fc259f46d770f82767163544f3662dfd45b1484a7bcffad396c7420651f092a4", + 0 +}; +static u3j_harm _140_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}}; +static c3_c* _140_one_gte_ha[] = { + "f3ff2c0fc1f386226183e8834cff87420a1206583f8710e1e75f0e34ed8df5fe", + 0 +}; +static u3j_harm _140_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}}; +static c3_c* _140_one_gth_ha[] = { + "62692d64c8166c7d48bb2a00713064846da9629a1dd2d924c3b15cfd18a5912a", + 0 +}; +static u3j_harm _140_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}}; +static c3_c* _140_one_lte_ha[] = { + "6ca61752aa27b453f28f20e12f652610d45695c3bd965190d5b4fa8b9daa518c", + 0 +}; +static u3j_harm _140_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}}; +static c3_c* _140_one_lth_ha[] = { + "39260325faffbbf5bd88c4abb3efb09c5a7e1deb81a2126498d6c0f49474955e", + 0 +}; +static u3j_harm _140_one_max_a[] = {{".2", u3wa_max, c3y}, {}}; +static c3_c* _140_one_max_ha[] = { + "39260325faffbbf5bd88c4abb3efb09c5a7e1deb81a2126498d6c0f49474955e", + 0 +}; +static u3j_harm _140_one_min_a[] = {{".2", u3wa_min, c3y}, {}}; +static c3_c* _140_one_min_ha[] = { + "39260325faffbbf5bd88c4abb3efb09c5a7e1deb81a2126498d6c0f49474955e", + 0 +}; +static u3j_harm _140_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}}; +static c3_c* _140_one_mod_ha[] = { + "374d2f3cd0ece33f680bd7103b99891d7dae03590f9eb9faac03a4a501f17038", + 0 +}; +static u3j_harm _140_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}}; +static c3_c* _140_one_mul_ha[] = { + "51e45dbea29cf65a5c26ead095a20eb12ba078840652c88b9c1997820e670bc6", + 0 +}; +static u3j_harm _140_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}}; +static c3_c* _140_one_sub_ha[] = { + "016695719ffe93c177e8a03afa5d29fc428ff596bb8962ace50f7706cd6e53a6", + 0 +}; + +static u3j_harm _140_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}}; +static c3_c* _140_one_cap_ha[] = { + "407e764ee978c712b81c9c3452932e0f7d33faeda36dfe99aaf81d543db16254", + 0 +}; +static u3j_harm _140_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}}; +static c3_c* _140_one_peg_ha[] = { + "8b608d2d2e2eccec3e2fc8cd2d92fd69504c72b26581bb9cbfa4ff51f997251f", + 0 +}; +static u3j_harm _140_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}}; +static c3_c* _140_one_mas_ha[] = { + "1439dcd809f0819b09fb5fe7e83bc1292ca6fd33b5819d78e706d402c053b02a", + 0 +}; + +static u3j_core _140_one_d[] = +{ { "two", 3, 0, _140_two_d, _140_two_ha }, + + { "add", 7, _140_one_add_a, 0, _140_one_add_ha }, + { "dec", 7, _140_one_dec_a, 0, _140_one_dec_ha }, + { "div", 7, _140_one_div_a, 0, _140_one_div_ha }, + { "dvr", 7, _140_one_dvr_a, 0, _140_one_dvr_ha }, + { "gte", 7, _140_one_gte_a, 0, _140_one_gte_ha }, + { "gth", 7, _140_one_gth_a, 0, _140_one_gth_ha }, + { "lte", 7, _140_one_lte_a, 0, _140_one_lte_ha }, + { "lth", 7, _140_one_lth_a, 0, _140_one_lth_ha }, + { "max", 7, _140_one_max_a, 0, _140_one_max_ha }, + { "min", 7, _140_one_min_a, 0, _140_one_min_ha }, + { "mod", 7, _140_one_mod_a, 0, _140_one_mod_ha }, + { "mul", 7, _140_one_mul_a, 0, _140_one_mul_ha }, + { "sub", 7, _140_one_sub_a, 0, _140_one_sub_ha }, + + { "cap", 7, _140_one_cap_a, 0, _140_one_cap_ha }, + { "mas", 7, _140_one_mas_a, 0, _140_one_mas_ha }, + { "peg", 7, _140_one_peg_a, 0, _140_one_peg_ha }, + {} +}; +static c3_c* _140_one_ha[] = { + "2501f8dbe62384d144ab0f805501ed66325bd77a733eca0c80d1da673e4b16fb", + 0 +}; + +u3j_core _k140_d[] = +{ { "one", 3, 0, _140_one_d, _140_one_ha }, + {} +}; +static c3_c* _k140_ha[] = { + "9b82a903093c077afb3f0b9d4e95e1a9c9789d1ca605b57bbacf79857e3d5c52", + 0 +}; + +/* new jets +*/ + static u3j_harm _139_hex_json_de_a[] = {{".2", u3we_json_de}, {}}; + static u3j_harm _139_hex_json_en_a[] = {{".2", u3we_json_en}, {}}; +static u3j_core _139_hex_json_d[] = + { { "de", 15, _139_hex_json_de_a, 0, no_hashes }, + { "en", 15, _139_hex_json_en_a, 0, no_hashes }, + {} + }; + + + +static u3j_core _139_hex_d[] = +{ + { "lore", 63, _140_hex_lore_a, 0, no_hashes }, + { "leer", 63, _140_hex_leer_a, 0, no_hashes }, + { "loss", 63, _140_hex_loss_a, 0, no_hashes }, + { "lune", 127, _140_hex_lune_a, 0, no_hashes }, + + { "coed", 63, 0, _140_hex_coed_d, no_hashes }, + { "aes", 31, 0, _140_hex_aes_d, no_hashes }, + + { "hmac", 63, 0, _140_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _140_hex_argon_d, no_hashes }, + { "blake", 31, 0, _140_hex_blake_d, no_hashes }, + { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _140_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _140_hex_scr_d, no_hashes }, + { "secp", 6, 0, _140_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _140_hex_mimes_d, no_hashes }, + { "json", 31, 0, _139_hex_json_d, no_hashes }, + {} +}; + +static u3j_core _139_pen_d[] = +{ { "hex", 7, 0, _139_hex_d, no_hashes }, + + { "cell", 7, _140_pen_cell_a, 0, no_hashes }, + { "comb", 7, _140_pen_comb_a, 0, no_hashes }, + { "cons", 7, _140_pen_cons_a, 0, no_hashes }, + { "core", 7, _140_pen_core_a, 0, no_hashes }, + { "face", 7, _140_pen_face_a, 0, no_hashes }, + { "fitz", 7, _140_pen_fitz_a, 0, no_hashes }, + { "flan", 7, _140_pen_flan_a, 0, no_hashes }, + { "flip", 7, _140_pen_flip_a, 0, no_hashes }, + { "flor", 7, _140_pen_flor_a, 0, no_hashes }, + { "fork", 7, _140_pen_fork_a, 0, no_hashes }, + { "look", 7, _140_pen_look_a, 0, no_hashes }, + { "loot", 7, _140_pen_loot_a, 0, no_hashes }, + { "ut", 15, 0, _140_pen__ut_d, no_hashes, _140_pen__ut_ho }, + {} +}; + +static u3j_core _139_qua_d[] = +{ { "pen", 3, 0, _139_pen_d, no_hashes, _140_pen_ho }, + + { "po", 7, 0, _140_qua__po_d, no_hashes }, + + { "trip", 7, _140_qua_trip_a, 0, no_hashes }, + + { "bend", 7, 0, _140_qua__bend_d, no_hashes }, + { "cold", 7, 0, _140_qua__cold_d, no_hashes }, + { "comp", 7, 0, _140_qua__comp_d, no_hashes }, + { "cook", 7, 0, _140_qua__cook_d, no_hashes }, + { "easy", 7, 0, _140_qua__easy_d, no_hashes }, + { "glue", 7, 0, _140_qua__glue_d, no_hashes }, + { "here", 7, 0, _140_qua__here_d, no_hashes }, + { "just", 7, 0, _140_qua__just_d, no_hashes }, + { "mask", 7, 0, _140_qua__mask_d, no_hashes }, + { "shim", 7, 0, _140_qua__shim_d, no_hashes }, + { "stag", 7, 0, _140_qua__stag_d, no_hashes }, + { "stew", 7, 0, _140_qua__stew_d, no_hashes }, + { "stir", 7, 0, _140_qua__stir_d, no_hashes }, + + { "pfix", 7, _140_qua_pfix_a, 0, no_hashes }, + { "plug", 7, _140_qua_plug_a, 0, no_hashes }, + { "pose", 7, _140_qua_pose_a, 0, no_hashes }, + { "sfix", 7, _140_qua_sfix_a, 0, no_hashes }, + + { "mink", 7, _140_qua_mink_a, 0, no_hashes }, + { "mole", 7, _140_qua_mole_a, 0, no_hashes }, + { "mule", 7, _140_qua_mule_a, 0, no_hashes }, + + { "scot", 7, _140_qua_scot_a, 0, no_hashes }, + { "scow", 7, _140_qua_scow_a, 0, no_hashes }, + { "slaw", 7, _140_qua_slaw_a, 0, no_hashes }, + {} +}; + +static u3j_core _139_tri_d[] = +{ { "qua", 3, 0, _139_qua_d, no_hashes, _140_qua_ho }, + + { "cofl", 7, 0, _140_tri__cofl_d, no_hashes }, + { "rd", 7, 0, _140_tri__rd_d, no_hashes }, + { "rs", 7, 0, _140_tri__rs_d, no_hashes }, + { "rq", 7, 0, _140_tri__rq_d, no_hashes }, + { "rh", 7, 0, _140_tri__rh_d, no_hashes }, + { "og", 7, 0, _140_tri__og_d, no_hashes }, + + { "sha", 7, 0, _140_tri__sha_d, no_hashes }, + { "shax", 7, _140_tri_shax_a, 0, no_hashes }, + { "shay", 7, _140_tri_shay_a, 0, no_hashes }, + { "shas", 7, _140_tri_shas_a, 0, no_hashes }, + { "shal", 7, _140_tri_shal_a, 0, no_hashes }, + + { "ob", 3, 0, _140_ob_d, no_hashes, _140_ob_ho }, + {} +}; + +static u3j_harm _139_two__in_apt_a[] = {{".2", u3wdi_apt}, {}}; + +static u3j_core _139_two__in_d[] = + { { "apt", 7, _139_two__in_apt_a, 0, no_hashes }, + { "bif", 7, _140_two__in_bif_a, 0, no_hashes }, + { "del", 7, _140_two__in_del_a, 0, no_hashes }, + { "dif", 7, _140_two__in_dif_a, 0, no_hashes }, + { "gas", 7, _140_two__in_gas_a, 0, no_hashes }, + { "has", 7, _140_two__in_has_a, 0, no_hashes }, + { "int", 7, _140_two__in_int_a, 0, no_hashes }, + { "put", 7, _140_two__in_put_a, 0, no_hashes }, + { "rep", 7, _140_two__in_rep_a, 0, no_hashes }, + { "run", 7, _140_two__in_run_a, 0, no_hashes }, + { "tap", 7, _140_two__in_tap_a, 0, no_hashes }, + { "uni", 7, _140_two__in_uni_a, 0, no_hashes }, + { "wyt", 3, _140_two__in_wyt_a, 0, no_hashes }, + {} + }; + +static u3j_core _139_two_d[] = +{ { "tri", 3, 0, _139_tri_d, no_hashes, _140_tri_ho }, + + { "find", 7, _140_two_find_a, 0, no_hashes }, + { "flop", 7, _140_two_flop_a, 0, no_hashes }, + { "lent", 7, _140_two_lent_a, 0, no_hashes }, + { "levy", 7, _140_two_levy_a, 0, no_hashes }, + { "lien", 7, _140_two_lien_a, 0, no_hashes }, + { "murn", 7, _140_two_murn_a, 0, no_hashes }, + { "need", 7, _140_two_need_a, 0, no_hashes }, + { "reap", 7, _140_two_reap_a, 0, no_hashes }, + { "reel", 7, _140_two_reel_a, 0, no_hashes }, + { "roll", 7, _140_two_roll_a, 0, no_hashes }, + { "skid", 7, _140_two_skid_a, 0, no_hashes }, + { "skim", 7, _140_two_skim_a, 0, no_hashes }, + { "skip", 7, _140_two_skip_a, 0, no_hashes }, + { "scag", 7, _140_two_scag_a, 0, no_hashes }, + { "slag", 7, _140_two_slag_a, 0, no_hashes }, + { "snag", 7, _140_two_snag_a, 0, no_hashes }, + { "sort", 7, _140_two_sort_a, 0, no_hashes }, + { "turn", 7, _140_two_turn_a, 0, no_hashes }, + { "weld", 7, _140_two_weld_a, 0, no_hashes }, + { "welp", 7, _140_two_welp_a, 0, no_hashes }, + { "zing", 7, _140_two_zing_a, 0, no_hashes }, + + { "bex", 7, _140_two_bex_a, 0, no_hashes }, + { "cat", 7, _140_two_cat_a, 0, no_hashes }, + { "can", 7, _140_two_can_a, 0, no_hashes }, + { "con", 7, _140_two_con_a, 0, no_hashes }, + { "cue", 7, _140_two_cue_a, 0, no_hashes }, + { "cut", 7, _140_two_cut_a, 0, no_hashes }, + { "dis", 7, _140_two_dis_a, 0, no_hashes }, + { "dor", 7, _140_two_dor_a, 0, no_hashes }, + { "end", 7, _140_two_end_a, 0, no_hashes }, + { "gor", 7, _140_two_gor_a, 0, no_hashes }, + { "jam", 7, _140_two_jam_a, 0, no_hashes }, + { "lsh", 7, _140_two_lsh_a, 0, no_hashes }, + { "mat", 7, _140_two_mat_a, 0, no_hashes }, + { "met", 7, _140_two_met_a, 0, no_hashes }, + { "mix", 7, _140_two_mix_a, 0, no_hashes }, + { "mor", 7, _140_two_mor_a, 0, no_hashes }, + { "mug", 7, _140_two_mug_a, 0, no_hashes }, + { "muk", 59, _140_two_muk_a, 0, no_hashes }, + { "rap", 7, _140_two_rap_a, 0, no_hashes }, + { "rep", 7, _140_two_rep_a, 0, no_hashes }, + { "rev", 7, _140_two_rev_a, 0, no_hashes }, + { "rip", 7, _140_two_rip_a, 0, no_hashes }, + { "rsh", 7, _140_two_rsh_a, 0, no_hashes }, + { "swp", 7, _140_two_swp_a, 0, no_hashes }, + { "rub", 7, _140_two_rub_a, 0, no_hashes }, + { "pow", 7, _140_two_pow_a, 0, no_hashes }, + { "sqt", 7, _140_two_sqt_a, 0, no_hashes }, + { "xeb", 7, _140_two_xeb_a, 0, no_hashes }, + + { "by", 7, 0, _140_two__by_d, no_hashes }, + { "in", 7, 0, _139_two__in_d, no_hashes }, + {} +}; + +static u3j_core _139_one_d[] = +{ { "two", 3, 0, _139_two_d, no_hashes }, + + { "add", 7, _140_one_add_a, 0, no_hashes }, + { "dec", 7, _140_one_dec_a, 0, no_hashes }, + { "div", 7, _140_one_div_a, 0, no_hashes }, + { "dvr", 7, _140_one_dvr_a, 0, no_hashes }, + { "gte", 7, _140_one_gte_a, 0, no_hashes }, + { "gth", 7, _140_one_gth_a, 0, no_hashes }, + { "lte", 7, _140_one_lte_a, 0, no_hashes }, + { "lth", 7, _140_one_lth_a, 0, no_hashes }, + { "max", 7, _140_one_max_a, 0, no_hashes }, + { "min", 7, _140_one_min_a, 0, no_hashes }, + { "mod", 7, _140_one_mod_a, 0, no_hashes }, + { "mul", 7, _140_one_mul_a, 0, no_hashes }, + { "sub", 7, _140_one_sub_a, 0, no_hashes }, + + { "cap", 7, _140_one_cap_a, 0, no_hashes }, + { "mas", 7, _140_one_mas_a, 0, no_hashes }, + { "peg", 7, _140_one_peg_a, 0, no_hashes }, + {} +}; + +u3j_core _k139_d[] = +{ { "one", 3, 0, _139_one_d, no_hashes }, + {} +}; + + static u3j_harm _138_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}}; + static u3j_harm _138_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}}; + static u3j_harm _138_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}}; + static u3j_core _138_hex_blake3_d[] = + { { "hash", 7, _138_hex_blake3_hash_a, 0, no_hashes }, + { "chunk-output", 7, _138_hex_blake3_chunk_output_a, 0, no_hashes }, + {} + }; + static u3j_core _138_hex_blake3_impl_d[] = + { { "compress", 7, _138_hex_blake3_compress_a, 0, no_hashes }, + { "blake3", 7, 0, _138_hex_blake3_d, no_hashes }, + {} + }; +static u3j_core _138_hex_blake_d[] = + { { "blake2b", 7, _140_hex_blake2b_a, 0, no_hashes }, + { "blake3-impl", 7, 0, _138_hex_blake3_impl_d, no_hashes }, + {} + }; + + static u3j_harm _138_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}}; + static u3j_harm _138_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}}; +static u3j_core _138_hex_chacha_d[] = + { { "crypt", 7, _138_hex_chacha_crypt_a, 0, no_hashes }, + { "xchacha", 7, _138_hex_chacha_xchacha_a, 0, no_hashes }, + {} + }; + +static u3j_core _138_hex_d[] = +{ { "lore", 63, _140_hex_lore_a, 0, no_hashes }, + { "leer", 63, _140_hex_leer_a, 0, no_hashes }, + { "loss", 63, _140_hex_loss_a, 0, no_hashes }, + { "lune", 127, _140_hex_lune_a, 0, no_hashes }, + + { "coed", 63, 0, _140_hex_coed_d, no_hashes }, + { "aes", 31, 0, _140_hex_aes_d, no_hashes }, + + { "hmac", 63, 0, _140_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _140_hex_argon_d, no_hashes }, + { "blake", 31, 0, _138_hex_blake_d, no_hashes }, + { "chacha", 31, 0, _138_hex_chacha_d, no_hashes }, + { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _140_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _140_hex_scr_d, no_hashes }, + { "secp", 6, 0, _140_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _140_hex_mimes_d, no_hashes }, + { "json", 31, 0, _139_hex_json_d, no_hashes }, + {} +}; + +static u3j_core _138_pen_d[] = +{ { "hex", 7, 0, _138_hex_d, no_hashes }, + + { "cell", 7, _140_pen_cell_a, 0, no_hashes }, + { "comb", 7, _140_pen_comb_a, 0, no_hashes }, + { "cons", 7, _140_pen_cons_a, 0, no_hashes }, + { "core", 7, _140_pen_core_a, 0, no_hashes }, + { "face", 7, _140_pen_face_a, 0, no_hashes }, + { "fitz", 7, _140_pen_fitz_a, 0, no_hashes }, + // flan, flip, and flor removed + // + { "fork", 7, _140_pen_fork_a, 0, no_hashes }, + { "look", 7, _140_pen_look_a, 0, no_hashes }, + { "loot", 7, _140_pen_loot_a, 0, no_hashes }, + { "ut", 15, 0, _140_pen__ut_d, no_hashes, _140_pen__ut_ho }, + {} +}; + +static u3j_core _138_qua_d[] = +{ { "pen", 3, 0, _138_pen_d, no_hashes, _140_pen_ho }, + + { "po", 7, 0, _140_qua__po_d, no_hashes }, + + { "trip", 7, _140_qua_trip_a, 0, no_hashes }, + + { "bend", 7, 0, _140_qua__bend_d, no_hashes }, + { "cold", 7, 0, _140_qua__cold_d, no_hashes }, + { "comp", 7, 0, _140_qua__comp_d, no_hashes }, + { "cook", 7, 0, _140_qua__cook_d, no_hashes }, + { "easy", 7, 0, _140_qua__easy_d, no_hashes }, + { "glue", 7, 0, _140_qua__glue_d, no_hashes }, + { "here", 7, 0, _140_qua__here_d, no_hashes }, + { "just", 7, 0, _140_qua__just_d, no_hashes }, + { "mask", 7, 0, _140_qua__mask_d, no_hashes }, + { "shim", 7, 0, _140_qua__shim_d, no_hashes }, + { "stag", 7, 0, _140_qua__stag_d, no_hashes }, + { "stew", 7, 0, _140_qua__stew_d, no_hashes }, + { "stir", 7, 0, _140_qua__stir_d, no_hashes }, + + { "pfix", 7, _140_qua_pfix_a, 0, no_hashes }, + { "plug", 7, _140_qua_plug_a, 0, no_hashes }, + { "pose", 7, _140_qua_pose_a, 0, no_hashes }, + { "sfix", 7, _140_qua_sfix_a, 0, no_hashes }, + + { "mink", 7, _140_qua_mink_a, 0, no_hashes }, + { "mole", 7, _140_qua_mole_a, 0, no_hashes }, + { "mule", 7, _140_qua_mule_a, 0, no_hashes }, + + { "scot", 7, _140_qua_scot_a, 0, no_hashes }, + { "scow", 7, _140_qua_scow_a, 0, no_hashes }, + { "slaw", 7, _140_qua_slaw_a, 0, no_hashes }, + {} +}; + +static u3j_core _138_tri_d[] = +{ { "qua", 3, 0, _138_qua_d, no_hashes, _140_qua_ho }, + + { "cofl", 7, 0, _140_tri__cofl_d, no_hashes }, + { "rd", 7, 0, _140_tri__rd_d, no_hashes }, + { "rs", 7, 0, _140_tri__rs_d, no_hashes }, + { "rq", 7, 0, _140_tri__rq_d, no_hashes }, + { "rh", 7, 0, _140_tri__rh_d, no_hashes }, + { "og", 7, 0, _140_tri__og_d, no_hashes }, + + { "sha", 7, 0, _140_tri__sha_d, no_hashes }, + { "shax", 7, _140_tri_shax_a, 0, no_hashes }, + { "shay", 7, _140_tri_shay_a, 0, no_hashes }, + { "shas", 7, _140_tri_shas_a, 0, no_hashes }, + { "shal", 7, _140_tri_shal_a, 0, no_hashes }, + + { "ob", 3, 0, _140_ob_d, no_hashes, _140_ob_ho }, + {} +}; + +static u3j_harm _138_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}}; + +static u3j_core _138_two__by_d[] = + { { "all", 7, _140_two__by_all_a, 0, _140_two__by_all_ha }, + { "any", 7, _140_two__by_any_a, 0, _140_two__by_any_ha }, + { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha }, + { "bif", 7, _138_two__by_bif_a, 0, no_hashes }, + { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha }, + { "dif", 7, _140_two__by_dif_a, 0, _140_two__by_dif_ha }, + { "gas", 7, _140_two__by_gas_a, 0, _140_two__by_gas_ha }, + { "get", 7, _140_two__by_get_a, 0, _140_two__by_get_ha }, + { "has", 7, _140_two__by_has_a, 0, _140_two__by_has_ha }, + { "int", 7, _140_two__by_int_a, 0, _140_two__by_int_ha }, + { "jab", 7, _140_two__by_jab_a, 0, _140_two__by_jab_ha }, + { "key", 7, _140_two__by_key_a, 0, _140_two__by_key_ha }, + { "put", 7, _140_two__by_put_a, 0, _140_two__by_put_ha }, + { "rep", 7, _140_two__by_rep_a, 0, _140_two__by_rep_ha }, + { "run", 7, _140_two__by_run_a, 0, _140_two__by_run_ha }, + { "tap", 7, _140_two__by_tap_a, 0, _140_two__by_tap_ha }, + { "uni", 7, _140_two__by_uni_a, 0, _140_two__by_uni_ha }, + { "urn", 7, _140_two__by_urn_a, 0, _140_two__by_urn_ha }, + { "wyt", 3, _140_two__by_wyt_a, 0, _140_two__by_wyt_ha }, + {} + }; + +static u3j_harm _138_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}}; + +static u3j_harm _138_two_aor_a[] = {{".2", u3wc_aor, c3y}, {}}; + +static u3j_core _138_two_d[] = +{ { "tri", 3, 0, _138_tri_d, no_hashes, _140_tri_ho }, + + { "find", 7, _140_two_find_a, 0, no_hashes }, + { "flop", 7, _140_two_flop_a, 0, no_hashes }, + { "lent", 7, _140_two_lent_a, 0, no_hashes }, + { "levy", 7, _140_two_levy_a, 0, no_hashes }, + { "lien", 7, _140_two_lien_a, 0, no_hashes }, + { "murn", 7, _140_two_murn_a, 0, no_hashes }, + { "need", 7, _140_two_need_a, 0, no_hashes }, + { "mate", 7, _138_two_mate_a, 0, no_hashes }, + { "reap", 7, _140_two_reap_a, 0, no_hashes }, + { "reel", 7, _140_two_reel_a, 0, no_hashes }, + { "roll", 7, _140_two_roll_a, 0, no_hashes }, + { "skid", 7, _140_two_skid_a, 0, no_hashes }, + { "skim", 7, _140_two_skim_a, 0, no_hashes }, + { "skip", 7, _140_two_skip_a, 0, no_hashes }, + { "scag", 7, _140_two_scag_a, 0, no_hashes }, + { "slag", 7, _140_two_slag_a, 0, no_hashes }, + { "snag", 7, _140_two_snag_a, 0, no_hashes }, + { "sort", 7, _140_two_sort_a, 0, no_hashes }, + { "turn", 7, _140_two_turn_a, 0, no_hashes }, + { "weld", 7, _140_two_weld_a, 0, no_hashes }, + { "welp", 7, _140_two_welp_a, 0, no_hashes }, + { "zing", 7, _140_two_zing_a, 0, no_hashes }, + + { "aor", 7, _138_two_aor_a, 0, no_hashes }, + { "bex", 7, _140_two_bex_a, 0, no_hashes }, + { "cat", 7, _140_two_cat_a, 0, no_hashes }, + { "can", 7, _140_two_can_a, 0, no_hashes }, + { "con", 7, _140_two_con_a, 0, no_hashes }, + { "cue", 7, _140_two_cue_a, 0, no_hashes }, + { "cut", 7, _140_two_cut_a, 0, no_hashes }, + { "dis", 7, _140_two_dis_a, 0, no_hashes }, + { "dor", 7, _140_two_dor_a, 0, no_hashes }, + { "end", 7, _140_two_end_a, 0, no_hashes }, + { "gor", 7, _140_two_gor_a, 0, no_hashes }, + { "jam", 7, _140_two_jam_a, 0, no_hashes }, + { "lsh", 7, _140_two_lsh_a, 0, no_hashes }, + { "mat", 7, _140_two_mat_a, 0, no_hashes }, + { "met", 7, _140_two_met_a, 0, no_hashes }, + { "mix", 7, _140_two_mix_a, 0, no_hashes }, + { "mor", 7, _140_two_mor_a, 0, no_hashes }, + { "mug", 7, _140_two_mug_a, 0, no_hashes }, + { "muk", 59, _140_two_muk_a, 0, no_hashes }, + { "rap", 7, _140_two_rap_a, 0, no_hashes }, + { "rep", 7, _140_two_rep_a, 0, no_hashes }, + { "rev", 7, _140_two_rev_a, 0, no_hashes }, + { "rip", 7, _140_two_rip_a, 0, no_hashes }, + { "rsh", 7, _140_two_rsh_a, 0, no_hashes }, + { "swp", 7, _140_two_swp_a, 0, no_hashes }, + { "rub", 7, _140_two_rub_a, 0, no_hashes }, + { "pow", 7, _140_two_pow_a, 0, no_hashes }, + { "sqt", 7, _140_two_sqt_a, 0, no_hashes }, + { "xeb", 7, _140_two_xeb_a, 0, no_hashes }, + + { "by", 7, 0, _138_two__by_d, no_hashes }, + { "in", 7, 0, _139_two__in_d, no_hashes }, + {} +}; + +static u3j_core _138_one_d[] = +{ { "two", 3, 0, _138_two_d, no_hashes }, + + { "add", 7, _140_one_add_a, 0, no_hashes }, + { "dec", 7, _140_one_dec_a, 0, no_hashes }, + { "div", 7, _140_one_div_a, 0, no_hashes }, + { "dvr", 7, _140_one_dvr_a, 0, no_hashes }, + { "gte", 7, _140_one_gte_a, 0, no_hashes }, + { "gth", 7, _140_one_gth_a, 0, no_hashes }, + { "lte", 7, _140_one_lte_a, 0, no_hashes }, + { "lth", 7, _140_one_lth_a, 0, no_hashes }, + { "max", 7, _140_one_max_a, 0, no_hashes }, + { "min", 7, _140_one_min_a, 0, no_hashes }, + { "mod", 7, _140_one_mod_a, 0, no_hashes }, + { "mul", 7, _140_one_mul_a, 0, no_hashes }, + { "sub", 7, _140_one_sub_a, 0, no_hashes }, + + { "cap", 7, _140_one_cap_a, 0, no_hashes }, + { "mas", 7, _140_one_mas_a, 0, no_hashes }, + { "peg", 7, _140_one_peg_a, 0, no_hashes }, + {} +}; + +static u3j_core _k138_d[] = +{ { "one", 3, 0, _138_one_d, no_hashes }, + {} +}; + + +static u3j_core _a50_two__by_d[] = + { { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha }, + { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha }, + { "get", 7, _140_two__by_get_a, 0, _140_two__by_get_ha }, + { "has", 7, _140_two__by_has_a, 0, _140_two__by_has_ha }, + { "put", 7, _140_two__by_put_a, 0, _140_two__by_put_ha }, + {} + }; + +static u3j_core _a50_two__in_d[] = + { { "apt", 7, _140_two__in_apt_a, 0, _140_two__in_apt_ha }, // NB: 140 jet + { "del", 7, _140_two__in_del_a, 0, _140_two__in_del_ha }, + { "put", 7, _140_two__in_put_a, 0, _140_two__in_put_ha }, + {} + }; + +u3j_core _a50_d[] = +{ { "add", 7, _140_one_add_a, 0, _140_one_add_ha }, + { "dec", 7, _140_one_dec_a, 0, _140_one_dec_ha }, + { "div", 7, _140_one_div_a, 0, _140_one_div_ha }, + { "dvr", 7, _140_one_dvr_a, 0, _140_one_dvr_ha }, + { "gte", 7, _140_one_gte_a, 0, _140_one_gte_ha }, + { "gth", 7, _140_one_gth_a, 0, _140_one_gth_ha }, + { "lte", 7, _140_one_lte_a, 0, _140_one_lte_ha }, + { "lth", 7, _140_one_lth_a, 0, _140_one_lth_ha }, + { "mod", 7, _140_one_mod_a, 0, _140_one_mod_ha }, + { "mul", 7, _140_one_mul_a, 0, _140_one_mul_ha }, + { "sub", 7, _140_one_sub_a, 0, _140_one_sub_ha }, + + { "bex", 7, _140_two_bex_a, 0, _140_two_bex_ha }, + { "cat", 7, _140_two_cat_a, 0, _140_two_cat_ha }, + { "can", 7, _140_two_can_a, 0, _140_two_can_ha }, + { "con", 7, _140_two_con_a, 0, _140_two_con_ha }, + { "cut", 7, _140_two_cut_a, 0, _140_two_cut_ha }, + { "dis", 7, _140_two_dis_a, 0, _140_two_dis_ha }, + { "dor", 7, _140_two_dor_a, 0, _140_two_dor_ha }, + { "end", 7, _140_two_end_a, 0, _140_two_end_ha }, + { "gor", 7, _140_two_gor_a, 0, _140_two_gor_ha }, + { "lsh", 7, _140_two_lsh_a, 0, _140_two_lsh_ha }, + { "met", 7, _140_two_met_a, 0, _140_two_met_ha }, + { "mix", 7, _140_two_mix_a, 0, _140_two_mix_ha }, + { "mor", 7, _140_two_mor_a, 0, _140_two_mor_ha }, + { "mug", 7, _140_two_mug_a, 0, _140_two_mug_ha }, + { "rep", 7, _140_two_rep_a, 0, _140_two_rep_ha }, + { "rip", 7, _140_two_rip_a, 0, _140_two_rip_ha }, + { "rsh", 7, _140_two_rsh_a, 0, _140_two_rsh_ha }, + { "swp", 7, _140_two_swp_a, 0, _140_two_swp_ha }, + + { "flop", 7, _140_two_flop_a, 0, _140_two_flop_ha }, + { "lent", 7, _140_two_lent_a, 0, _140_two_lent_ha }, + { "levy", 7, _140_two_levy_a, 0, _140_two_levy_ha }, + { "reap", 7, _140_two_reap_a, 0, _140_two_reap_ha }, + { "slag", 7, _140_two_slag_a, 0, _140_two_slag_ha }, + { "snag", 7, _140_two_snag_a, 0, _140_two_snag_ha }, + { "turn", 7, _140_two_turn_a, 0, _140_two_turn_ha }, + { "welp", 7, _140_two_welp_a, 0, _140_two_welp_ha }, + + { "by", 7, 0, _a50_two__by_d, _140_two__by_ha }, + { "in", 7, 0, _a50_two__in_d, _140_two__in_ha }, + {} +}; + +extern u3j_core _k137_d[]; +extern u3j_core _k136_d[]; + +static u3j_core _d[] = +{ { "k140", 0, 0, _k140_d, _k140_ha, 0, (u3j_core*) 140, 0 }, + { "k139", 0, 0, _k139_d, no_hashes, 0, (u3j_core*) 139, 0 }, + { "k138", 0, 0, _k138_d, no_hashes, 0, (u3j_core*) 138, 0 }, + { "k137", 0, 0, _k137_d, no_hashes, 0, (u3j_core*) 137, 0 }, + { "k136", 0, 0, _k136_d, no_hashes, 0, (u3j_core*) 136, 0 }, + { "a50", 0, 0, _a50_d, _k140_ha, 0, (u3j_core*) c3__a50, 0 }, + {} +}; + +u3j_dash +u3j_Dash = { + _d, + 0, + 0 +}; + diff --git a/vere/pkg/noun/jets/w.h b/vere/pkg/noun/jets/w.h new file mode 100644 index 0000000..57d9677 --- /dev/null +++ b/vere/pkg/noun/jets/w.h @@ -0,0 +1,433 @@ +/// @file + +#ifndef U3_JETS_W_H +#define U3_JETS_W_H + +#include "types.h" + + /** Tier 1. + **/ + u3_noun u3wa_add(u3_noun); + u3_noun u3wa_dec(u3_noun); + u3_noun u3wa_div(u3_noun); + u3_noun u3wa_gte(u3_noun); + u3_noun u3wa_gth(u3_noun); + u3_noun u3wa_lte(u3_noun); + u3_noun u3wa_lth(u3_noun); + u3_noun u3wa_max(u3_noun); + u3_noun u3wa_min(u3_noun); + u3_noun u3wa_mod(u3_noun); + u3_noun u3wa_mul(u3_noun); + u3_noun u3wa_sub(u3_noun); + + /** Tier 2. + **/ + u3_noun u3wb_bind(u3_noun); + u3_noun u3wb_clap(u3_noun); + u3_noun u3wb_drop(u3_noun); + u3_noun u3wb_find(u3_noun); + u3_noun u3wb_flop(u3_noun); + u3_noun u3wb_lent(u3_noun); + u3_noun u3wb_levy(u3_noun); + u3_noun u3wb_lien(u3_noun); + u3_noun u3wb_murn(u3_noun); + u3_noun u3wb_need(u3_noun); + u3_noun u3wb_mate(u3_noun); + u3_noun u3wb_reap(u3_noun); + u3_noun u3wb_reel(u3_noun); + u3_noun u3wb_roll(u3_noun); + u3_noun u3wb_skid(u3_noun); + u3_noun u3wb_skim(u3_noun); + u3_noun u3wb_skip(u3_noun); + u3_noun u3wb_scag(u3_noun); + u3_noun u3wb_slag(u3_noun); + u3_noun u3wb_snag(u3_noun); + u3_noun u3wb_sort(u3_noun); + u3_noun u3wb_turn(u3_noun); + u3_noun u3wb_weld(u3_noun); +# define u3wb_welp u3wb_weld + u3_noun u3wb_zing(u3_noun); + + /** Tier 3. + **/ + u3_noun u3wc_aor(u3_noun); + u3_noun u3wc_bex(u3_noun); + u3_noun u3wc_xeb(u3_noun); + u3_noun u3wc_can(u3_noun); + u3_noun u3wc_cap(u3_noun); + u3_noun u3wc_cat(u3_noun); + u3_noun u3wc_clz(u3_noun); + u3_noun u3wc_con(u3_noun); + u3_noun u3wc_ctz(u3_noun); + u3_noun u3wc_cut(u3_noun); + u3_noun u3wc_dis(u3_noun); + u3_noun u3wc_dor(u3_noun); + u3_noun u3wc_dvr(u3_noun); + u3_noun u3wc_end(u3_noun); + u3_noun u3wc_gor(u3_noun); + u3_noun u3wc_ham(u3_noun); + u3_noun u3wc_hew(u3_noun); + u3_noun u3wc_lsh(u3_noun); + u3_noun u3wc_mas(u3_noun); + u3_noun u3wc_met(u3_noun); + u3_noun u3wc_mix(u3_noun); + u3_noun u3wc_mor(u3_noun); + u3_noun u3wc_mug(u3_noun); + u3_noun u3wc_muk(u3_noun); + u3_noun u3wc_peg(u3_noun); + u3_noun u3wc_pow(u3_noun); + u3_noun u3wc_rap(u3_noun); + u3_noun u3wc_rep(u3_noun); + u3_noun u3wc_rev(u3_noun); + u3_noun u3wc_rig(u3_noun); + u3_noun u3wc_rip(u3_noun); + u3_noun u3wc_rsh(u3_noun); + u3_noun u3wc_sew(u3_noun); + u3_noun u3wc_swp(u3_noun); + u3_noun u3wc_sqt(u3_noun); + + u3_noun u3wcp_ins(u3_noun); + u3_noun u3wcp_ind(u3_noun); + u3_noun u3wcp_tos(u3_noun); + u3_noun u3wcp_tod(u3_noun); + + /** Tier 4. + **/ + u3_noun u3wdb_all(u3_noun); + u3_noun u3wdb_any(u3_noun); + u3_noun u3wdb_apt(u3_noun); + u3_noun u3wdb_bif(u3_noun); + u3_noun u3wdb_del(u3_noun); + u3_noun u3wdb_dif(u3_noun); + u3_noun u3wdb_gas(u3_noun); + u3_noun u3wdb_get(u3_noun); + u3_noun u3wdb_has(u3_noun); + u3_noun u3wdb_int(u3_noun); + u3_noun u3wdb_jab(u3_noun); + u3_noun u3wdb_key(u3_noun); + u3_noun u3wdb_put(u3_noun); +# define u3wdb_tap u3wdi_tap + u3_noun u3wdb_uni(u3_noun); + u3_noun u3wdb_urn(u3_noun); +# define u3wdb_rep u3wdi_rep + u3_noun u3wdb_run(u3_noun); +# define u3wdb_wyt u3wdi_wyt + + u3_noun u3wdi_apt_140(u3_noun); + u3_noun u3wdi_apt(u3_noun); + u3_noun u3wdi_bif(u3_noun); + u3_noun u3wdi_del(u3_noun); + u3_noun u3wdi_dif(u3_noun); + u3_noun u3wdi_gas(u3_noun); + u3_noun u3wdi_has(u3_noun); + u3_noun u3wdi_int(u3_noun); + u3_noun u3wdi_put(u3_noun); + u3_noun u3wdi_rep(u3_noun); + u3_noun u3wdi_run(u3_noun); + u3_noun u3wdi_tap(u3_noun); + u3_noun u3wdi_uni(u3_noun); + u3_noun u3wdi_wyt(u3_noun); + + /** Tier 5. + **/ + u3_noun u3we_cue(u3_noun); + u3_noun u3we_jam(u3_noun); + u3_noun u3we_mat(u3_noun); + u3_noun u3we_rub(u3_noun); + u3_noun u3we_leer(u3_noun); + u3_noun u3we_lore(u3_noun); + u3_noun u3we_loss(u3_noun); + u3_noun u3we_lune(u3_noun); + u3_noun u3we_mice(u3_noun); + u3_noun u3we_mink(u3_noun); + u3_noun u3we_mole(u3_noun); + u3_noun u3we_mule(u3_noun); + u3_noun u3we_repg(u3_noun); + u3_noun u3we_rexp(u3_noun); + u3_noun u3we_trip(u3_noun); + + u3_noun u3we_scow(u3_noun); + u3_noun u3we_scot(u3_noun); + u3_noun u3we_slaw(u3_noun); + + u3_noun u3we_pfix(u3_noun); + u3_noun u3we_plug(u3_noun); + u3_noun u3we_pose(u3_noun); + u3_noun u3we_sfix(u3_noun); + + u3_noun u3wea_ecba_en(u3_noun); + u3_noun u3wea_ecba_de(u3_noun); + u3_noun u3wea_ecbb_en(u3_noun); + u3_noun u3wea_ecbb_de(u3_noun); + u3_noun u3wea_ecbc_en(u3_noun); + u3_noun u3wea_ecbc_de(u3_noun); + + u3_noun u3wea_cbca_en(u3_noun); + u3_noun u3wea_cbca_de(u3_noun); + u3_noun u3wea_cbcb_en(u3_noun); + u3_noun u3wea_cbcb_de(u3_noun); + u3_noun u3wea_cbcc_en(u3_noun); + u3_noun u3wea_cbcc_de(u3_noun); + + u3_noun u3wea_siva_en(u3_noun); + u3_noun u3wea_siva_de(u3_noun); + u3_noun u3wea_sivb_en(u3_noun); + u3_noun u3wea_sivb_de(u3_noun); + u3_noun u3wea_sivc_en(u3_noun); + u3_noun u3wea_sivc_de(u3_noun); + + u3_noun u3wea_de(u3_noun); + u3_noun u3wea_en(u3_noun); + + u3_noun u3wes_hsh(u3_noun); + u3_noun u3wes_hsl(u3_noun); + u3_noun u3wes_pbk(u3_noun); + u3_noun u3wes_pbl(u3_noun); + + u3_noun u3we_shax(u3_noun); + u3_noun u3we_shay(u3_noun); + u3_noun u3we_shas(u3_noun); + u3_noun u3we_shal(u3_noun); + u3_noun u3we_sha1(u3_noun); + + u3_noun u3we_fein_ob(u3_noun); + u3_noun u3we_fynd_ob(u3_noun); + + u3_noun u3weo_raw(u3_noun); + + u3_noun u3wee_scad(u3_noun); + u3_noun u3wee_scas(u3_noun); + u3_noun u3wee_scap(u3_noun); + + u3_noun u3wee_puck(u3_noun); + u3_noun u3wee_luck(u3_noun); + u3_noun u3wee_sign(u3_noun); + u3_noun u3wee_sign_raw(u3_noun); + u3_noun u3wee_veri(u3_noun); + u3_noun u3wee_sign_octs(u3_noun); + u3_noun u3wee_sign_octs_raw(u3_noun); + u3_noun u3wee_veri_octs(u3_noun); + u3_noun u3wee_shar(u3_noun); + u3_noun u3wee_slar(u3_noun); + u3_noun u3wee_recs(u3_noun); + u3_noun u3wee_smac(u3_noun); + u3_noun u3wee_point_neg(u3_noun); + u3_noun u3wee_point_add(u3_noun); + u3_noun u3wee_scalarmult(u3_noun); + u3_noun u3wee_scalarmult_base(u3_noun); + u3_noun u3wee_add_scalarmult_scalarmult_base(u3_noun); + u3_noun u3wee_add_double_scalarmult(u3_noun); + + u3_noun u3we_hmac(u3_noun); + + u3_noun u3we_kecc224(u3_noun); + u3_noun u3we_kecc256(u3_noun); + u3_noun u3we_kecc384(u3_noun); + u3_noun u3we_kecc512(u3_noun); + + u3_noun u3we_argon2(u3_noun); + + u3_noun u3we_blake2b(u3_noun); + u3_noun u3we_blake3_hash(u3_noun); + u3_noun u3we_blake3_chunk_output(u3_noun); + u3_noun u3we_blake3_compress(u3_noun); + + u3_noun u3we_chacha_crypt(u3_noun); + u3_noun u3we_chacha_xchacha(u3_noun); + + u3_noun u3we_adler32(u3_noun); + u3_noun u3we_crc32(u3_noun); + + u3_noun u3we_ripe(u3_noun); + + u3_noun u3we_make(u3_noun); + u3_noun u3we_sign(u3_noun); + u3_noun u3we_reco(u3_noun); + + u3_noun u3we_sosi(u3_noun); + u3_noun u3we_sove(u3_noun); + + u3_noun u3we_en_base16(u3_noun); + u3_noun u3we_de_base16(u3_noun); + + u3_noun u3we_json_de(u3_noun); + u3_atom u3we_json_en(u3_noun); + + u3_noun u3we_bend_fun(u3_noun); + u3_noun u3we_cold_fun(u3_noun); + u3_noun u3we_cook_fun(u3_noun); + u3_noun u3we_comp_fun(u3_noun); + u3_noun u3we_easy_fun(u3_noun); + u3_noun u3we_glue_fun(u3_noun); + u3_noun u3we_here_fun(u3_noun); + u3_noun u3we_just_fun(u3_noun); + u3_noun u3we_mask_fun(u3_noun); + u3_noun u3we_shim_fun(u3_noun); + u3_noun u3we_stag_fun(u3_noun); + u3_noun u3we_stew_fun(u3_noun); + u3_noun u3we_stir_fun(u3_noun); + + u3_noun u3wef_drg(u3_noun); + u3_noun u3wef_lug(u3_noun); + + u3_noun u3wer_add(u3_noun); + u3_noun u3wer_sub(u3_noun); + u3_noun u3wer_mul(u3_noun); + u3_noun u3wer_div(u3_noun); + u3_noun u3wer_sqt(u3_noun); + u3_noun u3wer_fma(u3_noun); + u3_noun u3wer_lth(u3_noun); + u3_noun u3wer_lte(u3_noun); + u3_noun u3wer_equ(u3_noun); + u3_noun u3wer_gte(u3_noun); + u3_noun u3wer_gth(u3_noun); + + u3_noun u3wet_add(u3_noun); + u3_noun u3wet_sub(u3_noun); + u3_noun u3wet_mul(u3_noun); + u3_noun u3wet_div(u3_noun); + u3_noun u3wet_sqt(u3_noun); + u3_noun u3wet_fma(u3_noun); + u3_noun u3wet_lth(u3_noun); + u3_noun u3wet_lte(u3_noun); + u3_noun u3wet_equ(u3_noun); + u3_noun u3wet_gte(u3_noun); + u3_noun u3wet_gth(u3_noun); + + u3_noun u3weq_add(u3_noun); + u3_noun u3weq_sub(u3_noun); + u3_noun u3weq_mul(u3_noun); + u3_noun u3weq_div(u3_noun); + u3_noun u3weq_sqt(u3_noun); + u3_noun u3weq_fma(u3_noun); + u3_noun u3weq_lth(u3_noun); + u3_noun u3weq_lte(u3_noun); + u3_noun u3weq_equ(u3_noun); + u3_noun u3weq_gte(u3_noun); + u3_noun u3weq_gth(u3_noun); + + u3_noun u3wes_add(u3_noun); + u3_noun u3wes_sub(u3_noun); + u3_noun u3wes_mul(u3_noun); + u3_noun u3wes_div(u3_noun); + u3_noun u3wes_sqt(u3_noun); + u3_noun u3wes_fma(u3_noun); + u3_noun u3wes_lth(u3_noun); + u3_noun u3wes_lte(u3_noun); + u3_noun u3wes_equ(u3_noun); + u3_noun u3wes_gte(u3_noun); + u3_noun u3wes_gth(u3_noun); + + u3_noun u3we_crc32(u3_noun); + u3_noun u3we_decompress_zlib(u3_noun); + u3_noun u3we_decompress_gzip(u3_noun); + + u3_noun u3we_lia_run_v1(u3_noun); + u3_noun u3we_lia_run_once(u3_noun); + + //+| %utilities + u3_noun u3we_bytestream_rip_octs(u3_noun); + u3_noun u3we_bytestream_cat_octs(u3_noun); + u3_noun u3we_bytestream_can_octs(u3_noun); + //+| %navigation + u3_noun u3we_bytestream_skip_line(u3_noun); + u3_noun u3we_bytestream_find_byte(u3_noun); + u3_noun u3we_bytestream_seek_byte(u3_noun); + //+| %read-byte + u3_noun u3we_bytestream_read_byte(u3_noun); + //+| %read-octs + u3_noun u3we_bytestream_read_octs(u3_noun); + //+| %transformation + u3_noun u3we_bytestream_chunk(u3_noun); + u3_noun u3we_bytestream_extract(u3_noun); + u3_noun u3we_bytestream_fuse_extract(u3_noun); + //+| %bitstream + u3_noun u3we_bytestream_need_bits(u3_noun); + u3_noun u3we_bytestream_drop_bits(u3_noun); + // u3_noun u3we_bytestream_skip_bits(u3_noun); + u3_noun u3we_bytestream_peek_bits(u3_noun); + u3_noun u3we_bytestream_read_bits(u3_noun); + // u3_noun u3we_bytestream_read_need_bits(u3_noun); + u3_noun u3we_bytestream_byte_bits(u3_noun); + + /** Tier 6. + **/ + u3_noun u3wf_bull(u3_noun); + u3_noun u3wf_cell(u3_noun); + u3_noun u3wf_comb(u3_noun); + u3_noun u3wf_cons(u3_noun); + u3_noun u3wf_core(u3_noun); + u3_noun u3wf_cube(u3_noun); + u3_noun u3wf_face(u3_noun); + u3_noun u3wf_fine(u3_noun); + u3_noun u3wf_fitz(u3_noun); + u3_noun u3wf_flan_139(u3_noun); + u3_noun u3wf_flay(u3_noun); + u3_noun u3wf_flip_139(u3_noun); + u3_noun u3wf_flor_139(u3_noun); + u3_noun u3wf_forq(u3_noun); + u3_noun u3wf_fork(u3_noun); + u3_noun u3wf_hint(u3_noun); + u3_noun u3wf_hike(u3_noun); + u3_noun u3wf_look(u3_noun); + u3_noun u3wf_loot(u3_noun); + + u3_noun u3wfl_bunt(u3_noun); + u3_noun u3wfl_whip(u3_noun); + + u3_noun u3wfp_hack(u3_noun); + u3_noun u3wfp_late(u3_noun); + u3_noun u3wfp_open(u3_noun); + u3_noun u3wfp_rake(u3_noun); + + u3_noun u3wfu_busk(u3_noun); + u3_noun u3wfu_crop(u3_noun); + u3_noun u3wfu_find(u3_noun); + u3_noun u3wfu_fond(u3_noun); + u3_noun u3wfu_fish(u3_noun); + u3_noun u3wfu_fuse(u3_noun); + u3_noun u3wfu_redo(u3_noun); + u3_noun u3wfu_mint(u3_noun); + u3_noun u3wfu_mull(u3_noun); + u3_noun u3wfu_nest_dext(u3_noun); + u3_noun u3wfu_peek(u3_noun); + u3_noun u3wfu_play(u3_noun); + u3_noun u3wfu_repo(u3_noun); + u3_noun u3wfu_rest(u3_noun); + + /** Tier 7. + **/ + u3_noun u3wg_plot_fax(u3_noun); + u3_noun u3wg_plot_met(u3_noun); + u3_noun u3wi_la_add(u3_noun); + u3_noun u3wi_la_sub(u3_noun); + u3_noun u3wi_la_mul(u3_noun); + u3_noun u3wi_la_div(u3_noun); + u3_noun u3wi_la_mod(u3_noun); + u3_noun u3wi_la_adds(u3_noun); + u3_noun u3wi_la_subs(u3_noun); + u3_noun u3wi_la_muls(u3_noun); + u3_noun u3wi_la_divs(u3_noun); + u3_noun u3wi_la_mods(u3_noun); + u3_noun u3wi_la_dot(u3_noun); + u3_noun u3wi_la_diag(u3_noun); + u3_noun u3wi_la_transpose(u3_noun); + u3_noun u3wi_la_cumsum(u3_noun); + u3_noun u3wi_la_argmin(u3_noun); + u3_noun u3wi_la_argmax(u3_noun); + u3_noun u3wi_la_ravel(u3_noun); + u3_noun u3wi_la_min(u3_noun); + u3_noun u3wi_la_max(u3_noun); + u3_noun u3wi_la_linspace(u3_noun); + u3_noun u3wi_la_range(u3_noun); + u3_noun u3wi_la_abs(u3_noun); + u3_noun u3wi_la_gth(u3_noun); + u3_noun u3wi_la_gte(u3_noun); + u3_noun u3wi_la_lth(u3_noun); + u3_noun u3wi_la_lte(u3_noun); + + u3_noun u3wi_la_trace(u3_noun); + u3_noun u3wi_la_mmul(u3_noun); + +#endif /* ifndef U3_JETS_W_H */ + diff --git a/vere/pkg/noun/jets_tests.c b/vere/pkg/noun/jets_tests.c new file mode 100644 index 0000000..222b31a --- /dev/null +++ b/vere/pkg/noun/jets_tests.c @@ -0,0 +1,994 @@ +/// @file + +#include "noun.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_init(1 << 20); + u3m_pave(c3y); +} + +static inline c3_i +_ud_etch(c3_d num_d, const c3_c* num_c) +{ + u3_atom num = u3i_chub(num_d); + c3_c* out_c; + size_t len_i = u3s_etch_ud_c(num, &out_c); + c3_i ret_i = 1; + + if ( 0 != strcmp(num_c, out_c) ) { + fprintf(stderr, "etch_ud: %" PRIu64 " fail; expected %s, got '%s'\r\n", + num_d, num_c, out_c); + ret_i = 0; + } + else { + u3_noun out = u3s_etch_ud(num); + u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c); + + if ( c3n == u3r_sing(tou, out) ) { + fprintf(stderr, "etch_ud: %" PRIu64 " mismatch; expected %s\r\n", num_d, num_c); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + u3z(tou); + } + + c3_free(out_c); + u3z(num); + + return ret_i; +} + +static c3_i +_test_etch_ud(void) +{ + c3_i ret_i = 1; + + ret_i &= _ud_etch(0, "0"); + ret_i &= _ud_etch(1, "1"); + ret_i &= _ud_etch(12, "12"); + ret_i &= _ud_etch(123, "123"); + ret_i &= _ud_etch(1234, "1.234"); + ret_i &= _ud_etch(12345, "12.345"); + ret_i &= _ud_etch(123456, "123.456"); + ret_i &= _ud_etch(1234567, "1.234.567"); + ret_i &= _ud_etch(12345678, "12.345.678"); + ret_i &= _ud_etch(123456789, "123.456.789"); + ret_i &= _ud_etch(100000000, "100.000.000"); + ret_i &= _ud_etch(101101101, "101.101.101"); + ret_i &= _ud_etch(201201201, "201.201.201"); + ret_i &= _ud_etch(302201100, "302.201.100"); + + ret_i &= _ud_etch(8589934592ULL, "8.589.934.592"); + ret_i &= _ud_etch(2305843009213693952ULL, "2.305.843.009.213.693.952"); + ret_i &= _ud_etch(18446744073709551615ULL, "18.446.744.073.709.551.615"); + + { + c3_c* num_c = "340.282.366.920.938.463.463.374.607.431.768.211.456"; + u3_atom num = u3qc_bex(128); + c3_c* out_c; + size_t len_i = u3s_etch_ud_c(num, &out_c); + + if ( 0 != strncmp(num_c, out_c, len_i) ) { + fprintf(stderr, "etch_ud: (bex 128) fail; expected %s, got '%s'\r\n", + num_c, out_c); + ret_i = 0; + } + else { + u3_noun out = u3s_etch_ud(num); + u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c); + + if ( c3n == u3r_sing(tou, out) ) { + fprintf(stderr, "etch_ud: (bex 128) mismatch; expected %s\r\n", num_c); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + u3z(tou); + } + + c3_free(out_c); + u3z(num); + } + + return ret_i; +} + +static inline c3_i +_ux_etch(c3_d num_d, const c3_c* num_c) +{ + u3_atom num = u3i_chub(num_d); + c3_c* out_c; + size_t len_i = u3s_etch_ux_c(num, &out_c); + c3_i ret_i = 1; + + if ( 0 != strcmp(num_c, out_c) ) { + fprintf(stderr, "etch_ux: 0x%" PRIx64 " fail; expected %s, got '%s'\r\n", + num_d, num_c, out_c); + ret_i = 0; + } + else { + u3_noun out = u3s_etch_ux(num); + u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c); + + if ( c3n == u3r_sing(tou, out) ) { + fprintf(stderr, "etch_ux: 0x%" PRIx64 " mismatch; expected %s\r\n", num_d, num_c); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + u3z(tou); + } + + c3_free(out_c); + u3z(num); + + return ret_i; +} + +static c3_i +_test_etch_ux(void) +{ + c3_i ret_i = 1; + + ret_i &= _ux_etch(0x0, "0x0"); + ret_i &= _ux_etch(0x1, "0x1"); + ret_i &= _ux_etch(0x12, "0x12"); + ret_i &= _ux_etch(0x123, "0x123"); + ret_i &= _ux_etch(0x1234, "0x1234"); + ret_i &= _ux_etch(0x12345, "0x1.2345"); + ret_i &= _ux_etch(0x123456, "0x12.3456"); + ret_i &= _ux_etch(0x1234567, "0x123.4567"); + ret_i &= _ux_etch(0x12345678, "0x1234.5678"); + ret_i &= _ux_etch(0x123456789, "0x1.2345.6789"); + ret_i &= _ux_etch(0x100000000, "0x1.0000.0000"); + ret_i &= _ux_etch(0x101101101, "0x1.0110.1101"); + ret_i &= _ux_etch(0x201201201, "0x2.0120.1201"); + ret_i &= _ux_etch(0x302201100, "0x3.0220.1100"); + + ret_i &= _ux_etch(0x123456789abcdefULL, "0x123.4567.89ab.cdef"); + ret_i &= _ux_etch(0x8589934592ULL, "0x85.8993.4592"); + ret_i &= _ux_etch(0x5843009213693952ULL, "0x5843.0092.1369.3952"); + ret_i &= _ux_etch(0x6744073709551615ULL, "0x6744.0737.0955.1615"); + + { + c3_c* num_c = "0x1.0000.0000.0000.0000.0000.0000.0000.0000"; + u3_atom num = u3qc_bex(128); + c3_c* out_c; + size_t len_i = u3s_etch_ux_c(num, &out_c); + + if ( 0 != strncmp(num_c, out_c, len_i) ) { + fprintf(stderr, "etch_ux: (bex 128) fail; expected %s, got '%s'\r\n", + num_c, out_c); + ret_i = 0; + } + else { + u3_noun out = u3s_etch_ux(num); + u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c); + + if ( c3n == u3r_sing(tou, out) ) { + fprintf(stderr, "etch_ux: (bex 128) mismatch; expected %s\r\n", num_c); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + u3z(tou); + } + + c3_free(out_c); + u3z(num); + } + + return ret_i; +} + +static inline c3_i +_uv_etch(c3_d num_d, const c3_c* num_c) +{ + u3_atom num = u3i_chub(num_d); + c3_c* out_c; + size_t len_i = u3s_etch_uv_c(num, &out_c); + c3_i ret_i = 1; + + if ( 0 != strcmp(num_c, out_c) ) { + fprintf(stderr, "etch_uv: 0x%" PRIx64 " fail; expected %s, got '%s'\r\n", + num_d, num_c, out_c); + ret_i = 0; + } + else { + u3_noun out = u3s_etch_uv(num); + u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c); + + if ( c3n == u3r_sing(tou, out) ) { + fprintf(stderr, "etch_uv: 0x%" PRIx64 " mismatch; expected %s\r\n", num_d, num_c); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + u3z(tou); + } + + c3_free(out_c); + u3z(num); + + return ret_i; +} + +static c3_i +_test_etch_uv(void) +{ + c3_i ret_i = 1; + + ret_i &= _uv_etch(0x0, "0v0"); + ret_i &= _uv_etch(0x1, "0v1"); + ret_i &= _uv_etch(0x10, "0vg"); + ret_i &= _uv_etch(0x12, "0vi"); + ret_i &= _uv_etch(0x123, "0v93"); + ret_i &= _uv_etch(0x1234, "0v4hk"); + ret_i &= _uv_etch(0x12345, "0v28q5"); + ret_i &= _uv_etch(0x123456, "0v14d2m"); + ret_i &= _uv_etch(0x1234567, "0vi6hb7"); + ret_i &= _uv_etch(0x12345678, "0v9.38ljo"); + ret_i &= _uv_etch(0x123456789, "0v4h.kaps9"); + ret_i &= _uv_etch(0x100000000, "0v40.00000"); + ret_i &= _uv_etch(0x101101101, "0v40.h0481"); + ret_i &= _uv_etch(0x201201201, "0v80.i04g1"); + ret_i &= _uv_etch(0x302201100, "0vc1.20480"); + + ret_i &= _uv_etch(0x123456789abcdefULL, "0v28.q5cu4.qnjff"); + ret_i &= _uv_etch(0x8589934592ULL, "0vgm4.p6hci"); + ret_i &= _uv_etch(0x5843009213693952ULL, "0v5gg.o0i89.mieai"); + ret_i &= _uv_etch(0x6744073709551615ULL, "0v6eh.076s4.la5gl"); + + { + c3_c* num_c = "0v8.00000.00000.00000.00000.00000"; + u3_atom num = u3qc_bex(128); + c3_c* out_c; + size_t len_i = u3s_etch_uv_c(num, &out_c); + + if ( 0 != strncmp(num_c, out_c, len_i) ) { + fprintf(stderr, "etch_uv: (bex 128) fail; expected %s, got '%s'\r\n", + num_c, out_c); + ret_i = 0; + } + else { + u3_noun out = u3s_etch_uv(num); + u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c); + + if ( c3n == u3r_sing(tou, out) ) { + // fprintf(stderr, "etch_uv: (bex 128) mismatch; expected %s\r\n", num_c); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + u3z(tou); + } + + c3_free(out_c); + u3z(num); + } + + return ret_i; +} + +static inline c3_i +_uw_etch(c3_d num_d, const c3_c* num_c) +{ + u3_atom num = u3i_chub(num_d); + c3_c* out_c; + size_t len_i = u3s_etch_uw_c(num, &out_c); + c3_i ret_i = 1; + + if ( 0 != strcmp(num_c, out_c) ) { + fprintf(stderr, "etch_uw: 0x%" PRIx64 " fail; expected %s, got '%s'\r\n", + num_d, num_c, out_c); + ret_i = 0; + } + else { + u3_noun out = u3s_etch_uw(num); + u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c); + + if ( c3n == u3r_sing(tou, out) ) { + fprintf(stderr, "etch_uw: 0x%" PRIx64 " mismatch; expected %s\r\n", num_d, num_c); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + u3z(tou); + } + + c3_free(out_c); + u3z(num); + + return ret_i; +} + +static c3_i +_test_etch_uw(void) +{ + c3_i ret_i = 1; + + ret_i &= _uw_etch(0x0, "0w0"); + ret_i &= _uw_etch(0x1, "0w1"); + ret_i &= _uw_etch(0x10, "0wg"); + ret_i &= _uw_etch(0x12, "0wi"); + ret_i &= _uw_etch(0x123, "0w4z"); + ret_i &= _uw_etch(0x1234, "0w18Q"); + ret_i &= _uw_etch(0x12345, "0wid5"); + ret_i &= _uw_etch(0x123456, "0w4zhm"); + ret_i &= _uw_etch(0x1234567, "0w18QlD"); + ret_i &= _uw_etch(0x12345678, "0wid5pU"); + ret_i &= _uw_etch(0x123456789, "0w4.zhmu9"); + ret_i &= _uw_etch(0x100000000, "0w4.00000"); + ret_i &= _uw_etch(0x101101101, "0w4.14141"); + ret_i &= _uw_etch(0x201201201, "0w8.18181"); + ret_i &= _uw_etch(0x302201100, "0wc.28140"); + + ret_i &= _uw_etch(0x123456789abcdefULL, "0w4zhmu.9GYTL"); + ret_i &= _uw_etch(0x8589934592ULL, "0w8m.9AQmi"); + ret_i &= _uw_etch(0x5843009213693952ULL, "0w5.x3098.jqjBi"); + ret_i &= _uw_etch(0x6744073709551615ULL, "0w6.t41Ps.9lhol"); + + { + c3_c* num_c = "0w40.00000.00000.00000.00000"; + u3_atom num = u3qc_bex(128); + c3_c* out_c; + size_t len_i = u3s_etch_uw_c(num, &out_c); + + if ( 0 != strncmp(num_c, out_c, len_i) ) { + fprintf(stderr, "etch_uw: (bex 128) fail; expected %s, got '%s'\r\n", + num_c, out_c); + ret_i = 0; + } + else { + u3_noun out = u3s_etch_uw(num); + u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c); + + if ( c3n == u3r_sing(tou, out) ) { + fprintf(stderr, "etch_uw: (bex 128) mismatch; expected %s\r\n", num_c); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + u3z(tou); + } + + c3_free(out_c); + u3z(num); + } + + return ret_i; +} + +static inline c3_i +_ud_good(c3_w num_w, const c3_c* num_c) +{ + u3_weak out; + if ( num_w != (out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c)) ) { + if ( u3_none == out ) { + fprintf(stderr, "sift_ud: %s fail; expected %u\r\n", num_c, num_w); + } + else { + fprintf(stderr, "sift_ud: %s wrong; expected %u: actual %u\r\n", num_c, num_w, out); + } + return 0; + } + + return 1; +} + +static inline c3_i +_ud_fail(const c3_c* num_c) +{ + u3_weak out; + if ( u3_none != (out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c)) ) { + u3m_p("out", out); + fprintf(stderr, "sift_ud: %s expected fail\r\n", num_c); + return 0; + } + + return 1; +} + +static c3_i +_test_sift_ud(void) +{ + c3_i ret_i = 1; + + ret_i &= _ud_good(0, "0"); + ret_i &= _ud_good(1, "1"); + ret_i &= _ud_good(12, "12"); + ret_i &= _ud_good(123, "123"); + ret_i &= _ud_good(1234, "1.234"); + ret_i &= _ud_good(12345, "12.345"); + ret_i &= _ud_good(123456, "123.456"); + ret_i &= _ud_good(1234567, "1.234.567"); + ret_i &= _ud_good(12345678, "12.345.678"); + ret_i &= _ud_good(123456789, "123.456.789"); + ret_i &= _ud_good(100000000, "100.000.000"); + ret_i &= _ud_good(101101101, "101.101.101"); + ret_i &= _ud_good(201201201, "201.201.201"); + ret_i &= _ud_good(302201100, "302.201.100"); + + ret_i &= _ud_fail("01"); + ret_i &= _ud_fail("02"); + ret_i &= _ud_fail("003"); + ret_i &= _ud_fail("1234"); + ret_i &= _ud_fail("1234.5"); + ret_i &= _ud_fail("1234.567.8"); + ret_i &= _ud_fail("1234.56..78."); + ret_i &= _ud_fail("123.45a"); + ret_i &= _ud_fail(".123.456"); + + { + c3_c* num_c = "4.294.967.296"; + u3_weak out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c); + u3_atom pro = u3qc_bex(32); + + if ( u3_none == out ) { + fprintf(stderr, "sift_ud: (bex 32) fail\r\n"); + ret_i = 0; + } + + if ( c3n == u3r_sing(pro, out) ) { + u3m_p("out", out); + fprintf(stderr, "sift_ud: (bex 32) wrong\r\n"); + ret_i = 0; + } + + u3z(out); u3z(pro); + } + + + { + c3_c* num_c = "340.282.366.920.938.463.463.374.607.431.768.211.456"; + u3_weak out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c); + u3_atom pro = u3qc_bex(128); + + if ( u3_none == out ) { + fprintf(stderr, "sift_ud: (bex 128) fail\r\n"); + ret_i = 0; + } + + if ( c3n == u3r_sing(pro, out) ) { + u3m_p("out", out); + fprintf(stderr, "sift_ud: (bex 128) wrong\r\n"); + ret_i = 0; + } + + u3z(out); u3z(pro); + } + + return ret_i; +} + +static c3_i +_test_en_base16(void) +{ + c3_i ret_i = 1; + + { + u3_atom dat = 0xaa; + u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat); + + if ( c3n == u3r_sing_c("aa", pro) ) { + fprintf(stderr, "en_base16: fail (a)\r\n"); + ret_i = 0; + } + + u3z(pro); + } + + { + u3_atom dat = 0x1234; + u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat); + + if ( c3n == u3r_sing_c("1234", pro) ) { + fprintf(stderr, "en_base16: fail (b)\r\n"); + ret_i = 0; + } + + u3z(pro); + } + + { + u3_atom dat = 0xf012; + u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat); + + if ( c3n == u3r_sing_c("f012", pro) ) { + fprintf(stderr, "en_base16: fail (c)\r\n"); + ret_i = 0; + } + + u3z(pro); + } + + { + u3_atom dat = 0x10b; + u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat); + + if ( c3n == u3r_sing_c("010b", pro) ) { + fprintf(stderr, "en_base16: fail (d)\r\n"); + ret_i = 0; + } + + u3z(pro); + } + + { + u3_atom pro = u3qe_en_base16(3, 0x1234); + + if ( c3n == u3r_sing_c("001234", pro) ) { + fprintf(stderr, "en_base16: fail (e)\r\n"); + ret_i = 0; + } + + u3z(pro); + } + + { + u3_atom pro = u3qe_en_base16(1, 0x1234); + + if ( c3n == u3r_sing_c("34", pro) ) { + fprintf(stderr, "en_base16: fail (f)\r\n"); + ret_i = 0; + } + + u3z(pro); + } + + return ret_i; +} + + +static c3_i +_test_de_base16(void) +{ + c3_i ret_i = 1; + + { + u3_noun inp = u3i_string("aa"); + u3_noun pro = u3qe_de_base16(inp); + u3_atom len, dat; + + if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { + fprintf(stderr, "de_base16: fail cell (a)\r\n"); + ret_i = 0; + } + + if ( 1 != len ) { + fprintf(stderr, "de_base16: fail len (a)\r\n"); + ret_i = 0; + } + + if ( 0xaa != dat ) { + fprintf(stderr, "de_base16: fail dat (a)\r\n"); + ret_i = 0; + } + + u3z(inp); u3z(pro); + } + + { + u3_noun inp = u3i_string("1234"); + u3_noun pro = u3qe_de_base16(inp); + u3_atom len, dat; + + if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { + fprintf(stderr, "de_base16: fail cell (b)\r\n"); + ret_i = 0; + } + + if ( 2 != len ) { + fprintf(stderr, "de_base16: fail len (b)\r\n"); + ret_i = 0; + } + + if ( 0x1234 != dat ) { + fprintf(stderr, "de_base16: fail dat (b)\r\n"); + ret_i = 0; + } + + u3z(inp); u3z(pro); + } + + { + u3_noun inp = u3i_string("f012"); + u3_noun pro = u3qe_de_base16(inp); + u3_atom len, dat; + + if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { + fprintf(stderr, "de_base16: fail cell (c)\r\n"); + ret_i = 0; + } + + if ( 2 != len ) { + fprintf(stderr, "de_base16: fail len (c)\r\n"); + ret_i = 0; + } + + if ( 0xf012 != dat ) { + fprintf(stderr, "de_base16: fail dat (c)\r\n"); + ret_i = 0; + } + + u3z(inp); u3z(pro); + } + + { + u3_noun inp = u3i_string("010b"); + u3_noun pro = u3qe_de_base16(inp); + u3_atom len, dat; + + if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { + fprintf(stderr, "de_base16: fail cell (d)\r\n"); + ret_i = 0; + } + + if ( 2 != len ) { + fprintf(stderr, "de_base16: fail len (d)\r\n"); + ret_i = 0; + } + + if ( 0x10b != dat ) { + fprintf(stderr, "de_base16: fail dat (d)\r\n"); + ret_i = 0; + } + + u3z(inp); u3z(pro); + } + + { + u3_noun inp = u3i_string("10b"); + u3_noun pro = u3qe_de_base16(inp); + u3_atom len, dat; + + if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { + fprintf(stderr, "de_base16: fail cell (e)\r\n"); + ret_i = 0; + } + + if ( 2 != len ) { + fprintf(stderr, "de_base16: fail len (e)\r\n"); + ret_i = 0; + } + + if ( 0x10b != dat ) { + fprintf(stderr, "de_base16: fail dat (e)\r\n"); + ret_i = 0; + } + + u3z(inp); u3z(pro); + } + + { + u3_noun inp = u3i_string("001234"); + u3_noun pro = u3qe_de_base16(inp); + u3_atom len, dat; + + if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { + fprintf(stderr, "de_base16: fail cell (f)\r\n"); + ret_i = 0; + } + + if ( 3 != len ) { + fprintf(stderr, "de_base16: fail len (f)\r\n"); + ret_i = 0; + } + + if ( 0x1234 != dat ) { + fprintf(stderr, "de_base16: fail dat (f)\r\n"); + ret_i = 0; + } + + u3z(inp); u3z(pro); + } + + return ret_i; +} + +static c3_i +_test_base16(void) +{ + c3_i ret_i = 1; + + ret_i &= _test_en_base16(); + ret_i &= _test_de_base16(); + + return ret_i; +} + +static c3_w +_fein_ob_w(c3_w inp_w) +{ + u3_atom inp = u3i_word(inp_w); + u3_atom act = u3qe_fein_ob(inp); + c3_w act_w = u3r_word(0, act); + u3z(inp); u3z(act); + return act_w; +} + +static c3_i +_expect_fein_ob_w(c3_w inp_w, c3_w exp_w) +{ + c3_w act_w = _fein_ob_w(inp_w); + + if ( act_w != exp_w ) { + fprintf(stderr, "fein: inp=0x%08x exp=0x%08x act=0x%08x\n", + inp_w, exp_w, act_w); + return 0; + } + + return 1; +} + +static c3_i +_test_fein_ob(void) +{ + c3_i ret_i = 1; + + ret_i &= _expect_fein_ob_w(0, 0); + ret_i &= _expect_fein_ob_w(0xffff, 0xffff); + ret_i &= _expect_fein_ob_w(0x1b08f, 0x76b920e5); + ret_i &= _expect_fein_ob_w(0x10000, 0x423e60bf); + ret_i &= _expect_fein_ob_w(0x10001, 0xd4400acb); + ret_i &= _expect_fein_ob_w(0x10002, 0xf429043); + ret_i &= _expect_fein_ob_w(0x10000000, 0xa04bc7fa); + ret_i &= _expect_fein_ob_w(0x1234abcd, 0x686f6c25); + ret_i &= _expect_fein_ob_w(0xabcd1234, 0x4a220c8); + ret_i &= _expect_fein_ob_w(0xdeadbeef, 0x909bc4a9); + ret_i &= _expect_fein_ob_w(0xfffff, 0x6746b96b); + ret_i &= _expect_fein_ob_w(0xffffffff, 0xbba4dcce); + + return ret_i; +} + +static c3_w +_fynd_ob_w(c3_w inp_w) +{ + u3_atom inp = u3i_word(inp_w); + u3_atom act = u3qe_fynd_ob(inp); + c3_w act_w = u3r_word(0, act); + u3z(inp); u3z(act); + return act_w; +} + +static c3_i +_expect_fynd_ob_w(c3_w exp_w, c3_w inp_w) +{ + c3_w act_w = _fynd_ob_w(inp_w); + + if ( act_w != exp_w ) { + fprintf(stderr, "fynd: inp=0x%08x exp=0x%08x act=0x%08x\n", + inp_w, exp_w, act_w); + return 0; + } + + return 1; +} + +static c3_i +_test_fynd_ob(void) +{ + c3_i ret_i = 1; + + ret_i &= _expect_fynd_ob_w(0, 0); + ret_i &= _expect_fynd_ob_w(0xffff, 0xffff); + ret_i &= _expect_fynd_ob_w(0x10000, 0x423e60bf); + ret_i &= _expect_fynd_ob_w(0x10001, 0xd4400acb); + ret_i &= _expect_fynd_ob_w(0x10002, 0xf429043); + ret_i &= _expect_fynd_ob_w(0x10000000, 0xa04bc7fa); + ret_i &= _expect_fynd_ob_w(0x1234abcd, 0x686f6c25); + ret_i &= _expect_fynd_ob_w(0xabcd1234, 0x4a220c8); + ret_i &= _expect_fynd_ob_w(0xdeadbeef, 0x909bc4a9); + ret_i &= _expect_fynd_ob_w(0xfffff, 0x6746b96b); + ret_i &= _expect_fynd_ob_w(0xffffffff, 0xbba4dcce); + + return ret_i; +} + +static c3_i +_exhaust_roundtrip_fein_fynd_ob(void) +{ + c3_i ret_i = 1; + c3_w fyn_w, i_w; + + { + u3_atom fen, fyn; + + for ( i_w = 0x10000; i_w < 0x80000000; i_w++ ) { + fen = u3qe_fein_ob(i_w); + fyn = u3qe_fynd_ob(fen); + fyn_w = u3r_word(0, fyn); + + if ( i_w != fyn_w ) { + fprintf(stderr, "fein/fynd: inp=0x%08x fein=0x%08x fynd=0x%08x\n", + i_w, u3r_word(0, fen), fyn_w); + ret_i = 0; + } + u3z(fen); u3z(fyn); + + if ( !(i_w % 0x1000000) ) { + fprintf(stderr, "fein/fynd: 0x%x done\n", i_w); + } + } + } + + { + c3_w fen_w; + + do { + fen_w = _fein_ob_w(i_w); + fyn_w = _fynd_ob_w(fen_w); + if ( i_w != fyn_w ) { + fprintf(stderr, "fein/fynd: inp=0x%08x fein=0x%08x fynd=0x%08x\n", + i_w, fen_w, fyn_w); + ret_i = 0; + } + + if ( !(i_w % 0x1000000) ) { + fprintf(stderr, "fein/fynd: 0x%x done\n", i_w); + } + } + while ( ++i_w ); + } + + return ret_i; +} + +static c3_i +_test_ob(void) +{ + c3_i ret_i = 1; + ret_i &= _test_fein_ob(); + ret_i &= _test_fynd_ob(); + // disabled, takes almost ~m15 + // + // ret_i &= _exhaust_roundtrip_fein_fynd_ob(); + return ret_i; +} + +static c3_i +_test_mas(void) +{ + c3_i ret_i = 1; + u3_atom res; + + if ( 0x4000 != (res = u3qc_mas(0x8000)) ) { + fprintf(stderr, "test mas fail: (mas 0x8000) != 0x4000: 0x'%x'\r\n", res); + ret_i = 0; + } + + if ( 0x20000000 != (res = u3qc_mas(0x40000000)) ) { + fprintf(stderr, "test mas fail: (mas 0x4000.0000) != 0x2000.0000: 0x%x\r\n", res); + ret_i = 0; + } + + { + u3_atom sam, pro; + + sam = u3qc_bex(36); + pro = u3qc_bex(35); + res = u3qc_mas(sam); + + if ( c3n == u3r_sing(pro, res) ) { + c3_c* out_c; + u3s_etch_ux_c(res, &out_c); + fprintf(stderr, "test mas fail: (mas (bex 36)) != (bex 35): %s\r\n", out_c); + c3_free(out_c); + ret_i = 0; + } + + u3z(res); u3z(sam); u3z(pro); + + sam = u3qc_bex(64); + pro = u3qc_bex(63); + res = u3qc_mas(sam); + + if ( c3n == u3r_sing(pro, res) ) { + c3_c* out_c; + u3s_etch_ux_c(res, &out_c); + fprintf(stderr, "test mas fail: (mas (bex 64)) != (bex 63): %s\r\n", out_c); + c3_free(out_c); + ret_i = 0; + } + + u3z(res); u3z(sam); u3z(pro); + + sam = u3qc_bex(65); + pro = u3qc_bex(64); + res = u3qc_mas(sam); + + if ( c3n == u3r_sing(pro, res) ) { + c3_c* out_c; + u3s_etch_ux_c(res, &out_c); + fprintf(stderr, "test mas fail: (mas (bex 65)) != (bex 64): %s\r\n", out_c); + c3_free(out_c); + ret_i = 0; + } + + u3z(res); u3z(sam); u3z(pro); + } + + return ret_i; +} + +static c3_i +_test_jets(void) +{ + c3_i ret_i = 1; + + if ( !_test_etch_ud() ) { + fprintf(stderr, "test jets: etch_ud: failed\r\n"); + ret_i = 0; + } + + if ( !_test_etch_ux() ) { + fprintf(stderr, "test jets: etch_ux: failed\r\n"); + ret_i = 0; + } + + if ( !_test_etch_uv() ) { + fprintf(stderr, "test jets: etch_uv: failed\r\n"); + ret_i = 0; + } + + if ( !_test_etch_uw() ) { + fprintf(stderr, "test jets: etch_uw: failed\r\n"); + ret_i = 0; + } + + if ( !_test_sift_ud() ) { + fprintf(stderr, "test jets: sift_ud: failed\r\n"); + ret_i = 0; + } + + if ( !_test_base16() ) { + fprintf(stderr, "test jets: base16: failed\r\n"); + ret_i = 0; + } + + if ( !_test_ob() ) { + fprintf(stderr, "test jets: ob: failed\r\n"); + ret_i = 0; + } + + if ( !_test_mas() ) { + fprintf(stderr, "test jets: mas: failed\r\n"); + ret_i = 0; + } + + return ret_i; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_jets() ) { + fprintf(stderr, "test jets: failed\r\n"); + exit(1); + } + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "test jets: ok\r\n"); + return 0; +} diff --git a/vere/pkg/noun/log.c b/vere/pkg/noun/log.c new file mode 100644 index 0000000..ee1888e --- /dev/null +++ b/vere/pkg/noun/log.c @@ -0,0 +1,40 @@ +/// @file + +#include "log.h" + +#include <stdarg.h> + +#include "options.h" + +void +u3l_log(const char* format, ...) +{ + va_list myargs; + va_start(myargs, format); + + if (u3C.stderr_log_f) { + // the user set their own logging function. render the line and redirect + // to them. + // + char msg[4096]; + vsnprintf(msg, 4096, format, myargs); + u3C.stderr_log_f(msg); + } else { + // this process did not set a logging function, fallback to stderr + // + vfprintf(stderr, format, myargs); + fprintf(stderr, "\r\n"); + fflush(stderr); + } + + va_end(myargs); +} + +u3_weak +u3l_punt(const char* name, u3_weak pro) +{ + if ( u3_none == pro ) { + u3l_log("%s-punt", name); + } + return pro; +} diff --git a/vere/pkg/noun/log.h b/vere/pkg/noun/log.h new file mode 100644 index 0000000..4e94147 --- /dev/null +++ b/vere/pkg/noun/log.h @@ -0,0 +1,24 @@ +/// @file + +#ifndef U3_LOG_H +#define U3_LOG_H + +#include "types.h" + +/* u3l_log(): logs to stderr or redirects to configured function. +*/ + void + u3l_log(const char* format, ...) + __attribute__ ((format (printf, 1, 2))); + +/* u3l_punt(): condtionally logs a named punt + * (e.g. "mint-punt" for the `name` "mint") + * when `pro` is u3_none, and returns pro. + * For use when a jet driver declines to handle + * a core, when the user should be somehow notified + * (e.g. in a cryptographic jet). + */ + u3_weak + u3l_punt(const char* name, u3_weak pro); + +#endif /* ifndef U3_LOG_H */ diff --git a/vere/pkg/noun/manage.c b/vere/pkg/noun/manage.c new file mode 100644 index 0000000..92e36dc --- /dev/null +++ b/vere/pkg/noun/manage.c @@ -0,0 +1,2615 @@ +/// @file + +#include "manage.h" + +#include <ctype.h> +#ifndef U3_OS_windows +#include <dlfcn.h> +#endif +#include <errno.h> +#include <signal.h> +#if defined(U3_OS_osx) +#include <execinfo.h> +#endif +#include <fcntl.h> +#include <sys/stat.h> +#if defined(U3_OS_linux) +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#endif + +#include "allocate.h" +#include "backtrace.h" +#include "events.h" +#include "hashtable.h" +#include "imprison.h" +#include "jets.h" +#include "jets/k.h" +#include "jets/q.h" +#include "log.h" +#include "nock.h" +#include "openssl/crypto.h" +#include "options.h" +#include "rsignal.h" +#include "retrieve.h" +#include "trace.h" +#include "urcrypt.h" +#include "vortex.h" +#include "whereami.h" +#include "xtract.h" + +// XX stack-overflow recovery should be gated by -a +// +#undef NO_OVERFLOW + + /* (u3_noun)setjmp(u3R->esc.buf): setjmp within road. + */ +#if 0 + c3_o + u3m_trap(void); +#else +# define u3m_trap() (u3_noun)(setjmp(u3R->esc.buf)) +#endif + + /* u3m_signal(): treat a nock-level exception as a signal interrupt. + */ + void + u3m_signal(u3_noun sig_l); + + /* u3m_dump(): dump the current road to stderr. + */ + void + u3m_dump(void); + + /* u3m_fall(): return to parent road. + */ + void + u3m_fall(void); + + /* u3m_leap(): in u3R, create a new road within the existing one. + */ + void + u3m_leap(c3_w pad_w); + + /* u3m_golf(): record cap length for u3m_flog(). + */ + c3_w + u3m_golf(void); + + /* u3m_flog(): pop the cap. + ** + ** A common sequence for inner allocation is: + ** + ** c3_w gof_w = u3m_golf(); + ** u3m_leap(); + ** // allocate some inner stuff... + ** u3m_fall(); + ** // inner stuff is still valid, but on cap + ** u3m_flog(gof_w); + ** + ** u3m_flog(0) simply clears the cap. + */ + void + u3m_flog(c3_w gof_w); + + /* u3m_soft_top(): top-level safety wrapper. + */ + u3_noun + u3m_soft_top(c3_w mil_w, // timer ms + c3_w pad_w, // base memory pad + u3_funk fun_f, + u3_noun arg); + + +// u3m_signal uses restricted functionality signals for compatibility reasons: +// some platforms may not provide true POSIX asynchronous signals and their +// compat layer will then implement this restricted functionality subset. +// u3m_signal never needs to interrupt I/O operations, its signal handlers +// do not manipulate signals, do not modify shared state, and always either +// return or longjmp. +// +static jmp_buf u3_Signal; + +#ifndef U3_OS_windows +#include "sigsegv.h" + +#ifndef SIGSTKSZ +# define SIGSTKSZ 16384 +#endif +#ifndef NO_OVERFLOW +static uint8_t Sigstk[SIGSTKSZ]; +#endif +#endif + +#ifdef U3_OS_windows +#include "veh_handler.h" +#endif + +#if 0 +/* _cm_punt(): crudely print trace. +*/ +static void +_cm_punt(u3_noun tax) +{ + u3_noun xat; + + for ( xat = tax; xat; xat = u3t(xat) ) { + u3m_p("&", u3h(xat)); + } +} +#endif + +/* _cm_emergency(): write emergency text to stderr, never failing. +*/ +static void +_cm_emergency(c3_c* cap_c, c3_l sig_l) +{ + write(2, "\r\n", 2); + write(2, cap_c, strlen(cap_c)); + + if ( sig_l ) { + write(2, ": ", 2); + write(2, &sig_l, 4); + } + + write(2, "\r\n", 2); +} + +static void _cm_overflow(void *arg1, void *arg2, void *arg3) +{ + (void)(arg1); + (void)(arg2); + (void)(arg3); + u3m_signal(c3__over); +} + +/* _cm_signal_handle(): handle a signal in general. +*/ +static void +_cm_signal_handle(c3_l sig_l) +{ +#ifndef U3_OS_windows + if ( c3__over == sig_l ) { +#ifndef NO_OVERFLOW + sigsegv_leave_handler(_cm_overflow, NULL, NULL, NULL); +#endif + } else +#endif + { + u3m_signal(sig_l); + } +} + +#ifndef NO_OVERFLOW +static void +#ifndef U3_OS_windows +_cm_signal_handle_over(int emergency, stackoverflow_context_t scp) +#else +_cm_signal_handle_over(int x) +#endif +{ + _cm_signal_handle(c3__over); +} +#endif + +static void +_cm_signal_handle_term(int x) +{ + // Ignore if we are using base memory from work memory, very rare. + // + if ( (0 != u3H->rod_u.kid_p) && (&(u3H->rod_u) == u3R) ) { + _cm_emergency("ignored", c3__term); + } + else { + _cm_signal_handle(c3__term); + } +} + +static void +_cm_signal_handle_intr(int x) +{ + // Interrupt: stop work. Ignore if not working, or (rarely) using base. + // + if ( &(u3H->rod_u) == u3R ) { + _cm_emergency("ignored", c3__intr); + } + else { + _cm_signal_handle(c3__intr); + } +} + +static void +_cm_signal_handle_alrm(int x) +{ + _cm_signal_handle(c3__alrm); +} + +/* _cm_signal_reset(): reset top road after signal longjmp. +*/ +static void +_cm_signal_reset(void) +{ + u3R = &u3H->rod_u; + u3R->cap_p = u3R->mat_p; + u3R->ear_p = 0; + u3R->kid_p = 0; +} + +#if 0 +/* _cm_stack_recover(): recover stack trace, with lacunae. +*/ +static u3_noun +_cm_stack_recover(u3a_road* rod_u) +{ + c3_w len_w; + + len_w = 0; + { + u3_noun tax = rod_u->bug.tax; + + while ( tax ) { + len_w++; + tax = u3t(tax); + } + + if ( len_w < 4096 ) { + return u3a_take(rod_u->bug.tax); + } + else { + u3_noun beg, fin; + c3_w i_w; + + tax = rod_u->bug.tax; + beg = u3_nul; + for ( i_w = 0; i_w < 2048; i_w++ ) { + beg = u3nc(u3a_take(u3h(tax)), beg); + tax = u3t(tax); + } + beg = u3kb_flop(beg); + + for ( i_w = 0; i_w < (len_w - 4096); i_w++ ) { + tax = u3t(tax); + } + fin = u3nc(u3nc(c3__lose, c3__over), u3a_take(tax)); + + return u3kb_weld(beg, fin); + } + } +} +#endif + +/* _cm_stack_unwind(): unwind to the top level, preserving all frames. +*/ +static u3_noun +_cm_stack_unwind(void) +{ + u3_noun tax; + + while ( u3R != &(u3H->rod_u) ) { + u3_noun yat = u3m_love(u3R->bug.tax); + + u3R->bug.tax = u3kb_weld(yat, u3R->bug.tax); + } + tax = u3R->bug.tax; + + u3R->bug.tax = 0; + return tax; +} + +/* _cm_signal_recover(): recover from a deep signal, after longjmp. Free arg. +*/ +static u3_noun +_cm_signal_recover(c3_l sig_l, u3_noun arg) +{ + u3_noun tax; + + // Unlikely to be set, but it can be made to happen. + // + tax = u3H->rod_u.bug.tax; + u3H->rod_u.bug.tax = 0; + + if ( NULL != stk_u ) { + stk_u->off_w = u3H->rod_u.off_w; + stk_u->fow_w = u3H->rod_u.fow_w; + } + + if ( &(u3H->rod_u) == u3R ) { + // A top-level crash - rather odd. We should GC. + // + _cm_emergency("recover: top", sig_l); + u3C.wag_w |= u3o_check_corrupt; + + // Reset the top road - the problem could be a fat cap. + // + _cm_signal_reset(); + + if ( (c3__meme == sig_l) && (u3a_open(u3R) <= 256) ) { + // Out of memory at the top level. Error becomes c3__full, + // and we release the emergency buffer. To continue work, + // we need to readjust the image, eg, migrate to 64 bit. + // + u3z(u3R->bug.mer); + u3R->bug.mer = 0; + sig_l = c3__full; + } + return u3nt(3, sig_l, tax); + } + else { + u3_noun pro; + + // A signal was generated while we were within Nock. + // + _cm_emergency("recover: dig", sig_l); + +#if 0 + // Descend to the innermost trace, collecting stack. + // + { + u3a_road* rod_u; + + u3R = &(u3H->rod_u); + rod_u = u3R; + + while ( rod_u->kid_p ) { +#if 0 + u3l_log("collecting %d frames", + u3kb_lent((u3to(u3_road, rod_u->kid_p)->bug.tax)); +#endif + tax = u3kb_weld(_cm_stack_recover(u3to(u3_road, rod_u->kid_p)), tax); + rod_u = u3to(u3_road, rod_u->kid_p); + } + } +#else + tax = _cm_stack_unwind(); +#endif + pro = u3nt(3, sig_l, tax); + _cm_signal_reset(); + + u3z(arg); + return pro; + } +} + +/* _cm_signal_deep(): start deep processing; set timer for [mil_w] or 0. +*/ +static void +_cm_signal_deep(c3_w mil_w) +{ + // disable outer system signal handling + // + if ( 0 != u3C.sign_hold_f ) { + u3C.sign_hold_f(); + } + +#ifndef NO_OVERFLOW +#ifndef U3_OS_windows + if ( 0 != stackoverflow_install_handler(_cm_signal_handle_over, Sigstk, SIGSTKSZ)) { + u3l_log("unable to install stack overflow handler"); + abort(); + } +#else + rsignal_install_handler(SIGSTK, _cm_signal_handle_over); +#endif +#endif + rsignal_install_handler(SIGINT, _cm_signal_handle_intr); + rsignal_install_handler(SIGTERM, _cm_signal_handle_term); + + // Provide a little emergency memory, for use in case things + // go utterly haywire. + // + if ( 0 == u3H->rod_u.bug.mer ) { + u3H->rod_u.bug.mer = u3i_string( + "emergency buffer with sufficient space to cons the trace and bail" + ); + } + + if ( mil_w ) { + struct itimerval itm_u; + + timerclear(&itm_u.it_interval); + itm_u.it_value.tv_sec = (mil_w / 1000); + itm_u.it_value.tv_usec = 1000 * (mil_w % 1000); + + if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { + u3l_log("loom: set timer failed %s", strerror(errno)); + } + else { + rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm); + } + } + + u3t_boot(); +} + +/* _cm_signal_done(): +*/ +static void +_cm_signal_done(void) +{ + rsignal_deinstall_handler(SIGINT); + rsignal_deinstall_handler(SIGTERM); + rsignal_deinstall_handler(SIGVTALRM); + +#ifndef NO_OVERFLOW +#ifndef U3_OS_windows + stackoverflow_deinstall_handler(); +#else + rsignal_install_handler(SIGSTK, _cm_signal_handle_over); +#endif +#endif + { + struct itimerval itm_u; + + timerclear(&itm_u.it_interval); + timerclear(&itm_u.it_value); + + if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { + u3l_log("loom: clear timer failed %s", strerror(errno)); + } + } + + // restore outer system signal handling + // + if ( 0 != u3C.sign_move_f ) { + u3C.sign_move_f(); + } + + u3t_boff(); +} + +/* u3m_signal(): treat a nock-level exception as a signal interrupt. +*/ +void +u3m_signal(u3_noun sig_l) +{ + rsignal_longjmp(u3_Signal, sig_l); +} + +/* u3m_file(): load file, as atom, or bail. +*/ +u3_noun +u3m_file(c3_c* pas_c) +{ + struct stat buf_b; + c3_i fid_i = c3_open(pas_c, O_RDONLY, 0644); + c3_w fln_w, red_w; + c3_y* pad_y; + + if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) { + u3l_log("%s: %s", pas_c, strerror(errno)); + return u3m_bail(c3__fail); + } + fln_w = buf_b.st_size; + pad_y = c3_malloc(buf_b.st_size); + + red_w = read(fid_i, pad_y, fln_w); + close(fid_i); + + if ( fln_w != red_w ) { + c3_free(pad_y); + return u3m_bail(c3__fail); + } + else { + u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y); + c3_free(pad_y); + + return pad; + } +} + +/* u3m_mark(): mark all nouns in the road. +*/ +u3m_quac** +u3m_mark(void) +{ + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 5); + qua_u[0] = u3v_mark(); + qua_u[1] = u3j_mark(); + qua_u[2] = u3n_mark(); + qua_u[3] = u3a_mark_road(); // NB: must be the last thing marked + qua_u[4] = NULL; + + return qua_u; +} + +/* _pave_parts(): build internal tables. +*/ +static void +_pave_parts(void) +{ + u3a_init_heap(); + + if ( &(u3H->rod_u) != u3R ) { + u3R->cel.cel_p = u3of(u3_post, u3a_walloc(1U << u3a_page)); + } + + u3R->cax.har_p = u3h_new_cache(u3C.hap_w); // transient + u3R->cax.per_p = u3h_new_cache(u3C.per_w); // persistent + u3R->jed.war_p = u3h_new(); + u3R->jed.cod_p = u3h_new(); + u3R->jed.han_p = u3h_new(); + u3R->jed.bas_p = u3h_new(); + u3R->byc.har_p = u3h_new(); +} + +static c3_d +_pave_params(void) +{ + // pam_d bits: + // { word-size[1], virtual-bits[2], page-size[3], bytecode[5], ... } + // + // word-size: 0==32, 1==64 + // page-size: relative binary-log in bytes + // + // + return 0 + ^ (u3a_vits << 1) + ^ ((u3a_page + 2 - 12) << 3) + ^ (U3N_VERLAT << 6); +} + +/* _pave_home(): initialize pristine home road. +*/ +static void +_pave_home(void) +{ + u3_post top_p = u3C.wor_i - u3a_walign; + u3_post bot_p = 1U << u3a_page; + + u3H = u3to(u3v_home, 0); + memset(u3H, 0, sizeof(u3v_home)); + u3H->ver_d = U3V_VERLAT; + u3H->pam_d = _pave_params(); + + u3R = &u3H->rod_u; + + u3R->rut_p = u3R->hat_p = bot_p; + u3R->mat_p = u3R->cap_p = top_p; + + _pave_parts(); +} + +STATIC_ASSERT( (c3_wiseof(u3v_home) <= (1U << u3a_page)), + "home road size" ); + +STATIC_ASSERT( ((c3_wiseof(u3v_home) * 4) == sizeof(u3v_home)), + "home road alignment" ); + +STATIC_ASSERT( U3N_VERLAT < (1U << 5), "5-bit bytecode version" ); + +/* _find_home(): in restored image, point to home road. +*/ +static void +_find_home(void) +{ + c3_d ver_d = *((c3_d*)u3_Loom); + + if ( ver_d != U3V_VERLAT ) { + fprintf(stderr, "loom: checkpoint version mismatch: " + "have %" PRIu64 ", need %" PRIu64 "\r\n", + ver_d, U3V_VERLAT); + abort(); + } + + c3_d pam_d = *((c3_d*)u3_Loom + 1); + + if ( pam_d & 1 ) { + fprintf(stderr, "word-size mismatch: 64-bit snapshot in 32-bit binary\r\n"); + abort(); + } + if ( ((pam_d >> 1) & 3) != u3a_vits ) { + fprintf(stderr, "virtual-bits mismatch: %u in snapshot; %u in binary\r\n", + (c3_w)((pam_d >> 1) & 3), u3a_vits); + abort(); + } + if ( (12 + ((pam_d >> 3) & 7)) != (u3a_page + 2) ) { + fprintf(stderr, "page-size mismatch: %u in snapshot; %u in binary\r\n", + 1U << (12 + ((pam_d >> 3) & 7)), (c3_w)u3a_page + 2); + abort(); + } + + // NB: the home road is always north + // + { + u3_post top_p = u3C.wor_i - u3a_walign; + + u3H = u3to(u3v_home, 0); + u3R = &u3H->rod_u; + + // this looks risky, but there are no legitimate scenarios + // where it's wrong + // + u3R->mat_p = u3R->cap_p = top_p; + } + + // check for obvious corruption + // + { + c3_w nor_w; + u3_post low_p, hig_p; + u3m_water(&low_p, &hig_p); + + nor_w = (low_p + ((1 << u3a_page) - 1)) >> u3a_page; + + if ( nor_w > u3P.img_u.pgs_w ) { + fprintf(stderr, "loom: corrupt size (%u, %u)\r\n", + nor_w, u3P.img_u.pgs_w); + u3_assert(!"loom: corrupt size"); + } + + // the north segment is in-order on disk; it being oversized + // doesn't necessarily indicate corruption. + // + if ( nor_w < u3P.img_u.pgs_w ) { + fprintf(stderr, "loom: strange size north (%u, %u)\r\n", + nor_w, u3P.img_u.pgs_w); + } + + // XX move me + // + u3a_ream(); + } + + /* As a further guard against any sneaky loom corruption */ + u3a_loom_sane(); + + _rod_vaal(u3R); + + if ( ((pam_d >> 6) & 31) != U3N_VERLAT ) { + fprintf(stderr, "loom: discarding stale bytecode programs\r\n"); + u3j_ream(); + u3n_ream(); + u3n_reclaim(); + u3j_reclaim(); + u3H->pam_d = _pave_params(); + } +} + +/* u3m_pave(): instantiate or activate image. +*/ +void +u3m_pave(c3_o nuu_o) +{ + if ( c3y == nuu_o ) { + _pave_home(); + } + else { + _find_home(); + } +} + +#if 0 +/* u3m_clear(): clear all allocated data in road. +*/ +void +u3m_clear(void) +{ + u3h_free(u3R->cax.har_p); + u3j_free(); + u3n_free(); +} + +void +u3m_dump(void) +{ + c3_w hat_w; + c3_w fre_w = 0; + c3_w i_w; + + hat_w = _(u3a_is_north(u3R)) ? u3R->hat_w - u3R->rut_w + : u3R->rut_w - u3R->hat_w; + + for ( i_w = 0; i_w < u3_cc_fbox_no; i_w++ ) { + u3a_fbox* fre_u = u3R->all.fre_u[i_w]; + + while ( fre_u ) { + fre_w += fre_u->box_u.siz_w; + fre_u = fre_u->nex_u; + } + } + u3l_log("dump: hat_w %x, fre_w %x, allocated %x", + hat_w, fre_w, (hat_w - fre_w)); + + if ( 0 != (hat_w - fre_w) ) { + c3_w* box_w = _(u3a_is_north(u3R)) ? u3R->rut_w : u3R->hat_w; + c3_w mem_w = 0; + + while ( box_w < (_(u3a_is_north(u3R)) ? u3R->hat_w : u3R->rut_w) ) { + u3a_box* box_u = (void *)box_w; + + if ( 0 != box_u->use_w ) { +#ifdef U3_MEMORY_DEBUG + // u3l_log("live %d words, code %x", box_u->siz_w, box_u->cod_w); +#endif + mem_w += box_u->siz_w; + } + box_w += box_u->siz_w; + } + + u3l_log("second count: %x", mem_w); + } +} +#endif + +struct bt_cb_data { + c3_y count; + c3_y fail; + c3_c* pn_c; +}; + +static void +err_cb(void* data, const char* msg, int errnum) +{ + struct bt_cb_data* bdata = (struct bt_cb_data *)data; + bdata->count++; + + if ( bdata->count <= 1 ) { + /* u3l_log("Backtrace error %d: %s", errnum, msg); */ + bdata->fail = 1; + } +} + +static int +bt_cb(void* data, + uintptr_t pc, + const char* filename, + int lineno, + const char* function) +{ + #ifndef U3_OS_windows + struct bt_cb_data* bdata = (struct bt_cb_data *)data; + bdata->count++; + + Dl_info info = {}; + c3_c* fname_c = {0}; + + if ( dladdr((void *)pc, &info) ) { + for ( c3_w i_w = 0; info.dli_fname[i_w] != 0; i_w++ ) + if ( info.dli_fname[i_w] == '/' ) { + fname_c = (c3_c*)&info.dli_fname[i_w + 1]; + } + } + + if ( bdata->count <= 100 ) { + c3_c* loc[128]; + if (filename != 0) { + snprintf((c3_c*)loc, 128, "%s:%d", filename, lineno); + } + else { + snprintf((c3_c*)loc, 128, "%s", fname_c != 0 ? fname_c : "-"); + } + + c3_c* fn_c; + if (function != 0 || bdata->pn_c != 0) { + fn_c = (c3_c*)(function != 0 ? function : bdata->pn_c); + } + else { + fn_c = (c3_c*)(info.dli_sname != 0 ? info.dli_sname : "-"); + } + + fprintf(stderr, "%-3d %-35s %s\r\n", bdata->count - 1, fn_c, (c3_c *)loc); + + bdata->pn_c = 0; + return 0; + } + else { + bdata->pn_c = 0; + return 1; + } + #endif + return 0; +} + +/* _self_path(): get binary self-path. + */ +static c3_y +_self_path(c3_c *pat_c) +{ + c3_i len_i = 0; + c3_i pat_i; + + if ( 0 < (len_i = wai_getExecutablePath(NULL, 0, &pat_i)) ) { + wai_getExecutablePath(pat_c, len_i, &pat_i); + pat_c[len_i] = 0; + return 0; + } + + return 1; +} + +void +u3m_stacktrace() +{ +#ifndef U3_OS_windows + void* bt_state; + struct bt_cb_data data = { 0, 0, 0 }; + c3_c* self_path_c[4096] = {0}; + +#if defined(U3_OS_osx) + fprintf(stderr, "Stacktrace:\r\n"); + + if ( _self_path((c3_c*)self_path_c) == 0 ) { + bt_state = backtrace_create_state((const c3_c*)self_path_c, 0, err_cb, 0); + backtrace_full(bt_state, 0, bt_cb, err_cb, &data); + if (data.fail == 0) { + fprintf(stderr, "\r\n"); + } + } + else { + data.fail = 1; + } + + if ( data.fail == 1 ) { + void* array[100]; + c3_c** strings; + size_t size = backtrace(array, 100); + + strings = backtrace_symbols(array, size); + + if ( strings[0] == NULL ) { + fprintf(stderr, "Backtrace failed\r\n"); + } + else { + for ( c3_i i = 0; i < size; i++ ) { + fprintf(stderr, "%s\r\n", strings[i]); + } + fprintf(stderr, "\r\n"); + } + + free(strings); + } +#elif defined(U3_OS_linux) + /* TODO: Fix unwind not getting past signal trampoline on linux aarch64 + */ + fprintf(stderr, "Stacktrace:\r\n"); + + if ( _self_path((c3_c*)self_path_c) == 0 ) { + bt_state = backtrace_create_state((const c3_c*)self_path_c, 0, err_cb, 0); + + unw_context_t context; + unw_cursor_t cursor; + unw_getcontext(&context); + unw_init_local(&cursor, &context); + unw_word_t pc, sp; + + c3_c* pn_c[1024] = {0}; + c3_w offp_w = 0; + + do { + unw_get_reg(&cursor, UNW_REG_IP, &pc); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + if ( 0 == unw_get_proc_name(&cursor, (c3_c*)pn_c, 1024, (unw_word_t *)&offp_w) ) + data.pn_c = (c3_c*)pn_c; + backtrace_pcinfo(bt_state, pc - 1, bt_cb, err_cb, &data); + } while (unw_step(&cursor) > 0); + + if ( (data.count > 0) ) { + fprintf(stderr, "\r\n"); + } + } + else { + data.fail = 1; + fprintf(stderr, "Backtrace failed\r\n"); + } +#endif +#endif +} + +/* u3m_bail(): bail out. Does not return. +** +** Bail motes: +** +** %evil :: erroneous cryptography +** %exit :: semantic failure +** %oops :: assertion failure +** %intr :: interrupt +** %fail :: computability failure +** %over :: stack overflow (a kind of %fail) +** %meme :: out of memory +** +** These are equivalents of the full exception noun, the error ball: +** +** $% [%0 success] +** [%1 paths] +** [%2 trace] +** [%3 code trace] +** == +** +** XX several of these abort() calls should be gated by -a +*/ +c3_i +u3m_bail(u3_noun how) +{ + // printf some metadata + // + switch ( how ) { + case c3__evil: + case c3__exit: break; + + default: { + if ( _(u3ud(how)) ) { + c3_c str_c[5]; + + str_c[0] = ((how >> 0) & 0xff); + str_c[1] = ((how >> 8) & 0xff); + str_c[2] = ((how >> 16) & 0xff); + str_c[3] = ((how >> 24) & 0xff); + str_c[4] = 0; + fprintf(stderr, "\r\nbail: %s\r\n", str_c); + } + else if ( 1 != u3h(how) ) { + u3_assert(_(u3ud(u3h(how)))); + fprintf(stderr, "\r\nbail: %d\r\n", u3h(how)); + } + } + } + + if ( &(u3H->rod_u) == u3R ) { + // XX set exit code + // + fprintf(stderr, "home: bailing out\r\n\r\n"); + u3m_stacktrace(); + abort(); + } + + // intercept fatal errors + // + switch ( how ) { + case c3__foul: + case c3__oops: { + // XX set exit code + // + fprintf(stderr, "bailing out\r\n\r\n"); + u3m_stacktrace(); + abort(); + } + } + + if ( &(u3H->rod_u) == u3R ) { + // For top-level errors, which shouldn't happen often, we have no + // choice but to use the signal process; and we require the flat + // form of how. + // + // XX JB: these seem unrecoverable, at least wrt memory management, + // so they've been disabled above for now + // + u3_assert(_(u3a_is_cat(how))); + u3m_signal(how); + } + + // release the emergency buffer, ensuring space for cells + // + u3z(u3R->bug.mer); + u3R->bug.mer = 0; + + /* Reconstruct a correct error ball. + */ + if ( _(u3ud(how)) ) { + switch ( how ) { + case c3__exit: { + how = u3nc(2, u3R->bug.tax); + } break; + + default: { + how = u3nt(3, how, u3R->bug.tax); + } break; + } + } + + // Reset the spin stack pointer + if ( NULL != stk_u ) { + stk_u->off_w = u3R->off_w; + stk_u->fow_w = u3R->fow_w; + } + + /* Longjmp, with an underscore. + */ + _longjmp(u3R->esc.buf, how); +} + +int c3_cooked(void) { return u3m_bail(c3__oops); } + +/* u3m_error(): bail out with %exit, ct_pushing error. +*/ +c3_i +u3m_error(c3_c* str_c) +{ + u3t_mean(u3i_string(str_c)); + return u3m_bail(c3__exit); +} + +/* u3m_leap(): in u3R, create a new road within the existing one. +*/ +void +u3m_leap(c3_w pad_w) +{ + u3_road* rod_u; + + _rod_vaal(u3R); + + // push a new road struct onto the stack + // + { + u3a_pile pil_u; + c3_p ptr_p; + u3a_pile_prep(&pil_u, sizeof(u3a_road) + 15); // XX refactor to wiseof + ptr_p = (c3_p)u3a_push(&pil_u); + + // XX add push_once, push_once_aligned + // + if ( ptr_p & 15 ) { + ptr_p &= ~15; + if ( c3n == u3a_is_north(u3R) ) { + ptr_p += 16; + } + } + + rod_u = (void*)ptr_p; + memset(rod_u, 0, sizeof(u3a_road)); + } + + /* Allocate a region on the cap. + */ + { + u3p(c3_w) bot_p, top_p; /* S: bot_p = new mat. N: bot_p = new rut */ + + if ( c3y == u3a_is_north(u3R) ) { + // pad and page-align the hat + // + bot_p = u3R->hat_p + pad_w; + bot_p += (1U << u3a_page) - 1; + bot_p &= ~((1U << u3a_page) - 1); + top_p = u3R->cap_p; + top_p &= ~((1U << u3a_page) - 1); + + if ( bot_p >= top_p ) { + u3m_bail(c3__meme); + } + + u3e_ward(bot_p - 1, top_p); + rod_u->mat_p = rod_u->cap_p = bot_p; + rod_u->rut_p = rod_u->hat_p = top_p; + + // in a south road, the heap is high and the stack is low + // + // the heap starts at the end of the memory segment; + // the stack starts at the base memory pointer [mem_w], + // and ends after the space for the road structure [siz_w] + // + // 00~~~|M|+++|C|######|H|---|R|~~~FFF + // ^---u3R which _pave_road returns + // + // XX obsolete? + + _rod_vaal(rod_u); +#if 0 + fprintf(stderr, "NPAR.hat_p: 0x%x %p, SKID.hat_p: 0x%x %p\r\n", + u3R->hat_p, u3a_into(u3R->hat_p), + rod_u->hat_p, u3a_into(rod_u->hat_p)); +#endif + } + else { + bot_p = u3R->cap_p; + bot_p += (1U << u3a_page) - 1; + bot_p &= ~((1U << u3a_page) - 1); + top_p = u3R->hat_p - pad_w; + top_p &= ~((1U << u3a_page) - 1); + + // XX moar + if ( (u3R->hat_p < pad_w) || (bot_p >= top_p) ) { + u3m_bail(c3__meme); + } + + u3e_ward(bot_p - 1, top_p); + rod_u->rut_p = rod_u->hat_p = bot_p; + rod_u->mat_p = rod_u->cap_p = top_p; + + // in a north road, the heap is low and the stack is high + // + // the heap starts at the base memory pointer [mem_w]; + // the stack starts at the end of the memory segment, + // minus space for the road structure [siz_w] + // + // 00~~~|R|---|H|######|C|+++|M|~~~FF + // ^--u3R which _pave_road returns (u3H for home road) + // + // XX obsolete? + + _rod_vaal(rod_u); + +#if 0 + fprintf(stderr, "SPAR.hat_p: 0x%x %p, NKID.hat_p: 0x%x %p\r\n", + u3R->hat_p, u3a_into(u3R->hat_p), + rod_u->hat_p, u3a_into(rod_u->hat_p)); + +#endif + } + } + + /* Attach the new road to its parents. + */ + { + u3_assert(0 == u3R->kid_p); + rod_u->par_p = u3of(u3_road, u3R); + u3R->kid_p = u3of(u3_road, rod_u); + } + + // Add slow stack pointer to rod_u + if ( NULL != stk_u ) { + rod_u->off_w = stk_u->off_w; + rod_u->fow_w = stk_u->fow_w; + } + + /* Set up the new road. + */ + { + u3R = rod_u; + _pave_parts(); + } +#ifdef U3_MEMORY_DEBUG + rod_u->all.fre_w = 0; +#endif + + _rod_vaal(u3R); +} + +void +_print_diff(c3_c* cap_c, c3_w a, c3_w b) +{ + c3_w diff = a<b ? b-a : a-b; + u3a_print_memory(stderr, cap_c, diff); +} + +/* u3m_fall(): in u3R, return an inner road to its parent. +*/ +void +u3m_fall(void) +{ + u3_assert(0 != u3R->par_p); + +#if 0 + /* If you're printing a lot of these you need to change + * u3a_print_memory from fprintf to u3l_log + */ + fprintf(stderr, "fall: from %s %p, to %s %p (cap 0x%x, was 0x%x)\r\n", + _(u3a_is_north(u3R)) ? "north" : "south", + (void*)u3R, + _(u3a_is_north(u3to(u3_road, u3R->par_p))) ? "north" : "south", + u3to(void, u3R->par_p), + u3R->hat_p, + u3R->rut_p); + _print_diff("unused free", u3R->hat_p, u3R->cap_p); + _print_diff("freeing", u3R->rut_p, u3R->hat_p); + _print_diff("stack", u3R->cap_p, u3R->mat_p); + static c3_w wat_w = 500000000; + if (u3to(u3_road, u3R->par_p) == &u3H->rod_u) { + wat_w = 500000000; + } + else { + wat_w = c3_min(wat_w, + u3R->hat_p < u3R->cap_p ? + u3R->cap_p - u3R->hat_p : + u3R->hat_p - u3R->cap_p); + } + u3a_print_memory(stderr, "low water mark", wat_w); + +#endif + + u3to(u3_road, u3R->par_p)->pro.nox_d += u3R->pro.nox_d; + u3to(u3_road, u3R->par_p)->pro.cel_d += u3R->pro.cel_d; + + /* The new cap is the old hat - it's as simple as that. + */ + u3to(u3_road, u3R->par_p)->cap_p = u3R->hat_p; + + /* And, we're back home. + */ + u3R = u3to(u3_road, u3R->par_p); + u3R->kid_p = 0; +} + +/* u3m_hate(): new, integrated leap mechanism (enter). +*/ +void +u3m_hate(c3_w pad_w) +{ + u3_assert(0 == u3R->ear_p); + + u3R->ear_p = u3R->cap_p; + u3m_leap(pad_w); + + u3R->bug.mer = u3i_string( + "emergency buffer with sufficient space to cons the trace and bail" + ); +} + +/* u3m_love(): return product from leap. +*/ +u3_noun +u3m_love(u3_noun pro) +{ + // save cache pointers from current road + // + u3p(u3h_root) byc_p = u3R->byc.har_p; + u3a_jets jed_u = u3R->jed; + u3p(u3h_root) per_p = u3R->cax.per_p; + + // fallback to parent road (child heap on parent's stack) + // + u3m_fall(); + + // copy product and caches off our stack + // + pro = u3a_take(pro); + jed_u = u3j_take(jed_u); + byc_p = u3n_take(byc_p); + per_p = u3h_take(per_p); + + // pop the stack + // + u3a_drop_heap(u3R->cap_p, u3R->ear_p); + u3R->cap_p = u3R->ear_p; + u3R->ear_p = 0; + + // integrate junior caches + // + u3j_reap(jed_u); + u3n_reap(byc_p); + u3z_reap(u3z_memo_keep, per_p); + + return pro; +} + +/* u3m_golf(): record cap_p length for u3m_flog(). +*/ +c3_w +u3m_golf(void) +{ + if ( c3y == u3a_is_north(u3R) ) { + return u3R->mat_p - u3R->cap_p; + } + else { + return u3R->cap_p - u3R->mat_p; + } +} + +/* u3m_flog(): reset cap_p. +*/ +void +u3m_flog(c3_w gof_w) +{ + // Enable memsets in case of memory corruption. + // + if ( c3y == u3a_is_north(u3R) ) { + u3_post bot_p = (u3R->mat_p - gof_w); + // c3_w len_w = (bot_w - u3R->cap_w); + + // memset(u3R->cap_w, 0, 4 * len_w); + u3R->cap_p = bot_p; + } + else { + u3_post bot_p = u3R->mat_p + gof_w; + // c3_w len_w = (u3R->cap_w - bot_w); + + // memset(bot_w, 0, 4 * len_w); // + u3R->cap_p = bot_p; + } +} + +/* u3m_water(): produce watermarks. +*/ +void +u3m_water(u3_post* low_p, u3_post* hig_p) +{ + // allow the segfault handler to fire before the road is set + // + // while not explicitly possible in the codebase, + // compiler optimizations can reorder stores + // + if ( !u3R ) { + *low_p = 0; + *hig_p = u3C.wor_i - 1; + } + // in a north road, hat points to the end of the heap + 1 word, + // while cap points to the top of the stack + // + else if ( c3y == u3a_is_north(u3R) ) { + *low_p = u3R->hat_p - 1; + *hig_p = u3R->cap_p; + } + // in a south road, hat points to the end of the heap, + // while cap points to the top of the stack + 1 word + // + else { + *low_p = u3R->cap_p - 1; + *hig_p = u3R->hat_p; + } +} + +/* u3m_soft_top(): top-level safety wrapper. +*/ +u3_noun +u3m_soft_top(c3_w mil_w, // timer ms + c3_w pad_w, // base memory pad + u3_funk fun_f, + u3_noun arg) +{ + u3_noun why, pro; + volatile c3_l sig_l = 0; + + /* Enter internal signal regime. + */ + _cm_signal_deep(mil_w); + + if ( 0 != (sig_l = rsignal_setjmp(u3_Signal)) ) { + // reinitialize trace state + // + u3t_init(); + + // return to blank state + // + _cm_signal_done(); + + // recover memory state from the top down + // + return _cm_signal_recover(sig_l, arg); + } + + /* Record the cap, and leap. + */ + u3m_hate(pad_w); + + /* Trap for ordinary nock exceptions. + */ + if ( 0 == (why = (u3_noun)setjmp(u3R->esc.buf)) ) { + pro = fun_f(arg); + + /* Make sure the inner routine did not create garbage. + */ + if ( u3C.wag_w & u3o_debug_ram ) { +#ifdef U3_CPU_DEBUG + if ( u3R->all.max_w > 1000000 ) { + u3a_print_memory(stderr, "execute: top", u3R->all.max_w); + } +#endif + u3m_grab(pro, u3_none); + } + + /* Revert to external signal regime. + */ + _cm_signal_done(); + + /* Produce success, on the old road. + */ + pro = u3nc(0, u3m_love(pro)); + } + else { + /* Overload the error result. + */ + pro = u3m_love(why); + } + + /* Revert to external signal regime. + */ + _cm_signal_done(); + + /* Free the argument. + */ + u3z(arg); + + /* Return the product. + */ + return pro; +} + +/* u3m_soft_sure(): top-level call assumed correct. +*/ +u3_noun +u3m_soft_sure(u3_funk fun_f, u3_noun arg) +{ + u3_noun pro, pru = u3m_soft_top(0, (1 << 18), fun_f, arg); + + u3_assert(_(u3du(pru))); + pro = u3k(u3t(pru)); + u3z(pru); + + return pro; +} + +/* u3m_soft_slam: top-level call. +*/ +u3_noun _cm_slam(u3_noun arg) { return u3n_slam_on(u3h(arg), u3t(arg)); } +u3_noun +u3m_soft_slam(u3_noun gat, u3_noun sam) +{ + return u3m_soft_sure(_cm_slam, u3nc(gat, sam)); +} + +/* u3m_soft_nock: top-level nock. +*/ +u3_noun _cm_nock(u3_noun arg) { return u3n_nock_on(u3h(arg), u3t(arg)); } +u3_noun +u3m_soft_nock(u3_noun bus, u3_noun fol) +{ + return u3m_soft_sure(_cm_nock, u3nc(bus, fol)); +} + +static void +_hamt_map(u3_noun kev, void* cax_p) +{ + u3_noun* old = cax_p; + u3_noun key, val, new; + u3x_cell(kev, &key, &val); + new = u3qdb_put(*old, u3t(key), val); + u3z(*old); + *old = new; +} + +/* u3m_soft_cax(): descend into virtualization context, with cache. +*/ +u3_noun +u3m_soft_cax(u3_funq fun_f, + u3_noun aga, + u3_noun agb) +{ + u3_noun why = 0, pro; + u3_noun cax = u3_nul; + + /* Save and set memo cache harvesting flag. + */ + c3_w wag_w = u3C.wag_w; + u3C.wag_w |= u3o_cash; + + /* Record the cap, and leap. + */ + u3m_hate(1 << 18); + + /* Configure the new road. + */ + { + u3R->ski.gul = u3_nul; + u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don; + u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace; + u3R->bug.tax = 0; + } + u3t_on(coy_o); + + /* Trap for exceptions. + */ + if ( 0 == (why = (u3_noun)setjmp(u3R->esc.buf)) ) { + u3t_off(coy_o); + pro = fun_f(aga, agb); + u3C.wag_w = wag_w; + +#ifdef U3_CPU_DEBUG + if ( u3R->all.max_w > 1000000 ) { + u3a_print_memory(stderr, "execute: run", u3R->all.max_w); + } +#endif + + /* Today you can't run -g without memory debug, but you should be + * able to. + */ +#ifdef U3_MEMORY_DEBUG + if ( u3C.wag_w & u3o_debug_ram ) { + u3m_grab(pro, u3_none); + } +#endif + + /* Produce success, on the old road. + */ + u3h_walk_with(u3R->cax.per_p, _hamt_map, &cax); + pro = u3nc(u3nc(0, pro), cax); + pro = u3m_love(pro); + } + else { + u3t_init(); + u3C.wag_w = wag_w; + + /* Produce - or fall again. + */ + { + u3_assert(_(u3du(why))); + switch ( u3h(why) ) { + default: u3_assert(0); return 0; + + case 1: { // blocking request + pro = u3nc(u3nc(2, u3m_love(u3R->bug.tax)), u3_nul); + } break; + + case 2: { // true exit + pro = u3nc(u3m_love(why), u3_nul); + } break; + + case 3: { // failure; rebail w/trace + u3_noun yod = u3m_love(u3t(why)); + + u3m_bail + (u3nt(3, + u3a_take(u3h(yod)), + u3kb_weld(u3t(yod), u3k(u3R->bug.tax)))); + } break; + } + } + } + /* Release the arguments. + */ + { + u3z(aga); + u3z(agb); + } + + /* Return the product. + */ + return pro; +} + +/* u3m_soft_run(): descend into virtualization context. +*/ +u3_noun +u3m_soft_run(u3_noun gul, + u3_funq fun_f, + u3_noun aga, + u3_noun agb) +{ + u3_noun why = 0, pro; + + /* Record the cap, and leap. + */ + u3m_hate(1 << 18); + + /* Configure the new road. + */ + + { + // XX review + if ( (u3_nul == gul) || (u3C.wag_w & u3o_cash) ) { + u3R->ski.gul = u3_nul; + } + else { + u3R->ski.gul = u3nc(gul, u3to(u3_road, u3R->par_p)->ski.gul); + } + u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don; + u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace; + u3R->bug.tax = 0; + } + u3t_on(coy_o); + + /* Trap for exceptions. + */ + if ( 0 == (why = (u3_noun)setjmp(u3R->esc.buf)) ) { + u3t_off(coy_o); + pro = fun_f(aga, agb); + +#ifdef U3_CPU_DEBUG + if ( u3R->all.max_w > 1000000 ) { + u3a_print_memory(stderr, "execute: run", u3R->all.max_w); + } +#endif + + /* Today you can't run -g without memory debug, but you should be + * able to. + */ +#ifdef U3_MEMORY_DEBUG + if ( u3C.wag_w & u3o_debug_ram ) { + u3m_grab(pro, u3_none); + } +#endif + + /* Produce success, on the old road. + */ + pro = u3nc(0, u3m_love(pro)); + } + else { + u3t_init(); + + /* Produce - or fall again. + */ + { + u3_assert(_(u3du(why))); + switch ( u3h(why) ) { + default: u3_assert(0); return 0; + + case 0: { // unusual: bail with success. + pro = u3m_love(why); + } break; + + case 1: { // blocking request + pro = u3m_love(why); + } break; + + case 2: { // true exit + pro = u3m_love(why); + } break; + + case 3: { // failure; rebail w/trace + u3_noun yod = u3m_love(u3t(why)); + + u3m_bail + (u3nt(3, + u3a_take(u3h(yod)), + u3kb_weld(u3t(yod), u3k(u3R->bug.tax)))); + } break; + + case 4: { // meta-bail + u3m_bail(u3m_love(u3t(why))); + } break; + } + } + } + + /* Release the arguments. + */ + { + u3z(gul); + u3z(aga); + u3z(agb); + } + + /* Return the product. + */ + return pro; +} + +/* u3m_soft_esc(): namespace lookup. Produces direct result. +*/ +u3_noun +u3m_soft_esc(u3_noun ref, u3_noun sam) +{ + u3_noun why, gul, pro; + + /* Assert preconditions. + */ + { + gul = u3h(u3R->ski.gul); + } + + /* Record the cap, and leap. + */ + u3m_hate(1 << 18); + + /* Configure the new road. + */ + { + u3R->ski.gul = u3t(u3to(u3_road, u3R->par_p)->ski.gul); + u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don; + u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace; + u3R->bug.tax = 0; + } + + /* Trap for exceptions. + */ + if ( 0 == (why = (u3_noun)setjmp(u3R->esc.buf)) ) { + pro = u3n_slam_on(gul, u3nc(ref, sam)); + + /* Fall back to the old road, leaving temporary memory intact. + */ + pro = u3m_love(pro); + } + else { + u3t_init(); + + /* Push the error back up to the calling context - not the run we + ** are in, but the caller of the run, matching pure nock semantics. + */ + u3m_bail(u3nc(4, u3m_love(why))); + } + + /* Release the sample. Note that we used it above, but in a junior + ** road, so its refcount is intact. + */ + u3z(ref); + u3z(sam); + + /* Return the product. + */ + return pro; +} + +/* u3m_grab(): garbage-collect the world, plus extra roots. +*/ +void +u3m_grab(u3_noun som, ...) // terminate with u3_none +{ + // u3h_free(u3R->cax.har_p); + // u3R->cax.har_p = u3h_new(); + + u3a_mark_init(); + { + va_list vap; + u3_noun tur; + + va_start(vap, som); + + if ( som != u3_none ) { + u3a_mark_noun(som); + + while ( u3_none != (tur = va_arg(vap, u3_noun)) ) { + u3a_mark_noun(tur); + } + } + va_end(vap); + } + u3m_mark(); // XX leaks + u3a_sweep(); +} + +/* u3m_soft(): top-level wrapper. +** +** Produces [0 product] or [%error (list tank)], top last. +*/ +u3_noun +u3m_soft(c3_w mil_w, + u3_funk fun_f, + u3_noun arg) +{ + u3_noun why; + + why = u3m_soft_top(mil_w, (1 << 20), fun_f, arg); // 4M pad + + if ( 0 == u3h(why) ) { + return why; + } + else { + u3_noun tax, cod, pro; + + switch ( u3h(why) ) { + case 2: { + cod = c3__exit; + tax = u3t(why); + } break; + + case 3: { + cod = u3h(u3t(why)); + tax = u3t(u3t(why)); + } break; + + // don't use .^ at the top level! + // + default: { + u3m_p("invalid mot", u3h(why)); + u3_assert(0); + } + } + + // don't call +mook if we have no kernel + // + // This is required to soft the boot sequence. + // + if ( 0 == u3A->roc ) { + while ( u3_nul != tax ) { + u3_noun dat, mot, val; + u3x_cell(tax, &dat, &tax); + + if ( c3y == u3r_cell(dat, &mot, &val) ) { + if ( c3__spot == mot ) { + u3m_p("tax", val); + } + else if ( (c3__mean == mot) + && (c3y == u3a_is_atom(val)) ) + { + u3m_p("men", val); + } + else { + u3m_p("mot", mot); + } + } + } + + pro = u3nc(u3k(cod), u3_nul); + } + // %evil leaves no trace + // + else if ( c3__evil == cod ) { + pro = u3nc(u3k(cod), u3_nul); + } + else { + u3_noun mok = u3dc("mook", 2, u3k(tax)); + pro = u3nc(u3k(cod), u3k(u3t(mok))); + u3z(mok); + } + + u3z(why); + return pro; + } +} + +/* _cm_is_tas(): yes iff som (RETAIN) is @tas. +*/ +static c3_o +_cm_is_tas(u3_atom som, c3_w len_w) +{ + c3_w i_w; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_c c_c = u3r_byte(i_w, som); + + if ( islower(c_c) || + (isdigit(c_c) && (0 != i_w) && ((len_w - 1) != i_w)) + || '-' == c_c ) + { + continue; + } + return c3n; + } + return c3y; +} + +/* _cm_is_ta(): yes iff som (RETAIN) is @ta. +*/ +static c3_o +_cm_is_ta(u3_noun som, c3_w len_w) +{ + c3_w i_w; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_c c_c = u3r_byte(i_w, som); + + if ( (c_c < 32) || (c_c > 127) ) { + return c3n; + } + } + return c3y; +} + +/* _cm_hex(): hex byte. +*/ +c3_y _cm_hex(c3_y c_y) +{ + if ( c_y < 10 ) + return '0' + c_y; + else return 'a' + (c_y - 10); +} + +/* _cm_in_pretty: measure/cut prettyprint. +*/ +static c3_w +_cm_in_pretty(u3_noun som, c3_o sel_o, c3_c* str_c) +{ + if ( _(u3du(som)) ) { + c3_w sel_w, one_w, two_w; + + sel_w = 0; + if ( _(sel_o) ) { + if ( str_c ) { *(str_c++) = '['; } + sel_w += 1; + } + + one_w = _cm_in_pretty(u3h(som), c3y, str_c); + if ( str_c ) { + str_c += one_w; + *(str_c++) = ' '; + } + two_w = _cm_in_pretty(u3t(som), c3n, str_c); + if ( str_c ) { str_c += two_w; } + + if ( _(sel_o) ) { + if ( str_c ) { *(str_c++) = ']'; } + sel_w += 1; + } + return one_w + two_w + 1 + sel_w; + } + else { + if ( som < 65536 ) { + c3_c buf_c[6]; + c3_w len_w; + + snprintf(buf_c, 6, "%d", som); + len_w = strlen(buf_c); + + if ( str_c ) { strcpy(str_c, buf_c); str_c += len_w; } + return len_w; + } + else { + c3_w len_w = u3r_met(3, som); + + if ( _(_cm_is_tas(som, len_w)) ) { + if ( str_c ) { + *(str_c++) = '%'; + u3r_bytes(0, len_w, (c3_y *)str_c, som); + str_c += len_w; + } + return len_w + 1; + } + else if ( _(_cm_is_ta(som, len_w)) ) { + if ( str_c ) { + *(str_c++) = '\''; + u3r_bytes(0, len_w, (c3_y *)str_c, som); + str_c += len_w; + *(str_c++) = '\''; + } + return len_w + 2; + } + else { + c3_c *buf_c = c3_malloc(2 + (2 * len_w) + 1); + c3_w i_w = 0; + c3_w a_w = 0; + + buf_c[a_w++] = '0'; + buf_c[a_w++] = 'x'; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_y c_y = u3r_byte(len_w - (i_w + 1), som); + + if ( (i_w == 0) && (c_y <= 0xf) ) { + buf_c[a_w++] = _cm_hex(c_y); + } else { + buf_c[a_w++] = _cm_hex(c_y >> 4); + buf_c[a_w++] = _cm_hex(c_y & 0xf); + } + } + buf_c[a_w] = 0; + len_w = a_w; + + if ( str_c ) { strcpy(str_c, buf_c); str_c += len_w; } + + c3_free(buf_c); + return len_w; + } + } + } +} + +/* u3m_pretty(): dumb prettyprint to string. +*/ +c3_c* +u3m_pretty(u3_noun som) +{ + c3_w len_w = _cm_in_pretty(som, c3y, 0); + c3_c* pre_c = c3_malloc(len_w + 1); + + _cm_in_pretty(som, c3y, pre_c); + pre_c[len_w] = 0; + return pre_c; +} + +/* _cm_in_pretty_path: measure/cut prettyprint. + * + * Modeled after _cm_in_pretty(), the backend to u3m_p(), but with the + * assumption that we're always displaying a path. + */ +static c3_w +_cm_in_pretty_path(u3_noun som, c3_c* str_c) +{ + if ( _(u3du(som)) ) { + c3_w sel_w, one_w, two_w; + if ( str_c ) { + *(str_c++) = '/'; + } + sel_w = 1; + + one_w = _cm_in_pretty_path(u3h(som), str_c); + if ( str_c ) { + str_c += one_w; + } + + two_w = _cm_in_pretty_path(u3t(som), str_c); + if ( str_c ) { + str_c += two_w; + } + + return sel_w + one_w + two_w; + } + else { + c3_w len_w = u3r_met(3, som); + if ( str_c && len_w ) { + u3r_bytes(0, len_w, (c3_y *)str_c, som); + str_c += len_w; + } + return len_w; + } +} + +/* u3m_pretty_path(): prettyprint a path to string. +*/ +c3_c* +u3m_pretty_path(u3_noun som) +{ + c3_w len_w = _cm_in_pretty_path(som, NULL); + c3_c* pre_c = c3_malloc(len_w + 1); + + _cm_in_pretty_path(som, pre_c); + pre_c[len_w] = 0; + return pre_c; +} + +/* u3m_p(): dumb print with caption. +*/ +void +u3m_p(const c3_c* cap_c, u3_noun som) +{ + c3_c* pre_c = u3m_pretty(som); + + u3l_log("%s: %s", cap_c, pre_c); + c3_free(pre_c); +} + +/* u3m_tape(): dump a tape to stdout. +*/ +void +u3m_tape(u3_noun tep) +{ + u3_noun tap = tep; + + while ( u3_nul != tap ) { + c3_c car_c; + + if ( u3h(tap) >= 127 ) { + car_c = '?'; + } else car_c = u3h(tap); + + putc(car_c, stdout); + tap = u3t(tap); + } + u3z(tep); +} + +/* u3m_wall(): dump a wall to stdout. +*/ +void +u3m_wall(u3_noun wol) +{ + u3_noun wal = wol; + + while ( u3_nul != wal ) { + u3m_tape(u3k(u3h(wal))); + + putc(13, stdout); + putc(10, stdout); + + wal = u3t(wal); + } + u3z(wol); +} + +/* _cm_limits(): set up global modes and limits. +*/ +static void +_cm_limits(void) +{ +#ifndef U3_OS_windows + struct rlimit rlm; + + // Moar stack. + // + { + u3_assert( 0 == getrlimit(RLIMIT_STACK, &rlm) ); + + rlm.rlim_cur = c3_min(rlm.rlim_max, (65536 << 10)); + + if ( 0 != setrlimit(RLIMIT_STACK, &rlm) ) { + u3l_log("boot: stack size: %s", strerror(errno)); + exit(1); + } + } + + // Moar filez. + // + { + getrlimit(RLIMIT_NOFILE, &rlm); + + #ifdef U3_OS_osx + rlm.rlim_cur = c3_min(OPEN_MAX, rlm.rlim_max); + #else + rlm.rlim_cur = rlm.rlim_max; + #endif + + // no exit, not a critical limit + // + if ( 0 != setrlimit(RLIMIT_NOFILE, &rlm) ) { + u3l_log("boot: open file limit: %s", strerror(errno)); + } + } + + // Moar core. + // +# ifndef ASAN_ENABLED + { + getrlimit(RLIMIT_CORE, &rlm); + rlm.rlim_cur = RLIM_INFINITY; + + // no exit, not a critical limit + // + if ( 0 != setrlimit(RLIMIT_CORE, &rlm) ) { + u3l_log("boot: core limit: %s", strerror(errno)); + } + } +# endif +#endif +} + +/* u3m_fault(): handle a memory event with libsigsegv protocol. + */ +c3_i +u3m_fault(void* adr_v, c3_i ser_i) +{ + c3_w* adr_w = (c3_w*)adr_v; + u3_post low_p, hig_p; + + // let the stack overflow handler run. + // + if ( 0 == ser_i ) { + return 0; + } + // this could be avoided by registering the loom bounds in libsigsegv + // + else if ( (adr_w < u3_Loom) || (adr_w >= (u3_Loom + u3C.wor_i)) ) { + fprintf(stderr, "loom: external fault: %p (%p : %p)\r\n\r\n", + (void *)adr_w, (void *)u3_Loom, (void *)(u3_Loom + u3C.wor_i)); + u3m_stacktrace(); + u3_assert(0); + return 0; + } + + u3m_water(&low_p, &hig_p); + + switch ( u3e_fault(low_p, hig_p, u3a_outa(adr_w)) ) { + // page tracking invariants violated, fatal + // + case u3e_flaw_sham: { + u3_assert(0); + return 0; + } + + // virtual memory failure (protections) + // + // XX s/b recoverable, need to u3m_signal() a new mote + // + case u3e_flaw_base: { + u3_assert(0); + return 0; + } + + // loom limits exceeded, recoverable + // + case u3e_flaw_meme: { + u3m_signal(c3__meme); // doesn't return + return 1; + } + + case u3e_flaw_good: return 1; + } + + u3_assert(!"unpossible"); +} + +/* u3m_foul(): dirty all pages and disable tracking. +*/ +void +u3m_foul(void) +{ + if ( c3n == u3e_yolo() ) { + return; + } + + u3e_foul(); +} + +/* u3m_save(): update the checkpoint. +*/ +void +u3m_save(void) +{ + u3_post low_p, hig_p; + u3m_water(&low_p, &hig_p); + + u3a_wait(); + + u3_assert(u3R == &u3H->rod_u); + + u3e_save(low_p, hig_p); + + u3a_dash(); +} + +/* u3m_toss(): discard ephemeral memory. +*/ +void +u3m_toss(void) +{ + u3_post low_p, hig_p; + u3m_water(&low_p, &hig_p); + + if ( ((low_p + u3C.tos_w) < u3C.wor_i) + && (hig_p > u3C.tos_w) ) + { + low_p += u3C.tos_w; + hig_p -= u3C.tos_w; + + if ( low_p < hig_p ) { + u3e_toss(low_p, hig_p); + } + } +} + +/* u3m_ward(): tend the guardpage. +*/ +void +u3m_ward(void) +{ + u3_post low_p, hig_p; + u3m_water(&low_p, &hig_p); + +#if 1 // XX redundant + { + c3_w low_w, hig_w; + + if ( c3y == u3a_is_north(u3R) ) { + low_w = u3R->hat_p; + hig_w = u3R->cap_p; + } + else { + low_w = u3R->cap_p; + hig_w = u3R->hat_p; + } + + if ( (low_w > (u3P.gar_w << u3a_page)) + || (hig_w < (u3P.gar_w << u3a_page)) ) + { + u3_assert( ((low_p >> u3a_page) >= u3P.gar_w) + || ((hig_p >> u3a_page) <= u3P.gar_w) ); + } + } +#endif + + u3e_ward(low_p, hig_p); +} + +/* _cm_signals(): set up interrupts, etc. +*/ +static void +_cm_signals(void) +{ +#ifndef U3_OS_windows + if ( 0 != sigsegv_install_handler(u3m_fault) ) { + u3l_log("boot: sigsegv install failed"); + exit(1); + } + +# if defined(U3_OS_PROF) + // Block SIGPROF, so that if/when we reactivate it on the + // main thread for profiling, we won't get hits in parallel + // on other threads. + if ( u3C.wag_w & u3o_debug_cpu ) { + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGPROF); + + if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) { + u3l_log("boot: thread mask SIGPROF: %s", strerror(errno)); + exit(1); + } + } +#endif +#else + if (0 == AddVectoredExceptionHandler(1, _windows_exception_filter)) { + u3l_log("boot: vectored exception handler install failed"); + exit(1); + } +#endif +} + +/* _cm_malloc_ssl(): openssl-shaped malloc +*/ +static void* +_cm_malloc_ssl(size_t len_i +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + , const char* file, int line +#endif + ) +{ + return u3a_malloc(len_i); +} + +/* _cm_realloc_ssl(): openssl-shaped realloc. +*/ +static void* +_cm_realloc_ssl(void* lag_v, size_t len_i +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + , const char* file, int line +#endif + ) +{ + return u3a_realloc(lag_v, len_i); +} + +/* _cm_free_ssl(): openssl-shaped free. +*/ +static void +_cm_free_ssl(void* tox_v +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + , const char* file, int line +#endif + ) +{ + u3a_free(tox_v); +} + +extern void u3je_secp_init(void); + +/* _cm_crypto(): initialize openssl and crypto jets. +*/ +static void +_cm_crypto(void) +{ + /* Initialize OpenSSL with loom allocation functions. */ + if ( 0 == CRYPTO_set_mem_functions(&_cm_malloc_ssl, + &_cm_realloc_ssl, + &_cm_free_ssl) ) { + u3l_log("%s", "openssl initialization failed"); + abort(); + } + + u3je_secp_init(); +} + +/* _cm_realloc2(): gmp-shaped realloc. +*/ +static void* +_cm_realloc2(void* lag_v, size_t old_i, size_t new_i) +{ + return u3a_realloc(lag_v, new_i); +} + +/* _cm_free2(): gmp-shaped free. +*/ +static void +_cm_free2(void* tox_v, size_t siz_i) +{ + u3a_free(tox_v); +} + +/* u3m_init(): start the environment. +*/ +void +u3m_init(size_t len_i) +{ + _cm_limits(); + _cm_signals(); + _cm_crypto(); + + u3a_init_once(); + + // make sure GMP uses our malloc. + // + mp_set_memory_functions(u3a_malloc, _cm_realloc2, _cm_free2); + + // make sure that [len_i] is a fully-addressible non-zero power of two. + // + if ( !len_i + || (len_i & (len_i - 1)) + || (len_i < (1 << (u3a_page + 2))) + || (len_i > u3a_bytes) ) + { + u3l_log("loom: bad size: %zu", len_i); + exit(1); + } + + // map at fixed address. + // + { + void* map_v = mmap((void *)u3_Loom, + len_i, + (PROT_READ | PROT_WRITE), + (MAP_ANON | MAP_FIXED | MAP_PRIVATE), + -1, 0); + + if ( -1 == (c3_ps)map_v ) { + map_v = mmap((void *)0, + len_i, + (PROT_READ | PROT_WRITE), + (MAP_ANON | MAP_PRIVATE), + -1, 0); + + u3l_log("boot: mapping %zuMB failed", len_i >> 20); + u3l_log("see https://docs.urbit.org/user-manual/running/cloud-hosting" + " for adding swap space"); + if ( -1 != (c3_ps)map_v ) { + u3l_log("if porting to a new platform, try U3_OS_LoomBase %p", + map_v); + } + exit(1); + } + + u3C.wor_i = len_i >> 2; + u3l_log("loom: mapped %zuMB", len_i >> 20); + } +} + +extern void u3je_secp_stop(void); + +/* u3m_stop(): graceful shutdown cleanup. +*/ +void +u3m_stop(void) +{ + u3t_sstack_exit(); + + u3e_stop(); + u3je_secp_stop(); +} + +/* u3m_pier(): make a pier. +*/ +c3_c* +u3m_pier(c3_c* dir_c) +{ + c3_c ful_c[8193]; + + u3C.dir_c = dir_c; + + snprintf(ful_c, 8192, "%s", dir_c); + if ( c3_mkdir(ful_c, 0700) ) { + if ( EEXIST != errno ) { + fprintf(stderr, "loom: pier create: %s\r\n", strerror(errno)); + exit(1); + } + } + + snprintf(ful_c, 8192, "%s/.urb", dir_c); + if ( c3_mkdir(ful_c, 0700) ) { + if ( EEXIST != errno ) { + fprintf(stderr, "loom: .urb create: %s\r\n", strerror(errno)); + exit(1); + } + } + + snprintf(ful_c, 8192, "%s/.urb/chk", dir_c); + if ( c3_mkdir(ful_c, 0700) ) { + if ( EEXIST != errno ) { + fprintf(stderr, "loom: .urb/chk create: %s\r\n", strerror(errno)); + exit(1); + } + } + + return strdup(dir_c); +} + +/* u3m_boot(): start the u3 system. return next event, starting from 1. +*/ +c3_d +u3m_boot(c3_c* dir_c, size_t len_i) +{ + c3_o nuu_o; + + u3C.dir_c = dir_c; + + /* Activate the loom. + */ + u3m_init(len_i); + + /* Activate the storage system. + */ + nuu_o = u3e_live(c3n, u3m_pier(dir_c)); + + /* Activate tracing. + */ + u3C.slog_f = 0; + u3C.sign_hold_f = 0; + u3C.sign_move_f = 0; + u3t_init(); + + /* Construct or activate the allocator. + */ + u3m_pave(nuu_o); + + /* GC immediately if requested + */ + if ( (c3n == nuu_o) && (u3C.wag_w & u3o_check_corrupt) ) { + u3l_log("boot: gc requested"); + u3m_grab(u3_none); + u3C.wag_w &= ~u3o_check_corrupt; + u3l_log("boot: gc complete"); + } + + /* Initialize the jet system. + */ + { + c3_w len_w = u3j_boot(nuu_o); + u3l_log("boot: installed %d jets", len_w); + } + + /* Reactivate jets on old kernel. + */ + if ( c3n == nuu_o ) { + u3j_ream(); + u3n_ream(); + return u3A->eve_d; + } + else { + /* Basic initialization. + */ + memset(u3A, 0, sizeof(*u3A)); + return 0; + } +} + +/* u3m_boot_lite(): start without checkpointing. +*/ +c3_d +u3m_boot_lite(size_t len_i) +{ + /* Activate the loom. + */ + u3m_init(len_i); + + /* Activate tracing. + */ + u3C.slog_f = 0; + u3C.sign_hold_f = 0; + u3C.sign_move_f = 0; + u3t_init(); + + /* Construct or activate the allocator. + */ + u3m_pave(c3y); + + /* Place the guard page. + */ + u3e_init(); + + /* Initialize the jet system. + */ + u3j_boot(c3y); + + /* Basic initialization. + */ + memset(u3A, 0, sizeof(*u3A)); + return 0; +} + +/* u3m_reclaim: clear persistent caches to reclaim memory. +*/ +void +u3m_reclaim(void) +{ + u3v_reclaim(); + u3j_reclaim(); + u3n_reclaim(); + u3a_reclaim(); +} + +/* _cm_pack_rewrite(): trace through arena, rewriting pointers. +*/ +static void +_cm_pack_rewrite(void) +{ + // XX fix u3a_rewrite* to support south roads + // + u3_assert( &(u3H->rod_u) == u3R ); + + // NB: these implementations must be kept in sync with u3m_reclaim(); + // anything not reclaimed must be rewritable + // + u3v_rewrite_compact(); + u3j_rewrite_compact(); + u3n_rewrite_compact(); + u3a_rewrite_compact(); +} + +/* u3m_pack: compact (defragment) memory, returns u3a_open delta. +*/ +c3_w +u3m_pack(void) +{ + c3_w pre_w = u3a_open(u3R); + + // reclaim first, to free space, and discard anything we can't/don't rewrite + // + u3m_reclaim(); + + // sweep the heap, finding and saving new locations + // + u3a_pack_seek(u3R); + + // trace roots, rewriting inner pointers + // + _cm_pack_rewrite(); + + // sweep the heap, relocating objects to their new locations + // + u3a_pack_move(u3R); + + return (u3a_open(u3R) - pre_w); +} diff --git a/vere/pkg/noun/manage.h b/vere/pkg/noun/manage.h new file mode 100644 index 0000000..f0779e9 --- /dev/null +++ b/vere/pkg/noun/manage.h @@ -0,0 +1,215 @@ +/// @file + +#ifndef U3_MANAGE_H +#define U3_MANAGE_H + +// #include "v1/manage.h" +// #include "v2/manage.h" + +#include "c3/c3.h" +#include "types.h" +#include "version.h" + + /** System management. + **/ + /* u3m_boot(): start the u3 system. return next event, starting from 1. + */ + c3_d + u3m_boot(c3_c* dir_c, size_t len_i); + + /* u3m_pier(): make a pier. + */ + c3_c* + u3m_pier(c3_c* dir_c); + + /* u3m_boot_lite(): start without checkpointing. + */ + c3_d + u3m_boot_lite(size_t len_i); + + /* u3m_stop(): graceful shutdown cleanup. */ + void + u3m_stop(void); + + /* u3m_bail(): bail out. Does not return. + ** + ** Bail motes: + ** + ** %exit :: semantic failure + ** %evil :: bad crypto + ** %intr :: interrupt + ** %fail :: execution failure + ** %foul :: assert failure + ** %need :: network block + ** %meme :: out of memory + ** %time :: timed out + ** %oops :: assertion failure + */ + c3_i + u3m_bail(c3_m how_m) __attribute__((noreturn)); + + /* u3m_fault(): handle a memory event with libsigsegv protocol. + */ + c3_i + u3m_fault(void* adr_v, c3_i ser_i); + + /* u3m_foul(): dirty all pages and disable tracking. + */ + void + u3m_foul(void); + + /* u3m_backup(): copy snapshot to .urb/bhk (if it doesn't exist yet). + */ + c3_o + u3m_backup(c3_o); + + /* u3m_save(): update the checkpoint. + */ + void + u3m_save(void); + + /* u3m_toss(): discard ephemeral memory. + */ + void + u3m_toss(void); + + /* u3m_ward(): tend the guardpage. + */ + void + u3m_ward(void); + + /* u3m_init(): start the environment. + */ + void + u3m_init(size_t len_i); + + /* u3m_pave(): instantiate or activate image. + */ + void + u3m_pave(c3_o nuu_o); + + /* u3m_signal(): treat a nock-level exception as a signal interrupt. + */ + void + u3m_signal(u3_noun sig_l); + + /* u3m_file(): load file, as atom, or bail. + */ + u3_noun + u3m_file(c3_c* pas_c); + + /* u3m_error(): bail out with %exit, ct_pushing error. + */ + c3_i + u3m_error(c3_c* str_c); + + /* u3m_hate(): new, integrated leap mechanism (enter). + */ + void + u3m_hate(c3_w pad_w); + + /* u3m_love(): return product from leap. + */ + u3_noun + u3m_love(u3_noun pro); + + /* u3m_soft(): system soft wrapper. unifies unix and nock errors. + ** + ** Produces [%$ result] or [%error (list tank)]. + */ + u3_noun + u3m_soft(c3_w mil_w, u3_funk fun_f, u3_noun arg); + + /* u3m_soft_cax(): descend into virtualization context, with cache. + */ + u3_noun + u3m_soft_cax(u3_funq fun_f, u3_noun aga, u3_noun agb); + + /* u3m_soft_slam: top-level call. + */ + u3_noun + u3m_soft_slam(u3_noun gat, u3_noun sam); + + /* u3m_soft_nock: top-level nock. + */ + u3_noun + u3m_soft_nock(u3_noun bus, u3_noun fol); + + /* u3m_soft_sure(): top-level call assumed correct. + */ + u3_noun + u3m_soft_sure(u3_funk fun_f, u3_noun arg); + + /* u3m_soft_run(): descend into virtualization context. + */ + u3_noun + u3m_soft_run(u3_noun gul, + u3_funq fun_f, + u3_noun aga, + u3_noun agb); + + /* u3m_soft_esc(): namespace lookup to (unit ,*). + */ + u3_noun + u3m_soft_esc(u3_noun ref, u3_noun sam); + + + /* u3m_quac: memory report. + */ + typedef struct _u3m_quac { + c3_c* nam_c; + c3_w siz_w; + struct _u3m_quac** qua_u; + } u3m_quac; + + /* u3m_mark(): mark all nouns in the road. + */ + u3m_quac** + u3m_mark(); + + /* u3m_grab(): garbage-collect the world, plus extra roots. + */ + void + u3m_grab(u3_noun som, ...); // terminate with u3_none + + /* u3m_water(): produce high and low watermarks. Asserts u3R == u3H. + */ + void + u3m_water(u3_post* low_p, u3_post* hig_p); + + /* u3m_pretty(): dumb prettyprint to string. RETAIN. + */ + c3_c* + u3m_pretty(u3_noun som); + + /* u3m_pretty_path(): prettyprint a path to string. RETAIN. + */ + c3_c* + u3m_pretty_path(u3_noun som); + + /* u3m_p(): dumb print with caption. RETAIN. + */ + void + u3m_p(const c3_c* cap_c, u3_noun som); + + /* u3m_tape(): dump a tape to stdout. + */ + void + u3m_tape(u3_noun tep); + + /* u3m_wall(): dump a wall to stdout. + */ + void + u3m_wall(u3_noun wol); + + /* u3m_reclaim: clear persistent caches to reclaim memory. + */ + void + u3m_reclaim(void); + + /* u3m_pack: compact (defragment) memory, returns u3a_open delta. + */ + c3_w + u3m_pack(void); + +#endif /* ifndef U3_MANAGE_H */ diff --git a/vere/pkg/noun/nock.c b/vere/pkg/noun/nock.c new file mode 100644 index 0000000..8218efa --- /dev/null +++ b/vere/pkg/noun/nock.c @@ -0,0 +1,3268 @@ +/// @file + +#include "nock.h" + +#include "allocate.h" +#include "hashtable.h" +#include "imprison.h" +#include "jets.h" +#include "jets/k.h" +#include "jets/q.h" +#include "manage.h" +#include "options.h" +#include "retrieve.h" +#include "trace.h" +#include "vortex.h" +#include "xtract.h" +#include "zave.h" + + +// define to have each opcode printed as it executes, +// along with some other debugging info +# undef VERBOSE_BYTECODE + +#if 0 +// Retained for debugging purposes. +static u3_noun _n_nock_on(u3_noun bus, u3_noun fol); + +/* _n_hint(): process hint. +*/ +static u3_noun +_n_hint(u3_noun zep, + u3_noun hod, + u3_noun bus, + u3_noun nex) +{ + switch ( zep ) { + default: { + // u3m_p("weird zep", zep); + u3a_lose(zep); + u3a_lose(hod); + + return _n_nock_on(bus, nex); + } + + case c3__hunk: + case c3__lose: + case c3__mean: + case c3__spot: { + u3_noun tac = u3nc(zep, hod); + u3_noun pro; + + u3t_push(tac); +#if 0 + { + static int low_i; + + if ( !low_i ) { + low_i = 1; + if ( 0 == (u3R->pro.nox_d % 65536ULL) ) { + if ( c3__spot == zep ) { + u3l_log("spot %d/%d : %d/%d", + u3h(u3h(u3t(hod))), + u3t(u3h(u3t(hod))), + u3h(u3t(u3t(hod))), + u3t(u3t(u3t(hod)))); + } + } + low_i = 0; + } + } +#endif + pro = _n_nock_on(bus, nex); + u3t_drop(); + + return pro; + } + + case c3__live: { + if ( c3y == u3ud(hod) ) { + u3t_off(noc_o); + u3t_heck(hod); + u3t_on(noc_o); + } else { + u3z(hod); + } + return _n_nock_on(bus, nex); + } + + case c3__slog: { + if ( !(u3C.wag_w & u3o_quiet) ) { + u3t_off(noc_o); + u3t_slog(hod); + u3t_on(noc_o); + } + return _n_nock_on(bus, nex); + } + + case c3__germ: { + u3_noun pro = _n_nock_on(bus, nex); + + if ( c3y == u3r_sing(pro, hod) ) { + u3z(pro); return hod; + } else { + u3z(hod); return pro; + } + } + + case c3__fast: { + u3_noun pro = _n_nock_on(bus, nex); + + u3t_off(noc_o); + u3j_mine(hod, u3k(pro)); + u3t_on(noc_o); + + return pro; + } + + case c3__memo: { + u3z(hod); +#if 0 + return _n_nock_on(bus, nex); +#else + { + u3_noun pro = u3z_find_2(144 + c3__nock, bus, nex); + + if ( pro != u3_none ) { + u3z(bus); u3z(nex); + return pro; + } + pro = _n_nock_on(u3k(bus), u3k(nex)); + + if ( &(u3H->rod_u) != u3R ) { + u3z_save_2(144 + c3__nock, bus, nex, pro); + } + + u3z(bus); u3z(nex); + + return pro; + } +#endif + } + + case c3__sole: { + u3z(hod); + { + u3_noun pro = _n_nock_on(bus, nex); + + // return u3z_uniq(pro); + return pro; + } + } + } +} + +/* _n_nock_on(): produce .*(bus fol). Do not virtualize. +*/ +static u3_noun +_n_nock_on(u3_noun bus, u3_noun fol) +{ + u3_noun hib, gal; + + while ( 1 ) { + hib = u3h(fol); + gal = u3t(fol); + +#ifdef U3_CPU_DEBUG + u3R->pro.nox_d += 1; +#endif + + if ( c3y == u3du(hib) ) { + u3_noun poz, riv; + + poz = _n_nock_on(u3k(bus), u3k(hib)); + riv = _n_nock_on(bus, u3k(gal)); + + u3a_lose(fol); + return u3i_cell(poz, riv); + } + else switch ( hib ) { + default: return u3m_bail(c3__exit); + + case 0: { + if ( c3n == u3ud(gal) ) { + return u3m_bail(c3__exit); + } + else { + u3_noun pro = u3k(u3at(gal, bus)); + + u3a_lose(bus); u3a_lose(fol); + return pro; + } + } + u3_assert(!"not reached"); + + case 1: { + u3_noun pro = u3k(gal); + + u3a_lose(bus); u3a_lose(fol); + return pro; + } + u3_assert(!"not reached"); + + case 2: { + u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal))); + u3_noun seb = _n_nock_on(bus, u3k(u3h(gal))); + + u3a_lose(fol); + bus = seb; + fol = nex; + continue; + } + u3_assert(!"not reached"); + + case 3: { + u3_noun gof, pro; + + gof = _n_nock_on(bus, u3k(gal)); + pro = u3du(gof); + + u3a_lose(gof); u3a_lose(fol); + return pro; + } + u3_assert(!"not reached"); + + case 4: { + u3_noun gof, pro; + + gof = _n_nock_on(bus, u3k(gal)); + pro = u3i_vint(gof); + + u3a_lose(fol); + return pro; + } + u3_assert(!"not reached"); + + case 5: { + u3_noun wim = _n_nock_on(bus, u3k(gal)); + u3_noun pro = u3r_sing(u3h(wim), u3t(wim)); + + u3a_lose(wim); u3a_lose(fol); + return pro; + } + u3_assert(!"not reached"); + + case 6: { + u3_noun b_gal, c_gal, d_gal; + + u3x_trel(gal, &b_gal, &c_gal, &d_gal); + { + u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal)); + u3_noun nex; + + if ( 0 == tys ) { + nex = u3k(c_gal); + } else if ( 1 == tys ) { + nex = u3k(d_gal); + } else return u3m_bail(c3__exit); + + u3a_lose(fol); + fol = nex; + continue; + } + } + u3_assert(!"not reached"); + + case 7: { + u3_noun b_gal, c_gal; + + u3x_cell(gal, &b_gal, &c_gal); + { + u3_noun bod = _n_nock_on(bus, u3k(b_gal)); + u3_noun nex = u3k(c_gal); + + u3a_lose(fol); + bus = bod; + fol = nex; + continue; + } + } + u3_assert(!"not reached"); + + case 8: { + u3_noun b_gal, c_gal; + + u3x_cell(gal, &b_gal, &c_gal); + { + u3_noun heb = _n_nock_on(u3k(bus), u3k(b_gal)); + u3_noun bod = u3nc(heb, bus); + u3_noun nex = u3k(c_gal); + + u3a_lose(fol); + bus = bod; + fol = nex; + continue; + } + } + u3_assert(!"not reached"); + + case 9: { + u3_noun b_gal, c_gal; + + u3x_cell(gal, &b_gal, &c_gal); + { + u3_noun seb = _n_nock_on(bus, u3k(c_gal)); + u3_noun pro; + + u3t_off(noc_o); + pro = u3j_kick(seb, b_gal); + u3t_on(noc_o); + + if ( u3_none != pro ) { + u3a_lose(fol); + return pro; + } + else { + if ( c3n == u3ud(b_gal) ) { + return u3m_bail(c3__exit); + } + else { + u3_noun nex = u3k(u3at(b_gal, seb)); + + u3a_lose(fol); + bus = seb; + fol = nex; + continue; + } + } + } + } + u3_assert(!"not reached"); + + case 10: { + u3_noun p_gal, q_gal; + + u3x_cell(gal, &p_gal, &q_gal); + { + u3_noun zep, hod, nex; + + if ( c3y == u3du(p_gal) ) { + u3_noun b_gal = u3h(p_gal); + u3_noun c_gal = u3t(p_gal); + u3_noun d_gal = q_gal; + + zep = u3k(b_gal); + hod = _n_nock_on(u3k(bus), u3k(c_gal)); + nex = u3k(d_gal); + } + else { + u3_noun b_gal = p_gal; + u3_noun c_gal = q_gal; + + zep = u3k(b_gal); + hod = u3_nul; + nex = u3k(c_gal); + } + + u3a_lose(fol); + return _n_hint(zep, hod, bus, nex); + } + } + + case 11: { + u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal))); + u3_noun gof = _n_nock_on(bus, u3k(u3t(gal))); + u3_noun val; + + u3t_off(noc_o); + val = u3m_soft_esc(u3k(ref), u3k(gof)); + u3t_on(noc_o); + + if ( !_(u3du(val)) ) { + u3m_bail(u3nt(1, gof, 0)); + } + if ( !_(u3du(u3t(val))) ) { + // + // replace with proper error stack push + // + u3t_push(u3nt(c3__hunk, ref, gof)); + return u3m_bail(c3__exit); + } + else { + u3_noun pro; + + u3z(ref); + u3z(gof); + u3z(fol); + pro = u3k(u3t(u3t(val))); + u3z(val); + + return pro; + } + } + u3_assert(!"not reached"); + } + } +} +#endif + +// Several opcodes "overflow" (from byte to short index) to their successor, so +// order can matter here. +// Note that we use an X macro (https://en.wikipedia.org/wiki/X_Macro) to unify +// the opcode's enum name, string representation, and computed goto into a +// single structure. +#define OPCODES \ + /* non-nock bytecodes */ \ + X(HALT, "halt", &&do_halt), /* 0: terminator, end of bytcode program */ \ + X(BAIL, "bail", &&do_bail), /* 1: deterministic crash */ \ + /* stack manipulation */ \ + X(COPY, "copy", &&do_copy), /* 2 */ \ + X(SWAP, "swap", &&do_swap), /* 3 */ \ + X(TOSS, "toss", &&do_toss), /* 4 */ \ + /* auto-cons */ \ + X(AUTO, "auto", &&do_auto), /* 5: kept */ \ + X(AULT, "ault", &&do_ault), /* 6: lost */ \ + /* general purposes */ \ + X(SNOC, "snoc", &&do_snoc), /* 7: keep */ \ + X(SNOL, "snol", &&do_snol), /* 8: lose */ \ + /* nock 0: head */ \ + X(HEAD, "head", &&do_head), /* 9: keep */ \ + X(HELD, "held", &&do_held), /* 10: lose */ \ + /* nock 0: tail */ \ + X(TAIL, "tail", &&do_tail), /* 11: keep */ \ + X(TALL, "tall", &&do_tall), /* 12: lose */ \ + /* nock 0: fragment (keep) */ \ + X(FABK, "fabk", &&do_fabk), /* 13: c3_y */ \ + X(FASK, "fask", &&do_fask), /* 14: c3_s */ \ + X(FIBK, "fibk", &&do_fibk), /* 15: c3_y */ \ + X(FISK, "fisk", &&do_fisk), /* 16: c3_s */ \ + /* nock 0: fragment (lose) */ \ + X(FABL, "fabl", &&do_fabl), /* 17: c3_y */ \ + X(FASL, "fasl", &&do_fasl), /* 18: c3_s */ \ + X(FIBL, "fibl", &&do_fibl), /* 19: c3_y */ \ + X(FISL, "fisl", &&do_fisl), /* 20: c3_s */ \ + /* nock 1: literal (keep) */ \ + X(LIT0, "lit0", &&do_lit0), /* 21: a literal 0 */ \ + X(LIT1, "lit1", &&do_lit1), /* 22: a literal 1 */ \ + X(LITB, "litb", &&do_litb), /* 23: c3_y */ \ + X(LITS, "lits", &&do_lits), /* 24: c3_s */ \ + X(LIBK, "libk", &&do_libk), /* 25: c3_y */ \ + X(LISK, "lisk", &&do_lisk), /* 26: c3_s */ \ + /* nock 1: literal (lose) */ \ + X(LIL0, "lil0", &&do_lil0), /* 27: a literal 0 */ \ + X(LIL1, "lil1", &&do_lil1), /* 28: a literal 1 */ \ + X(LILB, "lilb", &&do_lilb), /* 29: c3_y */ \ + X(LILS, "lils", &&do_lils), /* 30: c3_s */ \ + X(LIBL, "libl", &&do_libl), /* 31: c3_y */ \ + X(LISL, "lisl", &&do_lisl), /* 32: c3_s */ \ + /* nock 2: nock */ \ + X(NOLK, "nolk", &&do_nolk), /* 33, lost */ \ + X(NOCT, "noct", &&do_noct), /* 34, tail */ \ + X(NOCK, "nock", &&do_nock), /* 35, kept */ \ + /* nock 3 & 4 */ \ + X(DEEP, "deep", &&do_deep), /* 36 */ \ + X(BUMP, "bump", &&do_bump), /* 37 */ \ + /* nock 5: equality */ \ + X(SAM0, "sam0", &&do_sam0), /* 38: test that it is equal to 0 */ \ + X(SAM1, "sam1", &&do_sam1), /* 39: test that it is equal to 1 */ \ + X(SAMB, "samb", &&do_samb), /* 40: test equality for vars size c3_b */ \ + X(SAMS, "sams", &&do_sams), /* 41: test equality for vars size c3_s */ \ + X(SANB, "sanb", &&do_sanb), /* 42: test equality for vars size c3_b */ \ + X(SANS, "sans", &&do_sans), /* 43: test equality for vars size c3_s */ \ + X(SAME, "same", &&do_same), /* 44 */ \ + X(SALM, "salm", &&do_salm), /* 45 */ \ + X(SAMC, "samc", &&do_samc), /* 46 */ \ + /* related to nock 6: unconditional skips */ \ + X(SBIP, "sbip", &&do_sbip), /* 47: c3_b */ \ + X(SIPS, "sips", &&do_sips), /* 48: c3_s */ \ + X(SWIP, "swip", &&do_swip), /* 49: c3_l */ \ + /* related to nock 6: conditional skips */ \ + X(SBIN, "sbin", &&do_sbin), /* 50: c3_b */ \ + X(SINS, "sins", &&do_sins), /* 51: c3_s */ \ + X(SWIN, "swin", &&do_swin), /* 52: c3_l */ \ + /* nock 9 */ \ + X(KICB, "kicb", &&do_kicb), /* 53: c3_b */ \ + X(KICS, "kics", &&do_kics), /* 54: c3_s */ \ + X(TICB, "ticb", &&do_ticb), /* 55: c3_b */ \ + X(TICS, "tics", &&do_tics), /* 56: c3_s */ \ + /* nock 12: scry (only defined in arvo, not in base nock spec) */ \ + X(WILS, "wils", &&do_wils), /* 57 */ \ + X(WISH, "wish", &&do_wish), /* 58 */ \ + /* nock 11: hint processing */ \ + X(BUSH, "bush", &&do_bush), /* 59: c3_b */ \ + X(SUSH, "sush", &&do_sush), /* 60: c3_s */ \ + X(DROP, "drop", &&do_drop), /* 61 */ \ + X(HECK, "heck", &&do_heck), /* 62 */ \ + X(SLOG, "slog", &&do_slog), /* 63 */ \ + /* nock 11: fast (keep) */ \ + X(BAST, "bast", &&do_bast), /* 64: c3_b */ \ + X(SAST, "sast", &&do_sast), /* 65: c3_s */ \ + /* nock 11: fast (lost) */ \ + X(BALT, "balt", &&do_balt), /* 66: c3_b */ \ + X(SALT, "salt", &&do_salt), /* 67: c3_s */ \ + /* nock 11: memo (keep) */ \ + X(SKIB, "skib", &&do_skib), /* 68: c3_b */ \ + X(SKIS, "skis", &&do_skis), /* 69: c3_s */ \ + /* nock 11: memo (lose) */ \ + X(SLIB, "slib", &&do_slib), /* 70: c3_b */ \ + X(SLIS, "slis", &&do_slis), /* 71: c3_s */ \ + X(SAVE, "save", &&do_save), /* 72 */ \ + /* nock 11: before formula */ \ + X(HILB, "hilb", &&do_hilb), /* 73: atomic, byte */ \ + X(HILS, "hils", &&do_hils), /* 74: atomic, short */ \ + X(HINB, "hinb", &&do_hinb), /* 75: arbitrary, byte */ \ + X(HINS, "hins", &&do_hins), /* 76: arbitrary, short */ \ + /* nock 11: after formula */ \ + X(HILK, "hilk", &&do_hilk), /* 77: atomic, keep */ \ + X(HILL, "hill", &&do_hill), /* 78: atomic, lose */ \ + X(HINK, "hink", &&do_hink), /* 79: arbitrary, keep */ \ + X(HINL, "hinl", &&do_hinl), /* 80: arbitrary, lose */ \ + /* nock 10 */ \ + X(MUTH, "muth", &&do_muth), /* 81 */ \ + X(KUTH, "kuth", &&do_kuth), /* 82 */ \ + X(MUTT, "mutt", &&do_mutt), /* 83 */ \ + X(KUTT, "kutt", &&do_kutt), /* 84 */ \ + X(MUSM, "musm", &&do_musm), /* 85 */ \ + X(KUSM, "kusm", &&do_kusm), /* 86 */ \ + X(MUTB, "mutb", &&do_mutb), /* 87: c3_b */ \ + X(MUTS, "muts", &&do_muts), /* 88: c3_s */ \ + X(MITB, "mitb", &&do_mitb), /* 89: c3_b */ \ + X(MITS, "mits", &&do_mits), /* 90: c3_s */ \ + X(KUTB, "kutb", &&do_kutb), /* 91: c3_b */ \ + X(KUTS, "kuts", &&do_kuts), /* 92: c3_s */ \ + X(KITB, "kitb", &&do_kitb), /* 93: c3_b */ \ + X(KITS, "kits", &&do_kits), /* 94: c3_s */ \ + X(LAST, NULL, NULL), /* 95 */ + +// Opcodes. Define X to select the enum name from OPCODES. +#define X(opcode, name, indirect_jump) opcode +enum { OPCODES }; +#undef X + +/* _n_arg(): return the size (in bytes) of an opcode's argument + */ +static inline c3_y +_n_arg(c3_y cod_y) +{ + switch ( cod_y ) { + case FABK: case FABL: case FIBL: case FIBK: + case LILB: case LITB: case LIBL: case LIBK: + case SAMB: case SANB: case SBIP: case SBIN: + case SLIB: case SKIB: case KICB: case TICB: + case BUSH: case BAST: case BALT: + case MUTB: case KUTB: case MITB: case KITB: + case HILB: case HINB: + return sizeof(c3_y); + + case FASK: case FASL: case FISL: case FISK: + case LILS: case LITS: case LISL: case LISK: + case SAMS: case SANS: case SIPS: case SINS: + case SLIS: case SKIS: case KICS: case TICS: + case SUSH: case SAST: case SALT: + case MUTS: case KUTS: case MITS: case KITS: + case HILS: case HINS: + return sizeof(c3_s); + + case SWIP: case SWIN: + return sizeof(c3_l); + + default: + u3_assert( cod_y < LAST ); + return 0; + } +} + + +/* _n_melt(): measure space for list of ops (from _n_comp) */ +static u3_noun +_n_melt(u3_noun ops, c3_w* byc_w, c3_w* cal_w, + c3_w* reg_w, c3_w* lit_w, c3_w* mem_w) +{ + c3_w len_w = u3qb_lent(ops), + i_w = len_w - 1, + a_w; + c3_y cod_y; + c3_y* siz_y = u3a_malloc(len_w); + u3_noun op, sip = u3_nul; + + while ( u3_nul != ops ) { + op = u3h(ops); + if ( c3n == u3du(op) ) { + switch ( op ) { + default: + siz_y[i_w] = 1; + break; + + case BAST: case BALT: + a_w = (*reg_w)++; + if ( a_w <= 0xFF ) { + siz_y[i_w] = 2; + } + else if ( a_w <= 0xFFFF ) { + siz_y[i_w] = 3; + } + else { + fprintf(stderr, "_n_melt(): over 2^16 registration sites.\r\n"); + u3_assert(0); + } + break; + } + } + else { + cod_y = u3h(op); + + switch ( cod_y ) { + default: + siz_y[i_w] = 1 + _n_arg(cod_y); + break; + + case SBIP: case SBIN: { + c3_l tot_l = 0, + sip_l = u3t(op); + c3_w j_w, k_w = i_w; + for ( j_w = 0; j_w < sip_l; ++j_w ) { + tot_l += siz_y[++k_w]; + } + sip = u3nc(tot_l, sip); + siz_y[i_w] = tot_l <= 0xFF ? 2 : tot_l <= 0xFFFF ? 3 : 5; + break; + } + + case SKIB: case SLIB: { + c3_l tot_l = 0, + sip_l = u3h(u3t(u3t(op))); + c3_w j_w, k_w = i_w; + for ( j_w = 0; j_w < sip_l; ++j_w ) { + tot_l += siz_y[++k_w]; + } + sip = u3nc(tot_l, sip); + a_w = (*mem_w)++; + if ( a_w <= 0xFF ) { + siz_y[i_w] = 2; + } + else if ( a_w <= 0xFFFF ) { + siz_y[i_w] = 3; + } + else { + fprintf(stderr, "_n_melt(): over 2^16 memos.\r\n"); + u3_assert(0); + } + break; + } + + case SIPS: case SINS: case SWIP: case SWIN: + case SAST: case SALT: case KICS: case TICS: + case FISK: case FISL: case SUSH: case SANS: + case LISL: case LISK: case SKIS: case SLIS: + case HILS: case HINS: + u3_assert(0); //overflows + break; + + case KICB: case TICB: + a_w = (*cal_w)++; + if ( a_w <= 0xFF ) { + siz_y[i_w] = 2; + } + else if ( a_w <= 0xFFFF ) { + siz_y[i_w] = 3; + } + else { + fprintf(stderr, "_n_melt(): over 2^16 call sites.\r\n"); + u3_assert(0); + } + break; + + case BUSH: case FIBK: case FIBL: + case SANB: case LIBL: case LIBK: + case KITB: case MITB: + case HILB: case HINB: + a_w = (*lit_w)++; + if ( a_w <= 0xFF ) { + siz_y[i_w] = 2; + } + else if ( a_w <= 0xFFFF ) { + siz_y[i_w] = 3; + } + else { + fprintf(stderr, "_n_melt(): over 2^16 literals.\r\n"); + u3_assert(0); + } + break; + } + } + + *(byc_w) += siz_y[i_w--]; + ops = u3t(ops); + } + + u3a_free(siz_y); + return u3kb_flop(sip); +} + +/* _n_prog_dat(): return pointer to program's data segment + */ +static void* +_n_prog_dat(u3n_prog* pog_u) +{ + return ((void*) pog_u) + sizeof(u3n_prog); +} + +/* _n_prog_new(): allocate and set up pointers for u3n_prog + */ +static u3n_prog* +_n_prog_new(c3_w byc_w, c3_w cal_w, + c3_w reg_w, c3_w lit_w, c3_w mem_w) +{ + c3_w cab_w = (sizeof(u3j_site) * cal_w), + reb_w = (sizeof(u3j_rite) * reg_w), + lib_w = (sizeof(u3_noun) * lit_w), + meb_w = (sizeof(u3n_memo) * mem_w), + pad_w = (8 - byc_w % 8) % 8, + pod_w = lit_w % 2, + ped_w = mem_w % 2, + dat_w = byc_w + cab_w + reb_w + lib_w + meb_w + pad_w + + (pod_w * sizeof(u3_noun)) + (ped_w * sizeof(u3n_memo)); + + u3n_prog* pog_u = u3a_malloc(sizeof(u3n_prog) + dat_w); + pog_u->byc_u.own_o = c3y; + pog_u->byc_u.len_w = byc_w; + pog_u->byc_u.ops_y = (c3_y*) _n_prog_dat(pog_u); + + pog_u->lit_u.len_w = lit_w; + pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w + pad_w); + + pog_u->mem_u.len_w = mem_w; + pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w + pod_w); + + pog_u->cal_u.len_w = cal_w; + pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w + ped_w); + + pog_u->reg_u.len_w = reg_w; + pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); + + return pog_u; +} + +/* _n_prog_old(): as _n_prog_new(), + * but leech off senior program's data segment + */ +static u3n_prog* +_n_prog_old(u3n_prog* sep_u) +{ + c3_w cab_w = sizeof(u3j_site) * sep_u->cal_u.len_w, + reb_w = sizeof(u3j_rite) * sep_u->reg_u.len_w, + lib_w = sizeof(u3_noun) * sep_u->lit_u.len_w, + meb_w = sizeof(u3n_memo) * sep_u->mem_u.len_w, + pod_w = sep_u->lit_u.len_w % 2, + ped_w = sep_u->mem_u.len_w % 2, + dat_w = cab_w + reb_w + lib_w + meb_w + + (pod_w * sizeof(u3_noun)) + (ped_w * sizeof(u3n_memo)); + + u3n_prog* pog_u = u3a_malloc(sizeof(u3n_prog) + dat_w); + pog_u->byc_u.own_o = c3n; + pog_u->byc_u.len_w = sep_u->byc_u.len_w; + pog_u->byc_u.ops_y = sep_u->byc_u.ops_y; + + pog_u->lit_u.len_w = sep_u->lit_u.len_w; + pog_u->lit_u.non = (u3_noun*) _n_prog_dat(pog_u); + + pog_u->mem_u.len_w = sep_u->mem_u.len_w; + pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w + pod_w); + + pog_u->cal_u.len_w = sep_u->cal_u.len_w; + pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w + ped_w); + + pog_u->reg_u.len_w = sep_u->reg_u.len_w; + pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); + + memcpy(pog_u->lit_u.non, sep_u->lit_u.non, dat_w); + return pog_u; +} + +/* _n_prog_asm_inx(): write an index to the bytestream with overflow + */ +static void +_n_prog_asm_inx(c3_y* buf_y, c3_w* i_w, c3_s inx_s, c3_y cod) +{ + if ( inx_s <= 0xFF ) { + buf_y[(*i_w)--] = (c3_y) (inx_s); + buf_y[*i_w] = (c3_y) cod; + } + else { + buf_y[(*i_w)--] = (c3_y) (inx_s >> 8); + buf_y[(*i_w)--] = (c3_y) (inx_s); + // the short-index versions of these opcodes must immediately + // follow the byte-index versions because of this convention + buf_y[(*i_w)] = cod + 1; + } +} + +/* _n_prog_asm(): assemble list of ops (from _n_comp) into u3n_prog + */ +static void +_n_prog_asm(u3_noun ops, u3n_prog* pog_u, u3_noun sip) +{ + u3_noun top = ops; + c3_y* buf_y = pog_u->byc_u.ops_y; + c3_s lit_s = 0, + cal_s = 0, + mem_s = 0, + reg_s = 0; + c3_w i_w = pog_u->byc_u.len_w-1; + + buf_y[i_w] = HALT; + + while ( i_w-- > 0 ) { + u3_noun op = u3h(ops); + if ( c3y == u3ud(op) ) { + switch ( op ) { + default: + buf_y[i_w] = (c3_y) op; + break; + + /* registration site index args */ + case BAST: case BALT: { + _n_prog_asm_inx(buf_y, &i_w, reg_s, op); + u3j_rite* rit_u = &(pog_u->reg_u.rit_u[reg_s++]); + rit_u->own_o = c3n; + rit_u->clu = u3_none; + rit_u->fin_p = 0; + break; + } + } + } + else { + u3_noun cod = u3h(op); + switch ( cod ) { + default: + u3_assert(0); + return; + + /* memo index args */ + case SKIB: case SLIB: { + u3n_memo* mem_u; + c3_l sip_l = u3h(sip); + u3_noun tmp = sip; + sip = u3k(u3t(sip)); + u3z(tmp); + _n_prog_asm_inx(buf_y, &i_w, mem_s, cod); + mem_u = &(pog_u->mem_u.sot_u[mem_s++]); + mem_u->sip_l = sip_l; + // [op_y, cid, mem_w, nef] + mem_u->key = u3k(u3t(u3t(u3t(op)))); + mem_u->cid = u3h(u3t(op)); + break; + } + + /* skips */ + case SBIP: case SBIN: { + c3_l sip_l = u3h(sip); + u3_noun tmp = sip; + sip = u3k(u3t(sip)); + u3z(tmp); + if ( sip_l <= 0xFF ) { + buf_y[i_w--] = (c3_y) sip_l; + buf_y[i_w] = (c3_y) cod; + } + else if ( sip_l <= 0xFFFF ) { + buf_y[i_w--] = (c3_y) (sip_l >> 8); + buf_y[i_w--] = (c3_y) sip_l; + buf_y[i_w] = (c3_y) cod + 1; + } + else { + buf_y[i_w--] = (c3_y) (sip_l >> 24); + buf_y[i_w--] = (c3_y) (sip_l >> 16); + buf_y[i_w--] = (c3_y) (sip_l >> 8); + buf_y[i_w--] = (c3_y) sip_l; + buf_y[i_w] = (c3_y) cod + 2; + } + break; + } + + /* 8-bit direct args */ + case FABK: case FABL: + case LITB: case LILB: + case MUTB: case KUTB: + case SAMB: + buf_y[i_w--] = (c3_y) u3t(op); + buf_y[i_w] = (c3_y) cod; + break; + + /* 16-bit direct args */ + case FASK: case FASL: + case LILS: case LITS: + case MUTS: case KUTS: + case SAMS: case SIPS: case SINS: { + c3_s off_s = u3t(op); + buf_y[i_w--] = (c3_y) (off_s >> 8); + buf_y[i_w--] = (c3_y) off_s; + buf_y[i_w] = (c3_y) cod; + break; + } + + /* 31-bit direct args */ + case SWIP: case SWIN: { + c3_w off_l = u3t(op); + buf_y[i_w--] = (c3_y) (off_l >> 24); + buf_y[i_w--] = (c3_y) (off_l >> 16); + buf_y[i_w--] = (c3_y) (off_l >> 8); + buf_y[i_w--] = (c3_y) off_l; + buf_y[i_w] = (c3_y) cod; + break; + } + + /* literal index args */ + case FIBK: case FIBL: + case LIBK: case LIBL: + case BUSH: case SANB: + case KITB: case MITB: + case HILB: case HINB: + _n_prog_asm_inx(buf_y, &i_w, lit_s, cod); + pog_u->lit_u.non[lit_s++] = u3k(u3t(op)); + break; + + /* call site index args */ + case TICB: case KICB: { + _n_prog_asm_inx(buf_y, &i_w, cal_s, cod); + u3j_site* sit_u = &(pog_u->cal_u.sit_u[cal_s++]); + sit_u->axe = u3k(u3t(op)); + sit_u->pog_p = 0; + sit_u->bat = u3_none; + sit_u->bas = u3_none; + sit_u->loc = u3_none; + sit_u->lab = u3_none; + sit_u->jet_o = c3n; + sit_u->fon_o = c3n; + sit_u->cop_u = NULL; + sit_u->ham_u = NULL; + sit_u->fin_p = 0; + break; + } + } + } + ops = u3t(ops); + } + u3z(top); + // this assert will fail if we overflow a c3_w worth of instructions + u3_assert(u3_nul == ops); + // this is just a sanity check + u3_assert(u3_nul == sip); +} + +/* _n_prog_from_ops(): new program from _n_comp() product + */ +static u3n_prog* +_n_prog_from_ops(u3_noun ops) +{ + u3_noun sip; + u3n_prog* pog_u; + c3_w byc_w = 1, // HALT + cal_w = 0, + reg_w = 0, + lit_w = 0, + mem_w = 0; + + sip = _n_melt(ops, &byc_w, &cal_w, ®_w, &lit_w, &mem_w); + pog_u = _n_prog_new(byc_w, cal_w, reg_w, lit_w, mem_w); + _n_prog_asm(ops, pog_u, sip); + return pog_u; +} + +#if 0 +/* _n_print_stack(): print out the cap stack up to a designated "empty" + * used only for debugging + */ +static void _n_print_stack(u3p(u3_noun) empty) { + c3_w cur_p = u3R->cap_p; + fprintf(stderr, "["); + int first = 1; + while ( cur_p != empty ) { + if ( first ) { + first = 0; + } + else { + fprintf(stderr, " "); + } + if ( c3y == u3a_is_north(u3R) ) { + fprintf(stderr, "%u", *(u3to(u3_noun, cur_p))); + cur_p++; + } + else { + fprintf(stderr, "%u", *(u3to(u3_noun, cur_p-1))); + cur_p--; + } + } + fprintf(stderr, "]\r\n"); +} +#endif + +// Define X to select the opcode string representation from OPCODES. +# define X(opcode, name, indirect_jump) name +static c3_c* opcode_names[] = { OPCODES }; +# undef X + +/* _n_apen(): emit the instructions contained in src to dst + */ +static inline void +_n_apen(u3_noun* dst, u3_noun src) +{ + *dst = u3kb_weld(src, *dst); +} + +/* _n_emit(): emit a single instruction to ops + */ +static inline void +_n_emit(u3_noun *ops, u3_noun op) +{ + *ops = u3nc(op, *ops); +} + +static c3_w _n_comp(u3_noun*, u3_noun, c3_o, c3_o); + +/* _n_bint(): hint-processing helper for _n_comp. + * hif: hint-formula (first part of 11). RETAIN. + * nef: next-formula (second part of 11). RETAIN. + */ +static c3_w +_n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o) +{ + c3_w tot_w = 0; + + if ( c3n == u3du(hif) ) { + // compile whitelisted atomic hints to dispatch protocol; + // compute and drop all others; + // + switch ( hif ) { + default: { + return _n_comp(ops, nef, los_o, tel_o); + } + case c3__cash: + case c3__xray: + case c3__meme: + case c3__nara: + case c3__hela: + case c3__bout: { + u3_noun fen = u3_nul; + c3_w nef_w = _n_comp(&fen, nef, los_o, c3n); + // add appropriate hind opcode + ++nef_w; _n_emit(&fen, ( c3y == los_o ) ? HILL : HILK); + // skip over the cleanup opcode + ++nef_w; _n_emit(&fen, u3nc(SBIP, 1)); + + // call hilt_fore + // HILB overflows to HILS + ++tot_w; _n_emit(ops, u3nc(HILB, u3nc(u3k(hif), u3k(nef)))); + // if fore return c3n, skip fen + ++tot_w; _n_emit(ops, u3nc(SBIN, nef_w)); + tot_w += nef_w; _n_apen(ops, fen); + // post-skip cleanup opcode + ++tot_w; _n_emit(ops, ( c3y == los_o ) ? TOSS : SWAP); + } break; + } + } + else { + u3_noun zep, hod; + u3x_cell(hif, &zep, &hod); + + switch ( zep ) { + default: { + // compile whitelisted dynamic hints to dispatch protocol; + // compute and drop all others; + // + switch ( zep ) { + default: { + tot_w += _n_comp(ops, hod, c3n, c3n); + ++tot_w; _n_emit(ops, TOSS); + tot_w += _n_comp(ops, nef, los_o, tel_o); + } break; + case c3__xray: + case c3__meme: + case c3__nara: + case c3__hela: + case c3__spin: + case c3__bout: { + u3_noun fen = u3_nul; + c3_w nef_w = _n_comp(&fen, nef, los_o, c3n); + // add appropriate hind opcode + ++nef_w; _n_emit(&fen, ( c3y == los_o ) ? HINL : HINK); + // skip over the cleanup opcode + ++nef_w; _n_emit(&fen, u3nc(SBIP, 1)); + + // push clue + tot_w += _n_comp(ops, hod, c3n, c3n); + // call hint_fore + // HINB overflows to HINS + ++tot_w; _n_emit(ops, u3nc(HINB, u3nc(u3k(zep), u3k(nef)))); + // if fore return c3n, skip fen + ++tot_w; _n_emit(ops, u3nc(SBIN, nef_w)); + tot_w += nef_w; _n_apen(ops, fen); + // post-skip cleanup opcode + ++tot_w; _n_emit(ops, ( c3y == los_o ) ? TOSS : SWAP); + } break; + } + } break; + + case c3__hunk: + case c3__lose: + case c3__mean: + case c3__spot: + tot_w += _n_comp(ops, hod, c3n, c3n); + ++tot_w; _n_emit(ops, u3nc(BUSH, zep)); // overflows to SUSH + tot_w += _n_comp(ops, nef, los_o, c3n); + ++tot_w; _n_emit(ops, DROP); + break; + + case c3__live: + tot_w += _n_comp(ops, hod, c3n, c3n); + ++tot_w; _n_emit(ops, HECK); + tot_w += _n_comp(ops, nef, los_o, tel_o); + break; + + case c3__slog: + tot_w += _n_comp(ops, hod, c3n, c3n); + ++tot_w; _n_emit(ops, SLOG); + tot_w += _n_comp(ops, nef, los_o, tel_o); + break; + + // germ and sole are unused... + + case c3__fast: + tot_w += _n_comp(ops, hod, c3n, c3n); + ++tot_w; _n_emit(ops, SWAP); + tot_w += _n_comp(ops, nef, los_o, c3n); + // overflows to SALT / SAST + ++tot_w; _n_emit(ops, (c3y == los_o) ? BALT : BAST); + break; + + case c3__memo: { + u3_noun mem = u3_nul; + c3_w mem_w = 0; + c3_y op_y; + + tot_w += _n_comp(ops, hod, c3n, c3n); + ++tot_w; _n_emit(ops, TOSS); + + mem_w += _n_comp(&mem, nef, c3y, c3n); + ++mem_w; _n_emit(&mem, SAVE); + + op_y = (c3y == los_o) ? SLIB : SKIB; // overflows to SLIS / SKIS + u3z_cid cid = u3z_memo_toss; + { + u3_weak con = u3r_skip(hod); + if ( (u3_none != con) && (c3y == u3du(con)) ) { + cid = u3z_memo_keep; + } + } + ++tot_w; _n_emit(ops, u3nq(op_y, cid, mem_w, u3k(nef))); + tot_w += mem_w; _n_apen(ops, mem); + break; + } + } + } + + return tot_w; +} + +static c3_t +_n_formulaic(u3_noun fol) +{ + u3_noun op, ar, a, b, c; + if ( c3n == u3r_cell(fol, &op, &ar) ) { + return 0; + } + if ( c3y == u3du(op) ) { + return _n_formulaic(op) && _n_formulaic(ar); + } + else switch ( op ) { + case 0: + return ( c3y == u3ud(ar) ); + case 1: + return 1; + case 3: + case 4: + return _n_formulaic(ar); + case 2: + case 5: + case 7: + case 8: + case 12: + return (c3y == u3r_cell(ar, &a, &b)) + && _n_formulaic(a) && _n_formulaic(b); + case 6: { + u3_noun lit; + + if ( c3n == u3r_trel(ar, &a, &b, &c) || !_n_formulaic(a) ) { + return 0; + } + + if ( c3n == u3r_safe(a, &lit) || u3_none == lit ) { + return _n_formulaic(b) || _n_formulaic(c); + } + + switch (lit) { + case 0: return _n_formulaic(b); + case 1: return _n_formulaic(c); + default: return 0; + } + } + case 9: + return (c3y == u3r_cell(ar, &a, &b)) + && (c3y == u3ud(a)) + && _n_formulaic(b); + case 10: + if ( c3n == u3r_cell(ar, &a, &b) ) { + return 0; + } + if ( c3n == u3du(a) ) { + return 0; + } + if ( c3n == u3ud(u3h(a)) ) { + return 0; + } + return _n_formulaic(u3t(a)) && _n_formulaic(b); + case 11: + if ( c3n == u3r_cell(ar, &a, &b) ) { + return 0; + } + if ( !_n_formulaic(b) ) { + return 0; + } + if ( c3y == u3ud(a) ) { + return 1; + } + else { + return ( c3y == u3ud(u3h(a)) ) && _n_formulaic(u3t(a)); + } + default: + return 0; + } +} + +/* _n_comp(): compile nock formula to reversed opcode list + * ops is a pointer to a list (to be emitted to) + * fol is the nock formula to compile. RETAIN. + * los_o indicates whether we should remove our + * subject from the stack + * tel_o is yes if this formula is in tail position + * return: number of instructions added to the opcode list + */ +static c3_w +_n_comp(u3_noun* ops, u3_noun fol, c3_o los_o, c3_o tel_o) +{ + c3_y op_y; + c3_w tot_w = 0; + u3_noun cod, arg, hed, tel; + u3x_cell(fol, &cod, &arg); + if ( c3y == u3du(cod) ) { + tot_w += _n_comp(ops, cod, c3n, c3n); + ++tot_w; _n_emit(ops, SWAP); + tot_w += _n_comp(ops, arg, los_o, c3n); + ++tot_w; _n_emit(ops, (c3y == los_o ) ? AULT : AUTO); + } + else switch ( cod ) { + case 0: + if ( c3n == u3ud(arg) ) { + u3m_bail(c3__exit); + return 0; + } + switch ( arg ) { + case 0: + ++tot_w; _n_emit(ops, BAIL); + break; + case 1: + if ( c3n == los_o ) { + ++tot_w; _n_emit(ops, COPY); + } + break; + case 2: + ++tot_w; _n_emit(ops, (c3y == los_o) ? HELD : HEAD); + break; + case 3: + ++tot_w; _n_emit(ops, (c3y == los_o) ? TALL : TAIL); + break; + default: + op_y = (c3y == los_o) + ? (arg <= 0xFF ? FABL : arg <= 0xFFFF ? FASL : FIBL) // overflows to FISL + : (arg <= 0xFF ? FABK : arg <= 0xFFFF ? FASK : FIBK); // overflows to FISK + ++tot_w; _n_emit(ops, u3nc(op_y, u3k(arg))); + break; + } + break; + + case 1: + switch ( arg ) { + case 0: + ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL0 : LIT0); + break; + case 1: + ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL1 : LIT1); + break; + default: + op_y = (c3y == los_o) + ? (arg <= 0xFF ? LILB : arg <= 0xFFFF ? LILS : LIBL) // overflows to LISL + : (arg <= 0xFF ? LITB : arg <= 0xFFFF ? LITS : LIBK); // overflows to LISK + ++tot_w; _n_emit(ops, u3nc(op_y, u3k(arg))); + break; + } + break; + + case 2: + u3x_cell(arg, &hed, &tel); + tot_w += _n_comp(ops, hed, c3n, c3n); + ++tot_w; _n_emit(ops, SWAP); + tot_w += _n_comp(ops, tel, los_o, c3n); + /* things in tail position replace (so, lose) top of stack, + * so NOCT "loses" and there is no non-losing version */ + op_y = (c3y == tel_o) ? NOCT + : ((c3y == los_o) ? NOLK : NOCK); + ++tot_w; _n_emit(ops, op_y); + break; + + case 3: + tot_w += _n_comp(ops, arg, los_o, c3n); + ++tot_w; _n_emit(ops, DEEP); + break; + + case 4: + tot_w += _n_comp(ops, arg, los_o, c3n); + ++tot_w; _n_emit(ops, BUMP); + break; + + case 5: { + u3x_cell(arg, &hed, &tel); + + if ( c3n == u3du(hed) ) { + u3m_bail(c3__exit); + return 0; + } + else { + c3_t hec_t, tec_t; + hec_t = (1 == u3h(hed)); + if ( c3n == u3du(tel) ) { + u3m_bail(c3__exit); + break; + } + else { + tec_t = (1 == u3h(tel)); + } + if ( hec_t && tec_t ) { + if ( c3y == u3r_sing(u3t(hed), u3t(tel)) ) { + ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL0 : LIT0); + } + else { + ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL1 : LIT1); + } + } + else if ( !hec_t && !tec_t ) { + tot_w += _n_comp(ops, hed, c3n, c3n); + ++tot_w; _n_emit(ops, SWAP); + tot_w += _n_comp(ops, tel, los_o, c3n); + ++tot_w; _n_emit(ops, (c3y == los_o) ? SALM : SAME); + } + else { + tot_w += _n_comp(ops, (hec_t ? tel : hed), los_o, c3n); + u3_noun lit = u3t(hec_t ? hed : tel); + switch ( lit ) { + case 0: + ++tot_w; _n_emit(ops, SAM0); + break; + case 1: + ++tot_w; _n_emit(ops, SAM1); + break; + default: + // overflows to SANS + op_y = lit <= 0xFF ? SAMB : lit <= 0xFFFF ? SAMS : SANB; + ++tot_w; _n_emit(ops, u3nc(op_y, u3k(lit))); + } + } + } + break; + } + + case 6: { + u3_noun mid, lit; + u3x_trel(arg, &hed, &mid, &tel); + if ( c3y == u3r_safe(hed, &lit) && u3_none != lit ) { + switch ( lit ) { + case 0: + tot_w += _n_comp(ops, mid, los_o, tel_o); + break; + + case 1: + tot_w += _n_comp(ops, tel, los_o, tel_o); + break; + + default: + ++tot_w; _n_emit(ops, BAIL); + break; + } + } + else { + u3_noun yep = u3_nul, + nop = u3_nul; + c3_w yep_w, nop_w; + c3_t yep_t, nop_t; + + tot_w += _n_comp(ops, hed, c3n, c3n); + yep_t = _n_formulaic(mid); + nop_t = _n_formulaic(tel); + + if ( !yep_t && !nop_t ) { + u3m_bail(c3__exit); + break; + } + + if ( yep_t ) { + yep_w = _n_comp(&yep, mid, los_o, tel_o); + } + else { + yep_w = 1; _n_emit(&yep, BAIL); + } + + if ( nop_t ) { + nop_w = _n_comp(&nop, tel, los_o, tel_o); + } + else { + nop_w = 1; _n_emit(&nop, BAIL); + } + + // SBIP and SBIN get sized during assembly + ++yep_w; _n_emit(&yep, u3nc(SBIP, nop_w)); + ++tot_w; _n_emit(ops, u3nc(SBIN, yep_w)); + tot_w += yep_w; _n_apen(ops, yep); + tot_w += nop_w; _n_apen(ops, nop); + } + break; + } + + case 7: + u3x_cell(arg, &hed, &tel); + tot_w += _n_comp(ops, hed, los_o, c3n); + tot_w += _n_comp(ops, tel, c3y, tel_o); + break; + + case 8: + u3x_cell(arg, &hed, &tel); + tot_w += _n_comp(ops, hed, c3n, c3n); + ++tot_w; _n_emit(ops, (c3y == los_o) ? SNOL : SNOC); + tot_w += _n_comp(ops, tel, c3y, tel_o); + break; + + case 9: + u3x_cell(arg, &hed, &tel); + if ( (1 == hed) || (3 == u3qc_cap(u3x_atom(hed))) ) { + u3_noun mac = u3nq(7, u3k(tel), 2, u3nt(u3nc(0, 1), 0, u3k(hed))); + tot_w += _n_comp(ops, mac, los_o, tel_o); + u3z(mac); + } + else { + tot_w += _n_comp(ops, tel, (c3y == tel_o ? c3y : los_o), c3n); + op_y = (c3y == tel_o) ? TICB : KICB; // overflows to TICS/KICS + ++tot_w; _n_emit(ops, u3nc(op_y, u3k(hed))); + } + break; + + case 10: { + u3_noun axe, nef; + u3x_cell(arg, &hed, &tel); + u3x_cell(hed, &axe, &nef); + tot_w += _n_comp(ops, tel, c3n, c3n); + ++tot_w; _n_emit(ops, SWAP); + tot_w += _n_comp(ops, nef, los_o, c3n); + + ++tot_w; + switch ( axe ) { + case 2: + _n_emit(ops, (c3y == los_o) ? MUTH : KUTH); + break; + + case 3: + _n_emit(ops, (c3y == los_o) ? MUTT : KUTT); + break; + + case u3x_sam: + _n_emit(ops, (c3y == los_o) ? MUSM : KUSM); + break; + + default: + op_y = (c3y == los_o) + ? (axe <= 0xFF) ? MUTB : (axe <= 0xFFFF) ? MUTS : MITB // overflows to MITS + : (axe <= 0xFF) ? KUTB : (axe <= 0xFFFF) ? KUTS : KITB; // overflows to KITS + _n_emit(ops, u3nc(op_y, u3k(axe))); + break; + } + break; + } + + case 11: + u3x_cell(arg, &hed, &tel); + tot_w += _n_bint(ops, hed, tel, los_o, tel_o); + break; + + case 12: + u3x_cell(arg, &hed, &tel); + tot_w += _n_comp(ops, hed, c3n, c3n); + ++tot_w; _n_emit(ops, SWAP); + tot_w += _n_comp(ops, tel, los_o, c3n); + ++tot_w; _n_emit(ops, (c3y == los_o) ? WILS : WISH); + break; + + default: + u3m_bail(c3__exit); + return 0; + } + return tot_w; +} + +/* _n_push(): push a noun onto the stack. RETAIN + * mov: -1 north, 1 south + * off: 0 north, -1 south + */ +static inline void +_n_push(c3_ys mov, c3_ys off, u3_noun a) +{ + u3R->cap_p += mov; + + // XX switch to u3a_push() + // +#ifndef U3_GUARD_PAGE + if ( 0 == off ) { + if( !(u3R->cap_p > u3R->hat_p) ) { + u3m_bail(c3__meme); + } + } + else { + if( !(u3R->cap_p < u3R->hat_p) ) { + u3m_bail(c3__meme); + } + } +#endif + + u3_noun* p = u3to(u3_noun, u3R->cap_p + off); + *p = a; +} + +/* _n_peek(): pointer to noun at top of stack + * off: 0 north, -1 south + */ +static inline u3_noun* +_n_peek(c3_ys off) +{ + return u3to(u3_noun, u3R->cap_p + off); +} + +/* _n_peet(): address of the next-to-top of stack + * mov: -1 north, 1 south + * off: 0 north, -1 south + */ +static inline u3_noun* +_n_peet(c3_ys mov, c3_ys off) +{ + return u3to(u3_noun, (u3R->cap_p - mov) + off); +} + +/* _n_pop(): pop a noun from the cap stack + * mov: -1 north, 1 south + */ +static inline void +_n_pop(c3_ys mov) +{ + u3R->cap_p -= mov; +} + +/* _n_pep(): pop and return noun from the cap stack + * mov: -1 north, 1 south + * off: 0 north, -1 south + */ +static inline u3_noun +_n_pep(c3_ys mov, c3_ys off) +{ + u3_noun r = *(_n_peek(off)); + _n_pop(mov); + return r; +} + +/* _n_toss(): pep and lose + */ +static inline void +_n_toss(c3_ys mov, c3_ys off) +{ + u3z(_n_pep(mov, off)); +} + +/* _n_resh(): read a c3_s from the bytecode stream + */ +static inline c3_s +_n_resh(c3_y* buf, c3_w* ip_w) +{ + c3_y les = buf[(*ip_w)++]; + c3_y mos = buf[(*ip_w)++]; + return les | (mos << 8); +} + +/* _n_rewo(): read a c3_w from the bytecode stream. + */ +static inline c3_w +_n_rewo(c3_y* buf, c3_w* ip_w) +{ + c3_y one = buf[(*ip_w)++], + two = buf[(*ip_w)++], + tre = buf[(*ip_w)++], + qua = buf[(*ip_w)++]; + return one | (two << 8) | (tre << 16) | (qua << 24); +} + +/* _n_swap(): swap two items on the top of the stack, return pointer to top + */ +static inline u3_noun* +_n_swap(c3_ys mov, c3_ys off) +{ + u3_noun* top = _n_peek(off); + u3_noun* up = _n_peet(mov, off); + u3_noun tmp = *up; + *up = *top; + *top = tmp; + return top; +} + +#ifdef VERBOSE_BYTECODE +/* _n_print_byc(): print bytecode. used for debugging. + */ +static void +_n_print_byc(c3_y* pog, c3_w her_w) +{ + c3_w ip_w = 0; + if ( her_w == 0 ) { + fprintf(stderr, "begin: {"); + } + else { + fprintf(stderr, "resume: {"); + } + int first = 1; + while ( pog[ip_w] ) { + if ( first ) { + first = 0; + } + else if (ip_w == her_w) { + fprintf(stderr, " [*]"); + } + else { + fprintf(stderr, " "); + } + switch ( _n_arg(pog[ip_w]) ) { + case 0: + fprintf(stderr, "%s", opcode_names[pog[ip_w++]]); + break; + + case 1: + fprintf(stderr, "[%s ", opcode_names[pog[ip_w++]]); + fprintf(stderr, "%u]", pog[ip_w++]); + break; + + case 2: + fprintf(stderr, "[%s ", opcode_names[pog[ip_w++]]); + fprintf(stderr, "%u]", _n_resh(pog, &ip_w)); + break; + + case 4: + fprintf(stderr, "[%s", opcode_names[pog[ip_w++]]); + fprintf(stderr, "%u]", _n_rewo(pog, &ip_w)); + break; + default: + u3_assert(0); + break; + } + } + fprintf(stderr, " halt}\r\n"); +} +#endif + +/* _n_bite(): compile a nock formula to bytecode. RETAIN. + */ +static inline u3n_prog* +_n_bite(u3_noun fol) { + u3_noun ops = u3_nul; + _n_comp(&ops, fol, c3y, c3y); + return _n_prog_from_ops(ops); +} + +static inline c3_w +_cn_of_prog(u3n_prog *pog_u) +{ + u3_post pog_p = u3of(u3n_prog, pog_u); + return pog_p >> u3a_vits; +} + +static inline u3n_prog* +_cn_to_prog(c3_w pog_w) +{ + u3_post pog_p = pog_w << u3a_vits; + return u3to(u3n_prog, pog_p); +} + +/* _n_find(): return prog for given formula with prefix (u3_nul for none). + * RETAIN. + */ +static u3n_prog* +_n_find(u3_noun pre, u3_noun fol) +{ + u3_noun key = u3nc(u3k(pre), u3k(fol)); + u3_weak pog = u3h_git(u3R->byc.har_p, key); + if ( u3_none != pog ) { + u3z(key); + return _cn_to_prog(pog); + } + else if ( u3R != &u3H->rod_u ) { + u3a_road* rod_u = u3R; + while ( rod_u->par_p ) { + rod_u = u3to(u3a_road, rod_u->par_p); + pog = u3h_git(rod_u->byc.har_p, key); + if ( u3_none != pog ) { + c3_w i_w; + u3n_prog* old = _n_prog_old(_cn_to_prog(pog)); + for ( i_w = 0; i_w < old->reg_u.len_w; ++i_w ) { + u3j_rite* rit_u = &(old->reg_u.rit_u[i_w]); + rit_u->own_o = c3n; + } + for ( i_w = 0; i_w < old->cal_u.len_w; ++i_w ) { + u3j_site* sit_u = &(old->cal_u.sit_u[i_w]); + sit_u->bat = u3_none; + sit_u->pog_p = 0; + sit_u->fon_o = c3n; + } + u3h_put(u3R->byc.har_p, key, _cn_of_prog(old)); + u3z(key); + return old; + } + } + } + + { + u3n_prog* gop = _n_bite(fol); + u3h_put(u3R->byc.har_p, key, _cn_of_prog(gop)); + u3z(key); + return gop; + } +} + +/* u3n_find(): return prog for given formula, + * split by key (u3_nul for no key). RETAIN. + */ +u3p(u3n_prog) +u3n_find(u3_noun key, u3_noun fol) +{ + u3p(u3n_prog) pog_p; + u3t_on(noc_o); + pog_p = u3of(u3n_prog, _n_find(key, fol)); + u3t_off(noc_o); + return pog_p; +} + +/* _cn_prog_free(): free memory retained by program pog_u +*/ +static void +_cn_prog_free(u3n_prog* pog_u) +{ + c3_w dex_w; + for (dex_w = 0; dex_w < pog_u->lit_u.len_w; ++dex_w) { + u3z(pog_u->lit_u.non[dex_w]); + } + for (dex_w = 0; dex_w < pog_u->mem_u.len_w; ++dex_w) { + u3z(pog_u->mem_u.sot_u[dex_w].key); + } + for (dex_w = 0; dex_w < pog_u->cal_u.len_w; ++dex_w) { + u3j_site_lose(&(pog_u->cal_u.sit_u[dex_w])); + } + for (dex_w = 0; dex_w < pog_u->reg_u.len_w; ++dex_w) { + u3j_rite_lose(&(pog_u->reg_u.rit_u[dex_w])); + } + u3a_free(pog_u); +} + +/* _cn_intlen(): find the number of characters num_w would take to print. +** num_w: an int we want to later serialize to a string +*/ +c3_w +_cn_intlen(c3_w num_w) +{ + c3_w len_w=0; + while(num_w){ + num_w/=10; + len_w++; + } + return len_w; +} + +/* _cn_is_indexed(): return true if bop_w is an opcodes that uses pog_u->lit_u.non +** bop_w: opcode (assumed 0-94) +*/ +c3_b +_cn_is_indexed(c3_w bop_w) +{ + switch (bop_w) { + case FIBK: case FISK: + case FIBL: case FISL: + case LIBK: case LISK: + case LIBL: case LISL: + case BUSH: case SUSH: + case SANB: case SANS: + case KITB: case KITS: + case MITB: case MITS: + case HILB: case HILS: + case HINB: case HINS: + return 1; + default: + return 0; + } +} + +/* _cn_pog_to_num(): read a bytecode from the steam and advance the index +** par_w: c3_w: can be 0, 2, 4 +** pog_y: c3_y*: a bytecode stream +** ip_w: c3_w: an index into pog +*/ +#define _cn_pog_to_num(par_w, pog_y, ip_w) (\ + par_w == 4 ? _n_rewo(pog_y, &ip_w): \ + par_w == 2 ? _n_resh(pog_y, &ip_w): \ + pog_y[ip_w++]) + +/* _cn_etch_bytecode(): render a nock program as string of bytecodes +** fol: a nock formula to compile and render +** returns: a u3i_string noun of the rendered bytecode +*/ +u3_noun +_cn_etch_bytecode(u3_noun fol) { + u3n_prog* pog_u = _n_bite(fol); + c3_y* pog_y = pog_u->byc_u.ops_y; + c3_w len_w = pog_u->byc_u.len_w; + c3_w ip_w=0, num_w=0, bop_w=0, dex_w=0; + c3_w len_c = 2; // closing "}", null terminator + // set par_w (parameter flag) to an invalid value, + // so we can break imeadately if needed + c3_w par_w = 5; + // lets count the chars in this string + while ( ip_w < len_w ) { + par_w = _n_arg(pog_y[ip_w]); + bop_w = pog_y[ip_w++]; // move ip_w for reading a opcode name + dex_w = _cn_is_indexed(bop_w); // is this an indexed bytecode argument + len_c += 5; // a leading space, and opcode name + if (par_w > 0) { // if pair: "[bytecode arg]" else "bytecode" + len_c += 3; // "[", space between opcode & arg, "]" + if ( dex_w ) len_c += 2; // 'i:' + len_c += _cn_intlen( // length of the bytecode argument + _cn_pog_to_num(par_w, pog_y, ip_w) + ); + } + } + // reset so we can loop again + ip_w=0, num_w=0, bop_w=0, dex_w=0, par_w=5; + // init our string, and give it a trailing null + c3_c str_c[len_c]; + str_c[0] = 0; + // lets print this string + while ( ip_w < len_w ) { + par_w = _n_arg(pog_y[ip_w]); + bop_w = pog_y[ip_w++]; // move ip_w for reading a opcode name + dex_w = _cn_is_indexed(bop_w); // is this an indexed bytecode argument + strcat(str_c, " "); // leading space + if (par_w > 0) strcat(str_c, "["); // add "[" if the opcode pairs + strncat(str_c, opcode_names[bop_w], 4); // add the opcode name + if (par_w > 0) { // finish the pair + strcat(str_c, " "); // add the space between byt and arg + if ( dex_w ) strcat(str_c, "i:"); // indexed args are labeled as "index of arg" + num_w = _cn_pog_to_num(par_w, pog_y, ip_w); // the bytecode argument + if (num_w == 0) { // + strcat(str_c, "0"); // handle a literal zero + } // + else { // + c3_w x = 0; // + for (x = _cn_intlen(num_w); x > 0; x--) { // + strcat(str_c, "_"); // prefill the buffer + } // + c3_w f = strlen(str_c)-1; // get the index of the last prefill + while (num_w > 0) { // stringify number in LSB order + str_c[f--] = (num_w%10)+'0'; // .. stringify the tail of num into tail of buf + num_w /= 10; // .. turncate num by one digit + } // + } // + strcat(str_c, "]"); // add the closing brace + } + } + // replace the first leading space and append the last char to the string + str_c[0] = '{'; + strcat(str_c, "}"); + _cn_prog_free(pog_u); + return u3i_string(str_c); +} + + +/* _n_hilt_fore(): literal (atomic) dynamic hint, before formula evaluation. +** hin: [hint-atom, formula]. TRANSFER +** bus: subject. RETAIN +** out: token for _n_hilt_hind(); convention: +** [hint-atom] or [hint-atom data], ~ if unused. +** +** any hints herein must be whitelisted in _n_burn(). +*/ +static c3_o +_n_hilt_fore(u3_noun hin, u3_noun bus, u3_noun* out) +{ + u3_noun tag, fol; + u3x_cell(hin, &tag, &fol); + + switch ( tag ) { + case c3__cash: { + u3_atom har = u3i_word(u3h_count(u3R->cax.har_p)); + u3h_discount(u3R->cax.har_p); + u3_atom per = u3i_word(u3h_count(u3R->cax.per_p)); + u3h_discount(u3R->cax.per_p); + *out = u3i_cell(tag, u3i_cell(har, per)); + } break; + + case c3__bout: { + u3_atom now = u3i_chub(u3t_trace_time()); + *out = u3i_cell(tag, now); + } break; + + case c3__nara : { + u3t_slog_nara(0); + *out = u3_nul; + } break; + + case c3__hela : { + u3t_slog_hela(0); + *out = u3_nul; + } break; + + case c3__xray : { + u3t_slog(u3nc(0, _cn_etch_bytecode(fol))); + *out = u3_nul; + } break; + + case c3__meme : { + u3t_slog(u3nc(0, u3t_etch_meme(0))); + *out = u3_nul; + } break; + + default: { + *out = u3_nul; + } break; + } + + u3z(hin); + return c3y; +} + +/* _n_hilt_hind(): literal (atomic) dynamic hint, after formula evaluation. +** tok: token from _n_hilt_fore(). TRANSFER +** pro: product of formula evaluation. RETAIN +*/ +static void +_n_hilt_hind(u3_noun tok, u3_noun pro) +{ + u3_noun p_tok, q_tok, r_tok; + if ( (c3y == u3r_cell(tok, &p_tok, &q_tok)) && (c3__bout == p_tok) ) { + u3_atom delta = u3ka_sub(u3i_chub(u3t_trace_time()), u3k(q_tok)); + c3_c str_c[64]; + u3a_print_time(str_c, "took", u3r_chub(0, delta)); + u3t_slog(u3nc(0, u3i_string(str_c))); + u3z(delta); + } + else if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) && + (c3__cash == p_tok) ) { + c3_c str_c[4096]; + + u3_atom har = u3i_word(u3h_count(u3R->cax.har_p)); + u3h_discount(u3R->cax.har_p); + u3_atom har_delta = u3ka_sub(har, u3k(q_tok)); + u3a_print_memory_str(str_c, "ephemeral cache", + u3r_word(0, har_delta)); + u3t_slog(u3nc(0, u3i_string(str_c))); + + u3_atom per = u3i_word(u3h_count(u3R->cax.per_p)); + u3h_discount(u3R->cax.per_p); + u3_atom per_delta = u3ka_sub(per, u3k(r_tok)); + u3a_print_memory_str(str_c, "persistent cache", + u3r_word(0, per_delta)); + u3t_slog(u3nc(0, u3i_string(str_c))); + + u3z(har_delta); + u3z(per_delta); + } + else { + u3_assert( u3_nul == tok ); + } + + u3z(tok); +} + +/* _n_hint_fore(): arbitrary dynamic hint, before formula evaluation +** hin: [hint-atom, formula]. TRANSFER +** bus: subject. RETAIN +** clu: product of the hint-formula. TRANSFER +** also, token for _n_hilt_hind(); convention: +** [hint-atom] or [hint-atom data], ~ if unused. +** +** any hints herein must be whitelisted in _n_burn(). +*/ +static c3_o +_n_hint_fore(u3_cell hin, u3_noun bus, u3_noun* clu) +{ + u3_noun tag, fol; + u3x_cell(hin, &tag, &fol); + + switch ( tag ) { + case c3__bout: { + u3_atom now = u3i_chub(u3t_trace_time()); + *clu = u3nt(u3k(tag), *clu, now); + } break; + + case c3__spin: { + u3t_sstack_push(*clu); + *clu = c3__spin; + } break; + + case c3__nara: { + u3_noun pri, tan; + if ( c3y == u3r_cell(*clu, &pri, &tan) ) { + c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0; + u3t_slog_cap(pri_l, u3i_string("trace of"), u3k(tan)); + u3t_slog_nara(pri_l); + } + u3z(*clu); + *clu = u3_nul; + } break; + + case c3__hela: { + u3_noun pri, tan; + if ( c3y == u3r_cell(*clu, &pri, &tan) ) { + c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0; + u3t_slog_cap(pri_l, u3i_string("trace of"), u3k(tan)); + u3t_slog_hela(pri_l); + } + u3z(*clu); + *clu = u3_nul; + } break; + + case c3__xray : { + u3_noun pri, tan; + if ( c3y == u3r_cell(*clu, &pri, &tan) ) { + c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0; + u3t_slog_cap(pri_l, u3k(tan), _cn_etch_bytecode(fol)); + } + u3z(*clu); + *clu = u3_nul; + } break; + + case c3__meme : { + u3_noun pri, tan; + if ( c3y == u3r_cell(*clu, &pri, &tan) ) { + c3_l mod_l = c3y == u3a_is_cat(pri) ? pri : 0; + // replace with better str fmt + u3t_slog_cap(1, u3k(tan), u3t_etch_meme(mod_l)); + } + u3z(*clu); + *clu = u3_nul; + } break; + + default: { + u3z(*clu); + *clu = u3_nul; + } break; + } + + u3z(hin); + return c3y; +} + +/* _n_hint_hind(): arbitrary dynamic hint, after formula evaluation. +** tok: token from _n_hint_fore(). TRANSFER +** pro: product of formula evaluation. RETAIN +*/ +static void +_n_hint_hind(u3_noun tok, u3_noun pro) +{ + u3_noun p_tok, q_tok, r_tok; + if ( c3__spin == tok ) { + u3t_sstack_pop(); + } + else if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) && (c3__bout == p_tok) ) { + // get the microseconds elapsed + u3_atom delta = u3ka_sub(u3i_chub(u3t_trace_time()), u3k(r_tok)); + + // unpack q_tok to get the priority integer and the tank + // p_q_tok is the priority, q_q_tok is the tank we will work with + u3_noun p_q_tok, q_q_tok; + u3_assert(c3y == u3r_cell(q_tok, &p_q_tok, &q_q_tok)); + + // format the timing report + c3_c str_c[64]; + u3a_print_time(str_c, "took", u3r_chub(0, delta)); + + // join the timing report with the original tank from q_q_tok like so: + // "q_q_tok: report" + // prepend the priority to form a cell of the same shape q_tok + // send this to ut3_slog so that it can be logged out + c3_l pri_l = c3y == u3a_is_cat(p_q_tok) ? p_q_tok : 0; + u3t_slog_cap(pri_l, u3k(q_q_tok), u3i_string(str_c)); + u3z(delta); + } + else { + u3_assert( u3_nul == tok ); + } + + u3z(tok); +} + +/* _n_kick(): stop tracing noc and kick a u3j_site. + */ +static u3_weak +_n_kick(u3_noun cor, u3j_site* sit_u) +{ + u3_weak pro; + u3t_off(noc_o); + pro = u3j_site_kick(cor, sit_u); + u3t_on(noc_o); + return pro; +} + +/* _n_kale(): bail(exit) if not cell + */ +static inline u3_noun +_n_kale(u3_noun a) +{ + if ( c3n == u3du(a) ) { + u3m_bail(c3__exit); + } + return a; +} + +typedef struct __attribute__((__packed__)) { + u3n_prog* pog_u; + c3_w ip_w; +} burnframe; + +/* _n_burn(): pog: program + * bus: subject (TRANSFER) + * mov: -1 north, 1 south + * off: 0 north, -1 south + */ +static u3_noun +_n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) +{ + + // Opcode jump table. Define X to select the opcode computed goto from + // OPCODES. +# define X(opcode, name, indirect_jump) indirect_jump + static void* lab[] = { OPCODES }; +# undef X + + u3j_site* sit_u; + u3j_rite* rit_u; + u3n_memo* mem_u; + c3_y *pog = pog_u->byc_u.ops_y; + c3_w sip_w, ip_w = 0; + u3_noun* top; + u3_noun x, o; + u3p(void) empty; + burnframe* fam; + + empty = u3R->cap_p; + _n_push(mov, off, bus); + +#ifdef U3_CPU_DEBUG + u3R->pro.nox_d += 1; +#endif +#ifdef VERBOSE_BYTECODE + #define BURN() fprintf(stderr, "%s ", opcode_names[pog[ip_w]]); goto *lab[pog[ip_w++]] +#else + #define BURN() goto *lab[pog[ip_w++]] +#endif + BURN(); + { + do_halt: // [product ...burnframes...] + x = _n_pep(mov, off); +#ifdef VERBOSE_BYTECODE + fprintf(stderr, "return\r\n"); +#endif + if ( empty == u3R->cap_p ) { + return x; + } + else { + fam = u3to(burnframe, u3R->cap_p) + off; + pog_u = fam->pog_u; + pog = pog_u->byc_u.ops_y; + ip_w = fam->ip_w; + + u3R->cap_p = u3of(burnframe, fam - (mov+off)); + _n_push(mov, off, x); +#ifdef VERBOSE_BYTECODE + _n_print_byc(pog, ip_w); +#endif + BURN(); + } + + do_bail: + u3m_bail(c3__exit); + return u3_none; + + do_copy: + top = _n_peek(off); + _n_push(mov, off, u3k(*top)); + BURN(); + + do_swap: + _n_swap(mov, off); + BURN(); + + do_toss: + _n_toss(mov, off); + BURN(); + + do_auto: // [tel bus hed] + x = _n_pep(mov, off); // [bus hed] + top = _n_swap(mov, off); // [hed bus] + *top = u3nc(*top, x); // [pro bus] + BURN(); + + do_ault: // [tel hed] + x = _n_pep(mov, off); // [hed] + top = _n_peek(off); + *top = u3nc(*top, x); // [pro] + BURN(); + + do_snoc: // [hed tel] + x = _n_pep(mov, off); + top = _n_peek(off); + _n_push(mov, off, u3nc(x, u3k(*top))); + BURN(); + + do_snol: + x = _n_pep(mov, off); + top = _n_peek(off); + *top = u3nc(x, *top); + BURN(); + + do_head: + top = _n_peek(off); + _n_push(mov, off, u3k(u3h(_n_kale(*top)))); + BURN(); + + do_held: + top = _n_peek(off); + o = _n_kale(*top); + *top = u3k(u3h(o)); + u3z(o); + BURN(); + + do_tail: + top = _n_peek(off); + _n_push(mov, off, u3k(u3t(_n_kale(*top)))); + BURN(); + + do_tall: + top = _n_peek(off); + o = _n_kale(*top); + *top = u3k(u3t(o)); + u3z(o); + BURN(); + + do_fisk: + x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; + goto frag_in; + + do_fibk: + x = pog_u->lit_u.non[pog[ip_w++]]; + goto frag_in; + + do_fask: + x = _n_resh(pog, &ip_w); + goto frag_in; + + do_fabk: + x = pog[ip_w++]; + frag_in: + top = _n_peek(off); + _n_push(mov, off, u3k(u3x_at(x, *top))); + BURN(); + + do_fisl: + x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; + goto flag_in; + + do_fibl: + x = pog_u->lit_u.non[pog[ip_w++]]; + goto flag_in; + + do_fasl: + x = _n_resh(pog, &ip_w); + goto flag_in; + + do_fabl: + x = pog[ip_w++]; + flag_in: + top = _n_peek(off); + o = *top; + *top = u3k(u3x_at(x, o)); + u3z(o); + BURN(); + + do_lit0: + _n_push(mov, off, 0); + BURN(); + + do_lit1: + _n_push(mov, off, 1); + BURN(); + + do_litb: + _n_push(mov, off, pog[ip_w++]); + BURN(); + + do_lits: + _n_push(mov, off, _n_resh(pog, &ip_w)); + BURN(); + + do_libk: + _n_push(mov, off, u3k(pog_u->lit_u.non[pog[ip_w++]])); + BURN(); + + do_lisk: + _n_push(mov, off, u3k(pog_u->lit_u.non[_n_resh(pog, &ip_w)])); + BURN(); + + do_lil1: + x = 1; + goto lil_in; + + do_lilb: + x = pog[ip_w++]; + goto lil_in; + + do_lils: + x = _n_resh(pog, &ip_w); + goto lil_in; + + do_libl: + x = u3k(pog_u->lit_u.non[pog[ip_w++]]); + goto lil_in; + + do_lisl: + x = u3k(pog_u->lit_u.non[_n_resh(pog, &ip_w)]); + goto lil_in; + + do_lil0: + x = 0; + lil_in: + top = _n_peek(off); + u3z(*top); + *top = x; + BURN(); + + do_noct: // [fol bus] + o = _n_pep(mov, off); // [bus] + goto nock_out; + + do_nolk: // [fol bus] + o = _n_pep(mov, off); // [bus] + goto nock_in; + + do_nock: // [fol old bus] + o = _n_pep(mov, off); // [old bus] + _n_swap(mov, off); // [bus old] + nock_in: + x = _n_pep(mov, off); + fam = u3to(burnframe, u3R->cap_p) + off + mov; + u3R->cap_p = u3of(burnframe, fam - off); + fam->ip_w = ip_w; + fam->pog_u = pog_u; + _n_push(mov, off, x); + nock_out: + pog_u = _n_find(u3_nul, o); + pog = pog_u->byc_u.ops_y; + ip_w = 0; +#ifdef U3_CPU_DEBUG + u3R->pro.nox_d += 1; +#endif +#ifdef VERBOSE_BYTECODE + fprintf(stderr, "\r\nnock jump: %u\r\n", o); + _n_print_byc(pog, ip_w); +#endif + u3z(o); + BURN(); + + do_deep: + top = _n_peek(off); + o = *top; + *top = u3du(o); + u3z(o); + BURN(); + + do_bump: + top = _n_peek(off); + *top = u3i_vint(*top); + BURN(); + + do_sam0: + top = _n_peek(off); + if ( *top == 0 ) { + *top = c3y; + } + else { + u3z(*top); + *top = c3n; + } + BURN(); + + do_sam1: + top = _n_peek(off); + if ( *top == 1 ) { + *top = c3y; + } + else { + u3z(*top); + *top = c3n; + } + BURN(); + + do_samb: + top = _n_peek(off); + if ( *top == pog[ip_w++] ) { + *top = c3y; + } + else { + u3z(*top); + *top = c3n; + } + BURN(); + + do_sams: + top = _n_peek(off); + if ( *top == _n_resh(pog, &ip_w) ) { + *top = c3y; + } + else { + u3z(*top); + *top = c3n; + } + BURN(); + + do_sans: + x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; + goto samn_in; + do_sanb: + x = pog_u->lit_u.non[pog[ip_w++]]; + samn_in: + top = _n_peek(off); + o = *top; + *top = u3r_sing(o, x); + u3z(o); + BURN(); + + do_same: + x = _n_pep(mov, off); + _n_swap(mov, off); + goto same_in; + + do_salm: + x = _n_pep(mov, off); + goto same_in; + + same_in: + top = _n_peek(off); + o = *top; + *top = u3r_sing(x, o); + u3z(o); + u3z(x); + BURN(); + + do_samc: + top = _n_peek(off); + o = *top; + *top = u3r_sing(u3h(o), u3t(o)); + u3z(o); + BURN(); + + do_sbip: + sip_w = pog[ip_w++]; + ip_w += sip_w; + BURN(); + + do_sips: + sip_w = _n_resh(pog, &ip_w); + ip_w += sip_w; + BURN(); + + do_swip: + sip_w = _n_rewo(pog, &ip_w); + ip_w += sip_w; + BURN(); + + do_swin: + sip_w = _n_rewo(pog, &ip_w); + goto skin_in; + + do_sins: + sip_w = _n_resh(pog, &ip_w); + goto skin_in; + + do_sbin: + sip_w = pog[ip_w++]; + skin_in: + x = _n_pep(mov, off); + if ( c3n == x ) { + ip_w += sip_w; + } + else if ( c3y != x ) { + u3m_bail(c3__exit); + return u3_none; + } + BURN(); + + do_kics: + x = _n_resh(pog, &ip_w); + goto kick_in; + + do_kicb: + x = pog[ip_w++]; + kick_in: + sit_u = &(pog_u->cal_u.sit_u[x]); + top = _n_peek(off); + o = *top; + *top = _n_kick(o, sit_u); + if ( u3_none == *top ) { + _n_pop(mov); + + fam = u3to(burnframe, u3R->cap_p) + off + mov; + u3R->cap_p = u3of(burnframe, fam - off); + fam->ip_w = ip_w; + fam->pog_u = pog_u; + + pog_u = u3to(u3n_prog, sit_u->pog_p); + pog = pog_u->byc_u.ops_y; + ip_w = 0; +#ifdef U3_CPU_DEBUG + u3R->pro.nox_d += 1; +#endif +#ifdef VERBOSE_BYTECODE + fprintf(stderr, "\r\nhead kick jump: %u, sp: %p\r\n", u3r_at(sit_u->axe, cor), top); + _n_print_byc(pog, ip_w); +#endif + _n_push(mov, off, o); + } +#ifdef VERBOSE_BYTECODE + else { + fprintf(stderr, "head jet\r\n"); + } +#endif + BURN(); + + do_tics: + x = _n_resh(pog, &ip_w); + goto tick_in; + + do_ticb: + x = pog[ip_w++]; + tick_in: + sit_u = &(pog_u->cal_u.sit_u[x]); + top = _n_peek(off); + o = *top; + *top = _n_kick(o, sit_u); + if ( u3_none == *top ) { + *top = o; + pog_u = u3to(u3n_prog, sit_u->pog_p); + pog = pog_u->byc_u.ops_y; + ip_w = 0; +#ifdef U3_CPU_DEBUG + u3R->pro.nox_d += 1; +#endif +#ifdef VERBOSE_BYTECODE + fprintf(stderr, "\r\ntail kick jump: %u, sp: %p\r\n", u3x_at(sit_u->axe, o);, top); + _n_print_byc(pog, ip_w); +#endif + } +#ifdef VERBOSE_BYTECODE + else { + fprintf(stderr, "tail jet\r\n"); + } +#endif + BURN(); + + do_wils: // [gof ref] + o = _n_pep(mov,off); // [ref] + top = _n_peek(off); + goto wish_in; + + do_wish: // [gof bus ref] + o = _n_pep(mov,off); // [bus ref] + top = _n_swap(mov, off); // [ref bus] + wish_in: + u3t_off(noc_o); + x = u3m_soft_esc(u3k(*top), u3k(o)); + u3t_on(noc_o); + + if ( c3n == u3du(x) ) { + u3m_bail(u3nc(1, o)); + return u3_none; + } + else if ( c3n == u3du(u3t(x)) ) { + u3t_push(u3nt(c3__hunk, *top, o)); + u3m_bail(c3__exit); + return u3_none; + } + else { + u3z(o); + u3z(*top); + *top = u3k(u3t(u3t(x))); + u3z(x); + BURN(); + } + + do_sush: + x = _n_resh(pog, &ip_w); + goto cush_in; + + do_bush: + x = pog[ip_w++]; + cush_in: + x = u3k(pog_u->lit_u.non[x]); + o = _n_pep(mov, off); + u3t_push(u3nc(x, o)); + BURN(); + + do_drop: + u3t_drop(); + BURN(); + + do_heck: + x = _n_pep(mov, off); + if ( c3y == u3ud(x) ) { + u3t_off(noc_o); + u3t_heck(x); + u3t_on(noc_o); + } + else { + u3z(x); + } + BURN(); + + do_slog: + x = _n_pep(mov, off); + if ( !(u3C.wag_w & u3o_quiet) ) { + u3t_off(noc_o); + u3t_slog(x); + u3t_on(noc_o); + } + else { + u3z(x); + } + BURN(); + + + do_sast: + x = _n_resh(pog, &ip_w); + goto fast_in; + + do_bast: + x = pog[ip_w++]; + goto fast_in; + + do_salt: + x = _n_resh(pog, &ip_w); + goto falt_in; + do_balt: + x = pog[ip_w++]; + falt_in: // [pro clu] + o = _n_pep(mov, off); // [clu] + top = _n_peek(off); + goto fast_out; + + fast_in: // [pro bus clu] + o = _n_pep(mov, off); // [bus clu] + top = _n_swap(mov, off); // [clu bus] + fast_out: + rit_u = &(pog_u->reg_u.rit_u[x]); + u3t_off(noc_o); + u3j_rite_mine(rit_u, *top, u3k(o)); + u3t_on(noc_o); + *top = o; + BURN(); + + do_skis: + x = _n_resh(pog, &ip_w); + goto skim_in; + + do_skib: + x = pog[ip_w++]; + skim_in: + mem_u = &(pog_u->mem_u.sot_u[x]); + top = _n_peek(off); + x = u3k(*top); + goto skim_out; + + do_slis: + x = _n_resh(pog, &ip_w); + goto slim_in; + + do_slib: + x = pog[ip_w++]; + slim_in: + mem_u = &(pog_u->mem_u.sot_u[x]); + x = _n_pep(mov, off); + skim_out: + o = u3k(mem_u->key); + x = u3nc(x, o); + o = u3z_find_m(mem_u->cid, 144 + c3__nock, x); + if ( u3_none == o ) { + _n_push(mov, off, u3nc(mem_u->cid, x)); + _n_push(mov, off, u3k(u3h(x))); + } + else { + ip_w += mem_u->sip_l; + _n_push(mov, off, o); + u3z(x); + } + BURN(); + + do_save: + x = _n_pep(mov, off); // product + top = _n_peek(off); + o = *top; + if ( ( u3z_memo_toss == u3h(o) ) + ? ( &(u3H->rod_u) != u3R ) + : ( 0 == u3R->ski.gul ) ) { // prevents userspace from persistence + u3z_save_m(u3h(o), 144 + c3__nock, u3t(o), x); + } + // XX can we still print? + // else if ( u3z_memo_keep == u3h(o) ) { + // fprintf(stderr, "\r\nnock: userspace can't save to persistent cache\r\n"); + // } + *top = x; + u3z(o); + BURN(); + + do_hilb: + x = pog[ip_w++]; + goto hilt_fore_in; + + do_hils: + x = _n_resh(pog, &ip_w); + hilt_fore_in: + x = u3k(pog_u->lit_u.non[x]); + top = _n_peek(off); // bus + x = _n_hilt_fore(x, *top, &o); + _n_push(mov, off, o); + _n_swap(mov, off); // bus + _n_push(mov, off, x); // shortcircuit if c3n + BURN(); + + do_hinb: + x = pog[ip_w++]; + goto hint_fore_in; + + do_hins: + x = _n_resh(pog, &ip_w); + hint_fore_in: // [clu bus] + x = u3k(pog_u->lit_u.non[x]); + o = _n_pep(mov, off); // [bus] + top = _n_peek(off); + x = _n_hint_fore(x, *top, &o); + _n_push(mov, off, o); // [tok bus] + _n_swap(mov, off); // [bus tok] + _n_push(mov, off, x); // [kip bus tok] + BURN(); + + do_hilk: // [pro bus tok] + x = _n_pep(mov, off); // [bus tok] + _n_swap(mov, off); // [tok bus] + o = _n_pep(mov, off); // [bus] + _n_push(mov, off, x); // [pro bus] + _n_hilt_hind(o, x); + BURN(); + + do_hill: // [pro tok] + top = _n_swap(mov, off); // [tok pro] + o = _n_pep(mov, off); // [pro] + top = _n_peek(off); + _n_hilt_hind(o, *top); + BURN(); + + do_hink: // [pro bus tok] + x = _n_pep(mov, off); // [bus tok] + _n_swap(mov, off); // [tok bus] + o = _n_pep(mov, off); // [bus] + _n_push(mov, off, x); // [pro bus] + _n_hint_hind(o, x); + BURN(); + + do_hinl: // [pro tok] + top = _n_swap(mov, off); // [tok pro] + o = _n_pep(mov, off); // [pro] + top = _n_peek(off); + _n_hint_hind(o, *top); + BURN(); + + do_kuth: + x = _n_pep(mov, off); + top = _n_swap(mov, off); + goto muth_in; + do_muth: + x = _n_pep(mov, off); + top = _n_peek(off); + muth_in: + o = *top; + *top = u3nc(x, u3k(u3t(o))); + u3z(o); + BURN(); + + do_kutt: + x = _n_pep(mov, off); + top = _n_swap(mov, off); + goto mutt_in; + do_mutt: + x = _n_pep(mov, off); + top = _n_peek(off); + mutt_in: + o = *top; + *top = u3nc(u3k(u3h(o)), x); + u3z(o); + BURN(); + + do_kusm: + x = _n_pep(mov, off); + top = _n_swap(mov, off); + goto musm_in; + do_musm: + x = _n_pep(mov, off); + top = _n_peek(off); + musm_in: + o = *top; + *top = u3nt(u3k(u3h(o)), x, u3k(u3t(u3t(o)))); + u3z(o); + BURN(); + + do_kitb: + x = pog_u->lit_u.non[pog[ip_w++]]; + goto kut_in; + + do_kits: + x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; + goto kut_in; + + do_kuts: + x = _n_resh(pog, &ip_w); + goto kut_in; + + do_kutb: + x = pog[ip_w++]; + kut_in: + o = _n_pep(mov, off); + top = _n_swap(mov, off); + goto edit_in; + + do_mitb: + x = pog_u->lit_u.non[pog[ip_w++]]; + goto mut_in; + + do_mits: + x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; + goto mut_in; + + do_muts: + x = _n_resh(pog, &ip_w); + goto mut_in; + + do_mutb: + x = pog[ip_w++]; + mut_in: + o = _n_pep(mov, off); + top = _n_peek(off); + edit_in: + *top = u3i_edit(*top, x, o); + BURN(); + } +} + +/* _n_burn_out(): execute u3n_prog with bus as subject. + */ +static u3_noun +_n_burn_out(u3_noun bus, u3n_prog* pog_u) +{ + c3_ys mov, off; + if ( c3y == u3a_is_north(u3R) ) { + mov = -1; + off = 0; + } + else { + mov = 1; + off = -1; + } + return _n_burn(pog_u, bus, mov, off); +} + +/* u3n_burn(): execute u3n_prog with bus as subject. + */ +u3_noun +u3n_burn(u3p(u3n_prog) pog_p, u3_noun bus) +{ + u3_noun pro; + u3t_on(noc_o); + pro = _n_burn_out(bus, u3to(u3n_prog, pog_p)); + u3t_off(noc_o); + return pro; +} + +/* _n_burn_on(): produce .*(bus fol) with bytecode interpreter + */ +static u3_noun +_n_burn_on(u3_noun bus, u3_noun fol) +{ + u3n_prog* pog_u = _n_find(u3_nul, fol); + + u3z(fol); + return _n_burn_out(bus, pog_u); +} + +/* u3n_nock_on(): produce .*(bus fol). Do not virtualize. +*/ +u3_noun +u3n_nock_on(u3_noun bus, u3_noun fol) +{ + u3_noun pro; + + u3t_on(noc_o); +#if 0 + pro = _n_nock_on(bus, fol); +#else + pro = _n_burn_on(bus, fol); +#endif + u3t_off(noc_o); + + return pro; +} + +/* _cn_take_prog_dat(): take references from junior u3n_prog. +*/ +static void +_cn_take_prog_dat(u3n_prog* dst_u, u3n_prog* src_u) +{ + c3_w i_w; + + for ( i_w = 0; i_w < src_u->lit_u.len_w; ++i_w ) { + dst_u->lit_u.non[i_w] = u3a_take(src_u->lit_u.non[i_w]); + } + + for ( i_w = 0; i_w < src_u->mem_u.len_w; ++i_w ) { + u3n_memo* emo_u = &(src_u->mem_u.sot_u[i_w]); + u3n_memo* ome_u = &(dst_u->mem_u.sot_u[i_w]); + ome_u->sip_l = emo_u->sip_l; + ome_u->key = u3a_take(emo_u->key); + ome_u->cid = emo_u->cid; + } + + for ( i_w = 0; i_w < src_u->cal_u.len_w; ++i_w ) { + u3j_site_take(&(dst_u->cal_u.sit_u[i_w]), + &(src_u->cal_u.sit_u[i_w])); + } + + for ( i_w = 0; i_w < src_u->reg_u.len_w; ++i_w ) { + u3j_rite_take(&(dst_u->reg_u.rit_u[i_w]), + &(src_u->reg_u.rit_u[i_w])); + } +} + +/* _cn_take_prog_cb(): u3h_take_with cb for taking junior u3n_prog's. +*/ +static u3p(u3n_prog) +_cn_take_prog_cb(c3_w pog_w) +{ + u3n_prog* pog_u = _cn_to_prog(pog_w); + u3n_prog* gop_u; + + if ( c3y == pog_u->byc_u.own_o ) { + c3_w pad_w = (8 - pog_u->byc_u.len_w % 8) % 8; + gop_u = _n_prog_new(pog_u->byc_u.len_w, + pog_u->cal_u.len_w, + pog_u->reg_u.len_w, + pog_u->lit_u.len_w, + pog_u->mem_u.len_w); + memcpy(gop_u->byc_u.ops_y, pog_u->byc_u.ops_y, pog_u->byc_u.len_w + pad_w); + } + else { + gop_u = _n_prog_old(pog_u); + } + + _cn_take_prog_dat(gop_u, pog_u); + // _n_prog_take_dat(gop_u, pog_u, c3n); + + return _cn_of_prog(gop_u); +} + +/* u3n_take(): copy junior bytecode state. +*/ +u3p(u3h_root) +u3n_take(u3p(u3h_root) har_p) +{ + return u3h_take_with(har_p, _cn_take_prog_cb); +} + +/* _cn_merge_prog_dat(): copy references from src_u u3n_prog to dst_u. +*/ +static void +_cn_merge_prog_dat(u3n_prog* dst_u, u3n_prog* src_u) +{ + c3_w i_w; + + for ( i_w = 0; i_w < src_u->lit_u.len_w; ++i_w ) { + u3z(dst_u->lit_u.non[i_w]); + dst_u->lit_u.non[i_w] = src_u->lit_u.non[i_w]; + } + + for ( i_w = 0; i_w < src_u->mem_u.len_w; ++i_w ) { + u3n_memo* emo_u = &(dst_u->mem_u.sot_u[i_w]); + u3n_memo* ome_u = &(src_u->mem_u.sot_u[i_w]); + u3z(emo_u->key); + emo_u->sip_l = ome_u->sip_l; + emo_u->key = ome_u->key; + emo_u->cid = ome_u->cid; + } + + for ( i_w = 0; i_w < src_u->cal_u.len_w; ++i_w ) { + u3j_site_merge(&(dst_u->cal_u.sit_u[i_w]), + &(src_u->cal_u.sit_u[i_w])); + } + + for ( i_w = 0; i_w < src_u->reg_u.len_w; ++i_w ) { + u3j_rite_merge(&(dst_u->reg_u.rit_u[i_w]), + &(src_u->reg_u.rit_u[i_w])); + } +} + +/* _cn_merge_prog_cb(): u3h_walk_with cb for integrating taken u3n_prog's. +*/ +static void +_cn_merge_prog_cb(u3_noun kev, void* wit) +{ + u3p(u3h_root) har_p = *(u3p(u3h_root)*)wit; + u3n_prog* pog_u; + u3_weak got; + u3_noun key; + c3_w pog_w; + u3x_cell(kev, &key, &pog_w); + + pog_u = _cn_to_prog(pog_w); + got = u3h_git(har_p, key); + + if ( u3_none != got ) { + u3n_prog* sep_u = _cn_to_prog(got); + _cn_merge_prog_dat(sep_u, pog_u); + u3a_free(pog_u); + pog_u = sep_u; + } + + u3h_put(har_p, key, _cn_of_prog(pog_u)); +} + +/* u3n_reap(): promote bytecode state. +*/ +void +u3n_reap(u3p(u3h_root) har_p) +{ + u3h_walk_with(har_p, _cn_merge_prog_cb, &u3R->byc.har_p); + // NB *not* u3n_free, _cn_merge_prog_cb() transfers u3n_prog's + u3h_free(har_p); +} + +/* _n_ream(): ream program call sites +*/ +void +_n_ream(u3_noun kev) +{ + u3n_prog* pog_u = _cn_to_prog(u3t(kev)); + + c3_w pad_w = (8 - pog_u->byc_u.len_w % 8) % 8; + c3_w pod_w = pog_u->lit_u.len_w % 2; + c3_w ped_w = pog_u->mem_u.len_w % 2; + // fix up pointers for loom portability + pog_u->byc_u.ops_y = (c3_y*) _n_prog_dat(pog_u); + pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w + pad_w); + pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w + pod_w); + pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w + ped_w); + pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); + + for ( c3_w i_w = 0; i_w < pog_u->cal_u.len_w; ++i_w ) { + u3j_site_ream(&(pog_u->cal_u.sit_u[i_w])); + } +} + +/* u3n_ream(): refresh after restoring from checkpoint. +*/ +void +u3n_ream() +{ + u3_assert(u3R == &(u3H->rod_u)); + u3h_walk(u3R->byc.har_p, _n_ream); +} + +/* _n_prog_mark(): mark program for gc. +*/ +static c3_w +_n_prog_mark(u3n_prog* pog_u) +{ + c3_w i_w, tot_w = u3a_mark_mptr(pog_u); + + for ( i_w = 0; i_w < pog_u->lit_u.len_w; ++i_w ) { + tot_w += u3a_mark_noun(pog_u->lit_u.non[i_w]); + } + + for ( i_w = 0; i_w < pog_u->mem_u.len_w; ++i_w ) { + tot_w += u3a_mark_noun(pog_u->mem_u.sot_u[i_w].key); + } + + for ( i_w = 0; i_w < pog_u->cal_u.len_w; ++i_w ) { + tot_w += u3j_site_mark(&(pog_u->cal_u.sit_u[i_w])); + } + + for ( i_w = 0; i_w < pog_u->reg_u.len_w; ++i_w ) { + tot_w += u3j_rite_mark(&(pog_u->reg_u.rit_u[i_w])); + } + + return tot_w; +} + +/* _n_bam(): u3h_walk_with helper for u3n_mark + */ +static void +_n_bam(u3_noun kev, void* dat) +{ + u3n_prog* pog = _cn_to_prog(u3t(kev)); + c3_w* bam_w = dat; + + *bam_w += _n_prog_mark(pog); +} + +/* u3n_mark(): mark the bytecode cache for gc. + */ +u3m_quac* +u3n_mark() +{ + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 3); + + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("bytecode programs"); + + u3p(u3h_root) har_p = u3R->byc.har_p; + u3h_walk_with(har_p, _n_bam, &qua_u[0]->siz_w); + qua_u[0]->siz_w = qua_u[0]->siz_w * 4; + + qua_u[1] = c3_calloc(sizeof(*qua_u[1])); + qua_u[1]->nam_c = strdup("bytecode cache"); + qua_u[1]->siz_w = u3h_mark(har_p) * 4; + + qua_u[2] = NULL; + + u3m_quac* tot_u = c3_malloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total nock stuff"); + tot_u->siz_w = qua_u[0]->siz_w + qua_u[1]->siz_w; + tot_u->qua_u = qua_u; + + return tot_u; +} + +/* u3n_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3n_reclaim(void) +{ + // clear the bytecode cache + // + // We can't just u3h_free() -- the value is a post to a u3n_prog. + // Note that the hank cache *must* also be freed (in u3j_reclaim()) + // + u3n_free(); + u3R->byc.har_p = u3h_new(); +} + +/* u3n_rewrite_compact(): rewrite the bytecode cache for compaction. + * + * NB: u3R->byc.har_p *must* be cleared (currently via u3n_reclaim above), + * since it contains things that look like nouns but aren't. + * Specifically, it contains "cells" where the tail is a + * pointer to a u3a_malloc'ed block that contains loom pointers. + * + * You should be able to walk this with u3h_walk and rewrite the + * pointers, but you need to be careful to handle that u3a_malloc + * pointers can't be turned into a box by stepping back two words. You + * must step back one word to get the padding, step then step back that + * many more words (plus one?). + */ +void +u3n_rewrite_compact() +{ + u3h_relocate(&(u3R->byc.har_p)); +} + + +/* _n_feb(): u3h_walk helper for u3n_free + */ +static void +_n_feb(u3_noun kev) +{ + _cn_prog_free(_cn_to_prog(u3t(kev))); +} + +/* u3n_free(): free bytecode cache + */ +void +u3n_free() +{ + u3p(u3h_root) har_p = u3R->byc.har_p; + u3h_walk(har_p, _n_feb); + u3h_free(har_p); +} + +/* u3n_kick_on(): fire `gat` without changing the sample. +*/ +u3_noun +u3n_kick_on(u3_noun gat) +{ + return u3j_kink(gat, 2); +} + +c3_w exc_w; + +/* u3n_slam_on(): produce (gat sam). +*/ +u3_noun +u3n_slam_on(u3_noun gat, u3_noun sam) +{ + u3_noun cor = u3nc(u3k(u3h(gat)), u3nc(sam, u3k(u3t(u3t(gat))))); + +#if 0 + if ( &u3H->rod_u == u3R ) { + if ( exc_w == 1 ) { + u3_assert(0); + } + exc_w++; + } +#endif + u3z(gat); + return u3n_kick_on(cor); +} + +/* u3n_nock_et(): produce .*(bus fol), as ++toon, in namespace. +*/ +u3_noun +u3n_nock_et(u3_noun gul, u3_noun bus, u3_noun fol) +{ + return u3m_soft_run(gul, u3n_nock_on, bus, fol); +} + +/* u3n_slam_et(): produce (gat sam), as ++toon, in namespace. +*/ +u3_noun +u3n_slam_et(u3_noun gul, u3_noun gat, u3_noun sam) +{ + return u3m_soft_run(gul, u3n_slam_on, gat, sam); +} + +/* u3n_nock_an(): as nock_et(), but with the scry handler that always blocks. +*/ +u3_noun +u3n_nock_an(u3_noun bus, u3_noun fol) +{ + u3_noun gul = u3nt(u3nc(1, 0), u3nc(0, 0), 0); // |~(^ ~) + return u3n_nock_et(gul, bus, fol); +} + + diff --git a/vere/pkg/noun/nock.h b/vere/pkg/noun/nock.h new file mode 100644 index 0000000..5c34515 --- /dev/null +++ b/vere/pkg/noun/nock.h @@ -0,0 +1,149 @@ +/// @file + +#ifndef U3_NOCK_H +#define U3_NOCK_H + +#include <stdio.h> + +#include "c3/c3.h" +#include "jets.h" +#include "types.h" +#include "zave.h" + + /** Data structures. + *** + **/ + + /* u3n_memo: %memo hint space + */ + typedef struct { + c3_l sip_l; + u3_noun key; + u3z_cid cid; + } u3n_memo; + + /* u3n_prog: program compiled from nock + */ + typedef struct _u3n_prog { + struct { + c3_o own_o; // program owns ops_y? + c3_w len_w; // length of bytecode (bytes) + c3_y* ops_y; // actual array of bytes + } byc_u; // bytecode + struct { + c3_w len_w; // number of literals + u3_noun* non; // array of literals + } lit_u; // literals + struct { + c3_w len_w; // number of memo slots + u3n_memo* sot_u; // array of memo slots + } mem_u; // memo slot data + struct { + c3_w len_w; // number of calls sites + u3j_site* sit_u; // array of sites + } cal_u; // call site data + struct { + c3_w len_w; // number of registration sites + u3j_rite* rit_u; // array of sites + } reg_u; // registration site data + } u3n_prog; + + /** Functions. + **/ + /* u3n_nock_on(): produce .*(bus fol). + */ + u3_noun + u3n_nock_on(u3_noun bus, u3_noun fol); + + /* u3n_find(): return prog for given formula, + * split by key (u3_nul for none). RETAIN. + */ + u3p(u3n_prog) + u3n_find(u3_noun key, u3_noun fol); + + /* u3n_burn(): execute u3n_prog with bus as subject. + */ + u3_noun + u3n_burn(u3p(u3n_prog) pog_p, u3_noun bus); + + /* u3n_slam_on(): produce (gat sam). + */ + u3_noun + u3n_slam_on(u3_noun gat, u3_noun sam); + + /* u3n_kick_on(): fire `gat` without changing the sample. + */ + u3_noun + u3n_kick_on(u3_noun gat); + + /* u3n_nock_in(): produce .*(bus fol), as ++toon, in namespace. + */ + u3_noun + u3n_nock_in(u3_noun fly, u3_noun bus, u3_noun fol); + + /* u3n_nock_it(): produce .*(bus fol), as ++toon, in namespace. + */ + u3_noun + u3n_nock_it(u3_noun sea, u3_noun bus, u3_noun fol); + + /* u3n_nock_et(): produce .*(bus fol), as ++toon, in namespace. + */ + u3_noun + u3n_nock_et(u3_noun gul, u3_noun bus, u3_noun fol); + + /* u3n_slam_in(): produce (gat sam), as ++toon, in namespace. + */ + u3_noun + u3n_slam_in(u3_noun fly, u3_noun gat, u3_noun sam); + + /* u3n_slam_it(): produce (gat sam), as ++toon, in namespace. + */ + u3_noun + u3n_slam_it(u3_noun sea, u3_noun gat, u3_noun sam); + + /* u3n_slam_et(): produce (gat sam), as ++toon, in namespace. + */ + u3_noun + u3n_slam_it(u3_noun gul, u3_noun gat, u3_noun sam); + + /* u3n_nock_an(): as slam_in(), but with empty fly. + */ + u3_noun + u3n_nock_an(u3_noun bus, u3_noun fol); + + /* u3n_reap(): promote bytecode state. + */ + void + u3n_reap(u3p(u3h_root) har_p); + + /* u3n_take(): copy junior bytecode state. + */ + u3p(u3h_root) + u3n_take(u3p(u3h_root) har_p); + + /* u3n_mark(): mark bytecode cache. + */ + u3m_quac* + u3n_mark(); + + /* u3n_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3n_reclaim(void); + + /* u3n_rewrite_compact(): rewrite bytecode cache for compaction. + */ + void + u3n_rewrite_compact(void); + + /* u3n_free(): free bytecode cache. + */ + void + u3n_free(void); + + /* u3n_ream(): refresh after restoring from checkpoint. + */ + void + u3n_ream(void); + +#endif /* ifndef U3_NOCK_H */ diff --git a/vere/pkg/noun/nock_tests.c b/vere/pkg/noun/nock_tests.c new file mode 100644 index 0000000..8d4a7d2 --- /dev/null +++ b/vere/pkg/noun/nock_tests.c @@ -0,0 +1,83 @@ +/// @file + +#include "noun.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_boot_lite(1 << 24); +} + +static u3_noun +_nock_fol(u3_noun fol) +{ + return u3n_nock_on(u3_nul, fol); +} + +static c3_i +_test_nock_meme(void) +{ + // (jam !=(=(~ =|(i=@ |-(?:(=(i ^~((bex 32))) ~ [i $(i +(i))])))))) + // + const c3_y buf_y[] = { + 0xe1, 0x16, 0x1b, 0x4, 0x1b, 0xe1, 0x20, 0x58, 0x1c, 0x76, 0x4d, 0x96, 0xd8, + 0x31, 0x60, 0x0, 0x0, 0x0, 0x0, 0xd8, 0x8, 0x37, 0xce, 0xd, 0x92, 0x21, + 0x83, 0x68, 0x61, 0x87, 0x39, 0xce, 0x4d, 0xe, 0x92, 0x21, 0x87, 0x19, 0x8 + }; + u3_noun fol = u3s_cue_bytes(sizeof(buf_y), buf_y); + u3_noun gon; + c3_w i_w; + c3_i ret_i = 1; + + for ( i_w = 0; i_w < 3; i_w++ ) { + gon = u3m_soft(0, _nock_fol, u3k(fol)); + + if ( c3n == u3r_p(gon, c3__meme, 0) ) { + u3m_p("nock meme unexpected mote", u3h(gon)); + ret_i = 0; + u3z(gon); + break; + } + + u3z(gon); + } + + u3z(fol); + + return ret_i; +} + +static c3_i +_test_meme(void) +{ + c3_i ret_i = 1; + + if ( !_test_nock_meme() ) { + fprintf(stderr, "test nock meme: failed\r\n"); + ret_i = 0; + } + + return ret_i; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_meme() ) { + fprintf(stderr, "test meme: failed\r\n"); + exit(1); + } + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "test meme: ok\r\n"); + return 0; +} diff --git a/vere/pkg/noun/noun.h b/vere/pkg/noun/noun.h new file mode 100644 index 0000000..965330a --- /dev/null +++ b/vere/pkg/noun/noun.h @@ -0,0 +1,26 @@ +/// @file + +#ifndef U3_NOUN_H +#define U3_NOUN_H + +#include "allocate.h" +#include "hashtable.h" +#include "error.h" +#include "jets.h" +#include "jets/k.h" +#include "jets/q.h" +#include "manage.h" +#include "options.h" +#include "serial.h" +#include "types.h" +#include "vortex.h" +#include "zave.h" +#include "imprison.h" +#include "log.h" +#include "nock.h" +#include "retrieve.h" +#include "trace.h" +#include "urth.h" +#include "xtract.h" + +#endif /* ifndef U3_NOUN_H */ diff --git a/vere/pkg/noun/options.c b/vere/pkg/noun/options.c new file mode 100644 index 0000000..cef3479 --- /dev/null +++ b/vere/pkg/noun/options.c @@ -0,0 +1,5 @@ +/// @file + +#include "options.h" + +u3o_config u3o_Config; diff --git a/vere/pkg/noun/options.h b/vere/pkg/noun/options.h new file mode 100644 index 0000000..615b765 --- /dev/null +++ b/vere/pkg/noun/options.h @@ -0,0 +1,59 @@ +/// @file + +#ifndef U3_OPTIONS_H +#define U3_OPTIONS_H + +#include "c3/c3.h" +#include "types.h" + + /** Data structures. + **/ + /* u3o_config: process / system configuration. + */ + typedef struct _u3o_config { + u3_noun who; // single identity + c3_c* dir_c; // execution directory (pier) + c3_c* eph_c; // ephemeral file + c3_w wag_w; // flags (both ways) + size_t wor_i; // loom word-length (<= u3a_words) + c3_w tos_w; // loom toss skip-length + c3_w hap_w; // transient memoization cache size + c3_w per_w; // persistent memoization cache size + void (*stderr_log_f)(c3_c*); // errors from c code + void (*slog_f)(u3_noun); // function pointer for slog + void (*sign_hold_f)(void); // suspend system signal regime + void (*sign_move_f)(void); // restore system signal regime + } u3o_config; + + /* u3o_flag: process/system flags. + ** + ** _debug flags are set outside u3 and heard inside it. + ** _check flags are set inside u3 and heard outside it. + */ + enum u3o_flag { // execution flags + u3o_debug_ram = 1 << 0, // debug: gc + u3o_debug_cpu = 1 << 1, // debug: profile + u3o_check_corrupt = 1 << 2, // check: gc memory + u3o_check_fatal = 1 << 3, // check: unrecoverable + u3o_verbose = 1 << 4, // be remarkably wordy + u3o_dryrun = 1 << 5, // don't touch checkpoint + u3o_quiet = 1 << 6, // disable ~& + u3o_hashless = 1 << 7, // disable hashboard + u3o_trace = 1 << 8, // enables trace dumping + u3o_no_demand = 1 << 9, // disables demand paging + u3o_auto_meld = 1 << 10, // enables meld under pressure + u3o_soft_mugs = 1 << 11, // continue replay on mismatch + u3o_swap = 1 << 12, // enables ephemeral file + u3o_toss = 1 << 13, // reclaim often + u3o_cash = 1 << 14, // memo cache harvesting + u3o_yolo = 1 << 15 // no brakes! + }; + + /** Globals. + **/ + /* u3_Config / u3C: global memory control. + */ + extern u3o_config u3o_Config; +# define u3C u3o_Config + +#endif /* ifndef U3_OPTIONS_H */ diff --git a/vere/pkg/noun/palloc.c b/vere/pkg/noun/palloc.c new file mode 100644 index 0000000..f8999d6 --- /dev/null +++ b/vere/pkg/noun/palloc.c @@ -0,0 +1,2400 @@ + +#include "c3/c3.h" +#include "allocate.h" +#include "options.h" +#include "vortex.h" + +#undef SANITY + +#ifdef ASAN_ENABLED + // XX build problems importing <sanitizers/asan_interface.h> + // + void __asan_poison_memory_region(void const volatile *addr, size_t size); + void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +# define ASAN_POISON_MEMORY_REGION(addr, size) \ + __asan_poison_memory_region((addr), (size)) +# define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) +#else +# define ASAN_POISON_MEMORY_REGION(addr, size) ((void) (addr), (void) (size)) +# define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void) (addr), (void) (size)) +#endif + +#ifndef BASE + #define BASE u3R->rut_p +#endif + +#define page_to_post(pag_w) (BASE + (HEAP.dir_ws * (c3_ws)((c3_w)(pag_w - HEAP.off_ws) << u3a_page))) +#define post_to_page(som_p) (_abs_dif(som_p, (c3_ws)BASE + HEAP.off_ws) >> u3a_page) + +#ifndef HEAP + #define HEAP u3R->hep +#endif + +static u3_post _imalloc(c3_w); +static void _ifree(u3_post); + +static __inline__ c3_w +_abs_dif(c3_w a_w, c3_w b_w) +{ + // c3_ds dif_ds = a_w - b_w; + // c3_d mas_d = dif_ds >> 63; + // return (dif_ds + mas_d) ^ mas_d; + return (a_w > b_w ) ? a_w - b_w : b_w - a_w; +} + +static void +_init_once(void) +{ + u3a_hunk_dose *hun_u; + c3_s mun_w = 0; + + for (c3_g bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) { + hun_u = &(u3a_Hunk[bit_g]); + hun_u->log_s = bit_g + u3a_min_log; + hun_u->len_s = 1U << hun_u->log_s; + hun_u->tot_s = 1U << (u3a_page - hun_u->log_s); + hun_u->map_s = (hun_u->tot_s + 31) >> 5; + hun_u->siz_s = c3_wiseof(u3a_crag) + hun_u->map_s - 1; + + // metacircular base case + // + // trivially deducible from exhaustive enumeration + // + if ( hun_u->len_s <= (hun_u->siz_s << 1) ) { + hun_u->hun_s = 1U + ((hun_u->siz_s - 1) >> hun_u->log_s); + } + else { + hun_u->hun_s = 0; + } + + hun_u->ful_s = hun_u->tot_s - hun_u->hun_s; + mun_w = c3_max(mun_w, hun_u->hun_s); + } + + u3_assert( 32 > mun_w ); +} + +static void +_drop(u3_post som_p, c3_w len_w) +{ + ASAN_UNPOISON_MEMORY_REGION(u3a_into(som_p), (c3_z)len_w << 2); +} + +static void +_init_heap(void) +{ + u3p(u3a_crag) *dir_u; + + if ( c3y == u3a_is_north(u3R) ) { + HEAP.dir_ws = 1; + HEAP.off_ws = 0; + } + else { + HEAP.dir_ws = -1; + HEAP.off_ws = -1; + } + + assert( !(u3R->hat_p & ((1U << u3a_page) - 1)) ); + assert( u3R->hat_p > u3a_rest_pg ); + assert( u3R->hat_p == u3R->rut_p ); + + // XX check for overflow + + HEAP.pag_p = u3R->hat_p; + HEAP.pag_p += HEAP.off_ws * (c3_ws)(1U << u3a_page); + HEAP.siz_w = 1U << u3a_page; + HEAP.len_w = 1; + + u3R->hat_p += HEAP.dir_ws * (c3_ws)(1U << u3a_page); + + dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + + memset(dir_u, 0, 1U << (u3a_page + 2)); + dir_u[0] = u3a_head_pg; + +#ifdef SANITY + assert( 0 == post_to_page(HEAP.pag_p) ); + assert( HEAP.pag_p == page_to_post(0) ); + assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) ); +#endif + + HEAP.cac_p = _imalloc(c3_wiseof(u3a_dell)); +} + +static void +_extend_directory(c3_w siz_w) // num pages +{ + u3p(u3a_crag) *dir_u, *old_u; + u3_post old_p = HEAP.pag_p; + c3_w nex_w, dif_w, pag_w; + + old_u = u3to(u3p(u3a_crag), HEAP.pag_p); + nex_w = HEAP.len_w + siz_w; // num words + nex_w += (1U << u3a_page) - 1; + nex_w &= ~((1U << u3a_page) - 1); + dif_w = nex_w >> u3a_page; // new pages + + HEAP.pag_p = u3R->hat_p; + HEAP.pag_p += HEAP.off_ws * (c3_ws)nex_w; + u3R->hat_p += HEAP.dir_ws * (c3_ws)nex_w; // XX overflow + + // XX depend on the guard page for these? + // + if ( 1 == HEAP.dir_ws ) { + if ( u3R->hat_p >= u3R->cap_p ) { + u3m_bail(c3__meme); return; + } + } + else { + if ( u3R->hat_p <= u3R->cap_p ) { + u3m_bail(c3__meme); return; + } + } + + dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + pag_w = post_to_page(HEAP.pag_p); + +#ifdef SANITY + assert( pag_w == (HEAP.len_w - (HEAP.off_ws * (dif_w - 1))) ); +#endif + + { + c3_z len_z = (c3_z)HEAP.len_w << 2; + c3_z dif_z = (c3_z)dif_w << 2; + + ASAN_UNPOISON_MEMORY_REGION(dir_u, (c3_z)nex_w << 2); + + memcpy(dir_u, old_u, len_z); + + dir_u[pag_w] = u3a_head_pg; + + for ( c3_w i_w = 1; i_w < dif_w; i_w++ ) { + dir_u[pag_w + (HEAP.dir_ws * (c3_ws)i_w)] = u3a_rest_pg; + } + + memset((c3_y*)dir_u + len_z + dif_z, 0, ((c3_z)nex_w << 2) - len_z - dif_z); + } + + HEAP.len_w += dif_w; + HEAP.siz_w = nex_w; + + _ifree(old_p); + +#ifdef SANITY + assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) ); + assert( dir_u[HEAP.len_w - 1] ); +#endif +} + +static u3_post +_extend_heap(c3_w siz_w) // num pages +{ + u3_post pag_p; + +#ifdef SANITY + assert( HEAP.siz_w >= HEAP.len_w ); +#endif + + if ( (HEAP.siz_w - HEAP.len_w) < siz_w ) { + _extend_directory(siz_w); + } + + pag_p = u3R->hat_p; + pag_p += HEAP.off_ws * (c3_ws)(siz_w << u3a_page); + + u3R->hat_p += HEAP.dir_ws * (c3_ws)(siz_w << u3a_page); + + // XX depend on the guard page for these? + // + if ( 1 == HEAP.dir_ws ) { + if ( u3R->hat_p >= u3R->cap_p ) { + return u3m_bail(c3__meme); + } + } + else { + if ( u3R->hat_p <= u3R->cap_p ) { + return u3m_bail(c3__meme); + } + } + + HEAP.len_w += siz_w; + + ASAN_POISON_MEMORY_REGION(u3a_into(pag_p), siz_w << (u3a_page + 2)); + +#ifdef SANITY + assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) ); +#endif + + return pag_p; +} + +static u3_post +_alloc_pages(c3_w siz_w) // num pages +{ + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + u3a_dell* fre_u = u3tn(u3a_dell, HEAP.fre_p); + u3a_dell* del_u = NULL; + c3_w pag_w = 0; + + while ( fre_u ) { + // XX sanity + + if ( fre_u->siz_w < siz_w ) { + fre_u = u3tn(u3a_dell, fre_u->nex_p); + continue; + } + else if ( fre_u->siz_w == siz_w ) { + pag_w = fre_u->pag_w; + + if ( fre_u->nex_p ) { + u3to(u3a_dell, fre_u->nex_p)->pre_p = fre_u->pre_p; + } + else { + HEAP.erf_p = fre_u->pre_p; + } + + if ( fre_u->pre_p ) { + u3to(u3a_dell, fre_u->pre_p)->nex_p = fre_u->nex_p; + } + else { + HEAP.fre_p = fre_u->nex_p; + } + + del_u = fre_u; + } + else { + pag_w = fre_u->pag_w; + fre_u->pag_w += siz_w; + fre_u->siz_w -= siz_w; + } + break; + } + + u3_post pag_p; + + if ( pag_w ) { + // XX groace + // + pag_w -= HEAP.off_ws * (siz_w - 1); + pag_p = page_to_post(pag_w); + +#ifdef SANITY + assert( pag_w < HEAP.len_w ); + + // XX sanity + assert( u3a_free_pg == dir_u[pag_w] ); + for ( c3_w i_w = 1; i_w < siz_w; i_w++ ) { + assert( u3a_free_pg == dir_u[pag_w + (HEAP.dir_ws * (c3_ws)i_w)] ); + } +#endif + } + else { + pag_p = _extend_heap(siz_w); + pag_w = post_to_page(pag_p); + dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + +#ifdef SANITY + assert( pag_w < HEAP.len_w ); + assert( (pag_w + ((HEAP.off_ws + 1) * siz_w) - HEAP.off_ws) == HEAP.len_w ); +#endif + } + + dir_u[pag_w] = u3a_head_pg; + + for ( c3_w i_w = 1; i_w < siz_w; i_w++ ) { + dir_u[pag_w + (HEAP.dir_ws * (c3_ws)i_w)] = u3a_rest_pg; + } + + // XX junk + + ASAN_UNPOISON_MEMORY_REGION(u3a_into(pag_p), siz_w << (u3a_page + 2)); + + if ( del_u ) { + if ( !HEAP.cac_p ) { + HEAP.cac_p = u3of(u3a_dell, del_u); + } + else { + _ifree(u3of(u3a_dell, del_u)); + } + } + +#ifdef SANITY + assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) ); + assert( dir_u[HEAP.len_w - 1] ); +#endif + + return pag_p; +} + +static void +_rake_chunks(c3_w len_w, c3_w max_w, c3_t rak_t, c3_w* out_w, u3_post* out_p) +{ + c3_g bit_g = (c3_g)c3_bits_word(len_w - 1) - u3a_min_log; // 0-9, inclusive + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + u3_post pag_p = HEAP.wee_p[bit_g]; + u3a_crag *pag_u; + c3_w hav_w = *out_w; + + if ( rak_t ) { + c3_w *map_w; + c3_g pos_g; + u3_post bas_p; + c3_w off_w; + + while ( pag_p ) { + pag_u = u3to(u3a_crag, pag_p); + bas_p = page_to_post(pag_u->pag_w); + map_w = pag_u->map_w; + + while ( !*map_w ) { map_w++; } + off_w = (map_w - pag_u->map_w) << 5; + + if ( (max_w - hav_w) < pag_u->fre_s ) { + while ( hav_w < max_w ) { + pos_g = c3_tz_w(*map_w); + *map_w &= ~(1U << pos_g); + + out_p[hav_w++] = bas_p + ((off_w + pos_g) << pag_u->log_s); + pag_u->fre_s--; + + ASAN_UNPOISON_MEMORY_REGION(u3a_into(out_p[hav_w - 1]), (c3_z)hun_u->len_s << 2); + + if ( !*map_w ) { + do { map_w++; } while ( !*map_w ); + off_w = (map_w - pag_u->map_w) << 5; + } + } + + HEAP.wee_p[bit_g] = pag_p; + *out_w = hav_w; + return; + } + + ASAN_UNPOISON_MEMORY_REGION(u3a_into(bas_p), 1U << (u3a_page + 2)); + + while ( 1 ) { + pos_g = c3_tz_w(*map_w); + *map_w &= ~(1U << pos_g); + + out_p[hav_w++] = bas_p + ((off_w + pos_g) << pag_u->log_s); + + if ( !--pag_u->fre_s ) { + break; + } + + if ( !*map_w ) { + do { map_w++; } while ( !*map_w ); + off_w = (map_w - pag_u->map_w) << 5; + } + } + + pag_p = pag_u->nex_p; + pag_u->nex_p = 0; + + if ( hav_w == max_w ) { + HEAP.wee_p[bit_g] = pag_p; + *out_w = hav_w; + return; + } + } + + HEAP.wee_p[bit_g] = 0; + } + + // XX s/b ful_s + if ( hun_u->tot_s > (max_w - hav_w) ) { + *out_w = hav_w; + return; + } + + // manually inlined _make_chunks(), storing each chunk-post to [*out_p] + // + { + u3_post hun_p; + c3_w pag_w; + + pag_p = _alloc_pages(1); + pag_w = post_to_page(pag_p); + hun_p = ( hun_u->hun_s ) ? pag_p : _imalloc(hun_u->siz_s); + pag_u = u3to(u3a_crag, hun_p); + pag_u->pag_w = pag_w; + pag_u->log_s = hun_u->log_s; + pag_u->fre_s = 0; + pag_u->nex_p = 0; + // initialize bitmap (zeros, none free) + // + memset(pag_u->map_w, 0, (c3_z)hun_u->map_s << 2); + + { + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + dir_u[pag_w] = hun_p; + } + + for ( c3_s i_s = hun_u->hun_s; i_s < hun_u->tot_s; i_s++ ) { + out_p[hav_w++] = pag_p + (i_s << pag_u->log_s); + } + + *out_w = hav_w; + } +} + +static u3_post +_make_chunks(c3_g bit_g) // 0-9, inclusive +{ + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + u3a_crag *pag_u; + u3_post hun_p, pag_p = _alloc_pages(1); + c3_w pag_w = post_to_page(pag_p); + + ASAN_POISON_MEMORY_REGION(u3a_into(pag_p), 1U << (u3a_page + 2)); + + if ( hun_u->hun_s ) { + hun_p = pag_p; + ASAN_UNPOISON_MEMORY_REGION(u3a_into(pag_p), (c3_z)hun_u->hun_s << (hun_u->log_s + 2)); + } + else { + hun_p = _imalloc(hun_u->siz_s); + } + + pag_u = u3to(u3a_crag, hun_p); + pag_u->pag_w = pag_w; + pag_u->log_s = hun_u->log_s; + pag_u->fre_s = hun_u->ful_s; + + // initialize bitmap (ones, all free) + // + if ( hun_u->tot_s < 32 ) { + pag_u->map_w[0] = (1U << hun_u->tot_s) - 1; + } + else { + memset(pag_u->map_w, 0xff, (c3_z)hun_u->map_s << 2); + } + + // reserve chunks stolen for pginfo + // NB: max [hun_s] guarded by assertion in _init_once() + // + pag_u->map_w[0] &= ~0U << hun_u->hun_s; + + { + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + dir_u[pag_w] = hun_p; + } + + pag_u->nex_p = HEAP.wee_p[bit_g]; + HEAP.wee_p[bit_g] = hun_p; + + return hun_p; +} + +static u3_post +_alloc_words(c3_w len_w) // 4-2.048, inclusive +{ + c3_g bit_g = (c3_g)c3_bits_word(len_w - 1) - u3a_min_log; // 0-9, inclusive + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + u3a_crag *pag_u; + c3_w *map_w; + c3_g pos_g; + + if ( !HEAP.wee_p[bit_g] ) { + pag_u = u3to(u3a_crag, _make_chunks(bit_g)); + } + else { + pag_u = u3to(u3a_crag, HEAP.wee_p[bit_g]); + // XX sanity + + if ( 1 == pag_u->fre_s ) { + HEAP.wee_p[bit_g] = pag_u->nex_p; + pag_u->nex_p = 0; + } + } + + pag_u->fre_s--; + map_w = pag_u->map_w; + while ( !*map_w ) { map_w++; } + + pos_g = c3_tz_w(*map_w); + *map_w &= ~(1U << pos_g); + + { + u3_post out_p, bas_p = page_to_post(pag_u->pag_w); + c3_w off_w = (map_w - pag_u->map_w) << 5; + + out_p = bas_p + ((off_w + pos_g) << pag_u->log_s); + ASAN_UNPOISON_MEMORY_REGION(u3a_into(out_p), hun_u->len_s << 2); + // XX poison suffix + + return out_p; + } +} + +static u3_post +_imalloc(c3_w len_w) +{ + if ( len_w > (1U << (u3a_page - 1)) ) { + len_w += (1U << u3a_page) - 1; + len_w >>= u3a_page; + // XX poison suffix + return _alloc_pages(len_w); + } + + return _alloc_words(c3_max(len_w, u3a_minimum)); +} + +static inline c3_w +_pages_size(c3_w pag_w) +{ + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w siz_w = 1; + + // head-page 0 in a south road can only have a size of 1 + // + if ( pag_w || !HEAP.off_ws ) { + while( dir_u[pag_w + (HEAP.dir_ws * (c3_ws)siz_w)] == u3a_rest_pg ) { + siz_w++; + } + } + + return siz_w; +} + +static c3_w +_free_pages(u3_post som_p, c3_w pag_w, u3_post dir_p) +{ + u3a_dell *cac_u, *fre_u, *del_u = NULL; + c3_w nex_w, siz_w = 1; + u3_post fre_p; + + if ( u3a_free_pg == dir_p ) { + fprintf(stderr, "\033[31m" + "palloc: double free page som_p=0x%x pag_w=%u\r\n" + "\033[0m", + som_p, pag_w); + u3_assert(!"loom: corrupt"); return 0; + } + + if ( u3a_head_pg != dir_p ) { + fprintf(stderr, "\033[31m" + "palloc: wrong page som_p=0x%x dir_p=0x%x\r\n" + "\033[0m", + som_p, dir_p); + u3_assert(!"loom: corrupt"); return 0; + } + + if ( som_p & ((1U << u3a_page) - 1) ) { + fprintf(stderr, "\033[31m" + "palloc: bad page alignment som_p=0x%x\r\n" + "\033[0m", + som_p); + u3_assert(!"loom: corrupt"); return 0; + } + + { + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + + dir_u[pag_w] = u3a_free_pg; + + // head-page 0 in a south road can only have a size of 1 + // + if ( pag_w || !HEAP.off_ws ) { + while( dir_u[pag_w + (HEAP.dir_ws * (c3_ws)siz_w)] == u3a_rest_pg ) { + dir_u[pag_w + (HEAP.dir_ws * (c3_ws)siz_w)] = u3a_free_pg; + siz_w++; + } + } + } + + // XX groace + // + if ( HEAP.off_ws ) { + nex_w = pag_w + 1; + pag_w = nex_w - siz_w; + } + else { + nex_w = pag_w + siz_w; + } + +#ifdef SANITY + assert( pag_w < HEAP.len_w ); + assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) ); +#endif + + if ( nex_w == HEAP.len_w ) { + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w wiz_w = siz_w; + + // check if prior pages are already free + // + if ( !dir_u[HEAP.len_w - (siz_w + 1)] ) { + assert( HEAP.erf_p ); + fre_u = u3to(u3a_dell, HEAP.erf_p); + assert( (fre_u->pag_w + fre_u->siz_w) == pag_w ); + + if ( fre_u->pre_p ) { + HEAP.erf_p = fre_u->pre_p; + u3to(u3a_dell, fre_u->pre_p)->nex_p = 0; + } + else { + HEAP.fre_p = HEAP.erf_p = 0; + } + + pag_w = fre_u->pag_w; // NB: clobbers + siz_w += fre_u->siz_w; + + // XX groace + // + pag_w -= HEAP.off_ws * (siz_w - 1); + som_p = page_to_post(pag_w); + } + else { + fre_u = NULL; + } + + ASAN_UNPOISON_MEMORY_REGION(u3a_into(som_p), siz_w << (u3a_page + 2)); + u3R->hat_p -= HEAP.dir_ws * (c3_ws)(siz_w << u3a_page); + HEAP.len_w -= siz_w; + + // fprintf(stderr, "shrink heap 0x%x 0x%x %u:%u (%u) 0x%x\r\n", + // som_p, som_p + (siz_w << u3a_page), pag_w, wiz_w, siz_w, u3R->hat_p); + +#ifdef SANITY + assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) ); + assert( dir_u[HEAP.len_w - 1] ); +#endif + + if ( fre_u ) { + _ifree(u3of(u3a_dell, fre_u)); + } + + return wiz_w; + } + + // XX madv_free + + ASAN_POISON_MEMORY_REGION(u3a_into(som_p), siz_w << (u3a_page + 2)); + + // XX add temporary freelist entry? + // if ( !HEAP.cac_p && !HEAP.fre_p + // && !HEAP.wee_p[(c3_bits_word(c3_wiseof(*cac_u) - 1) - u3a_min_log)] ) + // { + // fprintf(stderr, "palloc: growing heap to free pages\r\n"); + // } + + if ( !HEAP.cac_p ) { + fre_p = _imalloc(c3_wiseof(*cac_u)); + } + else { + fre_p = HEAP.cac_p; + HEAP.cac_p = 0; + } + + cac_u = u3to(u3a_dell, fre_p); + cac_u->pag_w = pag_w; + cac_u->siz_w = siz_w; + + if ( !(fre_u = u3tn(u3a_dell, HEAP.fre_p)) ) { + // fprintf(stderr, "free pages 0x%x (%u) via 0x%x\r\n", som_p, siz_w, HEAP.cac_p); + cac_u->nex_p = 0; + cac_u->pre_p = 0; + HEAP.fre_p = HEAP.erf_p = fre_p; + fre_p = 0; + } + else { + c3_w fex_w; + + while ( ((fex_w = fre_u->pag_w + fre_u->siz_w) < pag_w) + && fre_u->nex_p ) + { + fre_u = u3to(u3a_dell, fre_u->nex_p); + } + + if ( fre_u->pag_w > nex_w ) { // insert before + cac_u->nex_p = u3of(u3a_dell, fre_u); + cac_u->pre_p = fre_u->pre_p; + + fre_u->pre_p = fre_p; + + // XX sanity + if ( cac_u->pre_p ) { + u3to(u3a_dell, cac_u->pre_p)->nex_p = fre_p; + } + else { + HEAP.fre_p = fre_p; + } + + fre_p = 0; + } + else if ( fex_w == pag_w ) { // append to entry + fre_u->siz_w += siz_w; + + // coalesce with next entry + // + if ( fre_u->nex_p + && ((fex_w + siz_w) == u3to(u3a_dell, fre_u->nex_p)->pag_w) ) + { + del_u = u3to(u3a_dell, fre_u->nex_p); + fre_u->siz_w += del_u->siz_w; + fre_u->nex_p = del_u->nex_p; + + // XX sanity + if ( del_u->nex_p ) { + u3to(u3a_dell, del_u->nex_p)->pre_p = u3of(u3a_dell, fre_u); + } + else { + HEAP.erf_p = u3of(u3a_dell, fre_u); + } + } + } + else if ( fre_u->pag_w == nex_w ) { // prepend to entry + fre_u->siz_w += siz_w; + fre_u->pag_w = pag_w; + } + else if ( !fre_u->nex_p ) { // insert after + cac_u->nex_p = 0; + cac_u->pre_p = u3of(u3a_dell, fre_u); + HEAP.erf_p = fre_u->nex_p = fre_p; + fre_p = 0; + } + else { + fprintf(stderr, "\033[31m" + "palloc: free list hosed at som_p=0x%x pag=%u len=%u\r\n" + "\033[0m", + (u3_post)u3of(u3a_dell, fre_u), fre_u->pag_w, fre_u->siz_w); + u3_assert(!"loom: corrupt"); return 0; + } + } + + if ( fre_p ) { + if ( !HEAP.cac_p ) { + HEAP.cac_p = fre_p; + } + else { + _ifree(fre_p); + } + + if ( del_u ) { + _ifree(u3of(u3a_dell, del_u)); + } + } + + return siz_w; +} + +static void +_free_words(u3_post som_p, c3_w pag_w, u3_post dir_p) +{ + u3a_crag *pag_u = u3to(u3a_crag, dir_p); + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + +#ifdef SANITY + assert( page_to_post(pag_u->pag_w) == (som_p & ~((1U << u3a_page) - 1)) ); + assert( pag_u->log_s < u3a_page ); +#endif + + c3_g bit_g = pag_u->log_s - u3a_min_log; + c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s; + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + + if ( som_p & (hun_u->len_s - 1) ) { + fprintf(stderr, "\033[31m" + "palloc: bad alignment som_p=0x%x pag=%u cag=0x%x len_s=%u\r\n" + "\033[0m", + som_p, post_to_page(som_p), dir_p, hun_u->len_s); + u3_assert(!"loom: corrupt"); return; + } + + if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) { + fprintf(stderr, "\033[31m" + "palloc: double free som_p=0x%x pag=0x%x\r\n" + "\033[0m", + som_p, dir_p); + u3_assert(!"loom: corrupt"); return; + } + + pag_u->map_w[pos_w >> 5] |= (1U << (pos_w & 31)); + pag_u->fre_s++; + + ASAN_POISON_MEMORY_REGION(u3a_into(som_p), hun_u->len_s << 2); + + { + u3_post *bit_p = &(HEAP.wee_p[bit_g]); + u3a_crag *bit_u, *nex_u; + + if ( 1 == pag_u->fre_s ) { + // page newly non-full, link + // + + if ( &(u3H->rod_u) == u3R ) { + while ( *bit_p ) { + bit_u = u3to(u3a_crag, *bit_p); + nex_u = u3tn(u3a_crag, bit_u->nex_p); + + if ( nex_u && (nex_u->pag_w < pag_u->pag_w) ) { + bit_p = &(bit_u->nex_p); + continue; + } + + break; + } + } + + pag_u->nex_p = *bit_p; + *bit_p = dir_p; + } + else if ( pag_u->fre_s == hun_u->ful_s ) { + // page now free + // + while ( *bit_p != dir_p ) { + bit_u = u3to(u3a_crag, *bit_p); + bit_p = &(bit_u->nex_p); + + // XX sanity: must be in list + } + + *bit_p = pag_u->nex_p; + + dir_u[pag_u->pag_w] = u3a_head_pg; + som_p = page_to_post(pag_u->pag_w); // NB: clobbers + if ( som_p != dir_p ) { + _ifree(dir_p); + } + _ifree(som_p); + } + } +} + +static void +_ifree(u3_post som_p) +{ + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w pag_w = post_to_page(som_p); + + if ( pag_w >= HEAP.len_w ) { + fprintf(stderr, "\033[31m" + "palloc: page out of heap som_p=0x%x pag_w=%u len_w=%u\r\n" + "\033[0m", + som_p, pag_w, HEAP.len_w); + u3_assert(!"loom: corrupt"); return; + } + + u3_post dir_p = dir_u[pag_w]; + + if ( dir_p <= u3a_rest_pg ) { + (void)_free_pages(som_p, pag_w, dir_p); + } + else { + _free_words(som_p, pag_w, dir_p); + } +} + +static u3_post +_irealloc(u3_post som_p, c3_w len_w) +{ + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w pag_w = post_to_page(som_p); + c3_w old_w; + + if ( pag_w >= HEAP.len_w ) { + fprintf(stderr, "\033[31m" + "palloc: realloc page out of heap som_p=0x%x pag_w=%u\r\n" + "\033[0m", + som_p, pag_w); + u3_assert(!"loom: corrupt"); return 0; + } + + u3_post dir_p = dir_u[pag_w]; + + if ( u3a_head_pg == dir_p ) { + if ( som_p & ((1U << u3a_page) - 1) ) { + fprintf(stderr, "\033[31m" + "palloc: realloc bad page alignment som_p=0x%x\r\n" + "\033[0m", + som_p); + u3_assert(!"loom: corrupt"); return 0; + } + + { + c3_w dif_w, siz_w = _pages_size(pag_w); + + old_w = siz_w << u3a_page; + + if ( (len_w < old_w) + && (dif_w = (old_w - len_w) >> u3a_page) ) + { + pag_w += HEAP.dir_ws * (siz_w - dif_w); + (void)_free_pages(page_to_post(pag_w), pag_w, u3a_head_pg); + + // XX junk + // XX unpoison prefix, poison suffix + return som_p; + } + + // XX also grow in place if sufficient adjacent pages are free? + } + } + else if ( u3a_rest_pg >= dir_p ) { + fprintf(stderr, "\033[31m" + "palloc: realloc wrong page som_p=0x%x\r\n" + "\033[0m", + som_p); + u3_assert(!"loom: corrupt"); return 0; + } + else { + u3a_crag *pag_u = u3to(u3a_crag, dir_p); + c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s; + const u3a_hunk_dose *hun_u = &(u3a_Hunk[pag_u->log_s - u3a_min_log]); + + if ( som_p & (hun_u->len_s - 1) ) { + fprintf(stderr, "\033[31m" + "palloc: realloc bad alignment som_p=0x%x pag=0x%x len_s=%u\r\n" + "\033[0m", + som_p, dir_p, hun_u->len_s); + u3_assert(!"loom: corrupt"); return 0; + } + + if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) { + fprintf(stderr, "\033[31m" + "palloc: realloc free som_p=0x%x pag=0x%x\r\n" + "\033[0m", + som_p, dir_p); + u3_assert(!"loom: corrupt"); return 0; + } + + old_w = hun_u->len_s; + + if ( (len_w <= old_w) + && ((len_w > (old_w >> 1)) || (u3a_minimum == old_w)) ) + { + // XX junk + // XX unpoison prefix, poison suffix + return som_p; + } + } + + { + u3_post new_p = _imalloc(len_w); + + memcpy(u3a_into(new_p), u3a_into(som_p), (c3_z)c3_min(len_w, old_w) << 2); + _ifree(som_p); + + return new_p; + } +} + +static void +_post_status(u3_post som_p) +{ + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w pag_w = post_to_page(som_p); + + if ( pag_w >= HEAP.len_w ) { + fprintf(stderr, "palloc: out of heap: post som_p=0x%x pag_w=%u len_w=%u\r\n", + som_p, pag_w, HEAP.len_w); + return; + } + + u3_post dir_p = dir_u[pag_w]; + + if ( dir_p <= u3a_rest_pg ) { + if ( som_p & ((1U << u3a_page) - 1) ) { + fprintf(stderr, "palloc: page not aligned som_p=0x%x (0x%x)\r\n", + som_p, som_p & ~(((1U << u3a_page) - 1))); + } + + if ( u3a_free_pg == dir_p ) { + fprintf(stderr, "palloc: free page som_p=0x%x pag_w=%u\r\n", + som_p, pag_w); + } + else if ( u3a_head_pg != dir_p ) { + fprintf(stderr, "palloc: rest page som_p=0x%x dir_p=0x%x\r\n", + som_p, dir_p); + } + else { + // XX include size + fprintf(stderr, "palloc: head page in-use som_p=0x%x\r\n", + som_p); + } + } + else { + u3a_crag *pag_u = u3to(u3a_crag, dir_p); + +#ifdef SANITY + assert( page_to_post(pag_u->pag_w) == (som_p & ~((1U << u3a_page) - 1)) ); + assert( pag_u->log_s < u3a_page ); +#endif + + c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s; + const u3a_hunk_dose *hun_u = &(u3a_Hunk[pag_u->log_s - u3a_min_log]); + + if ( som_p & (hun_u->len_s - 1) ) { + fprintf(stderr, "palloc: bad alignment som_p=0x%x (0x%x) pag=0x%x len_s=%u\r\n", + som_p, som_p & ~((1U << u3a_page) - 1), + dir_p, hun_u->len_s); + } + + if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) { + fprintf(stderr, "palloc: words free som_p=0x%x pag=0x%x len=%u\r\n", + som_p, dir_p, hun_u->len_s); + } + else { + fprintf(stderr, "palloc: words in-use som_p=0x%x pag=0x%x, len=%u\r\n", + som_p, dir_p, hun_u->len_s); + } + } +} + +static c3_w +_idle_pages(void) +{ + u3a_dell* fre_u = u3tn(u3a_dell, HEAP.fre_p); + c3_w tot_w = 0; + + while ( fre_u ) { + tot_w += fre_u->siz_w; + fre_u = u3tn(u3a_dell, fre_u->nex_p); + } + + return tot_w; +} + +static c3_w +_idle_words(void) +{ + u3a_crag *pag_u; + c3_w pag_w, siz_w, tot_w = 0; + + for ( c3_w i_w = 0; i_w < u3a_crag_no; i_w++ ) { + pag_u = u3tn(u3a_crag, HEAP.wee_p[i_w]); + siz_w = pag_w = 0; + + while ( pag_u ) { + siz_w += pag_u->fre_s; + pag_u = u3tn(u3a_crag, pag_u->nex_p); + pag_w++; + } + + if ( (u3C.wag_w & u3o_verbose) && siz_w ) { + fprintf(stderr, "idle words: class=%u (%u words) blocks=%u (in %u pages) ", + i_w, (1U << (i_w + u3a_min_log)), siz_w, pag_w); + u3a_print_memory(stderr, "total", siz_w << (i_w + u3a_min_log)); + } + + tot_w += siz_w << (i_w + u3a_min_log); + } + + return tot_w; +} + +static void +_poison_pages(void) +{ + u3a_dell *fre_u = u3tn(u3a_dell, HEAP.fre_p); + u3_post pag_p; + + while ( fre_u ) { + pag_p = page_to_post(fre_u->pag_w); + ASAN_POISON_MEMORY_REGION(u3a_into(pag_p), fre_u->siz_w << (u3a_page + 2)); + fre_u = u3tn(u3a_dell, fre_u->nex_p); + } +} + +static void +_poison_words(void) +{ + const u3a_hunk_dose *hun_u; + u3_post pag_p, hun_p; + u3a_crag *pag_u; + c3_w off_w, wor_w, len_w, *map_w; + c3_g pos_g; + c3_s fre_s; + + for ( c3_w i_w = 0; i_w < u3a_crag_no; i_w++ ) { + hun_u = &(u3a_Hunk[i_w]); + pag_u = u3tn(u3a_crag, HEAP.wee_p[i_w]); + + while ( pag_u ) { + pag_p = page_to_post(pag_u->pag_w); + map_w = pag_u->map_w; + len_w = (c3_w)hun_u->len_s << 2; + fre_s = pag_u->fre_s; + + do { + while ( !*map_w ) { map_w++; } + wor_w = *map_w; + off_w = (map_w - pag_u->map_w) << 5; + + do { + pos_g = c3_tz_w(wor_w); + wor_w &= ~(1U << pos_g); + hun_p = pag_p + ((off_w + pos_g) << pag_u->log_s); + + ASAN_POISON_MEMORY_REGION(u3a_into(hun_p), len_w); + + } while ( --fre_s && wor_w ); + + map_w++; + } while ( fre_s ); + + pag_u = u3tn(u3a_crag, pag_u->nex_p); + } + } +} + +static void +_unpoison_words(void) +{ + u3a_crag *pag_u; + u3_post pag_p; + + for ( c3_w i_w = 0; i_w < u3a_crag_no; i_w++ ) { + pag_u = u3tn(u3a_crag, HEAP.wee_p[i_w]); + + while ( pag_u ) { + pag_p = page_to_post(pag_u->pag_w); + ASAN_UNPOISON_MEMORY_REGION(u3a_into(pag_p), 1U << (u3a_page + 2)); + pag_u = u3tn(u3a_crag, pag_u->nex_p); + } + } +} + +static c3_w +_mark_post(u3_post som_p) +{ + c3_w pag_w = post_to_page(som_p); + c3_w blk_w = pag_w >> 5; + c3_w bit_w = pag_w & 31; + c3_w siz_w; + + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + u3_post dir_p = dir_u[pag_w]; + + // som_p is a one-or-more page allocation + // + if ( dir_p <= u3a_rest_pg ) { + if ( som_p & ((1U << u3a_page) - 1) ) { + fprintf(stderr, "palloc: mark: page not aligned som_p=0x%x (0x%x)\r\n", + som_p, som_p & ~(((1U << u3a_page) - 1))); + return 0; + } + + if ( u3a_free_pg == dir_p ) { + fprintf(stderr, "palloc: mark: free page som_p=0x%x pag_w=%u\r\n", + som_p, pag_w); + return 0; + } + else if ( u3a_head_pg != dir_p ) { + fprintf(stderr, "palloc: mark: rest page som_p=0x%x dir_p=0x%x\r\n", + som_p, dir_p); + return 0; + } + + // page(s) already marked + // + if ( u3a_Mark.bit_w[blk_w] & (1U << bit_w) ) { + return 0; + } + + u3a_Mark.bit_w[blk_w] |= 1U << bit_w; + + siz_w = _pages_size(pag_w); + siz_w <<= u3a_page; + + return siz_w; + } + // som_p is a chunk allocation + // + else { + u3a_crag *pag_u = u3to(u3a_crag, dir_p); + c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s; + c3_g bit_g = pag_u->log_s - u3a_min_log; + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + c3_w *mar_w; + + if ( som_p & (hun_u->len_s - 1) ) { + fprintf(stderr, "palloc: mark: bad alignment som_p=0x%x (0x%x) pag=0x%x (%u) len_s=%u\r\n", + som_p, som_p & ~((1U << u3a_page) - 1), + dir_p, pag_u->pag_w, hun_u->len_s); + return 0; + } + + if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) { + fprintf(stderr, "palloc: mark: words free som_p=0x%x pag=0x%x (%u) len=%u\r\n", + som_p, dir_p, pag_u->pag_w, hun_u->len_s); + return 0; + } + + // page is marked + // + if ( u3a_Mark.bit_w[blk_w] & (1U << bit_w) ) { + mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w]; + + if ( !(mar_w[pos_w >> 5] & (1U << (pos_w & 31))) ) { + return 0; + } + } + // page is unmarked, allocate and initialize mark-array + // + else { + mar_w = u3a_mark_alloc(hun_u->map_s); + u3a_Mark.buf_w[pag_w] = mar_w - u3a_Mark.buf_w; + memset(mar_w, 0xff, (c3_z)hun_u->map_s << 2); + + // mark page metadata + // + if ( !hun_u->hun_s ) { + u3a_Mark.wee_w[bit_g] += _mark_post(dir_p); + mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w]; + } + else { + // NB: max [hun_s] guarded by assertion in _init_once() + // + mar_w[0] &= ~0U << hun_u->hun_s; + u3a_Mark.wee_w[bit_g] += (c3_w)hun_u->hun_s << pag_u->log_s; + } + + u3a_Mark.bit_w[blk_w] |= 1U << bit_w; + } + + mar_w[pos_w >> 5] &= ~(1U << (pos_w & 31)); + siz_w = hun_u->len_s; + + return siz_w; + } +} + +static void +_print_chunk(FILE* fil_u, u3_post som_p, c3_w siz_w) +{ + c3_w *ptr_w = u3to(c3_w, som_p); + + fprintf(fil_u, "{ "); + // XX log minimum or u3a_minimum + for ( c3_w j_w = 0; j_w < 4; j_w++ ) { + fprintf(fil_u, "0x%x, ", ptr_w[j_w]); + } + + if ( siz_w > 4 ) { + fprintf(fil_u, "... "); + } + + fprintf(fil_u, "}\r\n"); +} + +static c3_w +_sweep_directory(void) +{ + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w pag_w, blk_w, bit_w, siz_w, leq_w = 0, tot_w = 0; + u3_post dir_p; + + // unlink leaked whole chunk-pages + // (we do this first so we won't need to dereference the metadata) + // + { + u3a_crag *pag_u; + u3_post *bit_p; + c3_g bit_g; + + for ( bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) { + bit_p = &(HEAP.wee_p[bit_g]); + + while ( *bit_p ) { + pag_u = u3to(u3a_crag, *bit_p); + pag_w = pag_u->pag_w; + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + + if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) { + *bit_p = pag_u->nex_p; + } + else { + bit_p = &(pag_u->nex_p); + } + } + } + } + + for ( pag_w = 0; pag_w < HEAP.len_w; pag_w++ ) { + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + dir_p = dir_u[pag_w]; + + if ( u3a_head_pg == dir_p ) { + if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) { + siz_w = _free_pages(page_to_post(pag_w), pag_w, dir_p); + if ( 1 == siz_w ) { + fprintf(stderr, "palloc: leaked page %u\r\n", pag_w); + } + else { + fprintf(stderr, "palloc: leaked pages %u-%u\r\n", + pag_w, pag_w + siz_w - 1); + } + leq_w += siz_w << u3a_page; + } + else { + siz_w = _pages_size(pag_w); + tot_w += siz_w << u3a_page; + } + } + else if ( u3a_rest_pg < dir_p ) { + // entire chunk page is unmarked + // + if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) { + fprintf(stderr, "palloc: leaked chunk page %u\r\n", pag_w); + (void)_free_pages(page_to_post(pag_w), pag_w, u3a_head_pg); + leq_w += 1U << u3a_page; + } + else { + u3a_crag *pag_u = u3to(u3a_crag, dir_p); + c3_g bit_g = pag_u->log_s - u3a_min_log; + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + u3_post som_p, bas_p = page_to_post(pag_u->pag_w); + c3_w *mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w]; + + siz_w = hun_u->len_s; + + if ( 0 == memcmp(mar_w, pag_u->map_w, (c3_z)hun_u->map_s << 2) ) { + tot_w += siz_w * (hun_u->tot_s - pag_u->fre_s); + } + // NB: since at least one chunk is marked, + // _free_words() will never free [pag_u] + // + else { + for ( c3_s i_s = 0; i_s < hun_u->tot_s; i_s++ ) { + blk_w = i_s >> 5; + bit_w = i_s & 31; + + if ( !(pag_u->map_w[blk_w] & (1U << bit_w)) ) { + if ( !(mar_w[blk_w] & (1U << bit_w)) ) { + tot_w += siz_w; + } + else { + som_p = bas_p + ((c3_w)i_s << pag_u->log_s); + + fprintf(stderr, "palloc: leak: 0x%x (chunk %u in page %u)\r\n", som_p, i_s, pag_w); + + _print_chunk(stderr, som_p, siz_w); + _free_words(som_p, pag_w, dir_p); + leq_w += siz_w; + } + } + } + } + } + } + } + + if ( leq_w ) { + u3a_print_memory(stderr, "palloc: sweep: leaked", leq_w); + // u3_assert(0); + } + + if ( u3C.wag_w & u3o_verbose ) { + u3a_print_memory(stderr, "palloc: off-heap: used", u3a_Mark.len_w); + u3a_print_memory(stderr, "palloc: off-heap: total", u3a_Mark.siz_w); + } + + u3a_mark_done(); // XX move + + return tot_w; +} + +static c3_w +_count_post(u3_post som_p, c3_y rat_y) +{ + c3_w pag_w = post_to_page(som_p); + c3_w blk_w = pag_w >> 5; + c3_w bit_w = pag_w & 31; + c3_w siz_w; + + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + u3_post dir_p = dir_u[pag_w]; + + // som_p is a one-or-more page allocation + // + if ( dir_p <= u3a_rest_pg ) { + if ( som_p & ((1U << u3a_page) - 1) ) { + fprintf(stderr, "palloc: mark: page not aligned som_p=0x%x (0x%x)\r\n", + som_p, som_p & ~(((1U << u3a_page) - 1))); + return 0; + } + + if ( u3a_free_pg == dir_p ) { + fprintf(stderr, "palloc: mark: free page som_p=0x%x pag_w=%u\r\n", + som_p, pag_w); + return 0; + } + else if ( u3a_head_pg != dir_p ) { + fprintf(stderr, "palloc: mark: rest page som_p=0x%x dir_p=0x%x\r\n", + som_p, dir_p); + return 0; + } + + switch ( rat_y ) { + case 0: { // not refcounted + u3_assert( (c3_ws)u3a_Mark.buf_w[pag_w] <= 0 ); + u3a_Mark.buf_w[pag_w] -= 1; + } break; + + case 1: { // refcounted + // NB: "premarked" + // + if ( 0x80000000 == u3a_Mark.buf_w[pag_w] ) { + u3a_Mark.buf_w[pag_w] = 1; + } + else { + u3_assert( (c3_ws)u3a_Mark.buf_w[pag_w] >= 0 ); + u3a_Mark.buf_w[pag_w] += 1; + } + } break; + + case 2: { // refcounted, pre-mark + if ( !u3a_Mark.buf_w[pag_w] ) { + u3a_Mark.buf_w[pag_w] = 0x80000000; + } + } break; + + default: u3_assert(0); + } + + // page(s) already marked + // + if ( u3a_Mark.bit_w[blk_w] & (1U << bit_w) ) { + return 0; + } + + u3a_Mark.bit_w[blk_w] |= 1U << bit_w; + + siz_w = _pages_size(pag_w); + siz_w <<= u3a_page; + + return siz_w; + } + // som_p is a chunk allocation + // + else { + u3a_crag *pag_u = u3to(u3a_crag, dir_p); + c3_g bit_g = pag_u->log_s - u3a_min_log; + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s; + c3_w *mar_w; + + if ( som_p & (hun_u->len_s - 1) ) { + fprintf(stderr, "palloc: count: bad alignment som_p=0x%x (0x%x) pag=0x%x (%u) len_s=%u\r\n", + som_p, som_p & ~((1U << u3a_page) - 1), + dir_p, pag_u->pag_w, hun_u->len_s); + return 0; + } + + if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) { + fprintf(stderr, "palloc: count: words free som_p=0x%x pag=0x%x (%u) len=%u\r\n", + som_p, dir_p, pag_u->pag_w, hun_u->len_s); + return 0; + } + + // page is marked + // + if ( u3a_Mark.bit_w[blk_w] & (1U << bit_w) ) { + mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w]; + siz_w = (!mar_w[pos_w]) ? hun_u->len_s : 0; + } + // page is unmarked, allocate and initialize mark-array + // + else { + siz_w = hun_u->len_s; + mar_w = u3a_mark_alloc(hun_u->tot_s); + u3a_Mark.buf_w[pag_w] = mar_w - u3a_Mark.buf_w; + memset(mar_w, 0, (c3_z)hun_u->tot_s << 2); + + // mark page metadata + // + if ( !hun_u->hun_s ) { + u3a_Mark.wee_w[bit_g] += _count_post(dir_p, 0); + mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w]; + } + else { + memset(mar_w, 0xff, (c3_z)hun_u->hun_s << 2); + u3a_Mark.wee_w[bit_g] += (c3_w)hun_u->hun_s << pag_u->log_s; + } + + u3a_Mark.bit_w[blk_w] |= 1U << bit_w; + } + + switch ( rat_y ) { + case 0: { // not refcounted + u3_assert( (c3_ws)mar_w[pos_w] <= 0 ); + mar_w[pos_w] -= 1; + } break; + + case 1: { // refcounted + // NB: "premarked" + // + if ( 0x80000000 == mar_w[pos_w] ) { + mar_w[pos_w] = 1; + } + else { + u3_assert( (c3_ws)mar_w[pos_w] >= 0 ); + mar_w[pos_w] += 1; + } + } break; + + case 2: { // refcounted, pre-mark + if ( !mar_w[pos_w] ) { + mar_w[pos_w] = 0x80000000; + } + } break; + + default: u3_assert(0); + } + + return siz_w; + } +} + +static c3_w +_sweep_counts(void) +{ + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w pag_w, blk_w, bit_w, siz_w, weq_w = 0, leq_w = 0, tot_w = 0; + u3_post dir_p, som_p; + c3_w *use_w; + + // unlink leaked whole chunk-pages + // (we do this first so we won't need to dereference the metadata) + // + { + u3a_crag *pag_u; + u3_post *bit_p; + c3_g bit_g; + + for ( bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) { + bit_p = &(HEAP.wee_p[bit_g]); + + while ( *bit_p ) { + pag_u = u3to(u3a_crag, *bit_p); + pag_w = pag_u->pag_w; + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + + if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) { + *bit_p = pag_u->nex_p; + } + else { + bit_p = &(pag_u->nex_p); + } + } + } + } + + for ( pag_w = 0; pag_w < HEAP.len_w; pag_w++ ) { + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + dir_p = dir_u[pag_w]; + + if ( u3a_head_pg == dir_p ) { + som_p = page_to_post(pag_w); + + if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) { + siz_w = _free_pages(som_p, pag_w, dir_p); + if ( 1 == siz_w ) { + fprintf(stderr, "palloc: leaked page %u (0x%x)\r\n", pag_w, page_to_post(pag_w)); + } + else { + fprintf(stderr, "palloc: leaked pages %u-%u (0x%x)\r\n", + pag_w, pag_w + siz_w - 1, page_to_post(pag_w)); + } + leq_w += siz_w << u3a_page; + } + else { + siz_w = _pages_size(pag_w); + + if ( (c3_ws)u3a_Mark.buf_w[pag_w] > 0 ) { + use_w = u3to(c3_w, som_p); + + if ( *use_w != u3a_Mark.buf_w[pag_w] ) { + fprintf(stderr, "weak: 0x%x have %u need %u\r\n", som_p, *use_w, u3a_Mark.buf_w[pag_w]); + *use_w = u3a_Mark.buf_w[pag_w]; + weq_w += siz_w << u3a_page;; + } + else { + tot_w += siz_w << u3a_page; + } + } + else if ( 0x80000000 == u3a_Mark.buf_w[pag_w] ) { + fprintf(stderr, "sweep: error: premarked %u pages at 0x%x\r\n", + siz_w, som_p); + u3_assert(0); + } + else { + tot_w += siz_w << u3a_page; + } + } + } + else if ( u3a_rest_pg < dir_p ) { + // entire chunk page is unmarked + // + if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) { + fprintf(stderr, "palloc: leaked chunk page %u\r\n", pag_w); + (void)_free_pages(page_to_post(pag_w), pag_w, u3a_head_pg); + leq_w += 1U << u3a_page; + } + else { + u3a_crag *pag_u = u3to(u3a_crag, dir_p); + c3_g bit_g = pag_u->log_s - u3a_min_log; + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + u3_post bas_p = page_to_post(pag_u->pag_w); + c3_w *mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w]; + c3_w pos_w; + + siz_w = hun_u->len_s; + + // NB: since at least one chunk is marked, + // _free_words() will never free [pag_u] + // + for ( c3_s i_s = 0; i_s < hun_u->tot_s; i_s++ ) { + pos_w = i_s; + blk_w = i_s >> 5; + bit_w = i_s & 31; + som_p = bas_p + ((c3_w)i_s << pag_u->log_s); + + if ( !(pag_u->map_w[blk_w] & (1U << bit_w)) ) { + if ( mar_w[pos_w] ) { + if ( (c3_ws)mar_w[pos_w] > 0 ) { + use_w = u3to(c3_w, som_p); + + if ( *use_w != mar_w[pos_w] ) { + fprintf(stderr, "weak: 0x%x have %u need %u\r\n", som_p, *use_w, mar_w[pos_w]); + _print_chunk(stderr, som_p, siz_w); + *use_w = mar_w[pos_w]; + weq_w += siz_w; + } + else { + tot_w += siz_w; + } + } + else if ( 0x80000000 == mar_w[pos_w] ) { + fprintf(stderr, "sweep: error: premarked 0x%x (chunk %u in page %u)\r\n", + som_p, i_s, pag_w); + u3_assert(0); + } + else { + if ( (c3_ws)mar_w[pos_w] < -1 ) { + fprintf(stderr, "alias: 0x%x count %d\r\n", som_p, (c3_ws)mar_w[pos_w]); + } + tot_w += siz_w; + } + } + else { + fprintf(stderr, "palloc: leak: 0x%x (chunk %u in page %u)\r\n", som_p, i_s, pag_w); + + _print_chunk(stderr, som_p, siz_w); + _free_words(som_p, pag_w, dir_p); + leq_w += siz_w; + } + } + } + } + } + } + + if ( leq_w ) { + u3a_print_memory(stderr, "palloc: sweep: leaked", leq_w); + // u3_assert(0); + } + if ( weq_w ) { + u3a_print_memory(stderr, "palloc: sweep: weaked", weq_w); + // u3_assert(0); + } + + if ( u3C.wag_w & u3o_verbose ) { + u3a_print_memory(stderr, "palloc: off-heap: used", u3a_Mark.len_w); + u3a_print_memory(stderr, "palloc: off-heap: total", u3a_Mark.siz_w); + } + + u3a_mark_done(); // XX move + + return tot_w; +} + +typedef struct { + u3_post dir_p; + c3_s log_s; // log2(len) + struct { + c3_w pag_w; // previous page in class (original number) + c3_s fre_s; // previous hunks available + c3_s pos_s; // previous hunks used + } pre_u; + c3_w mar_w[0]; +} _ca_prag; + +typedef struct { + u3_post dir_p; + c3_s log_s; + c3_w mar_w[0]; +} _ca_frag; + +// adapted from https://stackoverflow.com/a/27663998 and +// https://gist.github.com/ideasman42/5921b0edfc6aa41a9ce0 +// +static u3p(u3a_crag) +_sort_crag(u3p(u3a_crag) hed_p) +{ + c3_w bon_w, biz_w = 1; // block count, size + u3p(u3a_crag) s_p, l_p, r_p, *tal_p; + c3_w l_w, r_w; + c3_t l_t, r_t; + + do { + l_p = r_p = hed_p; + + hed_p = 0; + tal_p = &hed_p; + bon_w = 0; + + while ( l_p ) { + r_w = biz_w; + + bon_w++; + for ( l_w = 0; (l_w < biz_w) && r_p; l_w++) { + r_p = u3to(u3a_crag, r_p)->nex_p; + } + + l_t = (0 == l_w); + r_t = (0 == r_w) || !r_p; + + while ( !l_t || !r_t ) { + if ( r_t || (!l_t && (u3to(u3a_crag, l_p)->pag_w < u3to(u3a_crag, r_p)->pag_w)) ) { + s_p = l_p; + l_p = u3to(u3a_crag, l_p)->nex_p; + l_w--; + l_t = (0 == l_w); + } + else { + s_p = r_p; + r_p = u3to(u3a_crag, r_p)->nex_p; + r_w--; + r_t = (0 == r_w) || !r_p; + } + + *tal_p = s_p; + tal_p = &(u3to(u3a_crag, s_p)->nex_p); + } + + l_p = r_p; + } + + *tal_p = 0; + biz_w <<= 1; + } + while ( bon_w > 1 ); + + return hed_p; +} + +static void +_pack_seek_hunks(void) +{ + const u3a_hunk_dose *hun_u; + u3_post dir_p, nex_p, fre_p; + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w len_w, sum_w, i_w, *hap_w, *hum_w; + c3_g bit_g = u3a_crag_no; + u3a_crag *pag_u; + _ca_prag *rag_u; + + struct { + c3_w pag_w; // previous page in class (original number) + c3_s fre_s; // previous hunks available + c3_s pos_s; // previous hunks used + u3_post dir_p; + } pre_u; + + while ( bit_g-- ) { + if ( !HEAP.wee_p[bit_g] ) { + continue; + } + + // XX investigate, should only be required on inner roads + // + HEAP.wee_p[bit_g] = _sort_crag(HEAP.wee_p[bit_g]); + dir_p = HEAP.wee_p[bit_g]; + hun_u = &(u3a_Hunk[bit_g]); + memset(&pre_u, 0, sizeof(pre_u)); + + len_w = c3_wiseof(_ca_prag) + (3 * hun_u->map_s); + + while ( dir_p ) { + pag_u = u3to(u3a_crag, dir_p); + nex_p = pag_u->nex_p; + pag_u->nex_p = 0; + + u3_assert( (pre_u.pag_w < pag_u->pag_w) + || (!pre_u.pag_w && !pag_u->pag_w) ); + + rag_u = u3a_pack_alloc(len_w); + hap_w = &(rag_u->mar_w[hun_u->map_s]); + hum_w = &(hap_w[hun_u->map_s]); + rag_u->log_s = hun_u->log_s; + rag_u->pre_u.pag_w = pre_u.pag_w; + rag_u->pre_u.fre_s = pre_u.fre_s; + rag_u->pre_u.pos_s = pre_u.pos_s; + + memset(rag_u->mar_w, 0, hun_u->map_s << 2); + + for ( i_w = 0; i_w < hun_u->map_s; i_w++ ) { + hap_w[i_w] = ~(pag_u->map_w[i_w]); + } + + if ( hun_u->tot_s < 32 ) { + hap_w[0] &= (1U << hun_u->tot_s) - 1; + } + + sum_w = 0; + for ( i_w = 0; i_w < hun_u->map_s; i_w++ ) { + hum_w[i_w] = sum_w; + sum_w += c3_pc_w(hap_w[i_w]); + } + + u3a_Gack.buf_w[pag_u->pag_w] = ((c3_w*)rag_u - u3a_Gack.buf_w) | (1U << 31); + + c3_s pos_s = hun_u->ful_s - pag_u->fre_s; + + u3_assert( (pos_s + hun_u->hun_s) == sum_w ); + + // there is a previous page, and it will be full + // + if ( (pos_s == pre_u.fre_s) + || (pre_u.dir_p && (pos_s > pre_u.fre_s)) ) + { + u3a_crag *peg_u = u3to(u3a_crag, pre_u.dir_p); + memset(peg_u->map_w, 0, hun_u->map_s << 2); + peg_u->fre_s = 0; + } + + // current page will be empty + // + if ( pos_s <= pre_u.fre_s ) { + rag_u->dir_p = 0; + dir_u[pag_u->pag_w] = u3a_free_pg; + fre_p = hun_u->hun_s ? 0 : dir_p; + } + else { + fre_p = 0; + } + + // previous page is the same + // + if ( pos_s < pre_u.fre_s ) { + pre_u.fre_s -= pos_s; + pre_u.pos_s += pos_s; + } + // current becomes previous + // + else if ( pos_s > pre_u.fre_s ) { + rag_u->dir_p = dir_p; + pos_s -= pre_u.fre_s; + pre_u.fre_s += pag_u->fre_s; + pre_u.pag_w = pag_u->pag_w; + pre_u.pos_s = pos_s; + pre_u.dir_p = dir_p; + } + // no previous page + // + else { + memset(&pre_u, 0, sizeof(pre_u)); + } + + if ( fre_p ) { + _ifree(fre_p); + } + + dir_p = nex_p; + } + + HEAP.wee_p[bit_g] = pre_u.dir_p; + + if ( pre_u.dir_p ) { + u3a_crag *peg_u = u3to(u3a_crag, pre_u.dir_p); + c3_s pos_s = pre_u.pos_s + hun_u->hun_s; + c3_s max_s = pos_s >> 5; + + memset(peg_u->map_w, 0, max_s << 2); + peg_u->map_w[max_s++] = ~0U << (pos_s & 31); + memset(&(peg_u->map_w[max_s]), 0xff, (hun_u->map_s - max_s) << 2); + + peg_u->fre_s = pre_u.fre_s; + } + } +} + +static void +_pack_seek(void) +{ + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + c3_w blk_w, bit_w, fre_w = 0; + u3_post dir_p; + + { + u3_post fre_p; + u3a_dell *fre_u; + + while ( (fre_p = HEAP.fre_p) ) { + fre_u = u3to(u3a_dell, fre_p); + HEAP.fre_p = fre_u->nex_p; + _ifree(fre_p); + } + } + + _pack_seek_hunks(); + + for ( c3_w pag_w = 0; pag_w < HEAP.len_w; pag_w++ ) { + if ( u3a_free_pg == (dir_p = dir_u[pag_w]) ) { + fre_w++; + continue; + } + + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + u3a_Gack.pap_w[blk_w] |= 1U << bit_w; + + if ( u3a_rest_pg >= dir_p ) { + u3a_Gack.buf_w[pag_w] = dir_p; + } + // chunk page, not processed above (ie, full) + // + else if ( !u3a_Gack.buf_w[pag_w] ) { + u3a_crag *pag_u = u3to(u3a_crag, dir_p); + c3_g bit_g = pag_u->log_s - u3a_min_log; + const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]); + + _ca_frag *fag_u = u3a_pack_alloc(c3_wiseof(_ca_frag) + hun_u->map_s); + u3a_Gack.buf_w[pag_w] = (c3_w*)fag_u - u3a_Gack.buf_w; + + fag_u->dir_p = dir_p; + fag_u->log_s = pag_u->log_s; + memset(fag_u->mar_w, 0, (c3_z)hun_u->map_s << 2); + } + } + + // shrink page directory + // + { + c3_w old_w = HEAP.siz_w >> u3a_page; + c3_w dif_w = (HEAP.siz_w - (HEAP.len_w - fre_w)) >> u3a_page; + c3_w pag_w = post_to_page(HEAP.pag_p); + c3_w gap_w; + + for ( c3_w i_w = 0; i_w < dif_w; i_w++ ) { + gap_w = pag_w + (HEAP.dir_ws * (old_w - i_w - 1)); + blk_w = gap_w >> 5; + bit_w = gap_w & 31; + u3a_Gack.buf_w[gap_w] = u3a_free_pg; + u3a_Gack.pap_w[blk_w] &= ~(1U << bit_w); + } + + HEAP.siz_w -= dif_w << u3a_page; + } + + // calculate cumulative sums of bitmap popcounts + // + { + c3_w sum_w = 0, max_w = (HEAP.len_w + 31) >> 5; + + for ( c3_w i_w = 0; i_w < max_w; i_w++ ) { + u3a_Gack.pum_w[i_w] = sum_w; + sum_w += c3_pc_w(u3a_Gack.pap_w[i_w]); + } + } +} + +static inline c3_w +_pack_relocate_page(c3_w pag_w) +{ + c3_w blk_w = pag_w >> 5; + c3_w bit_w = pag_w & 31; + c3_w top_w = u3a_Gack.pap_w[blk_w] & ((1U << bit_w) - 1); + c3_w new_w = u3a_Gack.pum_w[blk_w]; // XX blk_w - 1, since pum_w[0] is always 0? + + return new_w + c3_pc_w(top_w); +} + +static inline u3_post +_pack_relocate_hunk(_ca_prag *rag_u, c3_w pag_w, c3_w pos_w) +{ + const u3a_hunk_dose *hun_u = &(u3a_Hunk[rag_u->log_s - u3a_min_log]); + c3_w blk_w = pos_w >> 5; + c3_w bit_w = pos_w & 31; + c3_w *hap_w = &(rag_u->mar_w[hun_u->map_s]); + c3_w *hum_w = &(hap_w[hun_u->map_s]); + c3_w top_w = hap_w[blk_w] & ((1U << bit_w) - 1); + c3_w new_w = hum_w[blk_w]; // XX blk_w - 1, since hum_w[0] is always 0? + + new_w += c3_pc_w(top_w); + + if ( new_w >= hun_u->hun_s ) { + if ( new_w < (rag_u->pre_u.fre_s + hun_u->hun_s) ) { + pag_w = rag_u->pre_u.pag_w; + new_w += rag_u->pre_u.pos_s; + } + else { + new_w -= rag_u->pre_u.fre_s; + } + } + + { + u3_post out_p = page_to_post(_pack_relocate_page(pag_w)); + out_p += new_w << rag_u->log_s; + return out_p; + } +} + +static u3_post +_pack_relocate_mark(u3_post som_p, c3_t *fir_t) +{ + c3_w pag_w = post_to_page(som_p); + c3_w dir_w = u3a_Gack.buf_w[pag_w]; + u3_post out_p = 0; + c3_t out_t = 0; + c3_w blk_w, bit_w; + + u3_assert(som_p); + + // som_p is a one-or-more page allocation + // + if ( u3a_rest_pg >= dir_w ) { + // XX sanity + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + + if ( !(u3a_Gack.bit_w[blk_w] & (1U << bit_w)) ) { + u3a_Gack.bit_w[blk_w] |= (1U << bit_w); + out_t = 1; + } + + out_p = page_to_post(_pack_relocate_page(pag_w)); + } + // som_p is a chunk in a full page (map old pag_w to new) + // + else if ( !(dir_w >> 31) ) { + // XX sanity + _ca_frag *fag_u = (void*)(u3a_Gack.buf_w + dir_w); + c3_w rem_w = som_p & ((1U << u3a_page) - 1); + c3_w pos_w = rem_w >> fag_u->log_s; // XX c/b pos_s + + blk_w = pos_w >> 5; + bit_w = pos_w & 31; + + if ( !(fag_u->mar_w[blk_w] & (1U << bit_w)) ) { + fag_u->mar_w[blk_w] |= (1U << bit_w); + out_t = 1; + } + + out_p = page_to_post(_pack_relocate_page(pag_w)); + out_p += rem_w; + } + // som_p is a chunk in a partial page (map old pos_w to new) + // + else { + _ca_prag *rag_u = (void*)(u3a_Gack.buf_w + (dir_w & ((1U << 31) - 1))); + c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> rag_u->log_s; // XX c/b pos_s + + // XX sanity + // NB map inverted, free state updated + + blk_w = pos_w >> 5; + bit_w = pos_w & 31; + + if ( !(rag_u->mar_w[blk_w] & (1U << bit_w)) ) { + rag_u->mar_w[blk_w] |= (1U << bit_w); + out_t = 1; + } + + out_p = _pack_relocate_hunk(rag_u, pag_w, pos_w); + } + + *fir_t = out_t; + return out_p; +} + +static u3_post +_pack_relocate(u3_post som_p) +{ + c3_w pag_w = post_to_page(som_p); + c3_w dir_w = u3a_Gack.buf_w[pag_w]; + u3_post out_p; + + u3_assert(som_p); + + // som_p is a one-or-more page allocation + // + if ( u3a_rest_pg >= dir_w ) { + // XX sanity + out_p = page_to_post(_pack_relocate_page(pag_w)); + } + // som_p is a chunk in a full page (map old pag_w to new) + // + else if ( !(dir_w >> 31) ) { + // XX sanity + out_p = page_to_post(_pack_relocate_page(pag_w)); + out_p += som_p & ((1U << u3a_page) - 1); + } + // som_p is a chunk in a partial page (map old pos_w to new) + // + else { + _ca_prag *rag_u = (void*)(u3a_Gack.buf_w + (dir_w & ((1U << 31) - 1))); + c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> rag_u->log_s; // XX c/b pos_s + + // XX sanity + // NB map inverted, free state updated + + out_p = _pack_relocate_hunk(rag_u, pag_w, pos_w); + } + + return out_p; +} + +static void +_pack_relocate_heap(void) +{ + // this is possible if freeing unused u3a_crag's + // caused an entire hunk page to be free'd + // NB: this corrupts pre_p + // + if ( HEAP.fre_p ) { + u3a_dell *fre_u; + + if ( !HEAP.cac_p ) { + fre_u = u3to(u3a_dell, HEAP.fre_p); + HEAP.cac_p = HEAP.fre_p; + HEAP.fre_p = fre_u->nex_p; + } + + u3_post *ref_p = &(HEAP.fre_p); + + while ( *ref_p ) { + fre_u = u3to(u3a_dell, *ref_p); + *ref_p = _pack_relocate(*ref_p); + ref_p = &(fre_u->nex_p); + } + } + + HEAP.pag_p = _pack_relocate(HEAP.pag_p); + + if ( HEAP.cac_p ) { + HEAP.cac_p = _pack_relocate(HEAP.cac_p); + } + + for ( c3_g bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) { + if ( HEAP.wee_p[bit_g] ) { + HEAP.wee_p[bit_g] = _pack_relocate(HEAP.wee_p[bit_g]); + } + } + + for ( c3_w pag_w = 0; pag_w < HEAP.len_w; pag_w++ ) { + c3_w *wor_w, dir_w = u3a_Gack.buf_w[pag_w]; + + if ( u3a_rest_pg < dir_w ) { + dir_w &= (1U << 31) - 1; + wor_w = u3a_Gack.buf_w + dir_w; // (fag_u | rag_u)->dir_p + if ( *wor_w ) { + u3a_crag *pag_u = u3to(u3a_crag, *wor_w); + pag_u->pag_w = _pack_relocate_page(pag_u->pag_w); + *wor_w = _pack_relocate(*wor_w); + } + } + } +} + +static c3_i +_pack_move_chunks(c3_w pag_w, c3_w dir_w) +{ + _ca_prag *rag_u = (void*)(u3a_Gack.buf_w + dir_w); + const u3a_hunk_dose *hun_u = &(u3a_Hunk[rag_u->log_s - u3a_min_log]); + c3_w *hap_w = &(rag_u->mar_w[hun_u->map_s]); + c3_w off_w = 1U << rag_u->log_s; + c3_z len_i = off_w << 2; + c3_w *src_w, *dst_w, new_w; + c3_s max_s, fre_s, new_s, pos_s = hun_u->hun_s; + + src_w = u3to(c3_w, page_to_post(pag_w) + (pos_s << rag_u->log_s)); + + max_s = 1U << (u3a_page - rag_u->log_s); + + if ( rag_u->pre_u.pag_w ) { + new_w = _pack_relocate_page(rag_u->pre_u.pag_w); + new_s = hun_u->hun_s + rag_u->pre_u.pos_s; + fre_s = rag_u->pre_u.fre_s; + + dst_w = u3to(c3_w, page_to_post(new_w) + (new_s << rag_u->log_s)); + + // move up to [fre_s] chunks to (relocated) previous page + // + while ( (pos_s < max_s) && fre_s ) { + if ( hap_w[pos_s >> 5] & (1U << (pos_s & 31)) ) { + ASAN_UNPOISON_MEMORY_REGION(dst_w, len_i); + memcpy(dst_w, src_w, len_i); + fre_s--; + dst_w += off_w; + } + + pos_s++; + src_w += off_w; + } + + // advance src position past any free chunks + // + while ( (pos_s < max_s) ) { + if ( hap_w[pos_s >> 5] & (1U << (pos_s & 31)) ) { + break; + } + + pos_s++; + src_w += off_w; + } + + if ( pos_s == max_s ) { + return 0; + } + } + + new_w = _pack_relocate_page(pag_w); + new_s = hun_u->hun_s; + + // skip chunks that don't need to move + // (possible if a partial-chunk page is in the first + // contiguously used pages in the heap) + // + // XX unlikely() + // + if ( new_w == pag_w ) { + if ( new_s == pos_s ) { + while ( (pos_s < max_s) + && (hap_w[pos_s >> 5] & (1U << (pos_s & 31))) ) + { + pos_s++; + src_w += off_w; + } + + new_s = pos_s++; + src_w += off_w; + } + } + // relocate inline metadata + // + else if ( hun_u->hun_s ) { + c3_w* soc_w = u3to(c3_w, page_to_post(pag_w)); + c3_w* doc_w = u3to(c3_w, page_to_post(new_w)); + + ASAN_UNPOISON_MEMORY_REGION(doc_w, len_i * hun_u->hun_s); + memcpy(doc_w, soc_w, len_i * hun_u->hun_s); + + // XX bump pos_s/src_w if !pos_s ? + } + + u3_assert( (new_w < pag_w) || (new_s < pos_s) ); + + dst_w = u3to(c3_w, page_to_post(new_w) + (new_s << rag_u->log_s)); + + // move remaining chunks to relocated page + // + while ( pos_s < max_s ) { + if ( hap_w[pos_s >> 5] & (1U << (pos_s & 31)) ) { + ASAN_UNPOISON_MEMORY_REGION(dst_w, len_i); + memcpy(dst_w, src_w, len_i); + dst_w += off_w; + } + + pos_s++; + src_w += off_w; + } + + // XX assume(rag_u->dir_p) + // + u3a_Gack.buf_w[new_w] = rag_u->dir_p; + return 1; +} + +static void +_pack_move(void) +{ + c3_z len_i = 1U << (u3a_page + 2); + c3_ws off_ws = HEAP.dir_ws * (1U << u3a_page); + c3_w dir_w, new_w, pag_w = 0; + c3_w *src_w, *dst_w; + + // NB: these loops iterate over the temp page dir instead of + // the bitmap, as partial chunk pages can be marked free + // + + // skip pages that don't need to move, + // compacting partial chunk-pages in-place + // + while ( (pag_w < HEAP.len_w) && (dir_w = u3a_Gack.buf_w[pag_w]) ) { + if ( u3a_rest_pg < dir_w ) { + if ( !(dir_w >> 31) ) { + u3a_Gack.buf_w[pag_w] = u3a_Gack.buf_w[dir_w]; // NB: fag_u->dir_p + } + else if ( !_pack_move_chunks(pag_w, dir_w & ((1U << 31) - 1)) ) { + break; + } + } + + pag_w++; + } + + new_w = pag_w++; + dst_w = u3to(c3_w, page_to_post(new_w)); + src_w = u3to(c3_w, page_to_post(pag_w)); + + while( pag_w < HEAP.len_w ) { + // XX assume(new_w < pag_w) + // XX assume(new_w == _pack_relocate_page(pag_w)) + // XX assume(dst_w == u3to(c3_w, page_to_post(new_w))) + // XX assume(src_w == u3to(c3_w, page_to_post(pag_w))) + // + dir_w = u3a_Gack.buf_w[pag_w]; + + if ( u3a_free_pg != dir_w ) { + if ( (u3a_rest_pg >= dir_w) || !(dir_w >> 31) ) { + ASAN_UNPOISON_MEMORY_REGION(dst_w, len_i); + memcpy(dst_w, src_w, len_i); + u3a_Gack.buf_w[new_w] = (u3a_rest_pg >= dir_w) + ? dir_w + : u3a_Gack.buf_w[dir_w]; // NB: fag_u->dir_p + new_w++; + dst_w += off_ws; + } + else if ( _pack_move_chunks(pag_w, dir_w & ((1U << 31) - 1)) ) { + new_w++; + dst_w += off_ws; + } + } + + pag_w++; + src_w += off_ws; + fflush(stderr); // XX remove + } + + _poison_words(); + + { + u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p); + HEAP.len_w = new_w; + memcpy(dir_u, u3a_Gack.buf_w, new_w << 2); + memset(dir_u + new_w, 0, (HEAP.siz_w - new_w) << 2); + } + + u3a_print_memory(stderr, "palloc: off-heap: used", u3a_Gack.len_w); + u3a_print_memory(stderr, "palloc: off-heap: total", u3a_Gack.siz_w); + + { + u3a_dell *fre_u; + u3_post fre_p; + + while ( (fre_p = HEAP.fre_p) ) { + fre_u = u3to(u3a_dell, fre_p); + HEAP.fre_p = fre_u->nex_p; + _ifree(fre_p); + } + } +} diff --git a/vere/pkg/noun/palloc_tests.c b/vere/pkg/noun/palloc_tests.c new file mode 100644 index 0000000..b93f634 --- /dev/null +++ b/vere/pkg/noun/palloc_tests.c @@ -0,0 +1,91 @@ +/// @file + +#include "events.h" + +struct heap { + u3p(u3a_dell) fre_p; // free list + u3p(u3a_dell) erf_p; // free list + u3p(u3a_dell) cac_p; // cached pgfree struct + u3_post bot_p; // XX s/b rut_p + c3_ws dir_ws; // 1 || -1 (multiplicand for local offsets) + c3_ws off_ws; // 0 || -1 (word-offset for hat && rut) + c3_w siz_w; // directory size + c3_w len_w; // directory entries + u3p(u3a_crag*) pag_p; // directory + u3p(u3a_crag) wee_p[u3a_crag_no]; // chunk lists +}; + +struct heap hep_u; + +#define HEAP (hep_u) +#define BASE (hep_u.bot_p) + +#include "./palloc.c" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_init(1 << 22); + u3e_init(); + u3m_pave(c3y); +} + +static void +_test_print_chunks(void) +{ + u3a_hunk_dose *hun_u; + c3_g met_g; + c3_w hun_w; + + for ( c3_g bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) { + hun_u = &(u3a_Hunk[bit_g]); + met_g = (c3_g)c3_bits_word((c3_w)hun_u->siz_s - 1) - u3a_min_log; + hun_w = 1U + ((hun_u->siz_s - 1) >> hun_u->log_s); + + fprintf(stderr, "chunks: %s pginfo: bit=%u log=%u len=%u tot=%u, siz=%u, chunks=%u met=%u\n", + ( hun_u->hun_s ? "inline" : "malloc" ), bit_g, + hun_u->log_s, hun_u->len_s, hun_u->tot_s, hun_u->siz_s, hun_w, met_g); + } +} + +static void +_test_print_pages(c3_w max_w) +{ + u3_post pot_p; + c3_w i_w; + + hep_u.dir_ws = 1; + hep_u.off_ws = 0; + hep_u.bot_p = 0x1000; + + for ( i_w = 0; i_w < max_w; i_w++ ) { + pot_p = page_to_post(i_w); + fprintf(stderr, "north at bot=0x%x pag=%u == 0x%x == pag=%u\n", + hep_u.bot_p, i_w, pot_p, post_to_page(pot_p)); + } + + + hep_u.dir_ws = -1; + hep_u.off_ws = -1; + hep_u.bot_p += max_w << u3a_page; + + for ( i_w = 0; i_w < max_w; i_w++ ) { + pot_p = page_to_post(i_w); + fprintf(stderr, "south at bot=0x%x pag=%u == 0x%x == pag=%u\n", + hep_u.bot_p, i_w, pot_p, post_to_page(pot_p)); + } +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + _test_print_chunks(); + _test_print_pages(10); + return 0; +} diff --git a/vere/pkg/noun/platform/darwin/rsignal.h b/vere/pkg/noun/platform/darwin/rsignal.h new file mode 100644 index 0000000..a14670e --- /dev/null +++ b/vere/pkg/noun/platform/darwin/rsignal.h @@ -0,0 +1,13 @@ +/// @file + +#ifndef NOUN_PLATFORM_DARWIN_RSIGNAL_H +#define NOUN_PLATFORM_DARWIN_RSIGNAL_H + +#define rsignal_jmpbuf sigjmp_buf +#define rsignal_setjmp(buf) sigsetjmp((buf), 1) +#define rsignal_longjmp siglongjmp +#define rsignal_install_handler signal +#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN) +#define rsignal_setitimer setitimer + +#endif /* ifndef NOUN_PLATFORM_DARWIN_RSIGNAL_H */ diff --git a/vere/pkg/noun/platform/linux/rsignal.h b/vere/pkg/noun/platform/linux/rsignal.h new file mode 100644 index 0000000..9c55cee --- /dev/null +++ b/vere/pkg/noun/platform/linux/rsignal.h @@ -0,0 +1,13 @@ +/// @file + +#ifndef NOUN_PLATFORM_LINUX_RSIGNAL_H +#define NOUN_PLATFORM_LINUX_RSIGNAL_H + +#define rsignal_jmpbuf sigjmp_buf +#define rsignal_setjmp(buf) sigsetjmp((buf), 1) +#define rsignal_longjmp siglongjmp +#define rsignal_install_handler signal +#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN) +#define rsignal_setitimer setitimer + +#endif /* ifndef NOUN_PLATFORM_LINUX_RSIGNAL_H */ diff --git a/vere/pkg/noun/platform/windows/rsignal.c b/vere/pkg/noun/platform/windows/rsignal.c new file mode 100644 index 0000000..d927835 --- /dev/null +++ b/vere/pkg/noun/platform/windows/rsignal.c @@ -0,0 +1,167 @@ +#include "noun.h" +#include "rsignal.h" +#include <windows.h> + +int err_win_to_posix(DWORD winerr); + +// The current implementation of rsignal_ is single-threaded, +// but it can be extended to multi-threaded by replacing these +// static variables with a thread id-based hash map. +// +static __p_sig_fn_t _fns[SIG_COUNT]; +static volatile DWORD _tid; +static HANDLE _hvt; + +void rsignal_install_handler(int sig, __p_sig_fn_t fn) +{ + if (sig < 0 || sig >= SIG_COUNT) + return; + + DWORD newtid = GetCurrentThreadId(); + DWORD oldtid = InterlockedExchange((volatile LONG*)&_tid, newtid); + if (oldtid != 0 && oldtid != newtid) { + fprintf(stderr, "\r\nrsignal_install_handler: %lu -> %lu\r\n", oldtid, newtid); + return; + } + + __p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], fn); + if (fn != 0 && oldfn != 0 && oldfn != fn) { + fprintf(stderr, "\r\nrsignal_install_handler: %p -> %p\r\n", oldfn, fn); + } +} + +void rsignal_deinstall_handler(int sig) +{ + rsignal_install_handler(sig, 0); +} + +void rsignal_raise(int sig) +{ + if (sig < 0 || sig >= SIG_COUNT) + return; + + __p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], 0); + if (oldfn == 0) + return; + + if (_tid == GetCurrentThreadId()) { + oldfn(sig); + return; + } + + HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, _tid); + if (!hthread) { + fprintf(stderr, "\r\nrsignal_raise: OpenThread(%lu): %lu\r\n", _tid, GetLastError()); + return; + } + + if (SuspendThread(hthread) < 0) { + fprintf(stderr, "\r\nrsignal_raise: SuspendThread(%lu): %lu\r\n", _tid, GetLastError()); + goto cleanup; + } + + oldfn(sig); + + if (!ResumeThread(hthread)) { + fprintf(stderr, "\r\nrsignal_raise: ResumeThread(%lu): %lu\r\n", _tid, GetLastError()); + + // abort because the main thread is stuck + abort(); + } + +cleanup: + CloseHandle(hthread); +} + +static void _rsignal_vt_cb(PVOID param, BOOLEAN timedOut) +{ + rsignal_raise(SIGVTALRM); +} + +int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out) +{ + if (in == 0) { + errno = EFAULT; + return -1; + } + + if (type != ITIMER_VIRTUAL || out != 0) { + errno = ENOTSUP; + return -1; + } + + if (_hvt != NULL) { + DeleteTimerQueueTimer(NULL, _hvt, NULL); + _hvt = NULL; + } + + if (timerisset(&in->it_value) && !CreateTimerQueueTimer(&_hvt, NULL, _rsignal_vt_cb, NULL, + in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000, + in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000, 0)) + { + errno = err_win_to_posix(GetLastError()); + return -1; + } else { + return 0; + } +} + +// direct import from ntdll.dll +extern DWORD64 __imp_KiUserExceptionDispatcher; + +static void _rsignal_longjmp(intptr_t* builtin_jb) +{ + __builtin_longjmp((void**)builtin_jb, 1); +} + +void rsignal_post_longjmp(DWORD tid, intptr_t* builtin_jb) +{ + HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid); + if (!hthread) { + fprintf(stderr, "\r\nrsignal: OpenThread(%lu): %lu\r\n", tid, GetLastError()); + return; + } + + CONTEXT context; + context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext(hthread, &context)) { + fprintf(stderr, "\r\nrsignal: GetThreadContext(%lu): %lu\r\n", tid, GetLastError()); + goto cleanup; + } + + // see if the thread is currently handling a structured exception + // if so, let the handler (usually the libsigsegv handler) finish + // and set up the the signal to run at the exception resume point + // otherwise, passing a parameter to fn is completely unreliable + // + DWORD64 kibase; + PRUNTIME_FUNCTION ki = RtlLookupFunctionEntry(__imp_KiUserExceptionDispatcher, &kibase, NULL); + CONTEXT c = context; + while (1) + { + DWORD64 base, frame; + PRUNTIME_FUNCTION f = RtlLookupFunctionEntry(c.Rip, &base, NULL); + if (!f) break; + if (f == ki) + { + // KiUserExceptionDispatcher has a "bare" frame + // with $rsp pointing to the CONTEXT structure + // + ((PCONTEXT)c.Rsp)->Rip = (DWORD64)_rsignal_longjmp; + ((PCONTEXT)c.Rsp)->Rcx = (DWORD64)builtin_jb; + goto cleanup; + } + PVOID handler_data; + RtlVirtualUnwind(0, base, c.Rip, f, &c, &handler_data, &frame, NULL); + } + + context.Rip = (DWORD64)_rsignal_longjmp; + context.Rcx = (DWORD64)builtin_jb; + if (!SetThreadContext(hthread, &context)) { + fprintf(stderr, "\r\nrsignal: SetThreadContext(%lu): %lu\r\n", tid, GetLastError()); + goto cleanup; + } + +cleanup: + CloseHandle(hthread); +} diff --git a/vere/pkg/noun/platform/windows/rsignal.h b/vere/pkg/noun/platform/windows/rsignal.h new file mode 100644 index 0000000..998652c --- /dev/null +++ b/vere/pkg/noun/platform/windows/rsignal.h @@ -0,0 +1,21 @@ +#include "windows.h" + +#ifndef _RSIGNAL_H +#define _RSIGNAL_H + +#define rsignal_setjmp setjmp +#define rsignal_longjmp longjmp + +void rsignal_raise(int sig); +void rsignal_install_handler(int sig, __p_sig_fn_t fn); +void rsignal_deinstall_handler(int sig); +void rsignal_post_longjmp(unsigned long tid, intptr_t* builtin_jb); + +#define ITIMER_VIRTUAL 1 +struct itimerval { + struct timeval it_value, it_interval; +}; + +int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out); + +#endif//_RSIGNAL_H diff --git a/vere/pkg/noun/platform/windows/veh_handler.c b/vere/pkg/noun/platform/windows/veh_handler.c new file mode 100644 index 0000000..d2a035c --- /dev/null +++ b/vere/pkg/noun/platform/windows/veh_handler.c @@ -0,0 +1,26 @@ +#include "noun.h" +#include "rsignal.h" + +c3_i +u3m_fault(void* adr_v, c3_i ser_i); + +/* _windows_exception_filter: replaces libsigsegv on windows + using vectored exception handling + */ +LONG WINAPI +_windows_exception_filter(struct _EXCEPTION_POINTERS *ExceptionInfo) +{ + EXCEPTION_RECORD ExceptionRecord = *ExceptionInfo->ExceptionRecord; + if (ExceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION && + ExceptionRecord.ExceptionInformation[0] == 1 && + u3m_fault((void*)ExceptionRecord.ExceptionInformation[1], 1)) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + + if (ExceptionRecord.ExceptionCode == EXCEPTION_STACK_OVERFLOW) { + rsignal_raise(SIGSTK); + } + + return EXCEPTION_CONTINUE_SEARCH; +} diff --git a/vere/pkg/noun/platform/windows/veh_handler.h b/vere/pkg/noun/platform/windows/veh_handler.h new file mode 100644 index 0000000..dfa4b69 --- /dev/null +++ b/vere/pkg/noun/platform/windows/veh_handler.h @@ -0,0 +1 @@ +LONG WINAPI _windows_exception_filter(struct _EXCEPTION_POINTERS *ExceptionInfo); diff --git a/vere/pkg/noun/retrieve.c b/vere/pkg/noun/retrieve.c new file mode 100644 index 0000000..3d2e182 --- /dev/null +++ b/vere/pkg/noun/retrieve.c @@ -0,0 +1,1943 @@ +/// @file + +#include "retrieve.h" + +#include "allocate.h" +#include "hashtable.h" +#include "imprison.h" +#include "murmur3.h" +#include "trace.h" +#include "xtract.h" + + +// declarations of inline functions +// +c3_o +u3r_cell(u3_noun a, u3_noun* b, u3_noun* c); +c3_o +u3r_trel(u3_noun a, u3_noun* b, u3_noun* c, u3_noun* d); +c3_o +u3r_qual(u3_noun a, + u3_noun* b, + u3_noun* c, + u3_noun* d, + u3_noun* e); +c3_o +u3r_quil(u3_noun a, + u3_noun* b, + u3_noun* c, + u3_noun* d, + u3_noun* e, + u3_noun* f); +c3_o +u3r_hext(u3_noun a, + u3_noun* b, + u3_noun* c, + u3_noun* d, + u3_noun* e, + u3_noun* f, + u3_noun* g); + +/* _frag_word(): fast fragment/branch prediction for top word. +*/ +static u3_weak +_frag_word(c3_w a_w, u3_noun b) +{ + u3_assert(0 != a_w); + + { + c3_w dep_w = u3x_dep(a_w); + + while ( dep_w ) { + if ( c3n == u3a_is_cell(b) ) { + return u3_none; + } + else { + u3a_cell* b_u = u3a_to_ptr(b); + + b = *(((u3_noun*)&(b_u->hed)) + (1 & (a_w >> (dep_w - 1)))); + dep_w--; + } + } + return b; + } +} + +/* _frag_deep(): fast fragment/branch for deep words. +*/ +static u3_weak +_frag_deep(c3_w a_w, u3_noun b) +{ + c3_w dep_w = 32; + + while ( dep_w ) { + if ( c3n == u3a_is_cell(b) ) { + return u3_none; + } + else { + u3a_cell* b_u = u3a_to_ptr(b); + + b = *(((u3_noun*)&(b_u->hed)) + (1 & (a_w >> (dep_w - 1)))); + dep_w--; + } + } + return b; +} + +/* u3r_at(): +** +** Return fragment (a) of (b), or u3_none if not applicable. +*/ +u3_weak +u3r_at(u3_atom a, u3_noun b) +{ + u3_assert(u3_none != a); + u3_assert(u3_none != b); + + u3t_on(far_o); + + if ( 0 == a ) { + u3t_off(far_o); + return u3_none; + } + + if ( _(u3a_is_cat(a)) ) { + u3t_off(far_o); + return _frag_word(a, b); + } + else { + if ( !_(u3a_is_pug(a)) ) { + u3t_off(far_o); + return u3_none; + } + else { + u3a_atom* a_u = u3a_to_ptr(a); + c3_w len_w = a_u->len_w; + + b = _frag_word(a_u->buf_w[len_w - 1], b); + len_w -= 1; + + if ( u3_none == b ) { + u3t_off(far_o); + return b; + } + + while ( len_w ) { + b = _frag_deep(a_u->buf_w[len_w - 1], b); + + if ( u3_none == b ) { + u3t_off(far_o); + + return b; + } else { + len_w--; + } + } + u3t_off(far_o); + + return b; + } + } +} + +/* u3r_mean(): +** +** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates. +** Axes must be sorted in tree order. +*/ + struct _mean_pair { + c3_w axe_w; + u3_noun* som; + }; + + static c3_w + _mean_cut(c3_w len_w, + struct _mean_pair* prs_m) + { + c3_w i_w, cut_t, cut_w; + + cut_t = 0; + cut_w = 0; + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w axe_w = prs_m[i_w].axe_w; + + if ( (cut_t == 0) && (3 == u3x_cap(axe_w)) ) { + cut_t = 1; + cut_w = i_w; + } + prs_m[i_w].axe_w = u3x_mas(axe_w); + } + return cut_t ? cut_w : i_w; + } + + static c3_o + _mean_extract(u3_noun som, + c3_w len_w, + struct _mean_pair* prs_m) + { + if ( len_w == 0 ) { + return c3y; + } + else if ( (len_w == 1) && (1 == prs_m[0].axe_w) ) { + *prs_m->som = som; + return c3y; + } + else { + if ( c3n == u3a_is_cell(som) ) { + return c3n; + } else { + c3_w cut_w = _mean_cut(len_w, prs_m); + + return c3a + (_mean_extract(u3a_h(som), cut_w, prs_m), + _mean_extract(u3a_t(som), (len_w - cut_w), (prs_m + cut_w))); + } + } + } + +c3_o +u3r_vmean(u3_noun som, va_list ap) +{ + va_list aq; + c3_w len_w; + struct _mean_pair* prs_m; + + u3_assert(u3_none != som); + + // traverse copy of va_list for alloca + // + va_copy(aq, ap); + len_w = 0; + + while ( 1 ) { + if ( 0 == va_arg(aq, c3_w) ) { + break; + } + va_arg(aq, u3_noun*); + len_w++; + } + + va_end(aq); + + u3_assert( 0 != len_w ); + prs_m = alloca(len_w * sizeof(struct _mean_pair)); + + // traverse va_list and extract args + // + { + c3_w i_w; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + prs_m[i_w].axe_w = va_arg(ap, c3_w); + prs_m[i_w].som = va_arg(ap, u3_noun*); + } + + va_end(ap); + } + + // extract axis from som + // + return _mean_extract(som, len_w, prs_m); +} + +c3_o +u3r_mean(u3_noun som, ...) +{ + c3_o ret_o; + va_list ap; + + va_start(ap, som); + ret_o = u3r_vmean(som, ap); + va_end(ap); + + return ret_o; +} + +// stack frame for tracking noun comparison and unification +// +// we always compare arbitrary nouns in a none-frame. +// when we compare two cells, we change the none-frame to a head-frame +// and push a new none-frame for their heads. if the heads are equal, +// we get the cells from the head-frame and unify their head pointers. +// then, we convert the head-frame to a tail-frame and repeat with +// the tails, mutatis mutandis. +// +// in Hoon, this structure would be: +// +// $% [%none a=* b=*] +// [%head a=^ b=^] +// [%tail a=^ b=^] +// == +// +#define SING_NONE 0 +#define SING_HEAD 1 +#define SING_TAIL 2 + +typedef struct { + c3_y sat_y; + u3_noun a; + u3_noun b; +} eqframe; + +/* _cr_sing_push(): push a new stack frame, initialized as SING_NONE. +*/ +static inline eqframe* +_cr_sing_push(u3a_pile* pil_u, u3_noun a, u3_noun b) +{ + eqframe* fam_u = u3a_push(pil_u); + fam_u->sat_y = SING_NONE; + fam_u->a = a; + fam_u->b = b; + return fam_u; +} + +/* _cr_sing_mug(): short-circuit comparison if mugs are present and not equal. +*/ +static inline c3_o +_cr_sing_mug(u3a_noun* a_u, u3a_noun* b_u) +{ + // XX add debug assertions that both mugs are 31-bit + // (ie, not u3a_take() relocation references) + // + if ( a_u->mug_w && b_u->mug_w && (a_u->mug_w != b_u->mug_w) ) { + return c3n; + } + + return c3y; +} + +/* _cr_sing_atom(): check if atom [a] is indirect and equal to noun [b] +*/ +static inline c3_o +_cr_sing_atom(u3_atom a, u3_noun b) +{ + // [a] is an atom, not pointer-equal to noun [b]. + // if they're not both indirect atoms, they can't be equal. + // + if ( (c3n == u3a_is_pug(a)) + || (c3n == u3a_is_pug(b)) ) + { + return c3n; + } + else { + u3a_atom* a_u = u3a_to_ptr(a); + u3a_atom* b_u = u3a_to_ptr(b); + + // [a] and [b] are not equal if their mugs are present and not equal. + // + if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) { + return c3n; + } + else { + c3_w a_w = a_u->len_w; + c3_w b_w = b_u->len_w; + + // [a] and [b] are not equal if their lengths are not equal + // + if ( a_w != b_w ) { + return c3n; + } + else { + c3_w i_w; + + // XX memcmp + // + for ( i_w = 0; i_w < a_w; i_w++ ) { + if ( a_u->buf_w[i_w] != b_u->buf_w[i_w] ) { + return c3n; + } + } + } + } + } + + return c3y; +} + +/* _cr_sing_cape_test(): check for previous comparison of [a] and [b]. +*/ +static inline c3_o +_cr_sing_cape_test(u3p(u3h_root) har_p, u3_noun a, u3_noun b) +{ + u3_noun key = u3nc(u3a_to_off(a) >> u3a_vits, + u3a_to_off(b) >> u3a_vits); + u3_noun val; + + u3t_off(euq_o); + val = u3h_git(har_p, key); + u3t_on(euq_o); + + u3z(key); + return ( u3_none != val ) ? c3y : c3n; +} + +/* _cr_sing_cape_keep(): store [a] and [b] to short-circuit subsequent tests. +** NB: [a] and [b] (which MUST be equal nouns) +** are cons'd as offsets (direct atoms) to avoid refcount churn. +*/ +static inline void +_cr_sing_cape_keep(u3p(u3h_root) har_p, u3_noun a, u3_noun b) +{ + // only store if [a] and [b] are copies of each other + // + if ( a != b ) { + c3_dessert( (c3n == u3a_is_cat(a)) && (c3n == u3a_is_cat(b)) ); + + u3_noun key = u3nc(u3a_to_off(a) >> u3a_vits, + u3a_to_off(b) >> u3a_vits); + u3t_off(euq_o); + u3h_put(har_p, key, c3y); + u3t_on(euq_o); + u3z(key); + } +} + +static inline __attribute__((always_inline)) void +_cr_sing_wed(u3_noun *restrict a, u3_noun *restrict b) +{ + if ( *a != *b ) { + u3a_wed(a, b); + } +} + +/* _cr_sing_cape(): unifying equality with comparison deduplication + * (tightly coupled to _cr_sing) + */ +static c3_o +_cr_sing_cape(u3a_pile* pil_u, u3p(u3h_root) har_p) +{ + eqframe* fam_u = u3a_peek(pil_u); + u3_noun a, b; + u3a_cell* a_u; + u3a_cell* b_u; + + // loop while arguments remain on the stack + // + do { + a = fam_u->a; + b = fam_u->b; + + switch ( fam_u->sat_y ) { + + // [a] and [b] are arbitrary nouns + // + case SING_NONE: { + if ( a == b ) { + break; + } + else if ( c3y == u3a_is_atom(a) ) { + if ( c3n == _cr_sing_atom(a, b) ) { + return c3n; + } + else { + break; + } + } + else if ( c3y == u3a_is_atom(b) ) { + return c3n; + } + // [a] and [b] are cells + // + else { + a_u = u3a_to_ptr(a); + b_u = u3a_to_ptr(b); + + // short-circuiting mug check + // + if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) { + return c3n; + } + // short-circuiting re-comparison check + // + else if ( c3y == _cr_sing_cape_test(har_p, a, b) ) { + fam_u = u3a_pop(pil_u); + continue; + } + // upgrade none-frame to head-frame, check heads + // + else { + fam_u->sat_y = SING_HEAD; + fam_u = _cr_sing_push(pil_u, a_u->hed, b_u->hed); + continue; + } + } + } break; + + // cells [a] and [b] have equal heads + // + case SING_HEAD: { + a_u = u3a_to_ptr(a); + b_u = u3a_to_ptr(b); + _cr_sing_wed(&(a_u->hed), &(b_u->hed)); + + // upgrade head-frame to tail-frame, check tails + // + fam_u->sat_y = SING_TAIL; + fam_u = _cr_sing_push(pil_u, a_u->tel, b_u->tel); + continue; + } + + // cells [a] and [b] are equal + // + case SING_TAIL: { + a_u = u3a_to_ptr(a); + b_u = u3a_to_ptr(b); + _cr_sing_wed(&(a_u->tel), &(b_u->tel)); + } break; + + default: { + u3_assert(0); + } break; + } + + // track equal pairs to short-circuit possible (re-)comparison + // + _cr_sing_cape_keep(har_p, a, b); + + fam_u = u3a_pop(pil_u); + } + while ( c3n == u3a_pile_done(pil_u) ); + + return c3y; +} + +/* _cr_sing(): unifying equality. +*/ +static c3_o +_cr_sing(u3_noun a, u3_noun b) +{ + c3_s ovr_s = 0; + u3a_cell* a_u; + u3a_cell* b_u; + eqframe* fam_u; + u3a_pile pil_u; + + // initialize stack control, push arguments onto the stack (none-frame) + // + u3a_pile_prep(&pil_u, sizeof(eqframe)); + fam_u = _cr_sing_push(&pil_u, a, b); + + // loop while arguments are on the stack + // + while ( c3n == u3a_pile_done(&pil_u) ) { + a = fam_u->a; + b = fam_u->b; + + switch ( fam_u->sat_y ) { + + // [a] and [b] are arbitrary nouns + // + case SING_NONE: { + if ( a == b ) { + break; + } + else if ( c3y == u3a_is_atom(a) ) { + if ( c3n == _cr_sing_atom(a, b) ) { + u3R->cap_p = pil_u.top_p; + return c3n; + } + else { + break; + } + } + else if ( c3y == u3a_is_atom(b) ) { + u3R->cap_p = pil_u.top_p; + return c3n; + } + // [a] and [b] are cells + // + else { + a_u = u3a_to_ptr(a); + b_u = u3a_to_ptr(b); + + // short-circuiting mug check + // + if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) { + u3R->cap_p = pil_u.top_p; + return c3n; + } + // upgrade none-frame to head-frame, check heads + // + else { + fam_u->sat_y = SING_HEAD; + fam_u = _cr_sing_push(&pil_u, a_u->hed, b_u->hed); + continue; + } + } + } break; + + // cells [a] and [b] have equal heads + // + case SING_HEAD: { + a_u = u3a_to_ptr(a); + b_u = u3a_to_ptr(b); + _cr_sing_wed(&(a_u->hed), &(b_u->hed)); + + // upgrade head-frame to tail-frame, check tails + // + fam_u->sat_y = SING_TAIL; + fam_u = _cr_sing_push(&pil_u, a_u->tel, b_u->tel); + continue; + } + + // cells [a] and [b] are equal + // + case SING_TAIL: { + a_u = u3a_to_ptr(a); + b_u = u3a_to_ptr(b); + _cr_sing_wed(&(a_u->tel), &(b_u->tel)); + } break; + + default: { + u3_assert(0); + } break; + } + + // [ovr_s] counts comparisons, if it overflows, we've likely hit + // a pathological case (highly duplicated tree), so we de-duplicate + // subsequent comparisons by maintaining a set of equal pairs. + // + if ( 0 == ++ovr_s ) { + u3p(u3h_root) har_p = u3h_new(); + c3_o ret_o = _cr_sing_cape(&pil_u, har_p); + u3h_free(har_p); + u3R->cap_p = pil_u.top_p; + return ret_o; + } + + fam_u = u3a_pop(&pil_u); + } + + return c3y; +} + +/* u3r_sing(): Yes iff [a] and [b] are the same noun. +*/ +c3_o +u3r_sing(u3_noun a, u3_noun b) +{ + c3_o ret_o; + u3t_on(euq_o); + ret_o = _cr_sing(a, b); + u3t_off(euq_o); + return ret_o; +} + +c3_o +u3r_fing(u3_noun a, + u3_noun b) +{ + return (a == b) ? c3y : c3n; +} + +/* u3r_sing_cell(): +** +** Yes iff `[p q]` and `b` are the same noun. +*/ +c3_o +u3r_sing_cell(u3_noun p, + u3_noun q, + u3_noun b) +{ + return c3a(_(u3a_is_cell(b)), + c3a(u3r_sing(p, u3a_h(b)), + u3r_sing(q, u3a_t(b)))); +} +c3_o +u3r_fing_cell(u3_noun p, + u3_noun q, + u3_noun b) +{ + return c3a(_(u3a_is_cell(b)), + c3a(u3r_fing(p, u3a_h(b)), + u3r_fing(q, u3a_t(b)))); +} + +/* u3r_sing_mixt(): +** +** Yes iff `[p q]` and `b` are the same noun. +*/ +c3_o +u3r_sing_mixt(const c3_c* p_c, + u3_noun q, + u3_noun b) +{ + return c3a(_(u3a_is_cell(b)), + c3a(u3r_sing_c(p_c, u3a_h(b)), + u3r_sing(q, u3a_t(b)))); +} +c3_o +u3r_fing_mixt(const c3_c* p_c, + u3_noun q, + u3_noun b) +{ + return c3a(_(u3a_is_cell(b)), + c3a(u3r_sing_c(p_c, u3a_h(b)), + u3r_fing(q, u3a_t(b)))); +} + +/* u3r_sing_trel(): +** +** Yes iff `[p q r]` and `b` are the same noun. +*/ +c3_o +u3r_sing_trel(u3_noun p, + u3_noun q, + u3_noun r, + u3_noun b) +{ + return c3a(_(u3a_is_cell(b)), + c3a(u3r_sing(p, u3a_h(b)), + u3r_sing_cell(q, r, u3a_t(b)))); +} +c3_o +u3r_fing_trel(u3_noun p, + u3_noun q, + u3_noun r, + u3_noun b) +{ + return c3a(_(u3a_is_cell(b)), + c3a(u3r_fing(p, u3a_h(b)), + u3r_fing_cell(q, r, u3a_t(b)))); +} + +/* u3r_sing_qual(): +** +** Yes iff `[p q r]` and `b` are the same noun. +*/ +c3_o +u3r_sing_qual(u3_noun p, + u3_noun q, + u3_noun r, + u3_noun s, + u3_noun b) +{ + return c3a(_(u3a_is_cell(b)), + c3a(u3r_sing(p, u3a_h(b)), + u3r_sing_trel(q, r, s, u3a_t(b)))); +} +c3_o +u3r_fing_qual(u3_noun p, + u3_noun q, + u3_noun r, + u3_noun s, + u3_noun b) +{ + return c3a(_(u3a_is_cell(b)), + c3a(u3r_fing(p, u3a_h(b)), + u3r_fing_trel(q, r, s, u3a_t(b)))); +} + +/* u3r_nord(): +** +** Return 0, 1 or 2 if `a` is below, equal to, or above `b`. +*/ +u3_atom +u3r_nord(u3_noun a, + u3_noun b) +{ + u3_assert(u3_none != a); + u3_assert(u3_none != b); + + if ( a == b ) { + return 1; + } + else { + if ( _(u3a_is_atom(a)) ) { + if ( !_(u3a_is_atom(b)) ) { + return 0; + } else { + if ( _(u3a_is_cat(a)) ) { + if ( _(u3a_is_cat(b)) ) { + return (a < b) ? 0 : 2; + } + else return 0; + } + else if ( _(u3a_is_cat(b)) ) { + return 2; + } + else { + u3a_atom* a_u = u3a_to_ptr(a); + u3a_atom* b_u = u3a_to_ptr(b); + + c3_w w_rez = a_u->len_w; + c3_w w_mox = b_u->len_w; + + if ( w_rez != w_mox ) { + return (w_rez < w_mox) ? 0 : 2; + } + else { + c3_w i_w; + + for ( i_w = 0; i_w < w_rez; i_w++ ) { + c3_w ai_w = a_u->buf_w[i_w]; + c3_w bi_w = b_u->buf_w[i_w]; + + if ( ai_w != bi_w ) { + return (ai_w < bi_w) ? 0 : 2; + } + } + return 1; + } + } + } + } else { + if ( _(u3a_is_atom(b)) ) { + return 2; + } else { + u3_atom c = u3r_nord(u3a_h(a), u3a_h(b)); + + if ( 1 == c ) { + return u3r_nord(u3a_t(a), u3a_t(b)); + } else { + return c; + } + } + } + } +} + +/* u3r_sing_c(): cord/C-string value equivalence. +*/ +c3_o +u3r_sing_c(const c3_c* a_c, + u3_noun b) +{ + u3_assert(u3_none != b); + + if ( !_(u3a_is_atom(b)) ) { + return c3n; + } + else { + c3_w w_sof = strlen(a_c); + c3_w i_w; + + if ( w_sof != u3r_met(3, b) ) { + return c3n; + } + for ( i_w = 0; i_w < w_sof; i_w++ ) { + if ( u3r_byte(i_w, b) != a_c[i_w] ) { + return c3n; + } + } + return c3y; + } +} + +/* u3r_bush(): +** +** Factor [a] as a bush [b.[p q] c]. +*/ +c3_o +u3r_bush(u3_noun a, + u3_noun* b, + u3_noun* c) +{ + u3_assert(u3_none != a); + + if ( _(u3a_is_atom(a)) ) { + return c3n; + } + else { + *b = u3a_h(a); + + if ( _(u3a_is_atom(*b)) ) { + return c3n; + } else { + *c = u3a_t(a); + return c3y; + } + } +} + +/* u3r_bite(): retrieve/default $bloq and $step from $bite. +*/ +c3_o +u3r_bite(u3_noun bite, u3_atom* bloq, u3_atom *step) +{ + u3_noun hed, tal; + + if ( c3n == u3r_cell(bite, &hed, &tal) ) { + *bloq = bite; + *step = 1; + return c3y; + } + else if ( (c3n == u3a_is_atom(hed)) + || (c3n == u3a_is_atom(tal)) ) + { + return c3n; + } + else { + *bloq = hed; + *step = tal; + return c3y; + } +} + +/* u3r_p(): +** +** & [0] if [a] is of the form [b *c]. +*/ +c3_o +u3r_p(u3_noun a, + u3_noun b, + u3_noun* c) +{ + u3_noun feg, nux; + + if ( (c3y == u3r_cell(a, &feg, &nux)) && + (c3y == u3r_sing(feg, b)) ) + { + if ( c ) *c = nux; + return c3y; + } + else return c3n; +} + +/* u3r_pq(): +** +** & [0] if [a] is of the form [b *c d]. +*/ +c3_o +u3r_pq(u3_noun a, + u3_noun b, + u3_noun* c, + u3_noun* d) +{ + u3_noun nux; + + if ( (c3y == u3r_p(a, b, &nux)) && + (c3y == u3r_cell(nux, c, d)) ) + { + return c3y; + } + else return c3n; +} + +/* u3r_pqr(): +** +** & [0] if [a] is of the form [b *c *d *e]. +*/ +c3_o +u3r_pqr(u3_noun a, + u3_noun b, + u3_noun* c, + u3_noun* d, + u3_noun* e) +{ + u3_noun nux; + + if ( (c3y == u3r_p(a, b, &nux)) && + (c3y == u3r_trel(nux, c, d, e)) ) + { + return c3y; + } + else return c3n; +} + +/* u3r_pqrs(): +** +** & [0] if [a] is of the form [b *c *d *e *f]. +*/ +c3_o +u3r_pqrs(u3_noun a, + u3_noun b, + u3_noun* c, + u3_noun* d, + u3_noun* e, + u3_noun* f) +{ + u3_noun nux; + + if ( (c3y == u3r_p(a, b, &nux)) && + (c3y == u3r_qual(nux, c, d, e, f)) ) + { + return c3y; + } + else return c3n; +} + +/* u3r_met(): +** +** Return the size of (b) in bits, rounded up to +** (1 << a_y). +** +** For example, (a_y == 3) returns the size in bytes. +** NB: (a_y) must be < 37. +*/ +c3_w +u3r_met(c3_y a_y, + u3_atom b) +{ + c3_dessert(u3_none != b); + c3_dessert(_(u3a_is_atom(b))); + + if ( b == 0 ) { + return 0; + } + /* gal_w: number of words besides (daz_w) in (b). + ** daz_w: top word in (b). + */ + c3_w gal_w; + c3_w daz_w; + + if ( _(u3a_is_cat(b)) ) { + gal_w = 0; + daz_w = b; + } + else { + u3a_atom* b_u = u3a_to_ptr(b); + + gal_w = (b_u->len_w) - 1; + daz_w = b_u->buf_w[gal_w]; + } + + /* 5 because 1<<2 bytes in c3_w, 1<<3 bits in byte. + aka log2(CHAR_BIT * sizeof gal_w) + a_y < 5 informs whether we shift return left or right + */ + if (a_y < 5) { + c3_y max_y = (1 << a_y) - 1; + c3_y gow_y = 5 - a_y; + + if (gal_w > ((UINT32_MAX - (32 + max_y)) >> gow_y)) + return u3m_bail(c3__fail); + + return (gal_w << gow_y) + + ((c3_bits_word(daz_w) + max_y) + >> a_y); + } + c3_y gow_y = (a_y - 5); + return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y; +} + +/* u3r_bit(): +** +** Return bit (a_w) of (b). +*/ +c3_b +u3r_bit(c3_w a_w, + u3_atom b) +{ + u3_assert(u3_none != b); + u3_assert(_(u3a_is_atom(b))); + + if ( _(u3a_is_cat(b)) ) { + if ( a_w >= 31 ) { + return 0; + } + else return (1 & (b >> a_w)); + } + else { + u3a_atom* b_u = u3a_to_ptr(b); + c3_y vut_y = (a_w & 31); + c3_w pix_w = (a_w >> 5); + + if ( pix_w >= b_u->len_w ) { + return 0; + } + else { + c3_w nys_w = b_u->buf_w[pix_w]; + + return (1 & (nys_w >> vut_y)); + } + } +} + +/* u3r_byte(): +** +** Return byte (a_w) of (b). +*/ +c3_y +u3r_byte(c3_w a_w, + u3_atom b) +{ + u3_assert(u3_none != b); + u3_assert(_(u3a_is_atom(b))); + + if ( _(u3a_is_cat(b)) ) { + if ( a_w > 3 ) { + return 0; + } + else return (255 & (b >> (a_w << 3))); + } + else { + u3a_atom* b_u = u3a_to_ptr(b); + c3_y vut_y = (a_w & 3); + c3_w pix_w = (a_w >> 2); + + if ( pix_w >= b_u->len_w ) { + return 0; + } + else { + c3_w nys_w = b_u->buf_w[pix_w]; + + return (255 & (nys_w >> (vut_y << 3))); + } + } +} + +/* u3r_bytes(): +** +** Copy bytes (a_w) through (a_w + b_w - 1) from (d) to (c). +*/ +void +u3r_bytes(c3_w a_w, + c3_w b_w, + c3_y* c_y, + u3_atom d) +{ + u3_assert(u3_none != d); + u3_assert(_(u3a_is_atom(d))); + + if ( _(u3a_is_cat(d)) ) { + c3_w e_w = d >> (c3_min(a_w, 4) << 3); + c3_w m_w = c3_min(b_w, 4); + memcpy(c_y, (c3_y*)&e_w, m_w); + if ( b_w > 4 ) { + memset(c_y + 4, 0, b_w - 4); + } + } + else { + u3a_atom* d_u = u3a_to_ptr(d); + c3_w n_w = d_u->len_w << 2; + c3_y* x_y = (c3_y*)d_u->buf_w + a_w; + + if ( a_w >= n_w ) { + memset(c_y, 0, b_w); + } + else { + c3_w z_w = c3_min(b_w, n_w - a_w); + memcpy(c_y, x_y, z_w); + if ( b_w > n_w - a_w ) { + memset(c_y + z_w, 0, b_w + a_w - n_w); + } + } + } +} + +/* u3r_bytes_fit(): +** +** Copy (len_w) bytes of (a) into (buf_y) if it fits, returning overage +*/ +c3_w +u3r_bytes_fit(c3_w len_w, c3_y *buf_y, u3_atom a) +{ + c3_w met_w = u3r_met(3, a); + if ( met_w <= len_w ) { + u3r_bytes(0, len_w, buf_y, a); + return 0; + } + else { + return len_w - met_w; + } +} + +/* u3r_bytes_alloc(): +** +** Copy (len_w) bytes starting at (a_w) from (b) into a fresh allocation. +*/ +c3_y* +u3r_bytes_alloc(c3_w a_w, + c3_w len_w, + u3_atom b) +{ + c3_y* b_y = u3a_malloc(len_w); + u3r_bytes(a_w, a_w + len_w, b_y, b); + return b_y; +} + +/* u3r_bytes_all(): +** +** Allocate and return a new byte array with all the bytes of (a), +** storing the length in (len_w). +*/ +c3_y* +u3r_bytes_all(c3_w* len_w, u3_atom a) +{ + c3_w met_w = *len_w = u3r_met(3, a); + return u3r_bytes_alloc(0, met_w, a); +} + +/* u3r_mp(): +** +** Copy (b) into (a_mp). +*/ +void +u3r_mp(mpz_t a_mp, + u3_atom b) +{ + u3_assert(u3_none != b); + u3_assert(_(u3a_is_atom(b))); + + if ( _(u3a_is_cat(b)) ) { + mpz_init_set_ui(a_mp, b); + } + else { + u3a_atom* b_u = u3a_to_ptr(b); + c3_w len_w = b_u->len_w; + c3_d bit_d = (c3_d)len_w << 5; + + // avoid reallocation on import, if possible + // + mpz_init2(a_mp, (c3_w)c3_min(bit_d, UINT32_MAX)); + mpz_import(a_mp, len_w, -1, sizeof(c3_w), 0, 0, b_u->buf_w); + } +} + +/* u3r_short(): +** +** Return short (a_w) of (b). +*/ +c3_s +u3r_short(c3_w a_w, + u3_atom b) +{ + u3_assert( u3_none != b ); + u3_assert( c3y == u3a_is_atom(b) ); + + if ( c3y == u3a_is_cat(b) ) { + switch ( a_w ) { + case 0: return b & 0xffff; + case 1: return b >> 16; + default: return 0; + } + } + else { + u3a_atom* b_u = u3a_to_ptr(b); + c3_w nix_w = a_w >> 1; + + if ( nix_w >= b_u->len_w ) { + return 0; + } + else { + c3_w wor_w = b_u->buf_w[nix_w]; + + return ( a_w & 1 ) ? (wor_w >> 16) : (wor_w & 0xffff); + } + } +} + +/* u3r_word(): +** +** Return word (a_w) of (b). +*/ +c3_w +u3r_word(c3_w a_w, + u3_atom b) +{ + u3_assert(u3_none != b); + u3_assert(_(u3a_is_atom(b))); + + if ( _(u3a_is_cat(b)) ) { + if ( a_w > 0 ) { + return 0; + } + else return b; + } + else { + u3a_atom* b_u = u3a_to_ptr(b); + + if ( a_w >= b_u->len_w ) { + return 0; + } + else return b_u->buf_w[a_w]; + } +} + +/* u3r_word_fit(): +** +** Fill (out_w) with (a) if it fits, returning success. +*/ +c3_t +u3r_word_fit(c3_w *out_w, u3_atom a) +{ + if ( u3r_met(5, a) > 1 ) { + return 0; + } + else { + *out_w = u3r_word(0, a); + return 1; + } +} + +/* u3r_chub(): +** +** Return double-word (a_w) of (b). +*/ +c3_d +u3r_chub(c3_w a_w, + u3_atom b) +{ + c3_w wlo_w = u3r_word(a_w * 2, b); + c3_w whi_w = u3r_word(1 + (a_w * 2), b); + + return (((uint64_t)whi_w) << 32ULL) | ((uint64_t)wlo_w); +} + +/* u3r_words(): +** +** Copy words (a_w) through (a_w + b_w - 1) from (d) to (c). +*/ +void +u3r_words(c3_w a_w, + c3_w b_w, + c3_w* c_w, + u3_atom d) +{ + u3_assert(u3_none != d); + u3_assert(_(u3a_is_atom(d))); + + if ( b_w == 0 ) { + return; + } + if ( _(u3a_is_cat(d)) ) { + if ( a_w == 0 ) { + *c_w = d; + memset((c3_y*)(c_w + 1), 0, (b_w - 1) << 2); + } + else { + memset((c3_y*)c_w, 0, b_w << 2); + } + } + else { + u3a_atom* d_u = u3a_to_ptr(d); + if ( a_w >= d_u->len_w ) { + memset((c3_y*)c_w, 0, b_w << 2); + } + else { + c3_w z_w = c3_min(b_w, d_u->len_w - a_w); + c3_w* x_w = d_u->buf_w + a_w; + memcpy((c3_y*)c_w, (c3_y*)x_w, z_w << 2); + if ( b_w > d_u->len_w - a_w ) { + memset((c3_y*)(c_w + z_w), 0, (b_w + a_w - d_u->len_w) << 2); + } + } + } +} + +/* u3r_chubs(): +** +** Copy double-words (a_w) through (a_w + b_w - 1) from (d) to (c). +*/ +void +u3r_chubs(c3_w a_w, + c3_w b_w, + c3_d* c_d, + u3_atom d) +{ + /* XX: assumes little-endian + */ + u3r_words(a_w * 2, b_w * 2, (c3_w *)c_d, d); +} + +/* u3r_safe_byte(): validate and retrieve byte. +*/ +c3_o +u3r_safe_byte(u3_noun dat, c3_y* out_y) +{ + if ( (c3n == u3a_is_atom(dat)) + || (1 < u3r_met(3, dat)) ) + { + return c3n; + } + + *out_y = u3r_byte(0, dat); + return c3y; +} + +/* u3r_safe_word(): validate and retrieve word. +*/ +c3_o +u3r_safe_word(u3_noun dat, c3_w* out_w) +{ + if ( (c3n == u3a_is_atom(dat)) + || (1 < u3r_met(5, dat)) ) + { + return c3n; + } + + *out_w = u3r_word(0, dat); + return c3y; +} + +/* u3r_safe_chub(): validate and retrieve chub. +*/ +c3_o +u3r_safe_chub(u3_noun dat, c3_d* out_d) +{ + if ( (c3n == u3a_is_atom(dat)) + || (1 < u3r_met(6, dat)) ) + { + return c3n; + } + + *out_d = u3r_chub(0, dat); + return c3y; +} + +/* u3r_chop_bits(): +** +** XOR `wid_d` bits from`src_w` at `bif_g` to `dst_w` at `bif_g` +** +** NB: [dst_w] must have space for [bit_g + wid_d] bits +*/ +void +u3r_chop_bits(c3_g bif_g, + c3_d wid_d, + c3_g bit_g, + c3_w* dst_w, + const c3_w* src_w) +{ + c3_y fib_y = 32 - bif_g; + c3_y tib_y = 32 - bit_g; + + // we need to chop words + // + if ( wid_d >= tib_y ) { + // align *dst_w + // + if ( bit_g ) { + c3_w low_w = src_w[0] >> bif_g; + + if ( bif_g > bit_g ) { + low_w ^= src_w[1] << fib_y; + } + + *dst_w++ ^= low_w << bit_g; + + wid_d -= tib_y; + bif_g += tib_y; + src_w += !!(bif_g >> 5); + bif_g &= 31; + fib_y = 32 - bif_g; + } + + { + size_t i_i, byt_i = wid_d >> 5; + + if ( !bif_g ) { + for ( i_i = 0; i_i < byt_i; i_i++ ) { + dst_w[i_i] ^= src_w[i_i]; + } + } + else { + for ( i_i = 0; i_i < byt_i; i_i++ ) { + dst_w[i_i] ^= (src_w[i_i] >> bif_g) ^ (src_w[i_i + 1] << fib_y); + } + } + + src_w += byt_i; + dst_w += byt_i; + wid_d &= 31; + bit_g = 0; + } + } + + // we need to chop (more) bits + // + if ( wid_d ) { + c3_w hig_w = src_w[0] >> bif_g; + + if ( wid_d > fib_y ) { + hig_w ^= src_w[1] << fib_y; + } + + *dst_w ^= (hig_w & (((c3_d)1 << wid_d) - 1)) << bit_g; + } +} + +/* u3r_chop_words(): +** +** Into the bloq space of `met`, from position `fum` for a +** span of `wid`, to position `tou`, XOR from `src_w` +** into `dst_w`. +** +** NB: [dst_w] must have space for [tou_w + wid_w] bloqs +*/ +void +u3r_chop_words(c3_g met_g, + c3_w fum_w, + c3_w wid_w, + c3_w tou_w, + c3_w* dst_w, + c3_w len_w, + const c3_w* src_w) +{ + // operate on words + // + if ( met_g >= 5 ) { + size_t i_i, wid_i; + + { + c3_g hut_g = met_g - 5; + size_t fum_i = (size_t)fum_w << hut_g; + size_t tou_i = (size_t)tou_w << hut_g; + size_t tot_i; + + wid_i = (size_t)wid_w << hut_g; + tot_i = fum_i + wid_i; + + // since [dst_w] must have space for (tou_w + wid_w) bloqs, + // neither conversion can overflow + // + if ( (fum_i >> hut_g != fum_w) || (tot_i - wid_i != fum_i) ) { + u3m_bail(c3__fail); + return; + } + else if ( fum_i >= len_w ) { + return; + } + + if ( tot_i > len_w ) { + wid_i -= tot_i - len_w; + } + + src_w += fum_i; + dst_w += tou_i; + } + + for ( i_i = 0; i_i < wid_i; i_i++ ) { + dst_w[i_i] ^= src_w[i_i]; + } + } + // operate on bits + // + else { + c3_d wid_d = (c3_d)wid_w << met_g; + c3_g bif_g, bit_g; + + { + c3_d len_d = (c3_d)len_w << 5; + c3_d fum_d = (c3_d)fum_w << met_g; + c3_d tou_d = (c3_d)tou_w << met_g; + c3_d tot_d = fum_d + wid_d; + + // see above + // + if ( (fum_d >> met_g != fum_w) || (tot_d - wid_d != fum_d) ) { + u3m_bail(c3__fail); + return; + } + else if ( fum_d > len_d ) { + return; + } + + if ( tot_d > len_d ) { + wid_d -= tot_d - len_d; + } + + src_w += fum_d >> 5; + dst_w += tou_d >> 5; + bif_g = fum_d & 31; + bit_g = tou_d & 31; + } + + u3r_chop_bits(bif_g, wid_d, bit_g, dst_w, src_w); + } +} + +/* u3r_chop(): +** +** Into the bloq space of `met`, from position `fum` for a +** span of `wid`, to position `tou`, XOR from atom `src` +** into `dst_w`. +** +** NB: [dst_w] must have space for [tou_w + wid_w] bloqs +*/ +void +u3r_chop(c3_g met_g, + c3_w fum_w, + c3_w wid_w, + c3_w tou_w, + c3_w* dst_w, + u3_atom src) +{ + c3_w* src_w; + c3_w len_w; + + if ( _(u3a_is_cat(src)) ) { + len_w = src ? 1 : 0; + src_w = &src; + } + else { + u3a_atom* src_u = u3a_to_ptr(src); + + u3_assert(u3_none != src); + u3_assert(_(u3a_is_atom(src))); + + len_w = src_u->len_w; + src_w = src_u->buf_w; + } + + u3r_chop_words(met_g, fum_w, wid_w, tou_w, dst_w, len_w, src_w); +} + +/* u3r_string(): `a` as malloced C string. +*/ +c3_c* +u3r_string(u3_atom a) +{ + c3_w met_w = u3r_met(3, a); + c3_c* str_c = c3_malloc(met_w + 1); + + u3r_bytes(0, met_w, (c3_y*)str_c, a); + str_c[met_w] = 0; + return str_c; +} + +/* u3r_tape(): `a`, a list of bytes, as malloced C string. +*/ +c3_y* +u3r_tape(u3_noun a) +{ + u3_noun b; + c3_w i_w; + c3_y *a_y; + + for ( i_w = 0, b=a; c3y == u3a_is_cell(b); i_w++, b=u3a_t(b) ) + ; + a_y = c3_malloc(i_w + 1); + + for ( i_w = 0, b=a; c3y == u3a_is_cell(b); i_w++, b=u3a_t(b) ) { + a_y[i_w] = u3a_h(b); + } + a_y[i_w] = 0; + + return a_y; +} + +/* u3r_mug_both(): Join two mugs. +*/ +c3_l +u3r_mug_both(c3_l lef_l, c3_l rit_l) +{ + c3_y len_y = 4 + ((c3_bits_word(rit_l) + 0x7) >> 3); + c3_w syd_w = 0xdeadbeef; + c3_w i_w = 0; + c3_y buf_y[8]; + + buf_y[0] = lef_l & 0xff; + buf_y[1] = (lef_l >> 8) & 0xff; + buf_y[2] = (lef_l >> 16) & 0xff; + buf_y[3] = (lef_l >> 24) & 0xff; + buf_y[4] = rit_l & 0xff; + buf_y[5] = (rit_l >> 8) & 0xff; + buf_y[6] = (rit_l >> 16) & 0xff; + buf_y[7] = (rit_l >> 24) & 0xff; + + while ( i_w < 8 ) { + c3_w haz_w; + c3_l ham_l; + + MurmurHash3_x86_32(buf_y, len_y, syd_w, &haz_w); + ham_l = (haz_w >> 31) ^ (haz_w & 0x7fffffff); + + if ( 0 == ham_l ) { + syd_w++; i_w++; + } + else { + return ham_l; + } + } + + return 0xfffe; +} + +/* u3r_mug_bytes(): Compute the mug of `buf`, `len`, LSW first. +*/ +c3_l +u3r_mug_bytes(const c3_y *buf_y, + c3_w len_w) +{ + c3_w syd_w = 0xcafebabe; + c3_w i_w = 0; + + while ( i_w < 8 ) { + c3_w haz_w; + c3_l ham_l; + + MurmurHash3_x86_32(buf_y, len_w, syd_w, &haz_w); + ham_l = (haz_w >> 31) ^ (haz_w & 0x7fffffff); + + if ( 0 == ham_l ) { + syd_w++; i_w++; + } + else { + return ham_l; + } + } + + return 0x7fff; +} + +/* u3r_mug_c(): Compute the mug of `a`, LSB first. +*/ +c3_l +u3r_mug_c(const c3_c* a_c) +{ + return u3r_mug_bytes((c3_y*)a_c, strlen(a_c)); +} + +/* u3r_mug_cell(): Compute the mug of the cell `[hed tel]`. +*/ +c3_l +u3r_mug_cell(u3_noun hed, + u3_noun tel) +{ + c3_w lus_w = u3r_mug(hed); + c3_w biq_w = u3r_mug(tel); + + return u3r_mug_both(lus_w, biq_w); +} + +/* u3r_mug_chub(): Compute the mug of `num`, LSW first. +*/ +c3_l +u3r_mug_chub(c3_d num_d) +{ + c3_w buf_w[2]; + + buf_w[0] = (c3_w)(num_d & 0xffffffffULL); + buf_w[1] = (c3_w)(num_d >> 32); + + return u3r_mug_words(buf_w, 2); +} + +/* u3r_mug_words(): 31-bit nonzero MurmurHash3 on raw words. +*/ +c3_l +u3r_mug_words(const c3_w* key_w, c3_w len_w) +{ + c3_w byt_w; + + // ignore trailing zeros + // + while ( len_w && !key_w[len_w - 1] ) { + len_w--; + } + + // calculate byte-width a la u3r_met(3, ...) + // + if ( !len_w ) { + byt_w = 0; + } + else { + c3_w gal_w = len_w - 1; + c3_w daz_w = key_w[gal_w]; + + byt_w = (gal_w << 2) + ((c3_bits_word(daz_w) + 7) >> 3); + } + + // XX: assumes little-endian + // + return u3r_mug_bytes((c3_y*)key_w, byt_w); +} + +/* _cr_mug: stack frame for recording cell traversal +** !mug == head-frame +*/ +typedef struct { + c3_l mug_l; + u3_cell cel; +} _cr_mugf; + +/* _cr_mug_next(): advance mug calculation, pushing cells onto the stack. +*/ +static inline c3_l +_cr_mug_next(u3a_pile* pil_u, u3_noun veb) +{ + while ( 1 ) { + // veb is a direct atom, mug is not memoized + // + if ( c3y == u3a_is_cat(veb) ) { + return (c3_l)u3r_mug_words(&veb, 1); + } + // veb is indirect, a pointer into the loom + // + else { + u3a_noun* veb_u = u3a_to_ptr(veb); + + // veb has already been mugged, return memoized value + // + // XX add debug assertion that mug is 31-bit? + // + if ( veb_u->mug_w ) { + return (c3_l)veb_u->mug_w; + } + // veb is an indirect atom, mug its bytes and memoize + // + else if ( c3y == u3a_is_atom(veb) ) { + u3a_atom* vat_u = (u3a_atom*)veb_u; + c3_l mug_l = u3r_mug_words(vat_u->buf_w, vat_u->len_w); + vat_u->mug_w = mug_l; + return mug_l; + } + // veb is a cell, push a stack frame to mark head-recursion + // and read the head + // + else { + u3a_cell* cel_u = (u3a_cell*)veb_u; + _cr_mugf* fam_u = u3a_push(pil_u); + + fam_u->mug_l = 0; + fam_u->cel = veb; + + veb = cel_u->hed; + continue; + } + } + } +} + +/* u3r_mug(): statefully mug a noun with 31-bit murmur3. +*/ +c3_l +u3r_mug(u3_noun veb) +{ + u3a_pile pil_u; + _cr_mugf* fam_u; + c3_l mug_l; + + // sanity check + // + u3_assert( u3_none != veb ); + + u3a_pile_prep(&pil_u, sizeof(*fam_u)); + + // commence mugging + // + mug_l = _cr_mug_next(&pil_u, veb); + + // process cell results + // + if ( c3n == u3a_pile_done(&pil_u) ) { + fam_u = u3a_peek(&pil_u); + + do { + // head-frame: stash mug and continue into the tail + // + if ( !fam_u->mug_l ) { + u3a_cell* cel_u = u3a_to_ptr(fam_u->cel); + + fam_u->mug_l = mug_l; + mug_l = _cr_mug_next(&pil_u, cel_u->tel); + fam_u = u3a_peek(&pil_u); + } + // tail-frame: calculate/memoize cell mug and pop the stack + // + else { + u3a_cell* cel_u = u3a_to_ptr(fam_u->cel); + + mug_l = u3r_mug_both(fam_u->mug_l, mug_l); + cel_u->mug_w = mug_l; + fam_u = u3a_pop(&pil_u); + } + } + while ( c3n == u3a_pile_done(&pil_u) ); + } + + return mug_l; +} + +/* u3r_skip(): +** +** Extract a constant from a formula, ignoring +** safe/static hints, doing no computation. +*/ +u3_weak +u3r_skip(u3_noun fol) +{ + while ( c3y == u3du(fol) ) { + switch ( u3h(fol) ) { + default: return u3_none; + case 1: return u3t(fol); + case 11: { + u3_noun arg = u3t(fol), + hod = u3h(arg); + + if ( (c3y == u3du(hod)) && (u3_none == u3r_skip(u3t(hod))) ) { + return u3_none; + } + fol = u3t(arg); + } + } + } + return u3_none; +} + +/* u3r_safe(): +** +** Returns yes if the formula won't crash +** and has no hints, returning constant result +** if possible. *out is undefined if the return +** is c3n +*/ +c3_o +u3r_safe(u3_noun fol, u3_weak* out) +{ + u3_noun h_fol, t_fol; + c3_o saf_o; + + if ( c3n == u3r_cell(fol, &h_fol, &t_fol) ) { + return c3n; + } + switch ( h_fol ) { + default: return c3n; + case 0: + *out = u3_none; + return __(1 == t_fol); + + case 1: + *out = t_fol; + return c3y; + + case 3: { + u3_weak o; + saf_o = u3r_safe(t_fol, &o); + if ( _(saf_o) ) { + *out = (u3_none == o) ? u3_none : u3du(o); + } + return saf_o; + } + + case 5: { + u3_noun p, q; + u3_weak o1, o2; + saf_o = c3a(u3r_cell(t_fol, &p, &q), + c3a(u3r_safe(p, &o1), u3r_safe(q, &o2))); + + if ( _(saf_o) ) { + *out = (u3_none == o1) ? u3_none + : (u3_none == o2) ? u3_none + : u3r_sing(o1, o2); + } + return saf_o; + } + + case 6: { + u3_noun p, q, r; + u3_weak o; + saf_o = c3a(u3r_trel(t_fol, &p, &q, &r), u3r_safe(p, &o)); + + if ( _(saf_o) ) { + switch ( o ) { + case c3y: return u3r_safe(q, out); + case c3n: return u3r_safe(r, out); + default: return c3n; + } + } + else { + return c3n; + } + } + + case 7: + case 8: { + u3_noun p, q; + u3_weak o; + return c3a(u3r_cell(t_fol, &p, &q), + c3a(u3r_safe(p, &o), u3r_safe(q, out))); + } + } +} diff --git a/vere/pkg/noun/retrieve.h b/vere/pkg/noun/retrieve.h new file mode 100644 index 0000000..c02c008 --- /dev/null +++ b/vere/pkg/noun/retrieve.h @@ -0,0 +1,547 @@ +/// @file + +#ifndef U3_RETRIEVE_H +#define U3_RETRIEVE_H + +#include "c3/c3.h" +#include "allocate.h" +#include "error.h" +#include "gmp.h" +#include "types.h" + + /** u3r_*: read without ever crashing. + **/ + + /* u3r_cell(): factor (a) as a cell (b c). + */ + inline c3_o + u3r_cell(u3_noun a, u3_noun* b, u3_noun* c) + { + u3a_cell* cel_u; + + u3_assert(u3_none != a); + + if ( c3y == u3a_is_cell(a) ) { + cel_u = u3a_to_ptr(a); + if ( b ) *b = cel_u->hed; + if ( c ) *c = cel_u->tel; + return c3y; + } + else { + return c3n; + } + } + + /* u3r_trel(): factor (a) as a trel (b c d). + */ + inline c3_o + u3r_trel(u3_noun a, u3_noun *b, u3_noun *c, u3_noun *d) + { + u3_noun guf; + + if ( (c3y == u3r_cell(a, b, &guf)) && + (c3y == u3r_cell(guf, c, d)) ) { + return c3y; + } + else { + return c3n; + } + } + + /* u3r_qual(): factor (a) as a qual (b c d e). + */ + inline c3_o + u3r_qual(u3_noun a, + u3_noun* b, + u3_noun* c, + u3_noun* d, + u3_noun* e) + { + u3_noun guf; + + if ( (c3y == u3r_cell(a, b, &guf)) && + (c3y == u3r_trel(guf, c, d, e)) ) { + return c3y; + } + else return c3n; + } + + /* u3r_quil(): factor (a) as a quil (b c d e f). + */ + inline c3_o + u3r_quil(u3_noun a, + u3_noun* b, + u3_noun* c, + u3_noun* d, + u3_noun* e, + u3_noun* f) + { + u3_noun guf; + + if ( (c3y == u3r_cell(a, b, &guf)) && + (c3y == u3r_qual(guf, c, d, e, f)) ) { + return c3y; + } + else return c3n; + } + + /* u3r_hext(): factor (a) as a hext (b c d e f g) + */ + inline c3_o + u3r_hext(u3_noun a, + u3_noun* b, + u3_noun* c, + u3_noun* d, + u3_noun* e, + u3_noun* f, + u3_noun* g) + { + u3_noun guf; + + if ( (c3y == u3r_cell(a, b, &guf)) && + (c3y == u3r_quil(guf, c, d, e, f, g)) ) { + return c3y; + } + else return c3n; + } + + /* u3r_at(): fragment `a` of `b`, or u3_none. + */ + u3_weak + u3r_at(u3_atom a, u3_weak b); + + /* u3r_mean(): + ** + ** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates. + ** Axes must be sorted in tree order. + */ + c3_o + u3r_vmean(u3_noun a, va_list ap); + c3_o + u3r_mean(u3_noun a, ...); + + /* u3r_mug_both(): Join two mugs. + */ + c3_l + u3r_mug_both(c3_w lef_w, c3_w rit_w); + + /* u3r_mug_bytes(): Compute the mug of `buf`, `len`, LSW first. + */ + c3_l + u3r_mug_bytes(const c3_y *buf_y, + c3_w len_w); + + /* u3r_mug_c(): Compute the mug of `a`, LSB first. + */ + c3_l + u3r_mug_c(const c3_c *a_c); + + /* u3r_mug_cell(): Compute the mug of the cell `[hed tel]`. + */ + c3_l + u3r_mug_cell(u3_noun hed, + u3_noun tel); + + /* u3r_mug_chub(): Compute the mug of `num`, LSW first. + */ + c3_l + u3r_mug_chub(c3_d num_d); + + /* u3r_mug_words(): 31-bit nonzero MurmurHash3 on raw words. + */ + c3_l + u3r_mug_words(const c3_w* key_w, c3_w len_w); + + /* u3r_mug(): statefully mug a noun with 31-bit murmur3. + */ + c3_l + u3r_mug(u3_noun veb); + + /* u3r_fing(): + ** + ** Yes iff (a) and (b) are the same copy of the same noun. + ** (Ie, by pointer equality - u3r_sing with false negatives.) + */ + c3_o + u3r_fing(u3_noun a, + u3_noun b); + + /* u3r_fing_cell(): + ** + ** Yes iff `[p q]` and `b` are the same copy of the same noun. + */ + c3_o + u3r_fing_cell(u3_noun p, + u3_noun q, + u3_noun b); + + /* u3r_fing_mixt(): + ** + ** Yes iff `[p q]` and `b` are the same copy of the same noun. + */ + c3_o + u3r_fing_mixt(const c3_c* p_c, + u3_noun q, + u3_noun b); + + /* u3r_fing_trel(): + ** + ** Yes iff `[p q r]` and `b` are the same copy of the same noun. + */ + c3_o + u3r_fing_trel(u3_noun p, + u3_noun q, + u3_noun r, + u3_noun b); + + /* u3r_fing_qual(): + ** + ** Yes iff `[p q r s]` and `b` are the same copy of the same noun. + */ + c3_o + u3r_fing_qual(u3_noun p, + u3_noun q, + u3_noun r, + u3_noun s, + u3_noun b); + + /* u3r_sing(): noun value equality. + ** + ** Unifies noun pointers on inner roads. + */ + c3_o + u3r_sing(u3_noun a, u3_noun b); + + /* u3r_sing_c(): cord/C-string value equivalence. + */ + c3_o + u3r_sing_c(const c3_c* a_c, + u3_noun b); + + /* u3r_sing_cell(): + ** + ** Yes iff `[p q]` and `b` are the same noun. + */ + c3_o + u3r_sing_cell(u3_noun p, + u3_noun q, + u3_noun b); + + /* u3r_sing_mixt(): + ** + ** Yes iff `[p q]` and `b` are the same noun. + */ + c3_o + u3r_sing_mixt(const c3_c* p_c, + u3_noun q, + u3_noun b); + + /* u3r_sing_trel(): + ** + ** Yes iff `[p q r]` and `b` are the same noun. + */ + c3_o + u3r_sing_trel(u3_noun p, + u3_noun q, + u3_noun r, + u3_noun b); + + /* u3r_sing_qual(): + ** + ** Yes iff `[p q r s]` and `b` are the same noun. + */ + c3_o + u3r_sing_qual(u3_noun p, + u3_noun q, + u3_noun r, + u3_noun s, + u3_noun b); + + /* u3r_nord(): + ** + ** Return 0, 1 or 2 if `a` is below, equal to, or above `b`. + */ + u3_atom + u3r_nord(u3_noun a, + u3_noun b); + + /* u3r_mold(): + ** + ** Divide `a` as a mold `[b.[p q] c]`. + */ + c3_o + u3r_mold(u3_noun a, + u3_noun* b, + u3_noun* c); + + /* u3r_bite(): retrieve/default $bloq and $step from $bite. + */ + c3_o + u3r_bite(u3_noun bite, u3_atom* bloq, u3_atom *step); + + /* u3r_p(): + ** + ** & [0] if [a] is of the form [b *c]. + */ + c3_o + u3r_p(u3_noun a, + u3_noun b, + u3_noun* c); + + /* u3r_bush(): + ** + ** Factor [a] as a bush [b.[p q] c]. + */ + c3_o + u3r_bush(u3_noun a, + u3_noun* b, + u3_noun* c); + + /* u3r_pq(): + ** + ** & [0] if [a] is of the form [b *c d]. + */ + c3_o + u3r_pq(u3_noun a, + u3_noun b, + u3_noun* c, + u3_noun* d); + + /* u3r_pqr(): + ** + ** & [0] if [a] is of the form [b *c *d *e]. + */ + c3_o + u3r_pqr(u3_noun a, + u3_noun b, + u3_noun* c, + u3_noun* d, + u3_noun* e); + + /* u3r_pqrs(): + ** + ** & [0] if [a] is of the form [b *c *d *e *f]. + */ + c3_o + u3r_pqrs(u3_noun a, + u3_noun b, + u3_noun* c, + u3_noun* d, + u3_noun* e, + u3_noun* f); + + /* u3r_met(): + ** + ** Return the size of (b) in bits, rounded up to + ** (1 << a_y). + ** + ** For example, (a_y == 3) returns the size in bytes. + ** NB: (a_y) must be < 37. + */ + c3_w + u3r_met(c3_y a_y, + u3_atom b); + + /* u3r_bit(): + ** + ** Return bit (a_w) of (b). + */ + c3_b + u3r_bit(c3_w a_w, + u3_atom b); + + /* u3r_byte(): + ** + ** Return byte (a_w) of (b). + */ + c3_y + u3r_byte(c3_w a_w, + u3_atom b); + + /* u3r_bytes(): + ** + ** Copy bytes (a_w) through (a_w + b_w - 1) from (d) to (c). + */ + void + u3r_bytes(c3_w a_w, + c3_w b_w, + c3_y* c_y, + u3_atom d); + + /* u3r_bytes_fit(): + ** + ** Copy (len_w) bytes of (a) into (buf_y) if it fits, returning overage. + */ + c3_w + u3r_bytes_fit(c3_w len_w, + c3_y* buf_y, + u3_atom a); + + /* u3r_bytes_alloc(): + ** + ** Copy (len_w) bytes starting at (a_w) from (b) into a fresh allocation. + */ + c3_y* + u3r_bytes_alloc(c3_w a_w, + c3_w len_w, + u3_atom b); + + /* u3r_bytes_all(): + ** + ** Allocate and return a new byte array with all the bytes of (a), + ** storing the length in (len_w). + */ + c3_y* + u3r_bytes_all(c3_w* len_w, + u3_atom a); + + /* u3r_chop_bits(): + ** + ** XOR `wid_d` bits from`src_w` at `bif_g` to `dst_w` at `bif_g` + ** + ** NB: [dst_w] must have space for [bit_g + wid_d] bits + */ + void + u3r_chop_bits(c3_g bif_g, + c3_d wid_d, + c3_g bit_g, + c3_w* dst_w, + const c3_w* src_w); + + /* u3r_chop_words(): + ** + ** Into the bloq space of `met`, from position `fum` for a + ** span of `wid`, to position `tou`, XOR from `src_w` + ** into `dst_w`. + ** + ** NB: [dst_w] must have space for [tou_w + wid_w] bloqs + */ + void + u3r_chop_words(c3_g met_g, + c3_w fum_w, + c3_w wid_w, + c3_w tou_w, + c3_w* dst_w, + c3_w len_w, + const c3_w* src_w); + + /* u3r_chop(): + ** + ** Into the bloq space of `met`, from position `fum` for a + ** span of `wid`, to position `tou`, XOR from atom `src` + ** into `dst_w`. + ** + ** NB: [dst_w] must have space for [tou_w + wid_w] bloqs + */ + void + u3r_chop(c3_g met_g, + c3_w fum_w, + c3_w wid_w, + c3_w tou_w, + c3_w* dst_w, + u3_atom src); + + /* u3r_mp(): + ** + ** Copy (b) into (a_mp). + */ + void + u3r_mp(mpz_t a_mp, + u3_atom b); + + /* u3r_short(): + ** + ** Return short (a_w) of (b). + */ + c3_s + u3r_short(c3_w a_w, + u3_atom b); + + /* u3r_word(): + ** + ** Return word (a_w) of (b). + */ + c3_w + u3r_word(c3_w a_w, + u3_atom b); + + + /* u3r_word_fit(): + ** + ** Fill (out_w) with (a) if it fits, returning success. + */ + c3_t + u3r_word_fit(c3_w* out_w, + u3_atom a); + + /* u3r_chub(): + ** + ** Return double-word (a_w) of (b). + */ + c3_d + u3r_chub(c3_w a_w, + u3_atom b); + + /* u3r_words(): + ** + ** Copy words (a_w) through (a_w + b_w - 1) from (d) to (c). + */ + void + u3r_words(c3_w a_w, + c3_w b_w, + c3_w* c_w, + u3_atom d); + + /* u3r_chubs(): + ** + ** Copy double-words (a_w) through (a_w + b_w - 1) from (d) to (c). + */ + void + u3r_chubs(c3_w a_w, + c3_w b_w, + c3_d* c_d, + u3_atom d); + + /* u3r_safe_byte(): validate and retrieve byte. + */ + c3_o + u3r_safe_byte(u3_noun dat, c3_y* out_y); + + /* u3r_safe_word(): validate and retrieve word. + */ + c3_o + u3r_safe_word(u3_noun dat, c3_w* out_w); + + /* u3r_safe_chub(): validate and retrieve chub. + */ + c3_o + u3r_safe_chub(u3_noun dat, c3_d* out_d); + + /* u3r_string(): `a`, a text atom, as malloced C string. + */ + c3_c* + u3r_string(u3_atom a); + + /* u3r_tape(): `a`, a list of bytes, as malloced C string. + */ + c3_y* + u3r_tape(u3_noun a); + + /* u3r_skip(): + ** + ** Extract a constant from a formula, ignoring + ** safe/static hints, doing no computation. + */ + u3_weak + u3r_skip(u3_noun fol); + + /* u3r_safe(): + ** + ** Returns yes if the formula won't crash + ** and has no hints, returning constant result + ** if possible + */ + c3_o + u3r_safe(u3_noun fol, u3_weak* out); + +#endif /* ifndef U3_RETRIEVE_H */ diff --git a/vere/pkg/noun/retrieve_tests.c b/vere/pkg/noun/retrieve_tests.c new file mode 100644 index 0000000..7ba7fa5 --- /dev/null +++ b/vere/pkg/noun/retrieve_tests.c @@ -0,0 +1,247 @@ +/// @file + +#include "noun.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_init(1 << 20); + u3m_pave(c3y); +} + +/* _test_mug(): spot check u3r_mug hashes. +*/ +static c3_i +_test_mug(void) +{ + c3_i ret_i = 1; + + if ( 0x4d441035 != u3r_mug_c("Hello, world!") ) { + fprintf(stderr, "fail (a)\r\n"); + ret_i = 0; + } + + { + u3_noun a = u3i_string("Hello, world!"); + + if ( 0x4d441035 != u3r_mug(a) ) { + fprintf(stderr, "fail (b)\r\n"); + ret_i = 0; + } + + u3z(a); + } + + { + c3_y byt_y[1]; + + if ( 0x79ff04e8 != u3r_mug_bytes(0, 0) ) { + fprintf(stderr, "fail (c) (0)\r\n"); + ret_i = 0; + } + + byt_y[0] = 1; + + if ( 0x715c2a60 != u3r_mug_bytes(byt_y, 1) ) { + fprintf(stderr, "fail (c) (1)\r\n"); + ret_i = 0; + } + + byt_y[0] = 2; + + if ( 0x718b9468 != u3r_mug_bytes(byt_y, 1) ) { + fprintf(stderr, "fail (c) (2)\r\n"); + ret_i = 0; + } + } + + if ( 0x3a811aec != u3r_mug_both(0x715c2a60, u3r_mug_cell(2, 3)) ) { + fprintf(stderr, "fail (d)\r\n"); + ret_i = 0; + } + + + { + if ( 0x192f5588 != u3r_mug_cell(0, 0) ) { + fprintf(stderr, "fail (e) (1)\r\n"); + ret_i = 0; + } + + if ( 0x6b32ec46 != u3r_mug_cell(1, 1) ) { + fprintf(stderr, "fail (e) (2)\r\n"); + ret_i = 0; + } + + if ( 0x2effe10 != u3r_mug_cell(2, 2) ) { + fprintf(stderr, "fail (e) (3)\r\n"); + ret_i = 0; + } + } + + { + u3_noun a = u3i_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + + if ( 0x64dfda5c != u3r_mug(a) ) { + fprintf(stderr, "fail (f)\r\n"); + ret_i = 0; + } + + u3z(a); + } + + { + u3_noun a = u3qc_bex(32); + + if ( 0x7cefb7f != u3r_mug_cell(0, a) ) { + fprintf(stderr, "fail (g)\r\n"); + ret_i = 0; + } + + u3z(a); + } + + { + u3_noun a = u3ka_dec(u3qc_bex(128)); + + if ( 0x2aa06bfc != u3r_mug_cell(a, 1) ) { + fprintf(stderr, "fail (h)\r\n"); + ret_i = 0; + } + + u3z(a); + } + + { + // stick some zero bytes in a string + // + u3_noun str = u3kc_lsh(3, 1, + u3kc_mix(u3qc_bex(212), + u3i_string("abcdefjhijklmnopqrstuvwxyz"))); + + c3_w byt_w = u3r_met(3, str); + c3_w wor_w = u3r_met(5, str); + c3_y* str_y = c3_malloc(byt_w); + c3_w* str_w = c3_malloc(4 * wor_w); + c3_d str_d = 0; + + u3r_bytes(0, byt_w, str_y, str); + u3r_words(0, wor_w, str_w, str); + + str_d |= str_w[0]; + str_d |= ((c3_d)str_w[1] << 32ULL); + + if ( 0x34d08717 != u3r_mug(str) ) { + fprintf(stderr, "fail (i) (1) \r\n"); + ret_i = 0; + } + if ( 0x34d08717 != u3r_mug_bytes(str_y, byt_w) ) { + fprintf(stderr, "fail (i) (2)\r\n"); + ret_i = 0; + } + if ( 0x34d08717 != u3r_mug_words(str_w, wor_w) ) { + fprintf(stderr, "fail (i) (3)\r\n"); + ret_i = 0; + } + if ( u3r_mug_words(str_w, 2) != u3r_mug_chub(str_d) ) { + fprintf(stderr, "fail (i) (4)\r\n"); + ret_i = 0; + } + + c3_free(str_y); + c3_free(str_w); + u3z(str); + } + + { + c3_w som_w[4] = { 0, 0, 0, 1 }; + u3_noun som = u3i_words(4, som_w); + + if ( 0x519bd45c != u3r_mug(som) ) { + fprintf(stderr, "fail (j) (1)\r\n"); + ret_i = 0; + } + + if ( 0x519bd45c != u3r_mug_words(som_w, 4) ) { + fprintf(stderr, "fail (j) (2)\r\n"); + ret_i = 0; + } + + u3z(som); + } + + { + c3_w som_w[4] = { 0, 1, 0, 1 }; + u3_noun som = u3i_words(4, som_w); + + if ( 0x540eb8a9 != u3r_mug(som) ) { + fprintf(stderr, "fail (k) (1)\r\n"); + ret_i = 0; + } + + if ( 0x540eb8a9 != u3r_mug_words(som_w, 4) ) { + fprintf(stderr, "fail (k) (2)\r\n"); + ret_i = 0; + } + + u3z(som); + } + + { + c3_w som_w[4] = { 1, 1, 0, 1 }; + u3_noun som = u3i_words(4, som_w); + + if ( 0x319d28f9 != u3r_mug(som) ) { + fprintf(stderr, "fail (l) (1)\r\n"); + ret_i = 0; + } + + if ( 0x319d28f9 != u3r_mug_words(som_w, 4) ) { + fprintf(stderr, "fail (l) (2)\r\n"); + ret_i = 0; + } + + u3z(som); + } + + { + c3_w som_w[4] = { 0, 0, 0, 0xffff }; + u3_noun som = u3i_words(4, som_w); + + if ( 0x5230a260 != u3r_mug(som) ) { + fprintf(stderr, "fail (m) (1)\r\n"); + ret_i = 0; + } + + if ( 0x5230a260 != u3r_mug_words(som_w, 4) ) { + fprintf(stderr, "fail (m) (2)\r\n"); + ret_i = 0; + } + + u3z(som); + } + + return ret_i; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_mug() ) { + fprintf(stderr, "test_mug: failed\r\n"); + exit(1); + } + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "test_mug: ok\n"); + + return 0; +} diff --git a/vere/pkg/noun/serial.c b/vere/pkg/noun/serial.c new file mode 100644 index 0000000..5dd6f59 --- /dev/null +++ b/vere/pkg/noun/serial.c @@ -0,0 +1,1456 @@ +/// @file + +#include "serial.h" + +#include <errno.h> +#include <fcntl.h> + +#include "allocate.h" +#include "hashtable.h" +#include "jets/k.h" +#include "jets/q.h" +#include "retrieve.h" +#include "serial.h" +#include "ur/ur.h" +#include "vortex.h" +#include "xtract.h" + +const c3_y u3s_dit_y[64] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '-', '~' +}; + +/* _cs_jam_buf: struct for tracking the fibonacci-allocated jam of a noun +*/ +struct _cs_jam_fib { + u3i_slab* sab_u; + u3p(u3h_root) har_p; + c3_w a_w; + c3_w b_w; + c3_w bit_w; +}; + +/* _cs_jam_fib_grow(): reallocate buffer with fibonacci growth +*/ +static inline void +_cs_jam_fib_grow(struct _cs_jam_fib* fib_u, c3_w mor_w) +{ + c3_w wan_w = fib_u->bit_w + mor_w; + + // check for c3_w overflow + // + if ( wan_w < mor_w ) { + u3m_bail(c3__fail); + return; + } + + if ( wan_w > fib_u->a_w ) { + c3_w c_w = 0; + + // fibonacci growth + // + while ( c_w < wan_w ) { + c_w = fib_u->a_w + fib_u->b_w; + fib_u->b_w = fib_u->a_w; + fib_u->a_w = c_w; + } + + u3i_slab_grow(fib_u->sab_u, 0, c_w); + } +} + +/* _cs_jam_fib_chop(): chop [met_w] bits of [a] into [fib_u] +*/ +static inline void +_cs_jam_fib_chop(struct _cs_jam_fib* fib_u, c3_w met_w, u3_noun a) +{ + c3_w bit_w = fib_u->bit_w; + _cs_jam_fib_grow(fib_u, met_w); + fib_u->bit_w += met_w; + + { + c3_w* buf_w = fib_u->sab_u->buf_w; + u3r_chop(0, 0, met_w, bit_w, buf_w, a); + } +} + +/* _cs_jam_fib_mat(): length-prefixed encode (mat) [a] into [fib_u] +*/ +static void +_cs_jam_fib_mat(struct _cs_jam_fib* fib_u, u3_noun a) +{ + if ( 0 == a ) { + _cs_jam_fib_chop(fib_u, 1, 1); + } + else { + c3_w a_w = u3r_met(0, a); + c3_w b_w = c3_bits_word(a_w); + c3_w bit_w = fib_u->bit_w; + + // amortize overflow checks and reallocation + // + { + c3_w met_w = a_w + (2 * b_w); + + if ( a_w > (UINT32_MAX - 64) ) { + u3m_bail(c3__fail); + return; + } + + _cs_jam_fib_grow(fib_u, met_w); + fib_u->bit_w += met_w; + } + + { + c3_w src_w[2]; + c3_w* buf_w = fib_u->sab_u->buf_w; + + // _cs_jam_fib_chop(fib_u, b_w+1, 1 << b_w); + // + { + c3_d dat_d = (c3_d)1 << b_w; + src_w[0] = (c3_w)dat_d; + src_w[1] = dat_d >> 32; + + u3r_chop_words(0, 0, b_w + 1, bit_w, buf_w, 2, src_w); + bit_w += b_w + 1; + } + + // _cs_jam_fib_chop(fib_u, b_w-1, a_w); + // + { + src_w[0] = a_w; + u3r_chop_words(0, 0, b_w - 1, bit_w, buf_w, 1, src_w); + bit_w += b_w - 1; + } + + // _cs_jam_fib_chop(fib_u, a_w, a); + // + u3r_chop(0, 0, a_w, bit_w, buf_w, a); + } + } +} + +/* _cs_jam_fib_atom_cb(): encode atom or backref +*/ +static void +_cs_jam_fib_atom_cb(u3_atom a, void* ptr_v) +{ + struct _cs_jam_fib* fib_u = ptr_v; + u3_weak b = u3h_git(fib_u->har_p, a); + + // if [a] has no backref, encode atom and put cursor into [har_p] + // + if ( u3_none == b ) { + u3h_put(fib_u->har_p, a, u3i_words(1, &(fib_u->bit_w))); + _cs_jam_fib_chop(fib_u, 1, 0); + _cs_jam_fib_mat(fib_u, a); + } + else { + c3_w a_w = u3r_met(0, a); + c3_w b_w = u3r_met(0, b); + + // if [a] is smaller than the backref, encode atom + // + if ( a_w <= b_w ) { + _cs_jam_fib_chop(fib_u, 1, 0); + _cs_jam_fib_mat(fib_u, a); + } + // otherwise, encode backref + // + else { + _cs_jam_fib_chop(fib_u, 2, 3); + _cs_jam_fib_mat(fib_u, b); + } + } +} + +/* _cs_jam_fib_cell_cb(): encode cell or backref +*/ +static c3_o +_cs_jam_fib_cell_cb(u3_noun a, void* ptr_v) +{ + struct _cs_jam_fib* fib_u = ptr_v; + u3_weak b = u3h_git(fib_u->har_p, a); + + // if [a] has no backref, encode cell and put cursor into [har_p] + // + if ( u3_none == b ) { + u3h_put(fib_u->har_p, a, u3i_words(1, &(fib_u->bit_w))); + _cs_jam_fib_chop(fib_u, 2, 1); + return c3y; + } + // otherwise, encode backref and shortcircuit traversal + // + else { + _cs_jam_fib_chop(fib_u, 2, 3); + _cs_jam_fib_mat(fib_u, b); + return c3n; + } +} + +/* u3s_jam_fib(): jam without atom allocation. +** +** returns atom-suitable words, and *bit_w will have +** the length (in bits). return should be freed with u3a_wfree(). +*/ +c3_w +u3s_jam_fib(u3i_slab* sab_u, u3_noun a) +{ + struct _cs_jam_fib fib_u; + fib_u.har_p = u3h_new(); + fib_u.sab_u = sab_u; + + // fib(12) is small enough to be reasonably fast to allocate. + // fib(11) is needed to get fib(13). + // + // + fib_u.a_w = ur_fib12; + fib_u.b_w = ur_fib11; + fib_u.bit_w = 0; + u3i_slab_init(sab_u, 0, fib_u.a_w); + + u3a_walk_fore(a, &fib_u, _cs_jam_fib_atom_cb, _cs_jam_fib_cell_cb); + + u3h_free(fib_u.har_p); + return fib_u.bit_w; +} + +typedef struct _jam_xeno_s { + u3p(u3h_root) har_p; + ur_bsw_t rit_u; +} _jam_xeno_t; + +/* _cs_coin_chub(): shortcircuit u3i_chubs(). +*/ +static inline u3_atom +_cs_coin_chub(c3_d a_d) +{ + return ( 0x7fffffffULL >= a_d ) ? a_d : u3i_chubs(1, &a_d); +} + +/* _cs_jam_xeno_atom(): encode in/direct atom in bitstream. +*/ +static inline void +_cs_jam_bsw_atom(ur_bsw_t* rit_u, c3_w met_w, u3_atom a) +{ + if ( c3y == u3a_is_cat(a) ) { + // XX need a ur_bsw_atom32() + // + ur_bsw_atom64(rit_u, (c3_y)met_w, (c3_d)a); + } + else { + u3a_atom* vat_u = u3a_to_ptr(a); + // XX assumes little-endian + // XX need a ur_bsw_atom_words() + // + c3_y* byt_y = (c3_y*)vat_u->buf_w; + ur_bsw_atom_bytes(rit_u, (c3_d)met_w, byt_y); + } +} + +/* _cs_jam_bsw_back(): encode in/direct backref in bitstream. +*/ +static inline void +_cs_jam_bsw_back(ur_bsw_t* rit_u, c3_w met_w, u3_atom a) +{ + c3_d bak_d = ( c3y == u3a_is_cat(a) ) + ? (c3_d)a + : u3r_chub(0, a); + + // XX need a ur_bsw_back32() + // + ur_bsw_back64(rit_u, (c3_y)met_w, bak_d); +} + +/* _cs_jam_xeno_atom(): encode atom or backref in bitstream. +*/ +static void +_cs_jam_xeno_atom(u3_atom a, void* ptr_v) +{ + _jam_xeno_t* jam_u = ptr_v; + ur_bsw_t* rit_u = &(jam_u->rit_u); + u3_weak bak = u3h_git(jam_u->har_p, a); + c3_w met_w = u3r_met(0, a); + + if ( u3_none == bak ) { + u3h_put(jam_u->har_p, a, _cs_coin_chub(rit_u->bits)); + _cs_jam_bsw_atom(rit_u, met_w, a); + } + else { + c3_w bak_w = u3r_met(0, bak); + + if ( met_w <= bak_w ) { + _cs_jam_bsw_atom(rit_u, met_w, a); + } + else { + _cs_jam_bsw_back(rit_u, bak_w, bak); + } + } +} + +/* _cs_jam_xeno_cell(): encode cell or backref in bitstream. +*/ +static c3_o +_cs_jam_xeno_cell(u3_noun a, void* ptr_v) +{ + _jam_xeno_t* jam_u = ptr_v; + ur_bsw_t* rit_u = &(jam_u->rit_u); + u3_weak bak = u3h_git(jam_u->har_p, a); + + if ( u3_none == bak ) { + u3h_put(jam_u->har_p, a, _cs_coin_chub(rit_u->bits)); + ur_bsw_cell(rit_u); + return c3y; + } + else { + _cs_jam_bsw_back(rit_u, u3r_met(0, bak), bak); + return c3n; + } +} + +/* u3s_jam_xeno(): jam with off-loom buffer (re-)allocation. +*/ +c3_d +u3s_jam_xeno(u3_noun a, c3_d* len_d, c3_y** byt_y) +{ + _jam_xeno_t jam_u = {0}; + ur_bsw_init(&jam_u.rit_u, ur_fib11, ur_fib12); + jam_u.har_p = u3h_new(); + + u3a_walk_fore(a, &jam_u, _cs_jam_xeno_atom, _cs_jam_xeno_cell); + + u3h_free(jam_u.har_p); + return ur_bsw_done(&jam_u.rit_u, len_d, byt_y); +} + +/* _cs_cue: stack frame for tracking intermediate cell results +*/ +typedef struct _cs_cue { + u3_weak hed; // head of a cell or u3_none + u3_atom wid; // bitwidth of [hed] or 0 + u3_atom cur; // bit-cursor position +} _cs_cue; + +/* _cs_rub: rub, TRANSFER [cur], RETAIN [a] +*/ +static inline u3_noun +_cs_rub(u3_atom cur, u3_atom a) +{ + u3_noun pro = u3qe_rub(cur, a); + u3z(cur); + return pro; +} + +/* _cs_cue_next(): advance into [a], reading next value +** TRANSFER [cur], RETAIN [a] +*/ +static inline u3_noun +_cs_cue_next(u3a_pile* pil_u, + u3p(u3h_root) har_p, + u3_atom cur, + u3_atom a, + u3_atom* wid) +{ + while ( 1 ) { + // read tag bit at cur + // + c3_y tag_y = u3qc_cut(0, cur, 1, a); + + // low bit unset, (1 + cur) points to an atom + // + // produce atom and the width we read + // + if ( 0 == tag_y ) { + u3_noun bur = _cs_rub(u3i_vint(cur), a); + u3_noun pro = u3k(u3t(bur)); + + u3h_put(har_p, cur, u3k(pro)); + *wid = u3qa_inc(u3h(bur)); + + u3z(bur); + return pro; + } + else { + // read tag bit at (1 + cur) + // + { + u3_noun x = u3qa_inc(cur); + tag_y = u3qc_cut(0, x, 1, a); + u3z(x); + } + + // next bit set, (2 + cur) points to a backref + // + // produce referenced value and the width we read + // + if ( 1 == tag_y ) { + u3_noun bur = _cs_rub(u3ka_add(2, cur), a); + u3_noun pro = u3x_good(u3h_get(har_p, u3t(bur))); + + *wid = u3qa_add(2, u3h(bur)); + + u3z(bur); + return pro; + } + // next bit unset, (2 + cur) points to the head of a cell + // + // push a head-frame onto the road stack and read the head + // + else { + _cs_cue* fam_u = u3a_push(pil_u); + + // NB: fam_u->wid unused in head-frame + // + fam_u->hed = u3_none; + fam_u->cur = cur; + + cur = u3qa_add(2, cur); + continue; + } + } + } +} + +u3_noun +u3s_cue(u3_atom a) +{ + // pro: cue'd noun product + // wid: bitwidth read to produce [pro] + // fam_u: stack frame + // har_p: backreference table + // pil_u: stack control structure + // + u3_noun pro; + u3_atom wid; + _cs_cue* fam_u; + u3p(u3h_root) har_p = u3h_new(); + u3a_pile pil_u; + + // initialize stack control + // + u3a_pile_prep(&pil_u, sizeof(*fam_u)); + + // commence cueing at bit-position 0 + // + pro = _cs_cue_next(&pil_u, har_p, 0, a, &wid); + + // process cell results + // + if ( c3n == u3a_pile_done(&pil_u) ) { + fam_u = u3a_peek(&pil_u); + + do { + // head-frame: stash [pro] and [wid]; continue into the tail + // + if ( u3_none == fam_u->hed ) { + // NB: fam_u->wid unused in head-frame + // + fam_u->hed = pro; + fam_u->wid = wid; + + // continue reading at the bit-position after [pro] + { + u3_noun cur = u3ka_add(2, u3qa_add(wid, fam_u->cur)); + pro = _cs_cue_next(&pil_u, har_p, cur, a, &wid); + } + + fam_u = u3a_peek(&pil_u); + } + // tail-frame: cons cell, recalculate [wid], and pop the stack + // + else { + pro = u3nc(fam_u->hed, pro); + u3h_put(har_p, fam_u->cur, u3k(pro)); + u3z(fam_u->cur); + wid = u3ka_add(2, u3ka_add(wid, fam_u->wid)); + fam_u = u3a_pop(&pil_u); + } + } while ( c3n == u3a_pile_done(&pil_u) ); + } + + u3z(wid); + u3h_free(har_p); + + return pro; +} + +/* +** stack frame for recording head vs tail iteration +** +** $? [u3_none bits=@] +** [hed=* bits=@] +*/ +typedef struct _cue_frame_s { + u3_weak ref; + c3_d bit_d; +} _cue_frame_t; + +/* _cs_cue_xeno_next(): read next value from bitstream, dictionary off-loom. +*/ +static inline ur_cue_res_e +_cs_cue_xeno_next(u3a_pile* pil_u, + ur_bsr_t* red_u, + ur_dict32_t* dic_u, + u3_noun* out) +{ + ur_root_t* rot_u = 0; + + while ( 1 ) { + c3_d len_d, bit_d = red_u->bits; + ur_cue_tag_e tag_e; + ur_cue_res_e res_e; + + if ( ur_cue_good != (res_e = ur_bsr_tag(red_u, &tag_e)) ) { + return res_e; + } + + switch ( tag_e ) { + default: u3_assert(0); + + case ur_jam_cell: { + _cue_frame_t* fam_u = u3a_push(pil_u); + + fam_u->ref = u3_none; + fam_u->bit_d = bit_d; + continue; + } + + case ur_jam_back: { + if ( ur_cue_good != (res_e = ur_bsr_rub_len(red_u, &len_d)) ) { + return res_e; + } + else if ( 62 < len_d ) { + return ur_cue_meme; + } + else { + c3_d bak_d = ur_bsr64_any(red_u, len_d); + c3_w bak_w; + + if ( !ur_dict32_get(rot_u, dic_u, bak_d, &bak_w) ) { + return ur_cue_back; + } + + *out = u3k((u3_noun)bak_w); + return ur_cue_good; + } + } + + case ur_jam_atom: { + if ( ur_cue_good != (res_e = ur_bsr_rub_len(red_u, &len_d)) ) { + return res_e; + } + + if ( 31 >= len_d ) { + *out = (u3_noun)ur_bsr32_any(red_u, len_d); + } + else { + c3_d byt_d = (len_d + 0x7) >> 3; + u3i_slab sab_u; + + if ( 0xffffffffULL < byt_d) { + return ur_cue_meme; + } + else { + u3i_slab_init(&sab_u, 3, byt_d); + ur_bsr_bytes_any(red_u, len_d, sab_u.buf_y); + *out = u3i_slab_mint_bytes(&sab_u); + } + } + + ur_dict32_put(rot_u, dic_u, bit_d, *out); + return ur_cue_good; + } + } + } +} + +struct _u3_cue_xeno { + ur_dict32_t dic_u; +}; + +/* _cs_cue_xeno(): cue on-loom, with off-loom dictionary in handle. +*/ +static u3_weak +_cs_cue_xeno(u3_cue_xeno* sil_u, + c3_d len_d, + const c3_y* byt_y) +{ + ur_bsr_t red_u = {0}; + ur_dict32_t* dic_u = &sil_u->dic_u; + u3a_pile pil_u; + _cue_frame_t* fam_u; + ur_cue_res_e res_e; + u3_noun ref; + + // initialize stack control + // + u3a_pile_prep(&pil_u, sizeof(*fam_u)); + + // init bitstream-reader + // + if ( ur_cue_good != (res_e = ur_bsr_init(&red_u, len_d, byt_y)) ) { + return c3n; + } + // bit-cursor (and backreferences) must fit in 62-bit direct atoms + // + else if ( 0x7ffffffffffffffULL < len_d ) { + return c3n; + } + + // advance into stream + // + res_e = _cs_cue_xeno_next(&pil_u, &red_u, dic_u, &ref); + + // process cell results + // + if ( (c3n == u3a_pile_done(&pil_u)) + && (ur_cue_good == res_e) ) + { + fam_u = u3a_peek(&pil_u); + + do { + // f is a head-frame; stash result and read the tail from the stream + // + if ( u3_none == fam_u->ref ) { + fam_u->ref = ref; + res_e = _cs_cue_xeno_next(&pil_u, &red_u, dic_u, &ref); + fam_u = u3a_peek(&pil_u); + } + // f is a tail-frame; pop the stack and continue + // + else { + ur_root_t* rot_u = 0; + + ref = u3nc(fam_u->ref, ref); + ur_dict32_put(rot_u, dic_u, fam_u->bit_d, ref); + fam_u = u3a_pop(&pil_u); + } + } + while ( (c3n == u3a_pile_done(&pil_u)) + && (ur_cue_good == res_e) ); + } + + if ( ur_cue_good == res_e ) { + return ref; + } + // on failure, unwind the stack and dispose of intermediate nouns + // + else if ( c3n == u3a_pile_done(&pil_u) ) { + do { + if ( u3_none != fam_u->ref ) { + u3z(fam_u->ref); + } + fam_u = u3a_pop(&pil_u); + } + while ( c3n == u3a_pile_done(&pil_u) ); + } + + return u3_none; +} + +/* u3s_cue_xeno_init_with(): initialize a cue_xeno handle as specified. +*/ +u3_cue_xeno* +u3s_cue_xeno_init_with(c3_d pre_d, c3_d siz_d) +{ + u3_cue_xeno* sil_u; + + sil_u = c3_calloc(sizeof(*sil_u)); + ur_dict32_grow((ur_root_t*)0, &sil_u->dic_u, pre_d, siz_d); + + return sil_u; +} + +/* u3s_cue_xeno_init(): initialize a cue_xeno handle. +*/ +u3_cue_xeno* +u3s_cue_xeno_init(void) +{ + return u3s_cue_xeno_init_with(ur_fib10, ur_fib11); +} + +/* u3s_cue_xeno_init(): cue on-loom, with off-loom dictionary in handle. +*/ +u3_weak +u3s_cue_xeno_with(u3_cue_xeno* sil_u, + c3_d len_d, + const c3_y* byt_y) +{ + u3_weak som; + + u3_assert( &(u3H->rod_u) == u3R ); + + som = _cs_cue_xeno(sil_u, len_d, byt_y); + ur_dict32_wipe(&sil_u->dic_u); + return som; +} + +/* u3s_cue_xeno_init(): dispose cue_xeno handle. +*/ +void +u3s_cue_xeno_done(u3_cue_xeno* sil_u) +{ + ur_dict_free((ur_dict_t*)&sil_u->dic_u); + c3_free(sil_u); +} + +/* u3s_cue_xeno(): cue on-loom, with off-loom dictionary. +*/ +u3_weak +u3s_cue_xeno(c3_d len_d, + const c3_y* byt_y) +{ + u3_cue_xeno* sil_u; + u3_weak som; + + u3_assert( &(u3H->rod_u) == u3R ); + + sil_u = u3s_cue_xeno_init(); + som = _cs_cue_xeno(sil_u, len_d, byt_y); + u3s_cue_xeno_done(sil_u); + return som; +} + +/* _cs_cue_need(): bail on ur_cue_* read failures. +*/ +static inline void +_cs_cue_need(ur_cue_res_e res_e) +{ + if ( ur_cue_good == res_e ) { + return; + } + else { + c3_m mot_m = (ur_cue_meme == res_e) ? c3__meme : c3__exit; + u3m_bail(mot_m); + } +} + +/* _cs_cue_get(): u3h_get wrapper handling allocation and refcounts. +*/ +static inline u3_weak +_cs_cue_get(u3p(u3h_root) har_p, c3_d key_d) +{ + u3_atom key = _cs_coin_chub(key_d); + u3_weak pro = u3h_get(har_p, key); + u3z(key); + return pro; +} + +/* _cs_cue_put(): u3h_put wrapper handling allocation and refcounts. +*/ +static inline u3_noun +_cs_cue_put(u3p(u3h_root) har_p, c3_d key_d, u3_noun val) +{ + u3_atom key = _cs_coin_chub(key_d); + u3h_put(har_p, key, u3k(val)); + u3z(key); + return val; +} + +/* _cs_cue_bytes_next(): read next value from bitstream. +*/ +static inline u3_noun +_cs_cue_bytes_next(u3a_pile* pil_u, + u3p(u3h_root) har_p, + ur_bsr_t* red_u) +{ + while ( 1 ) { + c3_d len_d, bit_d = red_u->bits; + ur_cue_tag_e tag_e; + + _cs_cue_need(ur_bsr_tag(red_u, &tag_e)); + + switch ( tag_e ) { + default: u3_assert(0); + + case ur_jam_cell: { + _cue_frame_t* fam_u = u3a_push(pil_u); + + fam_u->ref = u3_none; + fam_u->bit_d = bit_d; + continue; + } + + case ur_jam_back: { + _cs_cue_need(ur_bsr_rub_len(red_u, &len_d)); + + if ( 62 < len_d ) { + return u3m_bail(c3__meme); + } + else { + c3_d bak_d = ur_bsr64_any(red_u, len_d); + u3_weak bak = _cs_cue_get(har_p, bak_d); + return u3x_good(bak); + } + } + + case ur_jam_atom: { + u3_atom vat; + + _cs_cue_need(ur_bsr_rub_len(red_u, &len_d)); + + if ( 31 >= len_d ) { + vat = (u3_noun)ur_bsr32_any(red_u, len_d); + } + else { + u3i_slab sab_u; + u3i_slab_init(&sab_u, 0, len_d); + + ur_bsr_bytes_any(red_u, len_d, sab_u.buf_y); + vat = u3i_slab_mint_bytes(&sab_u); + } + + return _cs_cue_put(har_p, bit_d, vat); + } + } + } +} + +/* u3s_cue_bytes(): cue bytes onto the loom. +*/ +u3_noun +u3s_cue_bytes(c3_d len_d, const c3_y* byt_y) +{ + ur_bsr_t red_u = {0}; + u3a_pile pil_u; + _cue_frame_t* fam_u; + u3p(u3h_root) har_p; + u3_noun ref; + + // initialize stack control + // + u3a_pile_prep(&pil_u, sizeof(*fam_u)); + + // initialize a hash table for dereferencing backrefs + // + har_p = u3h_new(); + + // init bitstream-reader + // + _cs_cue_need(ur_bsr_init(&red_u, len_d, byt_y)); + + // bit-cursor (and backreferences) must fit in 62-bit direct atoms + // + if ( 0x7ffffffffffffffULL < len_d ) { + return u3m_bail(c3__meme); + } + + // advance into stream + // + ref = _cs_cue_bytes_next(&pil_u, har_p, &red_u); + + // process cell results + // + if ( c3n == u3a_pile_done(&pil_u) ) { + fam_u = u3a_peek(&pil_u); + + do { + // f is a head-frame; stash result and read the tail from the stream + // + if ( u3_none == fam_u->ref ) { + fam_u->ref = ref; + ref = _cs_cue_bytes_next(&pil_u, har_p, &red_u); + fam_u = u3a_peek(&pil_u); + } + // f is a tail-frame; pop the stack and continue + // + else { + ref = u3nc(fam_u->ref, ref); + _cs_cue_put(har_p, fam_u->bit_d, ref); + fam_u = u3a_pop(&pil_u); + } + } + while ( c3n == u3a_pile_done(&pil_u) ); + } + + u3h_free(har_p); + + return ref; +} + +/* u3s_cue_atom(): cue atom. +*/ +u3_noun +u3s_cue_atom(u3_atom a) +{ + c3_w len_w = u3r_met(3, a); + c3_y* byt_y; + + // XX assumes little-endian + // + if ( c3y == u3a_is_cat(a) ) { + byt_y = (c3_y*)&a; + } + else { + u3a_atom* vat_u = u3a_to_ptr(a); + byt_y = (c3_y*)vat_u->buf_w; + } + + return u3s_cue_bytes((c3_d)len_w, byt_y); +} + +/* _cs_etch_ud_size(): output length in @ud for given mpz_t. +*/ +static inline size_t +_cs_etch_ud_size(mpz_t a_mp) +{ + size_t len_i = mpz_sizeinbase(a_mp, 10); + return len_i + (len_i / 3); // separators +} + +/* _cs_etch_ud_bytes(): atom to @ud impl. +*/ +static size_t +_cs_etch_ud_bytes(mpz_t a_mp, size_t len_i, c3_y* hun_y) +{ + c3_y* buf_y = hun_y + (len_i - 1); + mpz_t b_mp; + c3_w b_w; + + mpz_init2(b_mp, 10); + + if ( !mpz_size(a_mp) ) { + *buf_y-- = '0'; + } + else { + while ( 1 ) { + b_w = mpz_tdiv_qr_ui(a_mp, b_mp, a_mp, 1000); + u3_assert( mpz_get_ui(b_mp) == b_w ); // XX + + if ( !mpz_size(a_mp) ) { + while ( b_w ) { + *buf_y-- = '0' + (b_w % 10); + b_w /= 10; + } + break; + } + + *buf_y-- = '0' + (b_w % 10); + b_w /= 10; + *buf_y-- = '0' + (b_w % 10); + b_w /= 10; + *buf_y-- = '0' + (b_w % 10); + *buf_y-- = '.'; + } + } + + buf_y++; + + u3_assert( buf_y >= hun_y ); // XX + + // mpz_sizeinbase may overestimate by 1 + // + { + size_t dif_i = buf_y - hun_y; + + if ( dif_i ) { + len_i -= dif_i; + memmove(hun_y, buf_y, len_i); + memset(hun_y + len_i, 0, dif_i); + } + } + + mpz_clear(b_mp); + + return len_i; +} + +/* u3s_etch_ud_smol(): c3_d to @ud +** +** =(26 (met 3 (scot %ud (dec (bex 64))))) +*/ +c3_y* +u3s_etch_ud_smol(c3_d a_d, c3_y hun_y[26]) +{ + c3_y* buf_y = hun_y + 25; + c3_w b_w; + + if ( !a_d ) { + *buf_y-- = '0'; + } + else { + while ( 1 ) { + b_w = a_d % 1000; + a_d /= 1000; + + if ( !a_d ) { + while ( b_w ) { + *buf_y-- = '0' + (b_w % 10); + b_w /= 10; + } + break; + } + + *buf_y-- = '0' + (b_w % 10); + b_w /= 10; + *buf_y-- = '0' + (b_w % 10); + b_w /= 10; + *buf_y-- = '0' + (b_w % 10); + *buf_y-- = '.'; + } + } + + return buf_y + 1; +} + +/* u3s_etch_ud(): atom to @ud. +*/ +u3_atom +u3s_etch_ud(u3_atom a) +{ + c3_d a_d; + + if ( c3y == u3r_safe_chub(a, &a_d) ) { + c3_y hun_y[26]; + c3_y* buf_y = u3s_etch_ud_smol(a_d, hun_y); + c3_w dif_w = (c3_p)buf_y - (c3_p)hun_y; + return u3i_bytes(26 - dif_w, buf_y); + } + + u3i_slab sab_u; + size_t len_i; + mpz_t a_mp; + u3r_mp(a_mp, a); + + len_i = _cs_etch_ud_size(a_mp); + u3i_slab_bare(&sab_u, 3, len_i); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + _cs_etch_ud_bytes(a_mp, len_i, sab_u.buf_y); + + mpz_clear(a_mp); + return u3i_slab_mint_bytes(&sab_u); +} + +/* u3s_etch_ud_c(): atom to @ud, as a malloc'd c string. +*/ +size_t +u3s_etch_ud_c(u3_atom a, c3_c** out_c) +{ + c3_d a_d; + size_t len_i; + c3_y* buf_y; + + if ( c3y == u3r_safe_chub(a, &a_d) ) { + c3_y hun_y[26]; + + buf_y = u3s_etch_ud_smol(a_d, hun_y); + len_i = 26 - ((c3_p)buf_y - (c3_p)hun_y); + + *out_c = c3_malloc(len_i + 1); + (*out_c)[len_i] = 0; + memcpy(*out_c, buf_y, len_i); + + return len_i; + } + + mpz_t a_mp; + u3r_mp(a_mp, a); + + len_i = _cs_etch_ud_size(a_mp); + buf_y = c3_malloc(len_i + 1); + buf_y[len_i] = 0; + + len_i = _cs_etch_ud_bytes(a_mp, len_i, buf_y); + + mpz_clear(a_mp); + + *out_c = (c3_c*)buf_y; + return len_i; +} + +/* _cs_etch_ux_bytes(): atom to @ux impl. +*/ +static void +_cs_etch_ux_bytes(u3_atom a, c3_w len_w, c3_y* buf_y) +{ + c3_w i_w; + c3_s inp_s; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + inp_s = u3r_short(i_w, a); + + *buf_y-- = u3s_dit_y[(inp_s >> 0) & 0xf]; + *buf_y-- = u3s_dit_y[(inp_s >> 4) & 0xf]; + *buf_y-- = u3s_dit_y[(inp_s >> 8) & 0xf]; + *buf_y-- = u3s_dit_y[(inp_s >> 12) & 0xf]; + *buf_y-- = '.'; + } + + inp_s = u3r_short(len_w, a); + + while ( inp_s ) { + *buf_y-- = u3s_dit_y[inp_s & 0xf]; + inp_s >>= 4; + } + + *buf_y-- = 'x'; + *buf_y = '0'; +} + +/* u3s_etch_ux(): atom to @ux. +*/ +u3_atom +u3s_etch_ux(u3_atom a) +{ + if ( u3_blip == a ) { + return c3_s3('0', 'x', '0'); + } + + c3_w sep_w = u3r_met(4, a) - 1; // number of separators + c3_w las_w = u3r_met(2, u3r_short(sep_w, a)); // digits before separator + c3_w len_w = 2 + las_w + (sep_w * 5); // output bytes + u3i_slab sab_u; + u3i_slab_bare(&sab_u, 3, len_w); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + _cs_etch_ux_bytes(a, sep_w, sab_u.buf_y + len_w - 1); + + return u3i_slab_moot_bytes(&sab_u); +} + +/* u3s_etch_ux_c(): atom to @ux, as a malloc'd c string. +*/ +size_t +u3s_etch_ux_c(u3_atom a, c3_c** out_c) +{ + if ( u3_blip == a ) { + *out_c = strdup("0x0"); + return 3; + } + + c3_y* buf_y; + c3_w sep_w = u3r_met(4, a) - 1; + c3_w las_w = u3r_met(2, u3r_short(sep_w, a)); + size_t len_i = 2 + las_w + (sep_w * 5); + + buf_y = c3_malloc(1 + len_i); + buf_y[len_i] = 0; + _cs_etch_ux_bytes(a, sep_w, buf_y + len_i - 1); + + *out_c = (c3_c*)buf_y; + return len_i; +} + +// uint div+ceil non-zero +// +#define _divc_nz(x, y) (((x) + ((y) - 1)) / (y)) + +/* _cs_etch_uv_size(): output length in @uv (and aligned bits). +*/ +static inline size_t +_cs_etch_uv_size(u3_atom a, c3_w* out_w) +{ + c3_w met_w = u3r_met(0, a); + c3_w sep_w = _divc_nz(met_w, 25) - 1; // number of separators + c3_w max_w = sep_w * 25; + c3_w end_w = 0; + u3r_chop(0, max_w, 25, 0, &end_w, a); + + c3_w bit_w = c3_bits_word(end_w); + c3_w las_w = _divc_nz(bit_w, 5); // digits before separator + + *out_w = max_w; + return 2 + las_w + (sep_w * 6); +} + + +/* _cs_etch_uv_bytes(): atom to @uv impl. +*/ +static void +_cs_etch_uv_bytes(u3_atom a, c3_w max_w, c3_y* buf_y) +{ + c3_w i_w; + c3_w inp_w; + + for ( i_w = 0; i_w < max_w; i_w += 25 ) { + inp_w = 0; + u3r_chop(0, i_w, 25, 0, &inp_w, a); + + *buf_y-- = u3s_dit_y[(inp_w >> 0) & 0x1f]; + *buf_y-- = u3s_dit_y[(inp_w >> 5) & 0x1f]; + *buf_y-- = u3s_dit_y[(inp_w >> 10) & 0x1f]; + *buf_y-- = u3s_dit_y[(inp_w >> 15) & 0x1f]; + *buf_y-- = u3s_dit_y[(inp_w >> 20) & 0x1f]; + *buf_y-- = '.'; + } + + inp_w = 0; + u3r_chop(0, max_w, 25, 0, &inp_w, a); + + while ( inp_w ) { + *buf_y-- = u3s_dit_y[inp_w & 0x1f]; + inp_w >>= 5; + } + + *buf_y-- = 'v'; + *buf_y = '0'; +} + +/* u3s_etch_uv(): atom to @uv. +*/ +u3_atom +u3s_etch_uv(u3_atom a) +{ + if ( u3_blip == a ) { + return c3_s3('0', 'v', '0'); + } + + u3i_slab sab_u; + c3_w max_w; + size_t len_i = _cs_etch_uv_size(a, &max_w); + + u3i_slab_bare(&sab_u, 3, len_i); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + _cs_etch_uv_bytes(a, max_w, sab_u.buf_y + len_i - 1); + + return u3i_slab_moot_bytes(&sab_u); +} + +/* u3s_etch_uv_c(): atom to @uv, as a malloc'd c string. +*/ +size_t +u3s_etch_uv_c(u3_atom a, c3_c** out_c) +{ + if ( u3_blip == a ) { + *out_c = strdup("0v0"); + return 3; + } + + c3_y* buf_y; + c3_w max_w; + size_t len_i = _cs_etch_uv_size(a, &max_w); + + buf_y = c3_malloc(1 + len_i); + buf_y[len_i] = 0; + _cs_etch_uv_bytes(a, max_w, buf_y + len_i - 1); + + *out_c = (c3_c*)buf_y; + return len_i; +} + +/* _cs_etch_uw_size(): output length in @uw (and aligned bits). +*/ +static inline size_t +_cs_etch_uw_size(u3_atom a, c3_w* out_w) +{ + c3_w met_w = u3r_met(0, a); + c3_w sep_w = _divc_nz(met_w, 30) - 1; // number of separators + c3_w max_w = sep_w * 30; + c3_w end_w = 0; + u3r_chop(0, max_w, 30, 0, &end_w, a); + + c3_w bit_w = c3_bits_word(end_w); + c3_w las_w = _divc_nz(bit_w, 6); // digits before separator + + *out_w = max_w; + return 2 + las_w + (sep_w * 6); +} + +/* _cs_etch_uw_bytes(): atom to @uw impl. +*/ +static void +_cs_etch_uw_bytes(u3_atom a, c3_w max_w, c3_y* buf_y) +{ + c3_w i_w; + c3_w inp_w; + + for ( i_w = 0; i_w < max_w; i_w += 30 ) { + inp_w = 0; + u3r_chop(0, i_w, 30, 0, &inp_w, a); + + *buf_y-- = u3s_dit_y[(inp_w >> 0) & 0x3f]; + *buf_y-- = u3s_dit_y[(inp_w >> 6) & 0x3f]; + *buf_y-- = u3s_dit_y[(inp_w >> 12) & 0x3f]; + *buf_y-- = u3s_dit_y[(inp_w >> 18) & 0x3f]; + *buf_y-- = u3s_dit_y[(inp_w >> 24) & 0x3f]; + *buf_y-- = '.'; + } + + inp_w = 0; + u3r_chop(0, max_w, 30, 0, &inp_w, a); + + while ( inp_w ) { + *buf_y-- = u3s_dit_y[inp_w & 0x3f]; + inp_w >>= 6; + } + + *buf_y-- = 'w'; + *buf_y = '0'; +} + +/* u3s_etch_uw(): atom to @uw. +*/ +u3_atom +u3s_etch_uw(u3_atom a) +{ + if ( u3_blip == a ) { + return c3_s3('0', 'w', '0'); + } + + u3i_slab sab_u; + c3_w max_w; + size_t len_i = _cs_etch_uw_size(a, &max_w); + + u3i_slab_bare(&sab_u, 3, len_i); + sab_u.buf_w[sab_u.len_w - 1] = 0; + + _cs_etch_uw_bytes(a, max_w, sab_u.buf_y + len_i - 1); + + return u3i_slab_moot_bytes(&sab_u); +} + +/* u3s_etch_uw_c(): atom to @uw, as a malloc'd c string. +*/ +size_t +u3s_etch_uw_c(u3_atom a, c3_c** out_c) +{ + if ( u3_blip == a ) { + *out_c = strdup("0w0"); + return 3; + } + + c3_y* buf_y; + c3_w max_w; + size_t len_i = _cs_etch_uw_size(a, &max_w); + + buf_y = c3_malloc(1 + len_i); + buf_y[len_i] = 0; + _cs_etch_uw_bytes(a, max_w, buf_y + len_i - 1); + + *out_c = (c3_c*)buf_y; + return len_i; +} + +#undef _divc_nz + +#define DIGIT(a) ( ((a) >= '0') && ((a) <= '9') ) +#define BLOCK(a) ( ('.' == (a)[0]) \ + && DIGIT(a[1]) \ + && DIGIT(a[2]) \ + && DIGIT(a[3]) ) + +/* u3s_sift_ud_bytes: parse @ud +*/ +u3_weak +u3s_sift_ud_bytes(c3_w len_w, c3_y* byt_y) +{ + c3_y num_y = len_w % 4; // leading digits length + c3_s val_s = 0; // leading digits value + + // +ape:ag: just 0 + // + if ( !len_w ) return u3_none; + if ( '0' == *byt_y ) return ( 1 == len_w ) ? (u3_noun)0 : u3_none; + + // +ted:ab: leading nonzero (checked above), plus up to 2 digits + // +#define NEXT() do { \ + if ( !DIGIT(*byt_y) ) return u3_none; \ + val_s *= 10; \ + val_s += *byt_y++ - '0'; \ + } while (0) + + switch ( num_y ) { + case 3: NEXT(); + case 2: NEXT(); + case 1: NEXT(); break; + case 0: return u3_none; + } + +#undef NEXT + + len_w -= num_y; + + // +tid:ab: dot-prefixed 3-digit blocks + // + // avoid gmp allocation if possible + // - 19 decimal digits fit in 64 bits + // - 18 digits is 24 bytes with separators + // + if ( ((1 == num_y) && (24 >= len_w)) + || (20 >= len_w) ) + { + c3_d val_d = val_s; + + while ( len_w ) { + if ( !BLOCK(byt_y) ) return u3_none; + + byt_y++; + + val_d *= 10; + val_d += *byt_y++ - '0'; + val_d *= 10; + val_d += *byt_y++ - '0'; + val_d *= 10; + val_d += *byt_y++ - '0'; + + len_w -= 4; + } + + return u3i_chub(val_d); + } + + { + // avoid gmp realloc if possible + // + mpz_t a_mp; + { + c3_d bit_d = (c3_d)(len_w / 4) * 10; + mpz_init2(a_mp, (c3_w)c3_min(bit_d, UINT32_MAX)); + mpz_set_ui(a_mp, val_s); + } + + while ( len_w ) { + if ( !BLOCK(byt_y) ) { + mpz_clear(a_mp); + return u3_none; + } + + byt_y++; + + val_s = *byt_y++ - '0'; + val_s *= 10; + val_s += *byt_y++ - '0'; + val_s *= 10; + val_s += *byt_y++ - '0'; + + mpz_mul_ui(a_mp, a_mp, 1000); + mpz_add_ui(a_mp, a_mp, val_s); + + len_w -= 4; + } + + return u3i_mp(a_mp); + } +} + +#undef BLOCK +#undef DIGIT + +/* u3s_sift_ud: parse @ud. +*/ +u3_weak +u3s_sift_ud(u3_atom a) +{ + c3_w len_w = u3r_met(3, a); + c3_y* byt_y; + + // XX assumes little-endian + // + if ( c3y == u3a_is_cat(a) ) { + byt_y = (c3_y*)&a; + } + else { + u3a_atom* vat_u = u3a_to_ptr(a); + byt_y = (c3_y*)vat_u->buf_w; + } + + return u3s_sift_ud_bytes(len_w, byt_y); +} diff --git a/vere/pkg/noun/serial.h b/vere/pkg/noun/serial.h new file mode 100644 index 0000000..d7dd5a8 --- /dev/null +++ b/vere/pkg/noun/serial.h @@ -0,0 +1,137 @@ +/// @file + +#ifndef U3_SERIAL_H +#define U3_SERIAL_H + +#include "c3/c3.h" +#include "imprison.h" +#include "types.h" + /* constants + */ + /* u3_dit_y: digit table for @ux/@uv/@uw. + */ + extern const c3_y u3s_dit_y[64]; + + /* opaque handles + */ + /* u3_cue_xeno: handle for cue-ing with an off-loom dictionary. + */ + typedef struct _u3_cue_xeno u3_cue_xeno; + + /* Noun serialization. All noun arguments RETAINED. + */ + + /* u3s_jam_fib(): jam without atom allocation. + ** + ** returns atom-suitable words, and *bit_w will have + ** the length (in bits). return should be freed with u3a_wfree(). + */ + c3_w + u3s_jam_fib(u3i_slab* sab_u, u3_noun a); + + /* u3s_jam_xeno(): jam with off-loom buffer (re-)allocation. + */ + c3_d + u3s_jam_xeno(u3_noun a, c3_d* len_d, c3_y** byt_y); + + /* u3s_cue(): cue [a] + */ + u3_noun + u3s_cue(u3_atom a); + + /* u3s_cue_xeno_init_with(): initialize a cue_xeno handle as specified. + */ + u3_cue_xeno* + u3s_cue_xeno_init_with(c3_d pre_d, c3_d siz_d); + + /* u3s_cue_xeno_init(): initialize a cue_xeno handle. + */ + u3_cue_xeno* + u3s_cue_xeno_init(void); + + /* u3s_cue_xeno_init(): cue on-loom, with off-loom dictionary in handle. + */ + u3_weak + u3s_cue_xeno_with(u3_cue_xeno* sil_u, + c3_d len_d, + const c3_y* byt_y); + + /* u3s_cue_xeno_init(): dispose cue_xeno handle. + */ + void + u3s_cue_xeno_done(u3_cue_xeno* sil_u); + + /* u3s_cue_xeno(): cue on-loom, with off-loom dictionary. + */ + u3_weak + u3s_cue_xeno(c3_d len_d, + const c3_y* byt_y); + + /* u3s_cue_bytes(): cue bytes onto the loom. + */ + u3_noun + u3s_cue_bytes(c3_d len_d, const c3_y* byt_y); + + /* u3s_cue_atom(): cue atom. + */ + u3_noun + u3s_cue_atom(u3_atom a); + + /* u3s_etch_ud_smol(): c3_d to @ud + ** + ** =(26 (met 3 (scot %ud (dec (bex 64))))) + */ + c3_y* + u3s_etch_ud_smol(c3_d a_d, c3_y hun_y[26]); + + /* u3s_etch_ud(): atom to @ud. + */ + u3_atom + u3s_etch_ud(u3_atom a); + + /* u3s_etch_ud_c(): atom to @ud, as a malloc'd c string. + */ + size_t + u3s_etch_ud_c(u3_atom a, c3_c** out_c); + + /* u3s_etch_ux(): atom to @ux. + */ + u3_atom + u3s_etch_ux(u3_atom a); + + /* u3s_etch_ux_c(): atom to @ux, as a malloc'd c string. + */ + size_t + u3s_etch_ux_c(u3_atom a, c3_c** out_c); + + /* u3s_etch_uv(): atom to @uv. + */ + u3_atom + u3s_etch_uv(u3_atom a); + + /* u3s_etch_uv_c(): atom to @uv, as a malloc'd c string. + */ + size_t + u3s_etch_uv_c(u3_atom a, c3_c** out_c); + + /* u3s_etch_uw(): atom to @uw. + */ + u3_atom + u3s_etch_uw(u3_atom a); + + /* u3s_etch_uw_c(): atom to @uw, as a malloc'd c string. + */ + size_t + u3s_etch_uw_c(u3_atom a, c3_c** out_c); + + /* u3s_sift_ud_bytes: parse @ud. + */ + u3_weak + u3s_sift_ud_bytes(c3_w len_w, c3_y* byt_y); + + /* u3s_sift_ud: parse @ud. + */ + u3_weak + u3s_sift_ud(u3_atom a); + +#endif /* ifndef U3_SERIAL_H */ diff --git a/vere/pkg/noun/serial_tests.c b/vere/pkg/noun/serial_tests.c new file mode 100644 index 0000000..5f1caf7 --- /dev/null +++ b/vere/pkg/noun/serial_tests.c @@ -0,0 +1,264 @@ +/// @file + +#include "noun.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_boot_lite(1 << 24); +} + +static void +_byte_print(c3_d out_d, + c3_y* out_y, + c3_w len_w, + const c3_y* byt_y) +{ + c3_d i_d; + + fprintf(stderr, " actual: { "); + for ( i_d = 0; i_d < out_d; i_d++ ) { + fprintf(stderr, "0x%x, ", out_y[i_d]); + } + fprintf(stderr, "}\r\n"); + fprintf(stderr, " expect: { "); + for ( i_d = 0; i_d < len_w; i_d++ ) { + fprintf(stderr, "0x%x, ", byt_y[i_d]); + } + fprintf(stderr, "}\r\n"); +} + +static c3_i +_test_jam_spec(const c3_c* cap_c, + u3_noun ref, + c3_w len_w, + const c3_y* byt_y) +{ + c3_i ret_i = 1; + c3_d out_d; + c3_y* out_y; + + { + u3s_jam_xeno(ref, &out_d, &out_y); + + if ( 0 != memcmp(out_y, byt_y, len_w) ) { + fprintf(stderr, "\033[31mjam xeno %s fail\033[0m\r\n", cap_c); + _byte_print(out_d, out_y, len_w, byt_y); + ret_i = 0; + } + + free(out_y); + } + + { + u3i_slab sab_u; + c3_w bit_w = u3s_jam_fib(&sab_u, ref); + + out_d = ((c3_d)bit_w + 0x7) >> 3; + // XX assumes little-endian + // + out_y = sab_u.buf_y; + + if ( 0 != memcmp(out_y, byt_y, len_w) ) { + fprintf(stderr, "\033[31mjam fib %s fail\033[0m\r\n", cap_c); + _byte_print(out_d, out_y, len_w, byt_y); + ret_i = 0; + } + + u3i_slab_free(&sab_u); + } + + return ret_i; +} + +static c3_i +_test_cue_spec(const c3_c* cap_c, + u3_noun ref, + c3_w len_w, + const c3_y* byt_y) +{ + c3_i ret_i = 1; + + { + u3_noun pro = u3m_soft(0, u3s_cue_atom, u3i_bytes(len_w, byt_y)); + u3_noun tag, out; + + u3x_cell(pro, &tag, &out); + + if ( u3_blip != tag ) { + fprintf(stderr, "\033[31mcue %s fail 1\033[0m\r\n", cap_c); + ret_i = 0; + } + else if ( c3n == u3r_sing(ref, out) ) { + fprintf(stderr, "\033[31mcue %s fail 2\033[0m\r\n", cap_c); + u3m_p("ref", ref); + u3m_p("out", out); + ret_i = 0; + } + + u3z(pro); + } + + { + u3_noun out; + + if ( u3_none == (out = u3s_cue_xeno(len_w, byt_y)) ) { + fprintf(stderr, "\033[31mcue %s fail 3\033[0m\r\n", cap_c); + ret_i = 0; + } + else if ( c3n == u3r_sing(ref, out) ) { + fprintf(stderr, "\033[31mcue %s fail 4\033[0m\r\n", cap_c); + u3m_p("ref", ref); + u3m_p("out", out); + ret_i = 0; + } + + u3z(out); + } + + return ret_i; +} + +static c3_i +_test_jam_roundtrip(void) +{ + c3_i ret_i = 1; + +# define TEST_CASE(a, b) \ + const c3_c* cap_c = a; \ + u3_noun ref = b; \ + ret_i &= _test_jam_spec(cap_c, ref, sizeof(res_y), res_y); \ + ret_i &= _test_cue_spec(cap_c, ref, sizeof(res_y), res_y); \ + u3z(ref); + + { + c3_y res_y[1] = { 0x2 }; + TEST_CASE("0", 0); + } + + { + c3_y res_y[1] = { 0xc }; + TEST_CASE("1", 1); + } + + { + c3_y res_y[1] = { 0x48 }; + TEST_CASE("2", 2); + } + + { + c3_y res_y[6] = { 0xc0, 0x37, 0xb, 0x9b, 0xa3, 0x3 }; + TEST_CASE("%fast", c3__fast); + } + + { + c3_y res_y[6] = { 0xc0, 0x37, 0xab, 0x63, 0x63, 0x3 }; + TEST_CASE("%full", c3__full); + } + + { + c3_y res_y[1] = { 0x29 }; + TEST_CASE("[0 0]", u3nc(0, 0)); + } + + { + c3_y res_y[2] = { 0x31, 0x3 }; + TEST_CASE("[1 1]", u3nc(1, 1)); + } + + { + c3_y res_y[2] = { 0x31, 0x12 }; + TEST_CASE("[1 2]", u3nc(1, 2)); + } + + { + c3_y res_y[2] = { 0x21, 0xd1 }; + TEST_CASE("[2 3]", u3nc(2, 3)); + } + + { + c3_y res_y[11] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0xe, 0x7c, 0xb3, 0x3a, 0x36, 0x36 }; + TEST_CASE("[%fast %full]", u3nc(c3__fast, c3__full)); + } + + { + c3_y res_y[2] = { 0x71, 0xcc }; + TEST_CASE("[1 1 1]", u3nc(1, u3nc(1, 1))); + } + + { + c3_y res_y[3] = { 0x71, 0x48, 0x34 }; + TEST_CASE("[1 2 3]", u3nt(1, 2, 3)); + } + + { + c3_y res_y[12] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0x1e, 0xf0, 0xcd, 0xea, 0xd8, 0xd8, 0x93 }; + TEST_CASE("[%fast %full %fast]", u3nc(c3__fast, u3nc(c3__full, c3__fast))); + } + + { + c3_y res_y[3] = { 0xc5, 0x48, 0x34 }; + TEST_CASE("[[1 2] 3]", u3nc(u3nc(1, 2), 3)); + } + + { + c3_y res_y[5] = { 0xc5, 0xc8, 0x26, 0x27, 0x1 }; + TEST_CASE("[[1 2] [1 2] 1 2]", u3nt(u3nc(1, 2), u3nc(1, 2), u3nc(1, 2))); + } + + { + c3_y res_y[6] = { 0xa5, 0x35, 0x19, 0xf3, 0x18, 0x5 }; + TEST_CASE("[[0 0] [[0 0] 1 1] 1 1]", u3nc(u3nc(0, 0), u3nc(u3nc(u3nc(0, 0), u3nc(1, 1)), u3nc(1, 1)))); + } + + { + c3_y res_y[14] = { 0x15, 0x17, 0xb2, 0xd0, 0x85, 0x59, 0xb8, 0x61, 0x87, 0x5f, 0x10, 0x54, 0x55, 0x5 }; + TEST_CASE("deep", u3nc(u3nc(u3nc(1, u3nc(u3nc(2, u3nc(u3nc(3, u3nc(u3nc(4, u3nc(u3nt(5, 6, u3nc(7, u3nc(u3nc(8, 0), 0))), 0)), 0)), 0)), 0)), 0), 0)); + } + + { + c3_y inp_y[33] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + c3_y res_y[35] = { 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 }; + TEST_CASE("wide", u3i_bytes(sizeof(inp_y), inp_y)); + } + + { + c3_y inp_y[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xa8, 0xab, 0x60, 0xef, 0x2d, 0xd, 0x0, 0x0, 0x80 }; + c3_y res_y[19] = { 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x50, 0x57, 0xc1, 0xde, 0x5b, 0x1a, 0x0, 0x0, 0x0, 0x1 }; + TEST_CASE("date", u3i_bytes(sizeof(inp_y), inp_y)); + } + + { + u3_noun a = u3i_string("abcdefjhijklmnopqrstuvwxyz"); + c3_y res_y[32] = { + 0x1, 0xf8, 0xc, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x53, 0x43, 0x4b, + 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b, 0x83, 0x8b, 0x93, 0x9b, 0xa3, + 0xab, 0xb3, 0xbb, 0xc3, 0xcb, 0xd3, 0x87, 0xc, 0x3d, 0x9 + }; + TEST_CASE("alpha", u3nq(u3k(a), 2, 3, a)); + } + + return ret_i; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_jam_roundtrip() ) { + fprintf(stderr, "test jam: failed\r\n"); + exit(1); + } + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "test jam: ok\r\n"); + return 0; +} diff --git a/vere/pkg/noun/ship.c b/vere/pkg/noun/ship.c new file mode 100644 index 0000000..6aebff7 --- /dev/null +++ b/vere/pkg/noun/ship.c @@ -0,0 +1,109 @@ +#include "c3/c3.h" +#include "types.h" +#include "imprison.h" +#include "retrieve.h" +#include "vortex.h" +#include "ship.h" + +static inline void +_s_chub_to_bytes(c3_y byt_y[8], c3_d num_d) +{ + byt_y[0] = num_d & 0xff; + byt_y[1] = (num_d >> 8) & 0xff; + byt_y[2] = (num_d >> 16) & 0xff; + byt_y[3] = (num_d >> 24) & 0xff; + byt_y[4] = (num_d >> 32) & 0xff; + byt_y[5] = (num_d >> 40) & 0xff; + byt_y[6] = (num_d >> 48) & 0xff; + byt_y[7] = (num_d >> 56) & 0xff; +} + +static inline c3_d +_s_bytes_to_chub(c3_y byt_y[8]) +{ + return (c3_d)byt_y[0] + | (c3_d)byt_y[1] << 8 + | (c3_d)byt_y[2] << 16 + | (c3_d)byt_y[3] << 24 + | (c3_d)byt_y[4] << 32 + | (c3_d)byt_y[5] << 40 + | (c3_d)byt_y[6] << 48 + | (c3_d)byt_y[7] << 56; +} + +void +u3_ship_to_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y) +{ + c3_y sip_y[16] = {0}; + + _s_chub_to_bytes(sip_y, who_u[0]); + _s_chub_to_bytes(sip_y + 8, who_u[1]); + + memcpy(buf_y, sip_y, c3_min(16, len_y)); +} + +void +u3_ship_of_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y) +{ + c3_y sip_y[16] = {0}; + memcpy(sip_y, buf_y, c3_min(16, len_y)); + + who_u[0] = _s_bytes_to_chub(sip_y); + who_u[1] = _s_bytes_to_chub(sip_y + 8); +} + +u3_atom +u3_ship_to_noun(u3_ship who_u) +{ + return u3i_chubs(2, who_u); +} + +c3_c* +u3_ship_to_string(u3_ship who_u) +{ + u3_noun ser = u3dc("scot", c3__p, u3_ship_to_noun(who_u)); + c3_c* who_c = u3r_string(ser); + u3z(ser); + return who_c; +} + +void +u3_ship_of_noun(u3_ship who_u, u3_noun who) +{ + u3r_chubs(0, 2, who_u, who); +} + +c3_o +u3_ships_equal(u3_ship sip_u, u3_ship sap_u) +{ + return __((sip_u[0] == sap_u[0]) && (sip_u[1] == sap_u[1])); +} + +void +u3_ship_copy(u3_ship des_u, u3_ship src_u) +{ + des_u[0] = src_u[0]; + des_u[1] = src_u[1]; +} + +c3_l +u3_ship_rank(u3_ship who_u) +{ + if ( who_u[1] ) return c3__pawn; + else if ( who_u[0] >> 32 ) return c3__earl; + else if ( who_u[0] >> 16 ) return c3__duke; + else if ( who_u[0] >> 8 ) return c3__king; + else return c3__czar; +} + +c3_y +u3_ship_czar(u3_ship who_u) { return who_u[0] & 0xFF; } + +c3_s +u3_ship_king(u3_ship who_u) { return who_u[0] & 0xffff; } + +c3_w +u3_ship_duke(u3_ship who_u) { return who_u[0] & 0xffffffff; } + +c3_d +u3_ship_earl(u3_ship who_u) { return who_u[0]; } diff --git a/vere/pkg/noun/ship.h b/vere/pkg/noun/ship.h new file mode 100644 index 0000000..8104c42 --- /dev/null +++ b/vere/pkg/noun/ship.h @@ -0,0 +1,57 @@ +#ifndef U3_SHIP_H +#define U3_SHIP_H + +#include "c3/c3.h" +#include "types.h" + +typedef c3_d u3_ship[2]; + +void +u3_ship_to_bytes(c3_d sip_d[2], c3_y len_y, c3_y* buf_y); + +void +u3_ship_of_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y); + +u3_atom +u3_ship_to_noun(u3_ship who_u); + +void +u3_ship_of_noun(u3_ship who_u, u3_noun who); + +c3_c* +u3_ship_to_string(u3_ship who_u); + +c3_o +u3_ships_equal(u3_ship sip_u, u3_ship sap_u); + +c3_l +u3_ship_rank(u3_ship who_u); + +void +u3_ship_copy(u3_ship des_u, u3_ship src_u); + +/** +* Returns a ship's galaxy byte prefix. +*/ +c3_y +u3_ship_czar(u3_ship who_u); + +/** +* Returns a ship's star prefix. +*/ +c3_s +u3_ship_king(u3_ship who_u); + +/** +* Returns a ship's planet prefix. +*/ +c3_w +u3_ship_duke(u3_ship who_u); + +/** +* Returns a ship's moon prefix. +*/ +c3_d +u3_ship_earl(u3_ship who_u); + +#endif /* ifndef U3_SHIP_H */ diff --git a/vere/pkg/noun/trace.c b/vere/pkg/noun/trace.c new file mode 100644 index 0000000..8ddbf2e --- /dev/null +++ b/vere/pkg/noun/trace.c @@ -0,0 +1,1242 @@ +/// @file + +#include "trace.h" + +#include <errno.h> +#include <pthread.h> +#include <sys/stat.h> +#include <time.h> +#include <signal.h> + +#include "allocate.h" +#include "imprison.h" +#include "jets/k.h" +#include "log.h" +#include "manage.h" +#include "options.h" +#include "retrieve.h" +#include "vortex.h" + +/** Global variables. +**/ +u3t_spin *stk_u; +u3t_trace u3t_Trace; + +static c3_o _ct_lop_o; + +/// Nock PID. +static c3_ws _nock_pid_i = 0; + +/// JSON trace file. +static FILE* _file_u = NULL; + +/// Trace counter. Tracks the number of entries written to the JSON trace file. +static c3_w _trace_cnt_w = 0; + +/// File counter. Tracks the number of times u3t_trace_close() has been called. +static c3_w _file_cnt_w = 0; + +/* u3t_push(): push on trace stack. +*/ +void +u3t_push(u3_noun mon) +{ + u3R->bug.tax = u3nc(mon, u3R->bug.tax); +} + +/* u3t_mean(): push `[%mean roc]` on trace stack. +*/ +void +u3t_mean(u3_noun roc) +{ + u3R->bug.tax = u3nc(u3nc(c3__mean, roc), u3R->bug.tax); +} + +/* u3t_drop(): drop from meaning stack. +*/ +void +u3t_drop(void) +{ + u3_assert(_(u3du(u3R->bug.tax))); + { + u3_noun tax = u3R->bug.tax; + + u3R->bug.tax = u3k(u3t(tax)); + u3z(tax); + } +} + +/* u3t_slog(): print directly. +*/ +void +u3t_slog(u3_noun hod) +{ + if ( 0 != u3C.slog_f ) { + u3C.slog_f(hod); + } + else { + u3z(hod); + } +} + +/* u3t_heck(): profile point. +*/ +void +u3t_heck(u3_atom cog) +{ +#if 0 + u3R->pro.cel_d++; +#else + c3_w len_w = u3r_met(3, cog); + c3_c* str_c = alloca(1 + len_w); + + u3r_bytes(0, len_w, (c3_y *)str_c, cog); + str_c[len_w] = 0; + + // Profile sampling, because it allocates on the home road, + // only works on when we're not at home. + // + if ( &(u3H->rod_u) != u3R ) { + u3a_road* rod_u; + + rod_u = u3R; + u3R = &(u3H->rod_u); + { + if ( 0 == u3R->pro.day ) { + u3R->pro.day = u3do("doss", 0); + } + u3R->pro.day = u3dc("pi-heck", u3i_string(str_c), u3R->pro.day); + } + u3R = rod_u; + } +#endif +} + +#if 0 +static void +_ct_sane(u3_noun lab) +{ + if ( u3_nul != lab ) { + u3_assert(c3y == u3du(lab)); + u3_assert(c3y == u3ud(u3h(lab))); + _ct_sane(u3t(lab)); + } +} +#endif + +#if 1 +/* _t_samp_process(): process raw sample data from live road. +*/ +static u3_noun +_t_samp_process(u3_road* rod_u) +{ + u3_noun pef = u3_nul; // (list (pair path (map path ,@ud))) + u3_noun muf = u3_nul; // (map path ,@ud) + c3_w len_w = 0; + + // Accumulate a label/map stack which collapses recursive segments. + // + while ( rod_u ) { + u3_noun don = rod_u->pro.don; + + while ( u3_nul != don ) { + // Get surface allocated label + // + // u3_noun lab = u3nc(u3i_string("foobar"), 0); + u3_noun laj = u3h(don), + lab = u3a_take(laj); + u3a_wash(laj); + + // Add the label to the traced label stack, trimming recursion. + // + { + u3_noun old; + + if ( u3_none == (old = u3kdb_get(u3k(muf), u3k(lab))) ) { + muf = u3kdb_put(muf, u3k(lab), len_w); + pef = u3nc(u3nc(lab, u3k(muf)), pef); + len_w += 1; + } + else { + if ( !_(u3a_is_cat(old)) ) { + u3m_bail(c3__fail); + } + + u3z(muf); + while ( len_w > (old + 1) ) { + u3_noun t_pef = u3k(u3t(pef)); + + len_w -= 1; + u3z(pef); + pef = t_pef; + } + muf = u3k(u3t(u3h(pef))); + u3z(lab); + } + } + don = u3t(don); + } + rod_u = u3tn(u3_road, rod_u->par_p); + } + u3z(muf); + + // Lose the maps and save a pure label stack in original order. + // + { + u3_noun pal = u3_nul; + + while ( u3_nul != pef ) { + u3_noun h_pef = u3h(pef); + u3_noun t_pef = u3k(u3t(pef)); + + pal = u3nc(u3k(u3h(h_pef)), pal); + + u3z(pef); + pef = t_pef; + } + + // u3l_log("sample: stack length %d", u3kb_lent(u3k(pal))); + return pal; + } +} +#endif + +/* u3t_samp(): sample. +*/ +void +u3t_samp(void) +{ + if ( c3y == _ct_lop_o ) { + // _ct_lop_o here is a mutex for modifying pro.don. we + // do not want to sample in the middle of doing that, as + // it can cause memory errors. + return; + } + + c3_w old_wag = u3C.wag_w; + u3C.wag_w &= ~u3o_debug_cpu; + u3C.wag_w &= ~u3o_trace; + + // Profile sampling, because it allocates on the home road, + // only works on when we're not at home. + // + if ( &(u3H->rod_u) != u3R ) { + c3_l mot_l; + u3a_road* rod_u; + + if ( _(u3T.mal_o) ) { + mot_l = c3_s3('m','a','l'); + } + else if ( _(u3T.coy_o) ) { + mot_l = c3_s3('c','o','y'); + } + else if ( _(u3T.euq_o) ) { + mot_l = c3_s3('e','u','q'); + } + else if ( _(u3T.far_o) ) { + mot_l = c3_s3('f','a','r'); + } + else if ( _(u3T.noc_o) ) { + u3_assert(!_(u3T.glu_o)); + mot_l = c3_s3('n','o','c'); + } + else if ( _(u3T.glu_o) ) { + mot_l = c3_s3('g','l','u'); + } + else { + mot_l = c3_s3('f','u','n'); + } + + rod_u = u3R; + u3R = &(u3H->rod_u); + { + u3_noun lab = _t_samp_process(rod_u); + + u3_assert(u3R == &u3H->rod_u); + if ( 0 == u3R->pro.day ) { + /* bunt a +doss + */ + u3R->pro.day = u3nt(u3nq(0, 0, 0, u3nq(0, 0, 0, 0)), 0, 0); + } + u3R->pro.day = u3dt("pi-noon", mot_l, lab, u3R->pro.day); + } + u3R = rod_u; + } + u3C.wag_w = old_wag; +} + +/* u3t_come(): push on profile stack; return yes if active push. RETAIN. +*/ +c3_o +u3t_come(u3_noun lab) +{ + if ( (u3_nul == u3R->pro.don) || !_(u3r_sing(lab, u3h(u3R->pro.don))) ) { + u3a_gain(lab); + _ct_lop_o = c3y; + u3R->pro.don = u3nc(lab, u3R->pro.don); + _ct_lop_o = c3n; + return c3y; + } + else return c3n; +} + +/* u3t_flee(): pop off profile stack. +*/ +void +u3t_flee(void) +{ + _ct_lop_o = c3y; + u3_noun don = u3R->pro.don; + u3R->pro.don = u3k(u3t(don)); + _ct_lop_o = c3n; + u3z(don); +} + +/* u3t_trace_open(): opens a trace file and writes the preamble. +*/ +void +u3t_trace_open(const c3_c* dir_c) +{ + c3_c fil_c[2048]; + + if ( !dir_c ) { + return; + } + + snprintf(fil_c, 2048, "%s/.urb/put/trace", dir_c); + + struct stat st; + if ( (-1 == stat(fil_c, &st)) + && (-1 == c3_mkdir(fil_c, 0700)) ) + { + fprintf(stderr, "mkdir: %s failed: %s\r\n", fil_c, strerror(errno)); + return; + } + + c3_c lif_c[2056]; + snprintf(lif_c, 2056, "%s/%d.json", fil_c, _file_cnt_w); + + _file_u = c3_fopen(lif_c, "w"); + _nock_pid_i = (int)getpid(); + + if ( !_file_u ) { + fprintf(stderr, "trace open: %s\r\n", strerror(errno)); + return; + } + + fprintf(_file_u, "[ "); + + // We have two "threads", the event processing and the nock stuff. + // tid 1 = event processing + // tid 2 = nock processing + fprintf(_file_u, + "{\"name\": \"process_name\", \"ph\": \"M\", \"pid\": %d, \"args\": " + "{\"name\": \"urbit\"}},\n", + _nock_pid_i); + fprintf(_file_u, + "{\"name\": \"thread_name\", \"ph\": \"M\", \"pid\": %d, \"tid\": 1, " + "\"args\": {\"name\": \"Event Processing\"}},\n", + _nock_pid_i); + fprintf(_file_u, + "{\"name\": \"thread_sort_index\", \"ph\": \"M\", \"pid\": %d, " + "\"tid\": 1, \"args\": {\"sort_index\": 1}},\n", + _nock_pid_i); + fprintf(_file_u, + "{\"name\": \"thread_name\", \"ph\": \"M\", \"pid\": %d, \"tid\": 2, " + "\"args\": {\"name\": \"Nock\"}},\n", + _nock_pid_i); + fprintf(_file_u, + "{\"name\": \"thread_sort_index\", \"ph\": \"M\", \"pid\": %d, " + "\"tid\": 2, \"args\": {\"sort_index\": 2}},\n", + _nock_pid_i); + _trace_cnt_w = 5; +} + +/* u3t_trace_close(): closes a trace file. optional. +*/ +void +u3t_trace_close(void) +{ + if ( !_file_u ) + return; + + // We don't terminate the JSON because of the file format. + fclose(_file_u); + _trace_cnt_w = 0; + _file_cnt_w++; +} + +/* u3t_trace_time(): microsecond clock +*/ +c3_d u3t_trace_time(void) +{ + struct timeval tim_tv; + gettimeofday(&tim_tv, 0); + return 1000000ULL * tim_tv.tv_sec + tim_tv.tv_usec; +} + +/* u3t_nock_trace_push(): push a trace onto the trace stack; returns yes if pushed. + * + * The trace stack is a stack of [path time-entered]. + */ +c3_o +u3t_nock_trace_push(u3_noun lab) +{ + if ( !_file_u ) + return c3n; + + if ( (u3_nul == u3R->pro.trace) || + !_(u3r_sing(lab, u3h(u3h(u3R->pro.trace)))) ) { + u3a_gain(lab); + c3_d time = u3t_trace_time(); + u3R->pro.trace = u3nc(u3nc(lab, u3i_chubs(1, &time)), u3R->pro.trace); + return c3y; + } + else { + return c3n; + } +} + +/* u3t_nock_trace_pop(): pops a trace from the trace stack. + * + * When we remove the trace from the stack, we check to see if the sample is + * large enough to process, as we'll otherwise keep track of individual +add + * calls. If it is, we write it out to the tracefile. + */ +void +u3t_nock_trace_pop(void) +{ + if ( !_file_u ) + return; + + u3_noun trace = u3R->pro.trace; + u3R->pro.trace = u3k(u3t(trace)); + + u3_noun item = u3h(trace); + u3_noun lab = u3h(item); + c3_d start_time = u3r_chub(0, u3t(item)); + + // 33microseconds (a 30th of a millisecond). + c3_d duration = u3t_trace_time() - start_time; + if (duration > 33) { + c3_c* name = u3m_pretty_path(lab); + + fprintf(_file_u, + "{\"cat\": \"nock\", \"name\": \"%s\", \"ph\":\"%c\", \"pid\": %d, " + "\"tid\": 2, \"ts\": %" PRIu64 ", \"dur\": %" PRIu64 "}, \n", + name, + 'X', + _nock_pid_i, + start_time, + duration); + + c3_free(name); + _trace_cnt_w++; + } + + u3z(trace); +} + +/* u3t_event_trace(): dumps a simple event from outside nock. +*/ +void +u3t_event_trace(const c3_c* name, c3_c type) +{ + if ( !_file_u ) + return; + + fprintf(_file_u, + "{\"cat\": \"event\", \"name\": \"%s\", \"ph\":\"%c\", \"pid\": %d, " + "\"tid\": 1, \"ts\": %" PRIu64 ", \"id\": \"0x100\"}, \n", + name, + type, + _nock_pid_i, + u3t_trace_time()); + _trace_cnt_w++; +} + +/* u3t_print_steps: print step counter. +*/ +void +u3t_print_steps(FILE* fil_u, c3_c* cap_c, c3_d sep_d) +{ + u3_assert( 0 != fil_u ); + + c3_w gib_w = (sep_d / 1000000000ULL); + c3_w mib_w = (sep_d % 1000000000ULL) / 1000000ULL; + c3_w kib_w = (sep_d % 1000000ULL) / 1000ULL; + c3_w bib_w = (sep_d % 1000ULL); + + // XX prints to stderr since it's called on shutdown, daemon may be gone + // + if ( sep_d ) { + if ( gib_w ) { + fprintf(fil_u, "%s: G/%d.%03d.%03d.%03d\r\n", + cap_c, gib_w, mib_w, kib_w, bib_w); + } + else if ( mib_w ) { + fprintf(fil_u, "%s: M/%d.%03d.%03d\r\n", cap_c, mib_w, kib_w, bib_w); + } + else if ( kib_w ) { + fprintf(fil_u, "%s: K/%d.%03d\r\n", cap_c, kib_w, bib_w); + } + else if ( bib_w ) { + fprintf(fil_u, "%s: %d\r\n", cap_c, bib_w); + } + } +} + +/* u3t_damp(): print and clear profile data. +*/ +void +u3t_damp(FILE* fil_u) +{ + u3_assert( 0 != fil_u ); + + if ( 0 != u3R->pro.day ) { + u3_noun wol = u3do("pi-tell", u3R->pro.day); + + // XX prints to stderr since it's called on shutdown, daemon may be gone + // + { + u3_noun low = wol; + + while ( u3_nul != low ) { + c3_c* str_c = (c3_c*)u3r_tape(u3h(low)); + fputs(str_c, fil_u); + fputs("\r\n", fil_u); + + c3_free(str_c); + low = u3t(low); + } + + u3z(wol); + } + + /* bunt a +doss + */ + u3R->pro.day = u3nt(u3nq(0, 0, 0, u3nq(0, 0, 0, 0)), 0, 0); + } + + u3t_print_steps(fil_u, "nocks", u3R->pro.nox_d); + u3t_print_steps(fil_u, "cells", u3R->pro.cel_d); + + u3R->pro.nox_d = 0; + u3R->pro.cel_d = 0; +} + +/* _ct_sigaction(): profile sigaction callback. +*/ +void _ct_sigaction(c3_i x_i) +{ + u3t_samp(); +} + +/* u3t_init(): initialize tracing layer. +*/ +void +u3t_init(void) +{ + u3T.noc_o = c3n; + u3T.glu_o = c3n; + u3T.mal_o = c3n; + u3T.far_o = c3n; + u3T.coy_o = c3n; + u3T.euq_o = c3n; +} + +c3_w +u3t_trace_cnt(void) +{ + return _trace_cnt_w; +} + +c3_w +u3t_file_cnt(void) +{ + return _file_cnt_w; +} + +/* u3t_boot(): turn sampling on. +*/ +void +u3t_boot(void) +{ +#ifndef U3_OS_windows + if ( u3C.wag_w & u3o_debug_cpu ) { + _ct_lop_o = c3n; +#if defined(U3_OS_PROF) + // skip profiling if we don't yet have an arvo kernel + // + if ( 0 == u3A->roc ) { + return; + } + + // Register _ct_sigaction to be called on `SIGPROF`. + { + struct sigaction sig_s = {{0}}; + sig_s.sa_handler = _ct_sigaction; + sigemptyset(&(sig_s.sa_mask)); + sigaction(SIGPROF, &sig_s, 0); + } + + // Unblock `SIGPROF` for this thread (we will block it again when `u3t_boff` is called). + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGPROF); + if ( 0 != pthread_sigmask(SIG_UNBLOCK, &set, NULL) ) { + u3l_log("trace: thread mask SIGPROF: %s", strerror(errno)); + } + } + + // Ask for SIGPROF to be sent every 10ms. + { + struct itimerval itm_v = {{0}}; + itm_v.it_interval.tv_usec = 10000; + itm_v.it_value = itm_v.it_interval; + setitimer(ITIMER_PROF, &itm_v, 0); + } +#endif + } +#endif +} + +/* u3t_boff(): turn profile sampling off. +*/ +void +u3t_boff(void) +{ +#ifndef U3_OS_windows + if ( u3C.wag_w & u3o_debug_cpu ) { +#if defined(U3_OS_PROF) + // Mask SIGPROF signals in this thread (and this is the only + // thread that unblocked them). + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGPROF); + if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) { + u3l_log("trace: thread mask SIGPROF: %s", strerror(errno)); + } + } + + // Disable the SIGPROF timer. + { + struct itimerval itm_v = {{0}}; + setitimer(ITIMER_PROF, &itm_v, 0); + } + + // Ignore SIGPROF signals. + { + struct sigaction sig_s = {{0}}; + sigemptyset(&(sig_s.sa_mask)); + sig_s.sa_handler = SIG_IGN; + sigaction(SIGPROF, &sig_s, 0); + } +#endif + } +#endif +} + + +/* u3t_slog_cap(): slog a tank with a caption with +** a given priority c3_l (assumed 0-3). +*/ +void +u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan) +{ + u3t_slog( + u3nc( + pri_l, + u3nt( + c3__rose, + u3nt(u3nt(':', ' ', u3_nul), u3_nul, u3_nul), + u3nt(cap, tan, u3_nul) + ) + ) + ); +} + + +/* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax +** flop the order into start-to-end, render, and slog each item +** until done. +*/ +void +u3t_slog_trace(c3_l pri_l, u3_noun tax) +{ + // render the stack + // Note: ton is a reference to a data struct + // we have just allocated + // lit is used as a moving cursor pointer through + // that allocated struct + // once we finish lit will be null, but ton will still + // point to the whole valid allocated data structure + // and thus we can free it safely at the end of the func + // to clean up after ourselves. + // Note: flop reverses the stack trace list 'tax' + u3_noun ton = u3dc("mook", 2, u3kb_flop(tax)); + u3_noun lit = u3t(ton); + + // print the stack one stack item at a time + while ( u3_nul != lit ) { + u3t_slog(u3nc(pri_l, u3k(u3h(lit)) )); + lit = u3t(lit); + } + + u3z(ton); +} + + +/* u3t_slog_nara(): slog only the deepest road's trace with +** c3_l priority pri +*/ +void +u3t_slog_nara(c3_l pri_l) +{ + u3_noun tax = u3k(u3R->bug.tax); + u3t_slog_trace(pri_l, tax); +} + + +/* u3t_slog_hela(): join all roads' traces together into one tax +** and pass it to slog_trace along with the given c3_l priority pri_l +*/ +void +u3t_slog_hela(c3_l pri_l) +{ + // rod_u protects us from mutating the global state + u3_road* rod_u = u3R; + + // inits to the the current road's trace + u3_noun tax = u3k(rod_u->bug.tax); + + // while there is a parent road ref ... + while ( &(u3H->rod_u) != rod_u ) { + // ... point at the next road and append its stack to tax + rod_u = u3tn(u3_road, rod_u->par_p); + tax = u3kb_weld(tax, u3k(rod_u->bug.tax)); + } + + u3t_slog_trace(pri_l, tax); +} + +/* _ct_roundf(): truncate a float to precision equivalent to %.2f */ +static float +_ct_roundf(float per_f) +{ + // scale the percentage so that all siginificant digits + // would be retained when truncted to an int, then add 0.5 + // to account for rounding without using round or roundf + float big_f = (per_f*10000)+0.5; + // truncate to int + c3_w big_w = (c3_w) big_f; + // convert to float and scale down such that + // our last two digits are right of the decimal + float tuc_f = (float) big_w/100.0; + return tuc_f; +} + +/* _ct_meme_percent(): convert two ints into a percentage */ +static float +_ct_meme_percent(c3_w lit_w, c3_w big_w) +{ + // get the percentage of our inputs as a float + float raw_f = (float) lit_w/big_w; + return _ct_roundf(raw_f); +} + +/* _ct_all_heap_size(): return the size in bytes of ALL space on the Loom +** over all roads, currently in use as heap. +*/ +static c3_w +_ct_all_heap_size(u3_road* r) { + if (r == &(u3H->rod_u)) { + return u3a_heap(r)*4; + } else { + // recurse + return (u3a_heap(r)*4) + _ct_all_heap_size(u3tn(u3_road, r->par_p)); + } +} + +/* These two structs, bar_item and bar_info, store the mutable data +** to normalize measured Loom usage values into ints that will fit +** into a fixed width ascii bar chart. +*/ +struct +bar_item { + // index + c3_w dex_w; + // lower bound + c3_w low_w; + // original value + float ori_f; + // difference + float dif_f; +}; + +struct +bar_info { + struct bar_item s[6]; +}; + +/* _ct_boost_small(): we want zero to be zero, +** anything between zero and one to be one, +** and all else to be whatever it is. +*/ +static float +_ct_boost_small(float num_f) +{ + return + 0.0 >= num_f ? 0.0: + 1.0 > num_f ? 1.0: + num_f; +} + +/* _ct_global_difference(): each low_w represents the normalized integer value + * of its loom item, and ideally the sum of all loom low_w + * values should be 100. This function reports how far from + * the ideal bar_u is. +*/ +static c3_ws +_ct_global_difference(struct bar_info bar_u) +{ + c3_w low_w = 0; + for (c3_w i=0; i < 6; i++) { + low_w += bar_u.s[i].low_w; + } + return 100 - low_w; +} + +/* _ct_compute_roundoff_error(): for each loom item in bar_u +** compute the current difference between the int +** size and the original float size. +*/ +static struct bar_info +_ct_compute_roundoff_error(struct bar_info bar_u) +{ + for (c3_w i=0; i < 6; i++) { + bar_u.s[i].dif_f = bar_u.s[i].ori_f - bar_u.s[i].low_w; + } + return bar_u; +} + +/* _ct_sort_by_roundoff_error(): sort loom items from most mis-sized to least */ +static struct bar_info +_ct_sort_by_roundoff_error(struct bar_info bar_u) +{ + struct bar_item tem_u; + for (c3_w i=1; i < 6; i++) { + for (c3_w j=0; j < 6-i; j++) { + if (bar_u.s[j+1].dif_f > bar_u.s[j].dif_f) { + tem_u = bar_u.s[j]; + bar_u.s[j] = bar_u.s[j+1]; + bar_u.s[j+1] = tem_u; + } + } + } + return bar_u; +} + +/* _ct_sort_by_index(): sort loom items into loom order */ +static struct bar_info +_ct_sort_by_index(struct bar_info bar_u) +{ + struct bar_item tem_u; + for (c3_w i=1; i < 6; i++) { + for (c3_w j=0; j < 6-i; j++) { + if (bar_u.s[j+1].dex_w < bar_u.s[j].dex_w) { + tem_u = bar_u.s[j]; + bar_u.s[j] = bar_u.s[j+1]; + bar_u.s[j+1] = tem_u; + } + } + } + return bar_u; +} + +/* _ct_reduce_error(): reduce error by one int step + * making oversized things a bit smaller + * and undersized things a bit bigger +*/ +static struct bar_info +_ct_reduce_error(struct bar_info bar_u, c3_ws dif_s) +{ + for (c3_w i=0; i < 6; i++) { + if (bar_u.s[i].low_w == 0) continue; + if (bar_u.s[i].low_w == 1) continue; + if (dif_s > 0) { + bar_u.s[i].low_w++; + dif_s--; + } + if (dif_s < 0) { + bar_u.s[i].low_w--; + dif_s++; + } + } + return bar_u; +} + +/* _ct_report_bargraph(): render all six raw loom elements into a fixed-size ascii bargraph */ +static void +_ct_report_bargraph( + c3_c bar_c[105], float hip_f, float hep_f, float fre_f, float pen_f, float tak_f, float tik_f +) +{ + float in[6]; + in[0] = _ct_boost_small(hip_f); + in[1] = _ct_boost_small(hep_f); + in[2] = _ct_boost_small(fre_f); + in[3] = _ct_boost_small(pen_f); + in[4] = _ct_boost_small(tak_f); + in[5] = _ct_boost_small(tik_f); + + // init the list of structs + struct bar_info bar_u; + for (c3_w i=0; i < 6; i++) { + bar_u.s[i].dex_w = i; + bar_u.s[i].ori_f = in[i]; + bar_u.s[i].low_w = (c3_w) bar_u.s[i].ori_f; + } + + // repeatedly adjust for roundoff error + // until it is elemenated or we go 100 cycles + c3_ws dif_s = 0; + for (c3_w x=0; x<100; x++) { + bar_u = _ct_compute_roundoff_error(bar_u); + dif_s = _ct_global_difference(bar_u); + if (dif_s == 0) break; + bar_u = _ct_sort_by_roundoff_error(bar_u); + bar_u = _ct_reduce_error(bar_u, dif_s); + } + bar_u = _ct_sort_by_index(bar_u); + + for (c3_w x=1; x<104; x++) { + bar_c[x] = ' '; + } + bar_c[0] = '['; + + // create our bar chart + const c3_c sym_c[6] = "=-%#+~"; + c3_w x = 0, y = 0; + for (c3_w i=0; i < 6; i++) { + x++; + for (c3_w j=0; j < bar_u.s[i].low_w; j++) { + bar_c[x+j] = sym_c[i]; + y = x+j; + } + if (y > 0) x = y; + } + bar_c[101] = ']'; + bar_c[102] = 0; +} + +/* _ct_size_prefix(): return the correct metric scalar prifix for a given int */ +static c3_c +_ct_size_prefix(c3_d num_d) +{ + return + (num_d / 1000000000) ? 'G': + (num_d % 1000000000) / 1000000 ? 'M': + (num_d % 1000000) / 1000 ? 'K': + (num_d % 1000) ? ' ': + 'X'; +} + +/* _ct_report_string(): convert a int into a string, adding a metric scale prefix letter*/ +static void +_ct_report_string(c3_c rep_c[32], c3_d num_d) +{ + memset(rep_c, ' ', 31); + + // add the G/M/K prefix + rep_c[24] = _ct_size_prefix(num_d); + // consume wor_w into a string one base-10 digit at a time + // including dot formatting + c3_w i = 0, j = 0; + while (num_d > 0) { + if (j == 3) { + rep_c[22-i] = '.'; + i++; + j = 0; + } else { + rep_c[22-i] = (num_d%10)+'0'; + num_d /= 10; + i++; + j++; + } + } +} + +/* _ct_etch_road_depth(): return a the current road depth as a fixed size string */ +static void + _ct_etch_road_depth(c3_c rep_c[32], u3_road* r, c3_w num_w) { + if (r == &(u3H->rod_u)) { + _ct_report_string(rep_c, num_w); + // this will be incorrectly indented, so we fix that here + c3_w i = 14; + while (i > 0) { + rep_c[i] = rep_c[i+16]; + rep_c[i+16] = ' '; + i--; + } + } else { + _ct_etch_road_depth(rep_c, u3tn(u3_road, r->par_p), ++num_w); + } +} + +/* _ct_etch_memory(): create a single line report of a given captioned item + * with a percentage of space used and the bytes used + * scaled by a metric scaling postfix (ie MB, GB, etc) +*/ +static void +_ct_etch_memory(c3_c rep_c[32], float per_f, c3_w num_w) +{ + // create the basic report string + _ct_report_string(rep_c, num_w); + // add the Bytes postfix to the size report + rep_c[25] = 'B'; + + // add the space-percentage into the report + rep_c[2] = '0', rep_c[3] = '.', rep_c[4] = '0', rep_c[5] = '0'; + c3_w per_i = (c3_w) (per_f*100); + c3_w i = 0; + while (per_i > 0 && i < 6) { + if (i != 2) { + rep_c[5-i] = (per_i%10)+'0'; + per_i /= 10; + } + i++; + } + // add the percent sign + rep_c[6] = '%'; +} + +/* _ct_etch_steps(): create a single line report of a given captioned item +** scaled by a metric scaling postfix, but unitless. +*/ +static void +_ct_etch_steps(c3_c rep_c[32], c3_d sep_d) +{ + _ct_report_string(rep_c, sep_d); +} + +/* u3t_etch_meme(): report memory stats at call time */ +u3_noun +u3t_etch_meme(c3_l mod_l) +{ + u3a_road* lum_r; + lum_r = &(u3H->rod_u); + // this will need to switch to c3_d when we go to a 64 loom + c3_w top_w = u3a_full(lum_r)*4, + ful_w = u3a_full(u3R)*4, + fre_w = u3a_idle(u3R)*4, + tak_w = u3a_temp(u3R)*4, + hap_w = u3a_heap(u3R)*4, + pen_w = u3a_open(u3R)*4; + + c3_w imu_w = top_w-ful_w; + c3_w hep_w = hap_w-fre_w; + + + float hep_f = _ct_meme_percent(hep_w, top_w), + fre_f = _ct_meme_percent(fre_w, top_w), + pen_f = _ct_meme_percent(pen_w, top_w), + tak_f = _ct_meme_percent(tak_w, top_w); + float ful_f = hep_f + fre_f + pen_f + tak_f; + + c3_w hip_w = _ct_all_heap_size(u3R) - hap_w; + c3_w tik_w = imu_w - hip_w; + float hip_f = _ct_meme_percent(hip_w, top_w), + tik_f = _ct_meme_percent(tik_w, top_w); + +#ifdef U3_CPU_DEBUG + /* iff we are using CPU_DEBUG env var + ** we can report more facts: + ** max_w: max allocated on the current road (not global, not including child roads) + ** cel_d: max cells allocated in current road (inc closed kids, but not parents) + ** nox_d: nock steps performed in current road + */ + c3_w max_w = (u3R->all.max_w*4)+imu_w; + float max_f = _ct_meme_percent(max_w, top_w); + c3_d cel_d = u3R->pro.cel_d; + c3_d nox_d = u3R->pro.nox_d; + // iff we have a max_f we will render it into the bar graph + // in other words iff we have max_f it will always replace something + c3_w inc_w = (max_f > hip_f+1.0) ? (c3_w) max_f+0.5 : (c3_w) hip_f+1.5; +#endif + + // warn if any sanity checks have failed + if (100.01 < (hip_f + hep_f + fre_f + pen_f + tak_f + tik_f)) + u3t_slog_cap(2, u3i_string("warning"), u3i_string("loom sums over 100.01%")); + if ( 99.99 > (hip_f + hep_f + fre_f + pen_f + tak_f + tik_f)) + u3t_slog_cap(2, u3i_string("warning"), u3i_string("loom sums under 99.99%")); + + c3_c bar_c[105]; + bar_c[0] = 0; + _ct_report_bargraph(bar_c, hip_f, hep_f, fre_f, pen_f, tak_f, tik_f); + + c3_w dol = (c3_w) _ct_roundf(hip_f/100); + bar_c[dol] = '$'; +#ifdef U3_CPU_DEBUG + if (max_f > 0.0) { + bar_c[inc_w] = '|'; + } +#endif + + c3_c dir_n[8]; + dir_n[0] = 0; + if ( u3a_is_north(u3R) == c3y ) { + strcat(dir_n, " North"); + } else { + strcat(dir_n, " South"); + } + + if (mod_l == 0) { + return u3i_string(bar_c); + } + else { + c3_c rep_c[32]; + rep_c[31] = 0; + c3_c str_c[1024]; + str_c[0] = 0; + // each report line is at most 54 chars long + strcat(str_c, "Legend | Report:"); + + strcat(str_c, "\n loom: "); _ct_etch_memory(rep_c, 100.0, top_w); strcat(str_c, rep_c); + strcat(str_c, "\n road: "); _ct_etch_memory(rep_c, ful_f, ful_w); strcat(str_c, rep_c); + strcat(str_c, "\n"); + strcat(str_c, "\n = immutable heap: "); _ct_etch_memory(rep_c, hip_f, hip_w); strcat(str_c, rep_c); + strcat(str_c, "\n - solid heap: "); _ct_etch_memory(rep_c, hep_f, hep_w); strcat(str_c, rep_c); + strcat(str_c, "\n % freed heap: "); _ct_etch_memory(rep_c, fre_f, fre_w); strcat(str_c, rep_c); + strcat(str_c, "\n # open space: "); _ct_etch_memory(rep_c, pen_f, pen_w); strcat(str_c, rep_c); + strcat(str_c, "\n + stack: "); _ct_etch_memory(rep_c, tak_f, tak_w); strcat(str_c, rep_c); + strcat(str_c, "\n ~ immutable stack: "); _ct_etch_memory(rep_c, tik_f, tik_w); strcat(str_c, rep_c); + strcat(str_c, "\n"); + strcat(str_c, "\n $ allocation frame: "); _ct_etch_memory(rep_c, hip_f, hip_w); strcat(str_c, rep_c); +#ifdef U3_CPU_DEBUG + strcat(str_c, "\n | road max memory: "); _ct_etch_memory(rep_c, max_f, max_w); strcat(str_c, rep_c); + strcat(str_c, "\n"); + strcat(str_c, "\n road cells made: "); _ct_etch_steps(rep_c, cel_d); strcat(str_c, rep_c); + strcat(str_c, "\n road nocks made: "); _ct_etch_steps(rep_c, nox_d); strcat(str_c, rep_c); +#endif + strcat(str_c, "\n road direction: "); strcat(str_c, dir_n); + strcat(str_c, "\n road depth: "); _ct_etch_road_depth(rep_c, u3R, 1); strcat(str_c, rep_c); + strcat(str_c, "\n\nLoom: "); strcat(str_c, bar_c); + return u3i_string(str_c); + } +} + +/* u3t_sstack_init: initalize a root node on the spin stack +*/ +void +u3t_sstack_init() +{ +#ifndef U3_OS_windows + c3_c shm_name[256]; + snprintf(shm_name, sizeof(shm_name), SLOW_STACK_NAME, getppid()); + c3_w shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666); + if ( -1 == shm_fd) { + perror("shm_open failed"); + return; + } + + if ( -1 == ftruncate(shm_fd, TRACE_PSIZE)) { + perror("truncate failed"); + return; + } + + stk_u = mmap(NULL, TRACE_PSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if ( MAP_FAILED == stk_u ) { + perror("mmap failed"); + return; + } + + stk_u->off_w = 0; + stk_u->fow_w = 0; + u3t_sstack_push(c3__root); +#endif +} + +#ifndef U3_OS_windows +/* u3t_sstack_open: initalize a root node on the spin stack + */ +u3t_spin* +u3t_sstack_open() +{ + //Setup spin stack + c3_c shm_name[256]; + snprintf(shm_name, sizeof(shm_name), SLOW_STACK_NAME, getpid()); + c3_w shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0); + if ( -1 == shm_fd) { + perror("shm_open failed"); + return NULL; + } + + u3t_spin* stk_u = mmap(NULL, TRACE_PSIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if ( MAP_FAILED == stk_u ) { + perror("mmap failed"); + return NULL; + } + + return stk_u; +} +#endif +/* u3t_sstack_exit: shutdown the shared memory for thespin stack +*/ +void +u3t_sstack_exit() +{ + munmap(stk_u, u3a_page); +} + +/* u3t_sstack_push: push a noun on the spin stack. +*/ +void +u3t_sstack_push(u3_noun nam) +{ + if ( !stk_u ) { + u3z(nam); + return; + } + + if ( c3n == u3ud(nam) ) { + u3z(nam); + nam = c3__cell; + } + + c3_w met_w = u3r_met(3, nam); + + // Exit if full + if ( 0 < stk_u->fow_w || + sizeof(stk_u->dat_y) < stk_u->off_w + met_w + sizeof(c3_w) ) { + stk_u->fow_w++; + return; + } + + u3r_bytes(0, met_w, (c3_y*)(stk_u->dat_y+stk_u->off_w), nam); + stk_u->off_w += met_w; + + memcpy(&stk_u->dat_y[stk_u->off_w], &met_w, sizeof(c3_w)); + stk_u->off_w += sizeof(c3_w); + u3z(nam); +} + +/* u3t_sstack_pop: pop a noun from the spin stack. +*/ +void +u3t_sstack_pop() +{ + if ( !stk_u ) return; + if ( 0 < stk_u->fow_w ) { + stk_u->fow_w--; + } else { + c3_w len_w = (c3_w) stk_u->dat_y[stk_u->off_w - sizeof(c3_w)]; + stk_u->off_w -= (len_w+sizeof(c3_w)); + } +} + diff --git a/vere/pkg/noun/trace.h b/vere/pkg/noun/trace.h new file mode 100644 index 0000000..f4e0f2b --- /dev/null +++ b/vere/pkg/noun/trace.h @@ -0,0 +1,230 @@ +/// @file + +#ifndef U3_TRACE_H +#define U3_TRACE_H + +#include <fcntl.h> +#include <unistd.h> + +#include "c3/c3.h" +#include "options.h" +#include "types.h" +#include "allocate.h" + +#ifdef U3_CPU_DEBUG +# include "options.h" +#endif + +#define SLOW_STACK_NAME "/spin_stack_page_%d" +#define TRACE_PSIZE (1U << (u3a_page +2)) + + /** Data structures. + **/ + /* u3t_trace: fast execution flags. + */ + typedef struct _u3t_trace { + c3_o noc_o; // now executing in nock interpreter + c3_o glu_o; // now executing in jet glue + c3_o mal_o; // now executing in allocator + c3_o far_o; // now executing in fragmentor + c3_o coy_o; // now executing in copy + c3_o euq_o; // now executing in equal + } u3t_trace; + + /* u3t_spin: %spin hint stack + */ + typedef struct { + c3_w off_w; + c3_w fow_w; + c3_y dat_y[TRACE_PSIZE - 2*sizeof(c3_w)]; + } u3t_spin; + + /** Macros. + **/ +# ifdef U3_CPU_DEBUG +# define u3t_on(var) \ + (u3T.var = (u3C.wag_w & u3o_debug_cpu) \ + ? (c3n == u3T.var) ? c3y : (abort(), 0) \ + : u3T.var) +# else +# define u3t_on(var) +#endif + +# ifdef U3_CPU_DEBUG +# define u3t_off(var) \ + (u3T.var = (u3C.wag_w & u3o_debug_cpu) \ + ? (c3y == u3T.var) ? c3n : (abort(), 0) \ + : u3T.var) +# else +# define u3t_off(var) +#endif + + + /** Functions. + **/ + /* u3t_init(): initialize tracing layer. + */ + void + u3t_init(void); + + /// @return Number of entries written to the JSON trace file. + c3_w + u3t_trace_cnt(void); + + /// @return Number of times u3t_trace_close() has been called. + c3_w + u3t_file_cnt(void); + + /* u3t_push(): push on trace stack. + */ + void + u3t_push(u3_noun mon); + + /* u3t_mean(): push `[%mean roc]` on trace stack. + */ + void + u3t_mean(u3_noun roc); + + /* u3t_drop(): drop from meaning stack. + */ + void + u3t_drop(void); + + /* u3t_slog(): print directly. + */ + void + u3t_slog(u3_noun hod); + + /* u3t_heck(): profile point. + */ + void + u3t_heck(u3_atom cog); + + /* u3t_samp(): sample. + */ + void + u3t_samp(void); + + /* u3t_come(): push on profile stack; return yes if active push. RETAIN. + */ + c3_o + u3t_come(u3_noun bat); + + /* u3t_flee(): pop off profile stack. + */ + void + u3t_flee(void); + + /* u3t_trace_open(): opens the path for writing tracing information. + */ + void + u3t_trace_open(const c3_c *dir_c); + + /* u3t_trace_close(): closes the trace file. optional. + */ + void + u3t_trace_close(void); + + /* u3t_trace_time(): returns current time since system epoc, + * whatever it is per system, in microseconds. + */ + c3_d + u3t_trace_time(void); + + /* u3t_nock_trace_push(): pushes a frame onto the trace stack; + * return yes if active push. + */ + c3_o + u3t_nock_trace_push(u3_noun lab); + + /* u3t_nock_trace_pop(): pop off trace stack. + */ + void + u3t_nock_trace_pop(void); + + /* u3t_event_trace(): record a lifecycle event. + */ + void + u3t_event_trace(const c3_c* name, c3_c type); + + /* u3t_damp(): print and clear profile data. + */ + void + u3t_damp(FILE* fil_u); + + /* u3t_boff(): turn profile sampling off. + */ + void + u3t_boff(void); + + /* u3t_boot(): turn sampling on. + */ + void + u3t_boot(void); + + /* u3t_slog_cap(): slog a tank with a caption with + ** a given priority c3_l (assumed 0-3). + */ + void + u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan); + + /* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax + ** flop the order into start-to-end, render, and slog each item + ** until done. + */ + void + u3t_slog_trace(c3_l pri_l, u3_noun tax); + + /* u3t_slog_nara(): slog only the deepest road's trace with + ** c3_l priority pri + */ + void + u3t_slog_nara(c3_l pri_l); + + /* u3t_slog_hela(): join all roads' traces together into one tax + ** and pass it to slog_trace along with the given c3_l priority pri_l + */ + void + u3t_slog_hela(c3_l pri_l); + + /* u3t_etch_meme(): report memory stats at call time + */ + u3_noun + u3t_etch_meme(c3_l mod_l); + + /* u3t_sstack_init: initalize a root node on the spin stack + */ + void + u3t_sstack_init(void); + + /* u3t_sstack_init: initalize a root node on the spin stack + */ + u3t_spin* + u3t_sstack_open(void); + + /* u3t_sstack_exit: initalize a root node on the spin stack + */ + void + u3t_sstack_exit(void); + + /* u3t_sstack_push: push a noun on the spin stack. + */ + void + u3t_sstack_push(u3_noun nam); + + /* u3t_sstack_pop: pop a noun from the spin stack. + */ + void + u3t_sstack_pop(void); + + + /** Globals. + **/ + /// Tracing profiler. + extern u3t_trace u3t_Trace; + extern u3t_spin* stk_u; + +# define u3T u3t_Trace + + +#endif /* ifndef U3_TRACE_H */ diff --git a/vere/pkg/noun/types.h b/vere/pkg/noun/types.h new file mode 100644 index 0000000..6819eb6 --- /dev/null +++ b/vere/pkg/noun/types.h @@ -0,0 +1,64 @@ +/// @file +/// +/// Various noun types. + +#ifndef U3_TYPES_H +#define U3_TYPES_H + +#include "c3/c3.h" + +/// Sentinel value for u3_noun types that aren't actually nouns. +#define u3_none (u3_noun)0xffffffff + +/// 0, or `~` in Hoon. +#define u3_nul 0 + +/// 0, or `%$` in Hoon. +#define u3_blip 0 + +/// Pointer offset into the loom. +/// +/// Declare variables of this type using u3p() to annotate the type of the +/// pointee. Ensure that variable names of this type end in `_p`. +typedef c3_w u3_post; +#define u3p(type) u3_post + +/// Tagged noun pointer. +/// +/// If bit 31 is 0, the noun is a direct 31-bit atom (also called a "cat"). +/// If bit 31 is 1 and bit 30 is 0, an indirect atom (also called a "pug"). +/// If bit 31 is 1 and bit 30 is 1, an indirect cell (also called a "pom"). +/// +/// Bits 0-29 are a word offset (i.e. u3_post) against the loom. +typedef c3_w u3_noun; + +/// Optional noun type. +/// +/// u3_weak is either a valid noun or u3_none. +typedef u3_noun u3_weak; + +/// Atom. +typedef u3_noun u3_atom; + +/// Term (Hoon aura @tas). +typedef u3_noun u3_term; + +/// Cell of the form `[a b]`. +typedef u3_noun u3_cell; + +/// Cell of the form `[a b c]`. +typedef u3_noun u3_trel; + +/// Cell of the form `[a b c d]`. +typedef u3_noun u3_qual; + +/// Cell of the form `[a b c d e]`. +typedef u3_noun u3_quin; + +/// Unary noun function. +typedef u3_noun (*u3_funk)(u3_noun); + +/// Binary noun function. +typedef u3_noun (*u3_funq)(u3_noun, u3_noun); + +#endif /* ifndef U3_TYPES_H */ diff --git a/vere/pkg/noun/urth.c b/vere/pkg/noun/urth.c new file mode 100644 index 0000000..91b64bb --- /dev/null +++ b/vere/pkg/noun/urth.c @@ -0,0 +1,1042 @@ +/// @file + +#include "urth.h" + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include "allocate.h" +#include "hashtable.h" +#include "imprison.h" +#include "jets.h" +#include "manage.h" +#include "options.h" +#include "retrieve.h" +#include "serial.h" +#include "ur/ur.h" +#include "vortex.h" + +/* _cu_atom_to_ref(): allocate indirect atom off-loom. +*/ +static inline ur_nref +_cu_atom_to_ref(ur_root_t* rot_u, u3a_atom* vat_u) +{ + ur_nref ref; + c3_d val_d; + + switch ( vat_u->len_w ) { + case 2: { + val_d = ((c3_d)vat_u->buf_w[1]) << 32 + | ((c3_d)vat_u->buf_w[0]); + ref = ur_coin64(rot_u, val_d); + } break; + + case 1: { + val_d = (c3_d)vat_u->buf_w[0]; + ref = ur_coin64(rot_u, val_d); + } break; + + default: { + // XX assumes little-endian + // + c3_y* byt_y = (c3_y*)vat_u->buf_w; + c3_d len_d = ((c3_d)vat_u->len_w) << 2; + + u3_assert( len_d ); + + // NB: this call will account for any trailing null bytes + // caused by an overestimate in [len_d] + // + ref = ur_coin_bytes(rot_u, len_d, byt_y); + } break; + } + + return ref; +} + +/* _cu_box_check(): check loom allocation box for relocation pointer. +*/ +static inline c3_o +_cu_box_check(u3a_noun* som_u, ur_nref* ref) +{ + c3_w* box_w = (void*)som_u; + + if ( 0xffffffff == box_w[0] ) { + *ref = ( ((c3_d)box_w[2]) << 32 + | ((c3_d)box_w[1]) ); + return c3y; + } + + return c3n; +} + +/* _cu_box_stash(): overwrite an allocation box with relocation pointer. +*/ +static inline void +_cu_box_stash(u3a_noun* som_u, ur_nref ref) +{ + c3_w* box_w = (void*)som_u; + + // overwrite u3a_atom with reallocated reference + // + box_w[0] = 0xffffffff; + box_w[1] = ref & 0xffffffff; + box_w[2] = ref >> 32; +} + +/* +** stack frame for recording head vs tail iteration +** +** $? [LOM_HEAD cell=*] +** [ref=* cell=*] +*/ + +#define LOM_HEAD 0xffffffffffffffffULL + +typedef struct _cu_frame_s +{ + ur_nref ref; + u3a_cell* cel_u; +} _cu_frame; + +typedef struct _cu_stack_s +{ + c3_w pre_w; + c3_w siz_w; + c3_w fil_w; + _cu_frame* fam_u; +} _cu_stack; + +/* _cu_from_loom_next(): advance off-loom reallocation traversal. +*/ +static inline ur_nref +_cu_from_loom_next(_cu_stack* tac_u, ur_root_t* rot_u, u3_noun a) +{ + while ( 1 ) { + // u3 direct == ur direct + // + if ( c3y == u3a_is_cat(a) ) { + return (ur_nref)a; + } + else { + u3a_noun* som_u = u3a_to_ptr(a); + ur_nref ref; + + // check for relocation pointers + // + if ( c3y == _cu_box_check(som_u, &ref) ) { + return ref; + } + // reallocate indirect atoms, stashing relocation pointers + // + else if ( c3y == u3a_is_atom(a) ) { + ref = _cu_atom_to_ref(rot_u, (u3a_atom*)som_u); + _cu_box_stash(som_u, ref); + return ref; + } + else { + u3a_cell* cel_u = (u3a_cell*)som_u; + + // reallocate the stack if full + // + if ( tac_u->fil_w == tac_u->siz_w ) { + c3_w nex_w = tac_u->pre_w + tac_u->siz_w; // XX overflow + tac_u->fam_u = c3_realloc(tac_u->fam_u, nex_w * sizeof(*tac_u->fam_u)); + tac_u->pre_w = tac_u->siz_w; + tac_u->siz_w = nex_w; + } + + // push a head-frame and continue into the head + // + { + _cu_frame* fam_u = &(tac_u->fam_u[tac_u->fil_w++]); + fam_u->ref = LOM_HEAD; + fam_u->cel_u = cel_u; + } + + a = cel_u->hed; + continue; + } + } + } +} + +/* _cu_from_loom(): reallocate [a] off loom, in [r]. +*/ +static ur_nref +_cu_from_loom(ur_root_t* rot_u, u3_noun a) +{ + _cu_stack tac_u = {0}; + ur_nref ref; + + tac_u.pre_w = ur_fib10; + tac_u.siz_w = ur_fib11; + tac_u.fam_u = c3_malloc(tac_u.siz_w * sizeof(*tac_u.fam_u)); + + ref = _cu_from_loom_next(&tac_u, rot_u, a); + + // incorporate reallocated ref, accounting for cells + // + while ( tac_u.fil_w ) { + // peek at the top of the stack + // + _cu_frame* fam_u = &(tac_u.fam_u[tac_u.fil_w - 1]); + + // [fam_u] is a head-frame; stash ref and continue into the tail + // + if ( LOM_HEAD == fam_u->ref ) { + fam_u->ref = ref; + ref = _cu_from_loom_next(&tac_u, rot_u, fam_u->cel_u->tel); + } + // [fam_u] is a tail-frame; cons refs and pop the stack + // + else { + ref = ur_cons(rot_u, fam_u->ref, ref); + _cu_box_stash((u3a_noun*)fam_u->cel_u, ref); + tac_u.fil_w--; + } + } + + c3_free(tac_u.fam_u); + + return ref; +} + +/* _cu_vec: parameters for cold-state hamt walk. +*/ +typedef struct _cu_vec_s { + ur_nvec_t* vec_u; + ur_root_t* rot_u; +} _cu_vec; + +/* _cu_hamt_walk(): reallocate key/value pair in hamt walk. +*/ +static void +_cu_hamt_walk(u3_noun kev, void* ptr) +{ + _cu_vec* dat_u = (_cu_vec*)ptr; + ur_nvec_t* vec_u = dat_u->vec_u; + ur_root_t* rot_u = dat_u->rot_u; + + vec_u->refs[vec_u->fill++] = _cu_from_loom(rot_u, kev); +} + +/* _cu_all_from_loom(): reallocate essential persistent state off-loom. +** +** NB: destroys the loom. +*/ +static ur_nref +_cu_all_from_loom(ur_root_t* rot_u, ur_nvec_t* cod_u) +{ + ur_nref ken = _cu_from_loom(rot_u, u3A->roc); + c3_w cod_w = u3h_wyt(u3R->jed.cod_p); + _cu_vec dat_u = { .vec_u = cod_u, .rot_u = rot_u }; + + ur_nvec_init(cod_u, cod_w); + u3h_walk_with(u3R->jed.cod_p, _cu_hamt_walk, &dat_u); + + return ken; +} + +typedef struct _cu_loom_s { + ur_dict32_t map_u; // direct->indirect mapping + u3_atom *vat; // indirect atoms + u3_noun *cel; // cells +} _cu_loom; + +/* _cu_ref_to_noun(): lookup/allocate [ref] on the loom. +*/ +static u3_noun +_cu_ref_to_noun(ur_root_t* rot_u, ur_nref ref, _cu_loom* lom_u) +{ + switch ( ur_nref_tag(ref) ) { + default: u3_assert(0); + + // all ur indirect atoms have been pre-reallocated on the loom. + // + case ur_iatom: return lom_u->vat[ur_nref_idx(ref)]; + + + // cells were allocated off-loom in cons-order, and are traversed + // in the same order: we've already relocated any one we could need here. + // + case ur_icell: return lom_u->cel[ur_nref_idx(ref)]; + + // u3 direct atoms are 31-bit, while ur direct atoms are 62-bit; + // we use a hashtable to deduplicate the non-overlapping space + // + case ur_direct: { + u3_atom vat; + + if ( 0x7fffffffULL >= ref ) { + return (u3_atom)ref; + } + else if ( ur_dict32_get(rot_u, &lom_u->map_u, ref, (c3_w*)&vat) ) { + return vat; + } + else { + { + c3_w wor_w[2] = { ref & 0xffffffff, ref >> 32 }; + vat = (c3_w)u3i_words(2, wor_w); + } + + ur_dict32_put(0, &lom_u->map_u, ref, (c3_w)vat); + return vat; + } + } break; + } +} + +/* _cu_all_to_loom(): reallocate all of [rot_u] on the loom, restore roots. +** NB: requires all roots to be cells +** does *not* track refcounts, which must be +** subsequently reconstructed via tracing. +*/ +static void +_cu_all_to_loom(ur_root_t* rot_u, ur_nref ken, ur_nvec_t* cod_u) +{ + _cu_loom lom_u = {0}; + c3_d i_d, fil_d; + + ur_dict32_grow(0, &lom_u.map_u, ur_fib11, ur_fib12); + + // allocate all atoms on the loom. + // + { + c3_d* len_d = rot_u->atoms.lens; + c3_y** byt_y = rot_u->atoms.bytes; + + fil_d = rot_u->atoms.fill; + lom_u.vat = calloc(fil_d, sizeof(u3_atom)); + + for ( i_d = 0; i_d < fil_d; i_d++ ) { + lom_u.vat[i_d] = u3i_bytes(len_d[i_d], byt_y[i_d]); + } + } + + // allocate all cells on the loom. + // + { + ur_nref* hed = rot_u->cells.heads; + ur_nref* tal = rot_u->cells.tails; + u3_noun cel; + + fil_d = rot_u->cells.fill; + lom_u.cel = c3_calloc(fil_d * sizeof(u3_noun)); + + for ( i_d = 0; i_d < fil_d; i_d++ ) { + cel = u3nc(_cu_ref_to_noun(rot_u, hed[i_d], &lom_u), + _cu_ref_to_noun(rot_u, tal[i_d], &lom_u)); + lom_u.cel[i_d] = cel; + u3r_mug(cel); + } + } + + // restore kernel reference (always a cell) + // + u3A->roc = lom_u.cel[ur_nref_idx(ken)]; + + // restore cold jet state (always cells) + // + { + c3_d max_d = cod_u->fill; + c3_d i_d; + ur_nref ref; + u3_noun kev; + + for ( i_d = 0; i_d < max_d; i_d++) { + ref = cod_u->refs[i_d]; + kev = lom_u.cel[ur_nref_idx(ref)]; + u3h_put(u3R->jed.cod_p, u3h(kev), u3k(u3t(kev))); + u3z(kev); + } + } + + // dispose of relocation pointers + // + c3_free(lom_u.cel); + c3_free(lom_u.vat); + ur_dict_free((ur_dict_t*)&lom_u.map_u); +} + +/* _cu_realloc(): hash-cons roots off-loom, reallocate on loom. +*/ +static ur_nref +_cu_realloc(FILE* fil_u, ur_root_t** tor_u, ur_nvec_t* doc_u) +{ +#ifdef U3_MEMORY_DEBUG + u3_assert(0); +#endif + + // bypassing page tracking as an optimization + // + // NB: u3m_foul() will mark all as dirty, and + // u3e_save() will reinstate protection flags + // + u3m_foul(); + + // stash event number + // + c3_d eve_d = u3A->eve_d; + + // reallocate kernel and cold jet state + // + ur_root_t* rot_u = ur_root_init(); + ur_nvec_t cod_u; + ur_nref ken = _cu_all_from_loom(rot_u, &cod_u); + + // print [rot_u] measurements + // + if ( fil_u ) { + ur_root_info(fil_u, rot_u); + fprintf(fil_u, "\r\n"); + } + + // reinitialize loom + // + // NB: hot jet state is not yet re-established + // + u3m_pave(c3y); + + // reallocate all nouns on the loom + // + _cu_all_to_loom(rot_u, ken, &cod_u); + + // allocate new hot jet state + // + u3j_boot(c3y); + + // establish correct refcounts via tracing + // + c3_w wag_w = u3C.wag_w; + u3C.wag_w |= u3o_debug_ram; + u3m_grab(u3_none); + u3C.wag_w = wag_w; + + // re-establish warm jet state + // + u3j_ream(); + + // restore event number + // + u3A->eve_d = eve_d; + + // mark all pages dirty + // + u3m_foul(); + + *tor_u = rot_u; + *doc_u = cod_u; + + return ken; +} + +/* u3u_meld(): globally deduplicate memory, returns u3a_open delta. +*/ +#ifdef U3_MEMORY_DEBUG +c3_w +u3u_meld(void) +{ + fprintf(stderr, "u3: unable to meld under U3_MEMORY_DEBUG\r\n"); + return 0; +} +#else +c3_w +u3u_meld(void) +{ + c3_w pre_w = u3a_open(u3R); + ur_root_t* rot_u; + ur_nvec_t cod_u; + + u3_assert( &(u3H->rod_u) == u3R ); + + _cu_realloc(stderr, &rot_u, &cod_u); + + // dispose off-loom structures + // + ur_nvec_free(&cod_u); + ur_root_free(rot_u); + return (u3a_open(u3R) - pre_w); +} +#endif + +/* BEGIN helper functions for u3u_melt + ------------------------------------------------------------------- +*/ +/* _cj_warm_tap(): tap war_p to rel +*/ +static void +_cj_warm_tap(u3_noun kev, void* wit) +{ + u3_noun* rel = wit; + *rel = u3nc(u3k(kev), *rel); +} + +static inline u3_weak +_cu_melt_get(u3p(u3h_root) set_p, u3_noun som) +{ + u3_post hav_p = u3h_git(set_p, som); + + if ( u3_none == hav_p ) { + return u3_none; + } + + // restore tag bits from [som] + // + return (hav_p >> u3a_vits) | (som & 0xc0000000); +} + +static inline void +_cu_melt_put(u3p(u3h_root) set_p, u3_noun som) +{ + // strip tag bits from [som] to skip refcounts + // + u3_post hav_p = u3a_to_off(som); + u3h_put(set_p, som, hav_p); +} + +static void +_cu_melt_noun(u3p(u3h_root) set_p, u3_noun* mos) +{ + u3_noun som = *mos; + u3_weak hav; + + // skip direct atoms + // + if ( c3y == u3a_is_cat(som) ) { + return; + } + + // [som] equals [hav], and [hav] is canonical + // + if ( u3_none != (hav = _cu_melt_get(set_p, som)) ) { + if ( hav != som ) { + u3z(som); + *mos = u3k(hav); + } + return; + } + + // traverse subtrees + // + if ( c3y == u3a_is_cell(som) ) { + u3a_cell *cel_u = u3a_to_ptr(som); + _cu_melt_noun(set_p, &cel_u->hed); + _cu_melt_noun(set_p, &cel_u->tel); + } + + // [som] is canonical + // + _cu_melt_put(set_p, som); +} + +/* u3u_melt(): globally deduplicate memory and pack in-place. +*/ +c3_w +u3u_melt(void) +{ + c3_w pre_w = u3a_open(u3R); + + // Verify that we're on the main road. + // + u3_assert( &(u3H->rod_u) == u3R ); + + // Store a cons list of the cold jet registrations in `cod` + // + u3_noun cod = u3_nul; + u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &cod); + + u3m_reclaim(); // refresh the byte-code interpreter. + + u3h_free(u3R->cax.per_p); + u3R->cax.per_p = u3h_new_cache(u3C.per_w); + + u3h_free(u3R->jed.cod_p); + u3R->jed.cod_p = u3h_new(); + + { + u3p(u3h_root) set_p = u3h_new(); // temp hashtable + + _cu_melt_noun(set_p, &cod); // melt the jets + _cu_melt_noun(set_p, &u3A->roc); // melt the kernel + + u3h_free(set_p); // release the temp hashtable + } + + // re-initialize the jets + // + u3j_boot(c3y); + + // Put the jet registrations back. Loop over cod putting them back into the cold jet + // dashboard. Then re-run the garbage collector. + // + { + u3_noun codc = cod; + + while(u3_nul != cod) { + u3_noun kev = u3h(cod); + u3h_put(u3R->jed.cod_p, u3h(kev), u3k(u3t(kev))); + cod = u3t(cod); + } + + u3z(codc); + } + + // remove free space + // + u3j_ream(); + u3m_pack(); + + return (u3a_open(u3R) - pre_w); +} + +/* _cu_rock_path(): format rock path. +*/ +static c3_o +_cu_rock_path(c3_c* dir_c, c3_d eve_d, c3_c** out_c) +{ + c3_w nam_w = 1 + snprintf(0, 0, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d); + c3_c* nam_c = c3_malloc(nam_w); + c3_i ret_i; + + ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d); + + if ( ret_i < 0 ) { + fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n", + dir_c, eve_d, strerror(errno)); + c3_free(nam_c); + return c3n; + } + else if ( ret_i >= nam_w ) { + fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n", + dir_c, eve_d); + c3_free(nam_c); + return c3n; + } + + *out_c = nam_c; + return c3y; +} + +/* _cu_rock_path_make(): format rock path, creating directory if necessary.. +*/ +static c3_o +_cu_rock_path_make(c3_c* dir_c, c3_d eve_d, c3_c** out_c) +{ + c3_w nam_w = 1 + snprintf(0, 0, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d); + c3_c* nam_c = c3_malloc(nam_w); + c3_i ret_i; + + // create $pier/.urb/roc, if it doesn't exist + // + // NB, $pier/.urb is guaranteed to already exist + // + { + ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc", dir_c); + + if ( ret_i < 0 ) { + fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n", + dir_c, eve_d, strerror(errno)); + c3_free(nam_c); + return c3n; + } + else if ( ret_i >= nam_w ) { + fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n", + dir_c, eve_d); + c3_free(nam_c); + return c3n; + } + + if ( c3_mkdir(nam_c, 0700) + && (EEXIST != errno) ) + { + fprintf(stderr, "rock: directory create failed (%s, %" PRIu64 "): %s\r\n", + dir_c, eve_d, strerror(errno)); + c3_free(nam_c); + return c3n; + } + } + + ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d); + + if ( ret_i < 0 ) { + fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n", + dir_c, eve_d, strerror(errno)); + c3_free(nam_c); + return c3n; + } + else if ( ret_i >= nam_w ) { + fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n", + dir_c, eve_d); + c3_free(nam_c); + return c3n; + } + + *out_c = nam_c; + return c3y; +} + +static c3_o +_cu_rock_save(c3_c* dir_c, c3_d eve_d, c3_d len_d, c3_y* byt_y) +{ + c3_i fid_i; + + // open rock file, creating the containing directory if necessary + // + { + c3_c* nam_c; + + if ( c3n == _cu_rock_path_make(dir_c, eve_d, &nam_c) ) { + return c3n; + } + + if ( -1 == (fid_i = c3_open(nam_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) { + fprintf(stderr, "rock: c3_open failed (%s, %" PRIu64 "): %s\r\n", + dir_c, eve_d, strerror(errno)); + c3_free(nam_c); + return c3n; + } + + c3_free(nam_c); + } + + // write jam-buffer into [fid_i] + // + // XX deduplicate with _write() wrapper in term.c + // + { + ssize_t ret_i; + + while ( len_d > 0 ) { + c3_w lop_w = 0; + // retry interrupt/async errors + // + do { + // abort pathological retry loop + // + if ( 100 == ++lop_w ) { + fprintf(stderr, "rock: write loop: %s\r\n", strerror(errno)); + close(fid_i); + // XX unlink file? + // + return c3n; + } + + ret_i = write(fid_i, byt_y, len_d); + } + while ( (ret_i < 0) + && ( (errno == EINTR) + || (errno == EAGAIN) + || (errno == EWOULDBLOCK) )); + + // assert on true errors + // + // NB: can't call u3l_log here or we would re-enter _write() + // + if ( ret_i < 0 ) { + fprintf(stderr, "rock: write failed %s\r\n", strerror(errno)); + close(fid_i); + // XX unlink file? + // + return c3n; + } + // continue partial writes + // + else { + len_d -= ret_i; + byt_y += ret_i; + } + } + } + + close(fid_i); + + return c3y; +} + +/* u3u_cram(): globably deduplicate memory, and write a rock to disk. +*/ +#ifdef U3_MEMORY_DEBUG +c3_o +u3u_cram(c3_c* dir_c, c3_d eve_d) +{ + fprintf(stderr, "u3: unable to cram under U3_MEMORY_DEBUG\r\n"); + return c3n; +} +#else +c3_o +u3u_cram(c3_c* dir_c, c3_d eve_d) +{ + c3_o ret_o = c3y; + c3_d len_d; + c3_y* byt_y; + + u3_assert( &(u3H->rod_u) == u3R ); + + { + ur_root_t* rot_u; + ur_nvec_t cod_u; + ur_nref ken = _cu_realloc(stderr, &rot_u, &cod_u); + + { + ur_nref roc = u3_nul; + c3_d max_d = cod_u.fill; + c3_d i_d; + + // cons vector of cold jet-state entries onto a list + // + for ( i_d = 0; i_d < max_d; i_d++) { + roc = ur_cons(rot_u, cod_u.refs[i_d], roc); + } + + { + c3_c* has_c = "hashboard"; + ur_nref has = ur_coin_bytes(rot_u, strlen(has_c), (c3_y*)has_c); + roc = ur_cons(rot_u, has, roc); + } + + roc = ur_cons(rot_u, ur_coin64(rot_u, c3__arvo), + ur_cons(rot_u, ken, roc)); + + ur_jam(rot_u, roc, &len_d, &byt_y); + } + + // dispose off-loom structures + // + ur_nvec_free(&cod_u); + ur_root_free(rot_u); + } + + // write jam-buffer into pier + // + if ( c3n == _cu_rock_save(dir_c, eve_d, len_d, byt_y) ) { + ret_o = c3n; + } + + c3_free(byt_y); + + return ret_o; +} +#endif + +/* u3u_mmap_read(): open and mmap the file at [pat_c] for reading. +*/ +c3_o +u3u_mmap_read(c3_c* cap_c, c3_c* pat_c, c3_d* out_d, c3_y** out_y) +{ + c3_i fid_i; + c3_d len_d; + + // open file + // + if ( -1 == (fid_i = c3_open(pat_c, O_RDONLY, 0644)) ) { + fprintf(stderr, "%s: c3_open failed (%s): %s\r\n", + cap_c, pat_c, strerror(errno)); + return c3n; + } + + // measure file + // + { + struct stat buf_b; + + if ( -1 == fstat(fid_i, &buf_b) ) { + fprintf(stderr, "%s: stat failed (%s): %s\r\n", + cap_c, pat_c, strerror(errno)); + close(fid_i); + return c3n; + } + + len_d = buf_b.st_size; + } + + // mmap file + // + { + void* ptr_v; + + if ( MAP_FAILED == (ptr_v = mmap(0, len_d, PROT_READ, MAP_SHARED, fid_i, 0)) ) { + fprintf(stderr, "%s: mmap failed (%s): %s\r\n", + cap_c, pat_c, strerror(errno)); + close(fid_i); + return c3n; + } + + *out_d = len_d; + *out_y = (c3_y*)ptr_v; + } + + // close file + // + close(fid_i); + + return c3y; +} + +/* u3u_mmap(): open/create file-backed mmap at [pat_c] for read/write. +*/ +c3_o +u3u_mmap(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y** out_y) +{ + c3_i fid_i; + + // open file + // + if ( -1 == (fid_i = c3_open(pat_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) { + fprintf(stderr, "%s: c3_open failed (%s): %s\r\n", + cap_c, pat_c, strerror(errno)); + return c3n; + } + + // grow [fid_i] to [len_w] + // + // XX build with _FILE_OFFSET_BITS == 64 ? + // + if ( 0 != ftruncate(fid_i, len_d) ) { + fprintf(stderr, "%s: ftruncate grow %s: %s\r\n", + cap_c, pat_c, strerror(errno)); + close(fid_i); + return c3n; + } + + // mmap file + // + { + void* ptr_v; + + if ( MAP_FAILED == (ptr_v = mmap(0, len_d, PROT_READ|PROT_WRITE, MAP_SHARED, fid_i, 0)) ) { + fprintf(stderr, "%s: mmap failed (%s): %s\r\n", + cap_c, pat_c, strerror(errno)); + close(fid_i); + return c3n; + } + + *out_y = (c3_y*)ptr_v; + } + + // close file + // + close(fid_i); + + return c3y; +} + +/* u3u_mmap_save(): sync file-backed mmap. +*/ +c3_o +u3u_mmap_save(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y* byt_y) +{ + if ( 0 != msync(byt_y, len_d, MS_SYNC) ) { + fprintf(stderr, "%s: msync %s: %s\r\n", cap_c, pat_c, strerror(errno)); + return c3n; + } + + return c3y; +} + +/* u3u_munmap(): unmap the region at [byt_y]. +*/ +c3_o +u3u_munmap(c3_d len_d, c3_y* byt_y) +{ + if ( 0 != munmap(byt_y, len_d) ) { + return c3n; + } + + return c3y; +} + +/* u3u_uncram(): restore persistent state from a rock. +*/ +c3_o +u3u_uncram(c3_c* dir_c, c3_d eve_d) +{ + c3_c* nam_c; + c3_d len_d; + c3_y* byt_y; + + // load rock file into buffer + // + if ( c3n == _cu_rock_path(dir_c, eve_d, &nam_c) ) { + fprintf(stderr, "uncram: failed to make rock path (%s, %" PRIu64 ")\r\n", + dir_c, eve_d); + return c3n; + } + else if ( c3n == u3u_mmap_read("rock", nam_c, &len_d, &byt_y) ) { + c3_free(nam_c); + return c3n; + } + + // bypassing page tracking as an optimization + // + // NB: u3m_foul() will mark all as dirty, and + // u3e_save() will reinstate protection flags + // + u3m_foul(); + + // reinitialize loom + // + // NB: hot jet state is not yet re-established + // + u3m_pave(c3y); + + // cue rock, restore persistent state + // + // XX errors are fatal, barring a full "u3m_reboot"-type operation. + // + { + // XX tune the initial dictionary size for less reallocation + // + u3_cue_xeno* sil_u = u3s_cue_xeno_init_with(ur_fib33, ur_fib34); + u3_weak ref = u3s_cue_xeno_with(sil_u, len_d, byt_y); + u3_noun roc, doc, tag, cod; + + u3s_cue_xeno_done(sil_u); + + if ( u3_none == ref ) { + fprintf(stderr, "uncram: failed to cue rock\r\n"); + c3_free(nam_c); + return c3n; + } + else if ( c3n == u3r_pq(ref, c3__arvo, &roc, &doc) + || (c3n == u3r_cell(doc, &tag, &cod)) + || (c3n == u3r_sing_c("hashboard", tag)) ) + { + fprintf(stderr, "uncram: failed: invalid rock format\r\n"); + u3z(ref); + c3_free(nam_c); + return c3n; + } + + u3A->roc = u3k(roc); + u3j_load(u3k(cod)); + + u3z(ref); + } + + u3u_munmap(len_d, byt_y); + + // allocate new hot jet state; re-establish warm + // + u3j_boot(c3y); + u3j_ream(); + + // restore event number + // + u3A->eve_d = eve_d; + + // leave rocks on disk + // + // if ( 0 != c3_unlink(nam_c) ) { + // fprintf(stderr, "uncram: failed to delete rock (%s, %" PRIu64 "): %s\r\n", + // dir_c, eve_d, strerror(errno)); + // c3_free(nam_c); + // return c3n; + // } + + c3_free(nam_c); + + return c3y; +} diff --git a/vere/pkg/noun/urth.h b/vere/pkg/noun/urth.h new file mode 100644 index 0000000..a11b9aa --- /dev/null +++ b/vere/pkg/noun/urth.h @@ -0,0 +1,49 @@ +/// @file + +#ifndef U3_URTH_H +#define U3_URTH_H + +#include "c3/c3.h" + + /** Functions. + **/ + /* u3u_meld(): globally deduplicate memory, returns u3a_open delta. + */ + c3_w + u3u_meld(void) __attribute__ ((deprecated)); + + /* u3u_melt(): globally deduplicate memory and pack in-place. + */ + c3_w + u3u_melt(void) __attribute__ ((deprecated)); + + /* u3u_cram(): globably deduplicate memory, and write a rock to disk. + */ + c3_o + u3u_cram(c3_c* dir_c, c3_d eve_d); + /* u3u_uncram(): restore persistent state from a rock. + */ + c3_o + u3u_uncram(c3_c* dir_c, c3_d eve_d); + + /* u3u_mmap_read(): open and mmap the file at [pat_c] for reading. + */ + c3_o + u3u_mmap_read(c3_c* cap_c, c3_c* pat_c, c3_d* out_d, c3_y** out_y); + + /* u3u_mmap(): open/create file-backed mmap at [pat_c] for read/write. + */ + c3_o + u3u_mmap(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y** out_y); + + /* u3u_mmap_save(): sync file-backed mmap. + */ + c3_o + u3u_mmap_save(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y* byt_y); + + /* u3u_munmap(): unmap the region at [byt_y]. + */ + c3_o + u3u_munmap(c3_d len_d, c3_y* byt_y); + +#endif /* ifndef U3_URTH_H */ diff --git a/vere/pkg/noun/version.h b/vere/pkg/noun/version.h new file mode 100644 index 0000000..88c6ac4 --- /dev/null +++ b/vere/pkg/noun/version.h @@ -0,0 +1,43 @@ +#ifndef U3_VERSION_H +#define U3_VERSION_H + +/* loom layout + */ +typedef c3_d u3v_version; + +#define U3V_VER1 (u3v_version)1 // 1.0 +#define U3V_VER2 (u3v_version)2 // 2.0: pointer compression +#define U3V_VER3 (u3v_version)3 // 3.0-rc: persistent memoization +#define U3V_VER4 (u3v_version)4 // 3.0: bytecode alignment +#define U3V_VER5 (u3v_version)5 // ?? palloc +#define U3V_VERLAT U3V_VER5 + +/* bytecode semantics (within u3v_version) + */ +typedef c3_w u3n_version; + +#define U3N_VER1 (u3n_version)0 // zero-indexedfor backcompat +#define U3N_VER2 (u3n_version)1 +#define U3N_VERLAT U3N_VER2 + +/* snapshot patch format + */ +typedef c3_w u3e_version; + +#define U3P_VER2 (u3e_version)2 // top-level checksum added +#define U3P_VERLAT U3P_VER2 + +/* top-level event log format + */ +#define U3D_VER1 1 // <= 2.0 +#define U3D_VER2 2 // migration to 3.0 in-progress +#define U3D_VER3 3 // 3.0 (epoch system) +#define U3D_VERLAT U3D_VER3 + +/* epoch layout +*/ +#define U3E_VER1 1 // north+south.bin +#define U3E_VER2 2 // image.bin +#define U3E_VERLAT U3E_VER2 + +#endif /* ifndef U3_VERSION_H */ diff --git a/vere/pkg/noun/verstable.h b/vere/pkg/noun/verstable.h new file mode 100644 index 0000000..e34cff0 --- /dev/null +++ b/vere/pkg/noun/verstable.h @@ -0,0 +1,1949 @@ +/*------------------------------------------------- VERSTABLE v2.1.1 --------------------------------------------------- + +Verstable is a C99-compatible, open-addressing hash table using quadratic probing and the following additions: + +* All keys that hash (i.e. "belong") to the same bucket (their "home bucket") are linked together by an 11-bit integer + specifying the quadratic displacement, relative to that bucket, of the next key in the chain. + +* If a chain of keys exists for a given bucket, then it always begins at that bucket. To maintain this policy, a 1-bit + flag is used to mark whether the key occupying a bucket belongs there. When inserting a new key, if the bucket it + belongs to is occupied by a key that does not belong there, then the occupying key is evicted and the new key takes + the bucket. + +* A 4-bit fragment of each key's hash code is also stored. + +* The aforementioned metadata associated with each bucket (the 4-bit hash fragment, the 1-bit flag, and the 11-bit link + to the next key in the chain) are stored together in a uint16_t array rather than in the bucket alongside the key and + (optionally) the value. + +One way to conceptualize this scheme is as a chained hash table in which overflowing keys are stored not in separate +memory allocations but in otherwise unused buckets. In this regard, it shares similarities with Malte Skarupke's Bytell +hash table (https://www.youtube.com/watch?v=M2fKMP47slQ) and traditional "coalesced hashing". + +Advantages of this scheme include: + +* Fast lookups impervious to load factor: If the table contains any key belonging to the lookup key's home bucket, then + that bucket contains the first in a traversable chain of all keys belonging to it. Hence, only the home bucket and + other buckets containing keys belonging to it are ever probed. Moreover, the stored hash fragments allow skipping most + non-matching keys in the chain without accessing the actual buckets array or calling the (potentially expensive) key + comparison function. + +* Fast insertions: Insertions are faster than they are in other schemes that move keys around (e.g. Robin Hood) because + they only move, at most, one existing key. + +* Fast, tombstone-free deletions: Deletions, which usually require tombstones in quadratic-probing hash tables, are + tombstone-free and only move, at most, one existing key. + +* Fast iteration: The separate metadata array allows keys in sparsely populated tables to be found without incurring the + frequent cache misses that would result from traversing the buckets array. + +Usage example: + + +---------------------------------------------------------+----------------------------------------------------------+ + | Using the generic macro API (C11 and later): | Using the prefixed functions API (C99 and later): | + |---------------------------------------------------------+----------------------------------------------------------+ + | #include <stdio.h> | #include <stdio.h> | + | | | + | // Instantiating a set template. | // Instantiating a set template. | + | #define NAME int_set | #define NAME int_set | + | #define KEY_TY int | #define KEY_TY int | + | #include "verstable.h" | #define HASH_FN vt_hash_integer | + | | #define CMPR_FN vt_cmpr_integer | + | // Instantiating a map template. | #include "verstable.h" | + | #define NAME int_int_map | | + | #define KEY_TY int | // Instantiating a map template. | + | #define VAL_TY int | #define NAME int_int_map | + | #include "verstable.h" | #define KEY_TY int | + | | #define VAL_TY int | + | int main( void ) | #define HASH_FN vt_hash_integer | + | { | #define CMPR_FN vt_cmpr_integer | + | // Set. | #include "verstable.h" | + | | | + | int_set our_set; | int main( void ) | + | vt_init( &our_set ); | { | + | | // Set. | + | // Inserting keys. | | + | for( int i = 0; i < 10; ++i ) | int_set our_set; | + | { | int_set_init( &our_set ); | + | int_set_itr itr = vt_insert( &our_set, i ); | | + | if( vt_is_end( itr ) ) | // Inserting keys. | + | { | for( int i = 0; i < 10; ++i ) | + | // Out of memory, so abort. | { | + | vt_cleanup( &our_set ); | int_set_itr itr = | + | return 1; | int_set_insert( &our_set, i ); | + | } | if( int_set_is_end( itr ) ) | + | } | { | + | | // Out of memory, so abort. | + | // Erasing keys. | int_set_cleanup( &our_set ); | + | for( int i = 0; i < 10; i += 3 ) | return 1; | + | vt_erase( &our_set, i ); | } | + | | } | + | // Retrieving keys. | | + | for( int i = 0; i < 10; ++i ) | // Erasing keys. | + | { | for( int i = 0; i < 10; i += 3 ) | + | int_set_itr itr = vt_get( &our_set, i ); | int_set_erase( &our_set, i ); | + | if( !vt_is_end( itr ) ) | | + | printf( "%d ", itr.data->key ); | // Retrieving keys. | + | } | for( int i = 0; i < 10; ++i ) | + | // Printed: 1 2 4 5 7 8 | { | + | | int_set_itr itr = int_set_get( &our_set, i ); | + | // Iteration. | if( !int_set_is_end( itr ) ) | + | for( | printf( "%d ", itr.data->key ); | + | int_set_itr itr = vt_first( &our_set ); | } | + | !vt_is_end( itr ); | // Printed: 1 2 4 5 7 8 | + | itr = vt_next( itr ) | | + | ) | // Iteration. | + | printf( "%d ", itr.data->key ); | for( | + | // Printed: 2 4 7 1 5 8 | int_set_itr itr = | + | | int_set_first( &our_set ); | + | vt_cleanup( &our_set ); | !int_set_is_end( itr ); | + | | itr = int_set_next( itr ) | + | // Map. | ) | + | | printf( "%d ", itr.data->key ); | + | int_int_map our_map; | // Printed: 2 4 7 1 5 8 | + | vt_init( &our_map ); | | + | | int_set_cleanup( &our_set ); | + | // Inserting keys and values. | | + | for( int i = 0; i < 10; ++i ) | // Map. | + | { | | + | int_int_map_itr itr = | int_int_map our_map; | + | vt_insert( &our_map, i, i + 1 ); | int_int_map_init( &our_map ); | + | if( vt_is_end( itr ) ) | | + | { | // Inserting keys and values. | + | // Out of memory, so abort. | for( int i = 0; i < 10; ++i ) | + | vt_cleanup( &our_map ); | { | + | return 1; | int_int_map_itr itr = | + | } | int_int_map_insert( &our_map, i, i + 1 ); | + | } | if( int_int_map_is_end( itr ) ) | + | | { | + | // Erasing keys and values. | // Out of memory, so abort. | + | for( int i = 0; i < 10; i += 3 ) | int_int_map_cleanup( &our_map ); | + | vt_erase( &our_map, i ); | return 1; | + | | } | + | // Retrieving keys and values. | } | + | for( int i = 0; i < 10; ++i ) | | + | { | // Erasing keys and values. | + | int_int_map_itr itr = vt_get( &our_map, i ); | for( int i = 0; i < 10; i += 3 ) | + | if( !vt_is_end( itr ) ) | int_int_map_erase( &our_map, i ); | + | printf( | | + | "%d:%d ", | // Retrieving keys and values. | + | itr.data->key, | for( int i = 0; i < 10; ++i ) | + | itr.data->val | { | + | ); | int_int_map_itr itr = | + | } | int_int_map_get( &our_map, i ); | + | // Printed: 1:2 2:3 4:5 5:6 7:8 8:9 | if( !int_int_map_is_end( itr ) ) | + | | printf( | + | // Iteration. | "%d:%d ", | + | for( | itr.data->key, | + | int_int_map_itr itr = vt_first( &our_map ); | itr.data->val | + | !vt_is_end( itr ); | ); | + | itr = vt_next( itr ) | } | + | ) | // Printed: 1:2 2:3 4:5 5:6 7:8 8:9 | + | printf( | | + | "%d:%d ", | // Iteration. | + | itr.data->key, | for( | + | itr.data->val | int_int_map_itr itr = | + | ); | int_int_map_first( &our_map ); | + | // Printed: 2:3 4:5 7:8 1:2 5:6 8:9 | !int_int_map_is_end( itr ); | + | | itr = int_int_map_next( itr ) | + | vt_cleanup( &our_map ); | ) | + | } | printf( | + | | "%d:%d ", | + | | itr.data->key, | + | | itr.data->val | + | | ); | + | | // Printed: 2:3 4:5 7:8 1:2 5:6 8:9 | + | | | + | | int_int_map_cleanup( &our_map ); | + | | } | + | | | + +---------------------------------------------------------+----------------------------------------------------------+ + +API: + + Instantiating a hash table template: + + Create a new hash table type in the following manner: + + #define NAME <your chosen type name> + #define KEY_TY <type> + #include "verstable.h" + + The NAME macro specifies the name of hash table type that the library will declare, the prefix for the functions + associated with it, and the prefix for the associated iterator type. + + The KEY_TY macro specifies the key type. + + In C99, it is also always necessary to define HASH_FN and CMPR_FN (see below) before including the header. + + The following macros may also be defined before including the header: + + #define VAL_TY <type> + + The type of the value associated with each key. + If this macro is defined, the hash table acts as a map associating keys with values. + Otherwise, it acts as a set containing only keys. + + #define HASH_FN <function name> + + The name of the existing function used to hash each key. + The function should have the signature uint64_t ( KEY_TY key ) and return a 64-bit hash code. + For best performance, the hash function should provide a high level of entropy across all bits. + There are two default hash functions: vt_hash_integer for all integer types up to 64 bits in size, and + vt_hash_string for NULL-terminated strings (i.e. char *). + When KEY_TY is one of such types and the compiler is in C11 mode or later, HASH_FN may be left undefined, in + which case the appropriate default function is inferred from KEY_TY. + Otherwise, HASH_FN must be defined. + + #define CMPR_FN <function name> + + The name of the existing function used to compare two keys. + The function should have the signature bool ( KEY_TY key_1, KEY_TY key_2 ) and return true if the two keys are + equal. + There are two default comparison functions: vt_cmpr_integer for all integer types up to 64 bits in size, and + vt_cmpr_string for NULL-terminated strings (i.e. char *). + As with the default hash functions, in C11 or later the appropriate default comparison function is inferred if + KEY_TY is one of such types and CMPR_FN is left undefined. + Otherwise, CMPR_FN must be defined. + + #define MAX_LOAD <floating point value> + + The floating-point load factor at which the hash table automatically doubles the size of its internal buckets + array. + The default is 0.9, i.e. 90%. + + #define KEY_DTOR_FN <function name> + + The name of the existing destructor function, with the signature void ( KEY_TY key ), called on a key when it is + erased from the table or replaced by a newly inserted key. + The API functions that may call the key destructor are NAME_insert, NAME_erase, NAME_erase_itr, NAME_clear, + and NAME_cleanup. + + #define VAL_DTOR_FN <function name> + + The name of the existing destructor function, with the signature void ( VAL_TY val ), called on a value when it + is erased from the table or replaced by a newly inserted value. + The API functions that may call the value destructor are NAME_insert, NAME_erase, NAME_erase_itr, NAME_clear, + and NAME_cleanup. + + #define CTX_TY <type> + + The type of the hash table type's ctx (context) member. + This member only exists if CTX_TY was defined. + It is intended to be used in conjunction with MALLOC_FN and FREE_FN (see below). + + #define MALLOC_FN <function name> + + The name of the existing function used to allocate memory. + If CTX_TY was defined, the signature should be void *( size_t size, CTX_TY *ctx ), where size is the number of + bytes to allocate and ctx points to the table's ctx member. + Otherwise, the signature should be void *( size_t size ). + The default wraps stdlib.h's malloc. + + #define FREE_FN <function name> + + The name of the existing function used to free memory. + If CTX_TY was defined, the signature should be void ( void *ptr, size_t size, CTX_TY *ctx ), where ptr points to + the memory to free, size is the number of bytes that were allocated, and ctx points to the table's ctx member. + Otherwise, the signature should be void ( void *ptr, size_t size ). + The default wraps stdlib.h's free. + + #define HEADER_MODE + #define IMPLEMENTATION_MODE + + By default, all hash table functions are defined as static inline functions, the intent being that a given hash + table template should be instantiated once per translation unit; for best performance, this is the recommended + way to use the library. + However, it is also possible separate the struct definitions and function declarations from the function + definitions such that one implementation can be shared across all translation units (as in a traditional header + and source file pair). + In that case, instantiate a template wherever it is needed by defining HEADER_MODE, along with only NAME, + KEY_TY, and (optionally) VAL_TY, CTX_TY, and header guards, and including the library, e.g.: + + #ifndef INT_INT_MAP_H + #define INT_INT_MAP_H + #define NAME int_int_map + #define KEY_TY int + #define VAL_TY int + #define HEADER_MODE + #include "verstable.h" + #endif + + In one source file, define IMPLEMENTATION_MODE, along with NAME, KEY_TY, and any of the aforementioned optional + macros, and include the library, e.g.: + + #define NAME int_int_map + #define KEY_TY int + #define VAL_TY int + #define HASH_FN vt_hash_integer // C99. + #define CMPR_FN vt_cmpr_integer // C99. + #define MAX_LOAD 0.8 + #define IMPLEMENTATION_MODE + #include "verstable.h" + + Including the library automatically undefines all the aforementioned macros after they have been used to instantiate + the template. + + Functions: + + The functions associated with a hash table type are all prefixed with the name the user supplied via the NAME macro. + In C11 and later, the generic "vt_"-prefixed macros may be used to automatically select the correct version of the + specified function based on the arguments. + + void NAME_init( NAME *table ) + void NAME_init( NAME *table, CTX_TY ctx ) + // C11 generic macro: vt_init. + + Initializes the table for use. + If CTX_TY was defined, ctx sets the table's ctx member. + + bool NAME_init_clone( NAME *table, NAME *source ) + bool NAME_init_clone( NAME *table, NAME *source, CTX_TY ctx ) + // C11 generic macro: vt_init_clone. + + Initializes the table as a shallow copy of the specified source table. + If CTX_TY was defined, ctx sets the table's ctx member. + Returns false in the case of memory allocation failure. + + size_t NAME_size( NAME *table ) // C11 generic macro: vt_size. + + Returns the number of keys currently in the table. + + size_t NAME_bucket_count( NAME *table ) // C11 generic macro: vt_bucket_count. + + Returns the table's current bucket count. + + NAME_itr NAME_insert( NAME *table, KEY_TY key ) + NAME_itr NAME_insert( NAME *table, KEY_TY key, VAL_TY val ) + // C11 generic macro: vt_insert. + + Inserts the specified key (and value, if VAL_TY was defined) into the hash table. + If the same key already exists, then the new key (and value) replaces the existing key (and value). + Returns an iterator to the new key, or an end iterator in the case of memory allocation failure. + + NAME_itr NAME_get_or_insert( NAME *table, KEY_TY key ) + NAME_itr NAME_get_or_insert( NAME *table, KEY_TY key, VAL_TY val ) + // C11 generic macro: vt_get_or_insert. + + Inserts the specified key (and value, if VAL_TY was defined) if it does not already exist in the table. + Returns an iterator to the new key if it was inserted, or an iterator to the existing key, or an end iterator if + the key did not exist but the new key could not be inserted because of memory allocation failure. + Determine whether the key was inserted by comparing the table's size before and after the call. + + NAME_itr NAME_get( NAME *table, KEY_TY key ) // C11 generic macro: vt_get. + + Returns a iterator to the specified key, or an end iterator if no such key exists. + + bool NAME_erase( NAME *table, KEY_TY key ) // C11 generic macro: vt_erase. + + Erases the specified key (and associated value, if VAL_TY was defined), if it exists. + Returns true if a key was erased. + + NAME_itr NAME_erase_itr( NAME *table, NAME_itr itr ) // C11 generic macro: vt_erase_itr. + + Erases the key (and associated value, if VAL_TY was defined) pointed to by the specified iterator. + Returns an iterator to the next key in the table, or an end iterator if the erased key was the last one. + + bool NAME_reserve( NAME *table, size_t size ) // C11 generic macro: vt_reserve. + + Ensures that the bucket count is large enough to support the specified key count (i.e. size) without rehashing. + Returns false if unsuccessful due to memory allocation failure. + + bool NAME_shrink( NAME *table ) // C11 generic macro: vt_shrink. + + Shrinks the bucket count to best accommodate the current size. + Returns false if unsuccessful due to memory allocation failure. + + NAME_itr NAME_first( NAME *table ) // C11 generic macro: vt_first. + + Returns an iterator to the first key in the table, or an end iterator if the table is empty. + + bool NAME_is_end( NAME *table, NAME_itr itr ) // C11 generic macro: vt_is_end. + + Returns true if the iterator is an end iterator. + + NAME_itr NAME_next( NAME_itr itr ) // C11 generic macro: vt_next. + + Returns an iterator to the key after the one pointed to by the specified iterator, or an end iterator if the + specified iterator points to the last key in the table. + + void NAME_clear( NAME *table ) // C11 generic macro: vt_clear. + + Erases all keys (and values, if VAL_TY was defined) in the table. + + void NAME_cleanup( NAME *table ) // C11 generic macro: vt_cleanup. + + Erases all keys (and values, if VAL_TY was defined) in the table, frees all memory associated with it, and + initializes it for reuse. + + Iterators: + + Access the key (and value, if VAL_TY was defined) that an iterator points to using the NAME_itr struct's data + member: + + itr.data->key + itr.data->val + + Functions that may insert new keys (NAME_insert and NAME_get_or_insert), erase keys (NAME_erase and NAME_erase_itr), + or reallocate the internal bucket array (NAME_reserve and NAME_shrink) invalidate all exiting iterators. + To delete keys during iteration and resume iterating, use the return value of NAME_erase_itr. + +Version history: + + 18/06/2024 2.1.1: Fixed a bug affecting iteration on big-endian platforms under MSVC. + 27/05/2024 2.1.0: Replaced the Murmur3 mixer with the fast-hash mixer as the default integer hash function. + Fixed a bug that could theoretically cause a crash on rehash (triggerable in testing using + NAME_shrink with a maximum load factor significantly higher than 1.0). + 06/02/2024 2.0.0: Improved custom allocator support by introducing the CTX_TY option and allowing user-supplied free + functions to receive the allocation size. + Improved documentation. + Introduced various optimizations, including storing the buckets-array size mask instead of the + bucket count, eliminating empty-table checks, combining the buckets memory and metadata memory into + one allocation, and adding branch prediction macros. + Fixed a bug that caused a key to be used after destruction during erasure. + 12/12/2023 1.0.0: Initial release. + +License (MIT): + + Copyright (c) 2023-2024 Jackson L. Allan + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +/*--------------------------------------------------------------------------------------------------------------------*/ +/* Common header section */ +/*--------------------------------------------------------------------------------------------------------------------*/ + +#ifndef VERSTABLE_H +#define VERSTABLE_H + +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> + +// Two-way concatenation macro. +#define VT_CAT_( a, b ) a##b +#define VT_CAT( a, b ) VT_CAT_( a, b ) + +// Branch optimization macros. +#ifdef __GNUC__ +#define VT_LIKELY( expression ) __builtin_expect( (bool)( expression ), true ) +#define VT_UNLIKELY( expression ) __builtin_expect( (bool)( expression ), false ) +#else +#define VT_LIKELY( expression ) ( expression ) +#define VT_UNLIKELY( expression ) ( expression ) +#endif + +// Masks for manipulating and extracting data from a bucket's uint16_t metadatum. +#define VT_EMPTY 0x0000 +#define VT_HASH_FRAG_MASK 0xF000 // 0b1111000000000000. +#define VT_IN_HOME_BUCKET_MASK 0x0800 // 0b0000100000000000. +#define VT_DISPLACEMENT_MASK 0x07FF // 0b0000011111111111, also denotes the displacement limit. Set to VT_LOAD to 1.0 + // to test proper handling of encroachment on the displacement limit during + // inserts. + +// Extracts a hash fragment from a uint64_t hash code. +// We take the highest four bits so that keys that map (via modulo) to the same bucket have distinct hash fragments. +static inline uint16_t vt_hashfrag( uint64_t hash ) +{ + return ( hash >> 48 ) & VT_HASH_FRAG_MASK; +} + +// Standard quadratic probing formula that guarantees that all buckets are visited when the bucket count is a power of +// two (at least in theory, because the displacement limit could terminate the search early when the bucket count is +// high). +static inline size_t vt_quadratic( uint16_t displacement ) +{ + return ( (size_t)displacement * displacement + displacement ) / 2; +} + +#define VT_MIN_NONZERO_BUCKET_COUNT 8 // Must be a power of two. + +// Function to find the left-most non-zero uint16_t in a uint64_t. +// This function is used when we scan four buckets at a time while iterating and relies on compiler intrinsics wherever +// possible. + +#if defined( __GNUC__ ) && ULLONG_MAX == 0xFFFFFFFFFFFFFFFF + +static inline int vt_first_nonzero_uint16( uint64_t val ) +{ + const uint16_t endian_checker = 0x0001; + if( *(const char *)&endian_checker ) // Little-endian (the compiler will optimize away the check at -O1 and above). + return __builtin_ctzll( val ) / 16; + + return __builtin_clzll( val ) / 16; +} + +#elif defined( _MSC_VER ) && ( defined( _M_X64 ) || defined( _M_ARM64 ) ) + +#include <intrin.h> +#pragma intrinsic(_BitScanForward64) +#pragma intrinsic(_BitScanReverse64) + +static inline int vt_first_nonzero_uint16( uint64_t val ) +{ + unsigned long result; + + const uint16_t endian_checker = 0x0001; + if( *(const char *)&endian_checker ) + _BitScanForward64( &result, val ); + else + { + _BitScanReverse64( &result, val ); + result = 63 - result; + } + + return result / 16; +} + +#else + +static inline int vt_first_nonzero_uint16( uint64_t val ) +{ + int result = 0; + + uint32_t half; + memcpy( &half, &val, sizeof( uint32_t ) ); + if( !half ) + result += 2; + + uint16_t quarter; + memcpy( &quarter, (char *)&val + result * sizeof( uint16_t ), sizeof( uint16_t ) ); + if( !quarter ) + result += 1; + + return result; +} + +#endif + +// When the bucket count is zero, setting the metadata pointer to point to a VT_EMPTY placeholder, rather than NULL, +// allows us to avoid checking for a zero bucket count during insertion and lookup. +static const uint16_t vt_empty_placeholder_metadatum = VT_EMPTY; + +// Default hash and comparison functions. + +// Fast-hash, as described by https://jonkagstrom.com/bit-mixer-construction and +// https://code.google.com/archive/p/fast-hash. +// In testing, this hash function provided slightly better performance than the Murmur3 mixer. +static inline uint64_t vt_hash_integer( uint64_t key ) +{ + key ^= key >> 23; + key *= 0x2127599bf4325c37ull; + key ^= key >> 47; + return key; +} + +// FNV-1a. +static inline uint64_t vt_hash_string( char *key ) +{ + uint64_t hash = 0xcbf29ce484222325ull; + while( *key ) + hash = ( (unsigned char)*key++ ^ hash ) * 0x100000001b3ull; + + return hash; +} + +static inline bool vt_cmpr_integer( uint64_t key_1, uint64_t key_2 ) +{ + return key_1 == key_2; +} + +static inline bool vt_cmpr_string( char *key_1, char *key_2 ) +{ + return strcmp( key_1, key_2 ) == 0; +} + +// Default allocation and free functions. + +static inline void *vt_malloc( size_t size ) +{ + return malloc( size ); +} + +static inline void vt_free( void *ptr, size_t size ) +{ + (void)size; + free( ptr ); +} + +static inline void *vt_malloc_with_ctx( size_t size, void *ctx ) +{ + (void)ctx; + return malloc( size ); +} + +static inline void vt_free_with_ctx( void *ptr, size_t size, void *ctx ) +{ + (void)size; + (void)ctx; + free( ptr ); +} + +// The rest of the common header section pertains to the C11 generic macro API. +// This interface is based on the extendible-_Generic mechanism documented in detail at +// https://github.com/JacksonAllan/CC/blob/main/articles/Better_C_Generics_Part_1_The_Extendible_Generic.md. +// In summary, instantiating a template also defines wrappers for the template's types and functions with names in the +// pattern of vt_table_NNNN and vt_init_NNNN, where NNNN is an automatically generated integer unique to the template +// instance in the current translation unit. +// These wrappers plug in to _Generic-based API macros, which use preprocessor magic to automatically generate _Generic +// slots for every existing template instance. +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined( VT_NO_C11_GENERIC_API ) + +// Octal counter that supports up to 511 hash table templates. +#define VT_TEMPLATE_COUNT_D1 0 // Digit 1, i.e. least significant digit. +#define VT_TEMPLATE_COUNT_D2 0 +#define VT_TEMPLATE_COUNT_D3 0 + +// Four-way concatenation macro. +#define VT_CAT_4_( a, b, c, d ) a##b##c##d +#define VT_CAT_4( a, b, c, d ) VT_CAT_4_( a, b, c, d ) + +// Provides the current value of the counter as a three-digit octal number preceded by 0. +#define VT_TEMPLATE_COUNT VT_CAT_4( 0, VT_TEMPLATE_COUNT_D3, VT_TEMPLATE_COUNT_D2, VT_TEMPLATE_COUNT_D1 ) + +// _Generic-slot generation macros. + +#define VT_GENERIC_SLOT( ty, fn, n ) , VT_CAT( ty, n ): VT_CAT( fn, n ) +#define VT_R1_0( ty, fn, d3, d2 ) +#define VT_R1_1( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 0 ) ) +#define VT_R1_2( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 1 ) ) VT_R1_1( ty, fn, d3, d2 ) +#define VT_R1_3( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 2 ) ) VT_R1_2( ty, fn, d3, d2 ) +#define VT_R1_4( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 3 ) ) VT_R1_3( ty, fn, d3, d2 ) +#define VT_R1_5( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 4 ) ) VT_R1_4( ty, fn, d3, d2 ) +#define VT_R1_6( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 5 ) ) VT_R1_5( ty, fn, d3, d2 ) +#define VT_R1_7( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 6 ) ) VT_R1_6( ty, fn, d3, d2 ) +#define VT_R1_8( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 7 ) ) VT_R1_7( ty, fn, d3, d2 ) +#define VT_R2_0( ty, fn, d3 ) +#define VT_R2_1( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 0 ) +#define VT_R2_2( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 1 ) VT_R2_1( ty, fn, d3 ) +#define VT_R2_3( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 2 ) VT_R2_2( ty, fn, d3 ) +#define VT_R2_4( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 3 ) VT_R2_3( ty, fn, d3 ) +#define VT_R2_5( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 4 ) VT_R2_4( ty, fn, d3 ) +#define VT_R2_6( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 5 ) VT_R2_5( ty, fn, d3 ) +#define VT_R2_7( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 6 ) VT_R2_6( ty, fn, d3 ) +#define VT_R2_8( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 7 ) VT_R2_7( ty, fn, d3 ) +#define VT_R3_0( ty, fn ) +#define VT_R3_1( ty, fn ) VT_R2_8( ty, fn, 0 ) +#define VT_R3_2( ty, fn ) VT_R2_8( ty, fn, 1 ) VT_R3_1( ty, fn ) +#define VT_R3_3( ty, fn ) VT_R2_8( ty, fn, 2 ) VT_R3_2( ty, fn ) +#define VT_R3_4( ty, fn ) VT_R2_8( ty, fn, 3 ) VT_R3_3( ty, fn ) +#define VT_R3_5( ty, fn ) VT_R2_8( ty, fn, 4 ) VT_R3_4( ty, fn ) +#define VT_R3_6( ty, fn ) VT_R2_8( ty, fn, 5 ) VT_R3_5( ty, fn ) +#define VT_R3_7( ty, fn ) VT_R2_8( ty, fn, 6 ) VT_R3_6( ty, fn ) + +#define VT_GENERIC_SLOTS( ty, fn ) \ +VT_CAT( VT_R1_, VT_TEMPLATE_COUNT_D1 )( ty, fn, VT_TEMPLATE_COUNT_D3, VT_TEMPLATE_COUNT_D2 ) \ +VT_CAT( VT_R2_, VT_TEMPLATE_COUNT_D2 )( ty, fn, VT_TEMPLATE_COUNT_D3 ) \ +VT_CAT( VT_R3_, VT_TEMPLATE_COUNT_D3 )( ty, fn ) \ + +// Actual generic API macros. + +// vt_init must be handled as a special case because it could take one or two arguments, depending on whether CTX_TY +// was defined. +#define VT_ARG_3( _1, _2, _3, ... ) _3 +#define vt_init( ... ) VT_ARG_3( __VA_ARGS__, vt_init_with_ctx, vt_init_without_ctx, )( __VA_ARGS__ ) +#define vt_init_without_ctx( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_init_ ) )( table ) +#define vt_init_with_ctx( table, ... ) _Generic( *( table ) \ + VT_GENERIC_SLOTS( vt_table_, vt_init_ ) \ +)( table, __VA_ARGS__ ) \ + +#define vt_init_clone( table, ... ) _Generic( *( table ) \ + VT_GENERIC_SLOTS( vt_table_, vt_init_clone_ ) \ +)( table, __VA_ARGS__ ) \ + +#define vt_size( table )_Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_size_ ) )( table ) + +#define vt_bucket_count( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_bucket_count_ ) )( table ) + +#define vt_is_end( itr ) _Generic( itr VT_GENERIC_SLOTS( vt_table_itr_, vt_is_end_ ) )( itr ) + +#define vt_insert( table, ... ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_insert_ ) )( table, __VA_ARGS__ ) + +#define vt_get_or_insert( table, ... ) _Generic( *( table ) \ + VT_GENERIC_SLOTS( vt_table_, vt_get_or_insert_ ) \ +)( table, __VA_ARGS__ ) \ + +#define vt_get( table, ... ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_get_ ) )( table, __VA_ARGS__ ) + +#define vt_erase( table, ... ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_erase_ ) )( table, __VA_ARGS__ ) + +#define vt_next( itr ) _Generic( itr VT_GENERIC_SLOTS( vt_table_itr_, vt_next_ ) )( itr ) + +#define vt_erase_itr( table, ... ) _Generic( *( table ) \ + VT_GENERIC_SLOTS( vt_table_, vt_erase_itr_ ) \ +)( table, __VA_ARGS__ ) \ + +#define vt_reserve( table, ... ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_reserve_ ) )( table, __VA_ARGS__ ) + +#define vt_shrink( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_shrink_ ) )( table ) + +#define vt_first( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_first_ ) )( table ) + +#define vt_clear( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_clear_ ) )( table ) + +#define vt_cleanup( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_cleanup_ ) )( table ) + +#endif + +#endif + +/*--------------------------------------------------------------------------------------------------------------------*/ +/* Prefixed structs */ +/*--------------------------------------------------------------------------------------------------------------------*/ + +#ifndef IMPLEMENTATION_MODE + +typedef struct +{ + KEY_TY key; + #ifdef VAL_TY + VAL_TY val; + #endif +} VT_CAT( NAME, _bucket ); + +typedef struct +{ + VT_CAT( NAME, _bucket ) *data; + uint16_t *metadatum; + uint16_t *metadata_end; // Iterators carry an internal end pointer so that NAME_is_end does not need the table to be + // passed in as an argument. + // This also allows for the zero-bucket-count check to occur once in NAME_first, rather than + // repeatedly in NAME_is_end. + size_t home_bucket; // SIZE_MAX if home bucket is unknown. +} VT_CAT( NAME, _itr ); + +typedef struct +{ + size_t key_count; + size_t buckets_mask; // Rather than storing the bucket count directly, we store the bit mask used to reduce a hash + // code or displacement-derived bucket index to the buckets array, i.e. the bucket count minus + // one. + // Consequently, a zero bucket count (i.e. when .metadata points to the placeholder) constitutes + // a special case, represented by all bits unset (i.e. zero). + VT_CAT( NAME, _bucket ) *buckets; + uint16_t *metadata; // As described above, each metadatum consists of a 4-bit hash-code fragment (X), a 1-bit flag + // indicating whether the key in this bucket begins a chain associated with the bucket (Y), and + // an 11-bit value indicating the quadratic displacement of the next key in the chain (Z): + // XXXXYZZZZZZZZZZZ. + #ifdef CTX_TY + CTX_TY ctx; + #endif +} NAME; + +#endif + +/*--------------------------------------------------------------------------------------------------------------------*/ +/* Function prototypes */ +/*--------------------------------------------------------------------------------------------------------------------*/ + +#if defined( HEADER_MODE ) || defined( IMPLEMENTATION_MODE ) +#define VT_API_FN_QUALIFIERS +#else +#define VT_API_FN_QUALIFIERS static inline +#endif + +#ifndef IMPLEMENTATION_MODE + +VT_API_FN_QUALIFIERS void VT_CAT( NAME, _init )( + NAME * + #ifdef CTX_TY + , CTX_TY + #endif +); + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _init_clone )( + NAME *, + NAME * + #ifdef CTX_TY + , CTX_TY + #endif +); + +VT_API_FN_QUALIFIERS size_t VT_CAT( NAME, _size )( NAME * ); + +VT_API_FN_QUALIFIERS size_t VT_CAT( NAME, _bucket_count )( NAME * ); + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _is_end )( VT_CAT( NAME, _itr ) ); + +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert )( + NAME *, + KEY_TY + #ifdef VAL_TY + , VAL_TY + #endif +); + +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _get_or_insert )( + NAME *, + KEY_TY + #ifdef VAL_TY + , VAL_TY + #endif +); + +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _get )( + NAME *table, + KEY_TY key +); + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase )( NAME *, KEY_TY ); + +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _next )( VT_CAT( NAME, _itr ) ); + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _reserve )( NAME *, size_t ); + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _shrink )( NAME * ); + +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _first )( NAME * ); + +VT_API_FN_QUALIFIERS void VT_CAT( NAME, _clear )( NAME * ); + +VT_API_FN_QUALIFIERS void VT_CAT( NAME, _cleanup )( NAME * ); + +// Not an API function, but must be prototyped anyway because it is called by the inline NAME_erase_itr below. +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase_itr_raw ) ( NAME *, VT_CAT( NAME, _itr ) ); + +// Erases the key pointed to by itr and returns an iterator to the next key in the table. +// This function must be inlined to ensure that the compiler optimizes away the NAME_fast_forward call if the returned +// iterator is discarded. +#ifdef __GNUC__ +static inline __attribute__((always_inline)) +#elif defined( _MSC_VER ) +static __forceinline +#else +static inline +#endif +VT_CAT( NAME, _itr ) VT_CAT( NAME, _erase_itr )( NAME *table, VT_CAT( NAME, _itr ) itr ) +{ + if( VT_CAT( NAME, _erase_itr_raw )( table, itr ) ) + return VT_CAT( NAME, _next )( itr ); + + return itr; +} + +#endif + +/*--------------------------------------------------------------------------------------------------------------------*/ +/* Function implementations */ +/*--------------------------------------------------------------------------------------------------------------------*/ + +#ifndef HEADER_MODE + +// Default settings. + +#ifndef MAX_LOAD +#define MAX_LOAD 0.9 +#endif + +#if !defined( MALLOC ) || !defined( FREE ) +#include <stdlib.h> +#endif + +#ifndef MALLOC_FN +#ifdef CTX_TY +#define MALLOC_FN vt_malloc_with_ctx +#else +#define MALLOC_FN vt_malloc +#endif +#endif + +#ifndef FREE_FN +#ifdef CTX_TY +#define FREE_FN vt_free_with_ctx +#else +#define FREE_FN vt_free +#endif +#endif + +#ifndef HASH_FN +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#ifdef _MSC_VER // In MSVC, the compound literal in the _Generic triggers a warning about unused local variables at /W4. +#define HASH_FN \ +_Pragma( "warning( push )" ) \ +_Pragma( "warning( disable: 4189 )" ) \ +_Generic( ( KEY_TY ){ 0 }, char *: vt_hash_string, default: vt_hash_integer ) \ +_Pragma( "warning( pop )" ) +#else +#define HASH_FN _Generic( ( KEY_TY ){ 0 }, char *: vt_hash_string, default: vt_hash_integer ) +#endif +#else +#error Hash function inference is only available in C11 and later. In C99, you need to define HASH_FN manually to \ +vt_hash_integer, vt_hash_string, or your own custom function with the signature uint64_t ( KEY_TY ). +#endif +#endif + +#ifndef CMPR_FN +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#ifdef _MSC_VER +#define CMPR_FN \ +_Pragma( "warning( push )" ) \ +_Pragma( "warning( disable: 4189 )" ) \ +_Generic( ( KEY_TY ){ 0 }, char *: vt_cmpr_string, default: vt_cmpr_integer ) \ +_Pragma( "warning( pop )" ) +#else +#define CMPR_FN _Generic( ( KEY_TY ){ 0 }, char *: vt_cmpr_string, default: vt_cmpr_integer ) +#endif +#else +#error Comparison function inference is only available in C11 and later. In C99, you need to define CMPR_FN manually \ +to vt_cmpr_integer, vt_cmpr_string, or your own custom function with the signature bool ( KEY_TY, KEY_TY ). +#endif +#endif + +VT_API_FN_QUALIFIERS void VT_CAT( NAME, _init )( + NAME *table + #ifdef CTX_TY + , CTX_TY ctx + #endif +) +{ + table->key_count = 0; + table->buckets_mask = 0x0000000000000000ull; + table->buckets = NULL; + table->metadata = (uint16_t *)&vt_empty_placeholder_metadatum; + #ifdef CTX_TY + table->ctx = ctx; + #endif +} + +// For efficiency, especially in the case of a small table, the buckets array and metadata share the same dynamic memory +// allocation: +// +-----------------------------+-----+----------------+--------+ +// | Buckets | Pad | Metadata | Excess | +// +-----------------------------+-----+----------------+--------+ +// Any allocated metadata array requires four excess elements to ensure that iteration functions, which read four +// metadata at a time, never read beyond the end of it. +// This function returns the offset of the beginning of the metadata, i.e. the size of the buckets array plus the +// (usually zero) padding. +// It assumes that the bucket count is not zero. +static inline size_t VT_CAT( NAME, _metadata_offset )( NAME *table ) +{ + // Use sizeof, rather than alignof, for C99 compatibility. + return ( ( ( table->buckets_mask + 1 ) * sizeof( VT_CAT( NAME, _bucket ) ) + sizeof( uint16_t ) - 1 ) / + sizeof( uint16_t ) ) * sizeof( uint16_t ); +} + +// Returns the total allocation size, including the buckets array, padding, metadata, and excess metadata. +// As above, this function assumes that the bucket count is not zero. +static inline size_t VT_CAT( NAME, _total_alloc_size )( NAME *table ) +{ + return VT_CAT( NAME, _metadata_offset )( table ) + ( table->buckets_mask + 1 + 4 ) * sizeof( uint16_t ); +} + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _init_clone )( + NAME *table, + NAME *source + #ifdef CTX_TY + , CTX_TY ctx + #endif +) +{ + table->key_count = source->key_count; + table->buckets_mask = source->buckets_mask; + #ifdef CTX_TY + table->ctx = ctx; + #endif + + if( !source->buckets_mask ) + { + table->metadata = (uint16_t *)&vt_empty_placeholder_metadatum; + table->buckets = NULL; + return true; + } + + void *allocation = MALLOC_FN( + VT_CAT( NAME, _total_alloc_size )( table ) + #ifdef CTX_TY + , &table->ctx + #endif + ); + + if( VT_UNLIKELY( !allocation ) ) + return false; + + table->buckets = (VT_CAT( NAME, _bucket ) *)allocation; + table->metadata = (uint16_t *)( (unsigned char *)allocation + VT_CAT( NAME, _metadata_offset )( table ) ); + memcpy( allocation, source->buckets, VT_CAT( NAME, _total_alloc_size )( table ) ); + + return true; +} + +VT_API_FN_QUALIFIERS size_t VT_CAT( NAME, _size )( NAME *table ) +{ + return table->key_count; +} + +VT_API_FN_QUALIFIERS size_t VT_CAT( NAME, _bucket_count )( NAME *table ) +{ + // If the bucket count is zero, buckets_mask will be zero, not the bucket count minus one. + // We account for this special case by adding (bool)buckets_mask rather than one. + return table->buckets_mask + (bool)table->buckets_mask; +} + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _is_end )( VT_CAT( NAME, _itr ) itr ) +{ + return itr.metadatum == itr.metadata_end; +} + +// Finds the earliest empty bucket in which a key belonging to home_bucket can be placed, assuming that home_bucket +// is already occupied. +// The reason to begin the search at home_bucket, rather than the end of the existing chain, is that keys deleted from +// other chains might have freed up buckets that could fall in this chain before the final key. +// Returns true if an empty bucket within the range of the displacement limit was found, in which case the final two +// pointer arguments contain the index of the empty bucket and its quadratic displacement from home_bucket. +static inline bool VT_CAT( NAME, _find_first_empty )( + NAME *table, + size_t home_bucket, + size_t *empty, + uint16_t *displacement +) +{ + *displacement = 1; + size_t linear_dispacement = 1; + + while( true ) + { + *empty = ( home_bucket + linear_dispacement ) & table->buckets_mask; + if( table->metadata[ *empty ] == VT_EMPTY ) + return true; + + if( VT_UNLIKELY( ++*displacement == VT_DISPLACEMENT_MASK ) ) + return false; + + linear_dispacement += *displacement; + } +} + +// Finds the key in the chain beginning in home_bucket after which to link a new key with displacement_to_empty +// quadratic displacement and returns the index of the bucket containing that key. +// Although the new key could simply be linked to the end of the chain, keeping the chain ordered by displacement +// theoretically improves cache locality during lookups. +static inline size_t VT_CAT( NAME, _find_insert_location_in_chain )( + NAME *table, + size_t home_bucket, + uint16_t displacement_to_empty +) +{ + size_t candidate = home_bucket; + while( true ) + { + uint16_t displacement = table->metadata[ candidate ] & VT_DISPLACEMENT_MASK; + + if( displacement > displacement_to_empty ) + return candidate; + + candidate = ( home_bucket + vt_quadratic( displacement ) ) & table->buckets_mask; + } +} + +// Frees up a bucket occupied by a key not belonging there so that a new key belonging there can be placed there as the +// beginning of a new chain. +// This requires: +// * Finding the previous key in the chain to which the occupying key belongs by rehashing it and then traversing the +// chain. +// * Disconnecting the key from the chain. +// * Finding the appropriate empty bucket to which to move the key. +// * Moving the key (and value) data to the empty bucket. +// * Re-linking the key to the chain. +// Returns true if the eviction succeeded, or false if no empty bucket to which to evict the occupying key could be +// found within the displacement limit. +static inline bool VT_CAT( NAME, _evict )( NAME *table, size_t bucket ) +{ + // Find the previous key in chain. + size_t home_bucket = HASH_FN( table->buckets[ bucket ].key ) & table->buckets_mask; + size_t prev = home_bucket; + while( true ) + { + size_t next = ( home_bucket + vt_quadratic( table->metadata[ prev ] & VT_DISPLACEMENT_MASK ) ) & + table->buckets_mask; + + if( next == bucket ) + break; + + prev = next; + } + + // Disconnect the key from chain. + table->metadata[ prev ] = ( table->metadata[ prev ] & ~VT_DISPLACEMENT_MASK ) | ( table->metadata[ bucket ] & + VT_DISPLACEMENT_MASK ); + + // Find the empty bucket to which to move the key. + size_t empty; + uint16_t displacement; + if( VT_UNLIKELY( !VT_CAT( NAME, _find_first_empty )( table, home_bucket, &empty, &displacement ) ) ) + return false; + + // Find the key in the chain after which to link the moved key. + prev = VT_CAT( NAME, _find_insert_location_in_chain )( table, home_bucket, displacement ); + + // Move the key (and value) data. + table->buckets[ empty ] = table->buckets[ bucket ]; + + // Re-link the key to the chain from its new bucket. + table->metadata[ empty ] = ( table->metadata[ bucket ] & VT_HASH_FRAG_MASK ) | ( table->metadata[ prev ] & + VT_DISPLACEMENT_MASK ); + table->metadata[ prev ] = ( table->metadata[ prev ] & ~VT_DISPLACEMENT_MASK ) | displacement; + + return true; +} + +// Returns an end iterator, i.e. any iterator for which .metadatum == .metadata_end. +// This function just cleans up the library code in functions that return an end iterator as a failure indicator. +static inline VT_CAT( NAME, _itr ) VT_CAT( NAME, _end_itr )( void ) +{ + VT_CAT( NAME, _itr ) itr = { NULL, NULL, NULL, 0 }; + return itr; +} + +// Inserts a key, optionally replacing the existing key if it already exists. +// There are two main cases that must be handled: +// * If the key's home bucket is empty or occupied by a key that does not belong there, then the key is inserted there, +// evicting the occupying key if there is one. +// * Otherwise, the chain of keys beginning at the home bucket is (if unique is false) traversed in search of a matching +// key. +// If none is found, then the new key is inserted at the earliest available bucket, per quadratic probing from the +// home bucket, and then linked to the chain in a manner that maintains its quadratic order. +// The unique argument tells the function whether to skip searching for the key before inserting it (on rehashing, this +// step is unnecessary). +// The replace argument tells the function whether to replace an existing key. +// If replace is true, the function returns an iterator to the inserted key, or an end iterator if the key was not +// inserted because of the maximum load factor or displacement limit constraints. +// If replace is false, then the return value is as described above, except that if the key already exists, the function +// returns an iterator to the existing key. +static inline VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert_raw )( + NAME *table, + KEY_TY key, + #ifdef VAL_TY + VAL_TY *val, + #endif + bool unique, + bool replace +) +{ + uint64_t hash = HASH_FN( key ); + uint16_t hashfrag = vt_hashfrag( hash ); + size_t home_bucket = hash & table->buckets_mask; + + // Case 1: The home bucket is empty or contains a key that doesn't belong there. + // This case also implicitly handles the case of a zero bucket count, since home_bucket will be zero and metadata[ 0 ] + // will be the empty placeholder. + // In that scenario, the zero buckets_mask triggers the below load-factor check. + if( !( table->metadata[ home_bucket ] & VT_IN_HOME_BUCKET_MASK ) ) + { + if( + // Load-factor check. + VT_UNLIKELY( table->key_count + 1 > VT_CAT( NAME, _bucket_count )( table ) * MAX_LOAD ) || + // Vacate the home bucket if it contains a key. + ( table->metadata[ home_bucket ] != VT_EMPTY && VT_UNLIKELY( !VT_CAT( NAME, _evict )( table, home_bucket ) ) ) + ) + return VT_CAT( NAME, _end_itr )(); + + table->buckets[ home_bucket ].key = key; + #ifdef VAL_TY + table->buckets[ home_bucket ].val = *val; + #endif + table->metadata[ home_bucket ] = hashfrag | VT_IN_HOME_BUCKET_MASK | VT_DISPLACEMENT_MASK; + + ++table->key_count; + + VT_CAT( NAME, _itr ) itr = { + table->buckets + home_bucket, + table->metadata + home_bucket, + table->metadata + table->buckets_mask + 1, // Iteration stopper (i.e. the first of the four excess metadata). + home_bucket + }; + return itr; + } + + // Case 2: The home bucket contains the beginning of a chain. + + // Optionally, check the existing chain. + if( !unique ) + { + size_t bucket = home_bucket; + while( true ) + { + if( + ( table->metadata[ bucket ] & VT_HASH_FRAG_MASK ) == hashfrag && + VT_LIKELY( CMPR_FN( table->buckets[ bucket ].key, key ) ) + ) + { + if( replace ) + { + #ifdef KEY_DTOR_FN + KEY_DTOR_FN( table->buckets[ bucket ].key ); + #endif + table->buckets[ bucket ].key = key; + + #ifdef VAL_TY + #ifdef VAL_DTOR_FN + VAL_DTOR_FN( table->buckets[ bucket ].val ); + #endif + table->buckets[ bucket ].val = *val; + #endif + } + + VT_CAT( NAME, _itr ) itr = { + table->buckets + bucket, + table->metadata + bucket, + table->metadata + table->buckets_mask + 1, + home_bucket + }; + return itr; + } + + uint16_t displacement = table->metadata[ bucket ] & VT_DISPLACEMENT_MASK; + if( displacement == VT_DISPLACEMENT_MASK ) + break; + + bucket = ( home_bucket + vt_quadratic( displacement ) ) & table->buckets_mask; + } + } + + size_t empty; + uint16_t displacement; + if( + VT_UNLIKELY( + // Load-factor check. + table->key_count + 1 > VT_CAT( NAME, _bucket_count )( table ) * MAX_LOAD || + // Find the earliest empty bucket, per quadratic probing. + !VT_CAT( NAME, _find_first_empty )( table, home_bucket, &empty, &displacement ) + ) + ) + return VT_CAT( NAME, _end_itr )(); + + // Insert the new key (and value) in the empty bucket and link it to the chain. + + size_t prev = VT_CAT( NAME, _find_insert_location_in_chain )( table, home_bucket, displacement ); + + table->buckets[ empty ].key = key; + #ifdef VAL_TY + table->buckets[ empty ].val = *val; + #endif + table->metadata[ empty ] = hashfrag | ( table->metadata[ prev ] & VT_DISPLACEMENT_MASK ); + table->metadata[ prev ] = ( table->metadata[ prev ] & ~VT_DISPLACEMENT_MASK ) | displacement; + + ++table->key_count; + + VT_CAT( NAME, _itr ) itr = { + table->buckets + empty, + table->metadata + empty, + table->metadata + table->buckets_mask + 1, + home_bucket + }; + return itr; +} + +// Resizes the bucket array. +// This function assumes that bucket_count is a power of two and large enough to accommodate all keys without violating +// the maximum load factor. +// Returns false in the case of allocation failure. +// As this function is called very rarely in _insert and _get_or_insert, ideally it should not be inlined into those +// functions. +// In testing, the no-inline approach showed a performance benefit when inserting existing keys (i.e. replacing). +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" // Silence warning about combining noinline with static inline. +__attribute__((noinline)) static inline +#elif defined( _MSC_VER ) +__declspec(noinline) static inline +#else +static inline +#endif +bool VT_CAT( NAME, _rehash )( NAME *table, size_t bucket_count ) +{ + // The attempt to resize the bucket array and rehash the keys must occur inside a loop that incrementally doubles the + // target bucket count because a failure could theoretically occur at any load factor due to the displacement limit. + while( true ) + { + NAME new_table = { + 0, + bucket_count - 1, + NULL, + NULL + #ifdef CTX_TY + , table->ctx + #endif + }; + + void *allocation = MALLOC_FN( + VT_CAT( NAME, _total_alloc_size )( &new_table ) + #ifdef CTX_TY + , &new_table.ctx + #endif + ); + + if( VT_UNLIKELY( !allocation ) ) + return false; + + new_table.buckets = (VT_CAT( NAME, _bucket ) *)allocation; + new_table.metadata = (uint16_t *)( (unsigned char *)allocation + VT_CAT( NAME, _metadata_offset )( &new_table ) ); + + memset( new_table.metadata, 0x00, ( bucket_count + 4 ) * sizeof( uint16_t ) ); + + // Iteration stopper at the end of the actual metadata array (i.e. the first of the four excess metadata). + new_table.metadata[ bucket_count ] = 0x01; + + for( size_t bucket = 0; bucket < VT_CAT( NAME, _bucket_count )( table ); ++bucket ) + if( table->metadata[ bucket ] != VT_EMPTY ) + { + VT_CAT( NAME, _itr ) itr = VT_CAT( NAME, _insert_raw )( + &new_table, + table->buckets[ bucket ].key, + #ifdef VAL_TY + &table->buckets[ bucket ].val, + #endif + true, + false + ); + + if( VT_UNLIKELY( VT_CAT( NAME, _is_end )( itr ) ) ) + break; + } + + // If a key could not be reinserted due to the displacement limit, double the bucket count and retry. + if( VT_UNLIKELY( new_table.key_count < table->key_count ) ) + { + FREE_FN( + new_table.buckets, + VT_CAT( NAME, _total_alloc_size )( &new_table ) + #ifdef CTX_TY + , &new_table.ctx + #endif + ); + + bucket_count *= 2; + continue; + } + + if( table->buckets_mask ) + FREE_FN( + table->buckets, + VT_CAT( NAME, _total_alloc_size )( table ) + #ifdef CTX_TY + , &table->ctx + #endif + ); + + *table = new_table; + return true; + } +} +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +// Inserts a key, replacing the existing key if it already exists. +// This function wraps insert_raw in a loop that handles growing and rehashing the table if a new key cannot be inserted +// because of the maximum load factor or displacement limit constraints. +// Returns an iterator to the inserted key, or an end iterator in the case of allocation failure. +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert )( + NAME *table, + KEY_TY key + #ifdef VAL_TY + , VAL_TY val + #endif +) +{ + while( true ) + { + VT_CAT( NAME, _itr ) itr = VT_CAT( NAME, _insert_raw )( + table, + key, + #ifdef VAL_TY + &val, + #endif + false, + true + ); + + if( + // Lookup succeeded, in which case itr points to the found key. + VT_LIKELY( !VT_CAT( NAME, _is_end )( itr ) ) || + // Lookup failed and rehash also fails, in which case itr is an end iterator. + VT_UNLIKELY( + !VT_CAT( NAME, _rehash )( + table, table->buckets_mask ? VT_CAT( NAME, _bucket_count )( table ) * 2 : VT_MIN_NONZERO_BUCKET_COUNT + ) + ) + ) + return itr; + } +} + +// Same as NAME_insert, except that if the key already exists, no insertion occurs and the function returns an iterator +// to the existing key. +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _get_or_insert )( + NAME *table, + KEY_TY key + #ifdef VAL_TY + , VAL_TY val + #endif +) +{ + while( true ) + { + VT_CAT( NAME, _itr ) itr = VT_CAT( NAME, _insert_raw )( + table, + key, + #ifdef VAL_TY + &val, + #endif + false, + false + ); + + if( + // Lookup succeeded, in which case itr points to the found key. + VT_LIKELY( !VT_CAT( NAME, _is_end )( itr ) ) || + // Lookup failed and rehash also fails, in which case itr is an end iterator. + VT_UNLIKELY( + !VT_CAT( NAME, _rehash )( + table, table->buckets_mask ? VT_CAT( NAME, _bucket_count )( table ) * 2 : VT_MIN_NONZERO_BUCKET_COUNT + ) + ) + ) + return itr; + } +} + +// Returns an iterator pointing to the specified key, or an end iterator if the key does not exist. +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _get )( NAME *table, KEY_TY key ) +{ + uint64_t hash = HASH_FN( key ); + size_t home_bucket = hash & table->buckets_mask; + + // If the home bucket is empty or contains a key that does not belong there, then our key does not exist. + // This check also implicitly handles the case of a zero bucket count, since home_bucket will be zero and + // metadata[ 0 ] will be the empty placeholder. + if( !( table->metadata[ home_bucket ] & VT_IN_HOME_BUCKET_MASK ) ) + return VT_CAT( NAME, _end_itr )(); + + // Traverse the chain of keys belonging to the home bucket. + uint16_t hashfrag = vt_hashfrag( hash ); + size_t bucket = home_bucket; + while( true ) + { + if( + ( table->metadata[ bucket ] & VT_HASH_FRAG_MASK ) == hashfrag && + VT_LIKELY( CMPR_FN( table->buckets[ bucket ].key, key ) ) + ) + { + VT_CAT( NAME, _itr ) itr = { + table->buckets + bucket, + table->metadata + bucket, + table->metadata + table->buckets_mask + 1, + home_bucket + }; + return itr; + } + + uint16_t displacement = table->metadata[ bucket ] & VT_DISPLACEMENT_MASK; + if( displacement == VT_DISPLACEMENT_MASK ) + return VT_CAT( NAME, _end_itr )(); + + bucket = ( home_bucket + vt_quadratic( displacement ) ) & table->buckets_mask; + } +} + +// Erases the key pointed to by the specified iterator. +// The erasure always occurs at the end of the chain to which the key belongs. +// If the key to be erased is not the last in the chain, it is swapped with the last so that erasure occurs at the end. +// This helps keep a chain's keys close to their home bucket for the sake of cache locality. +// Returns true if, in the case of iteration from first to end, NAME_next should now be called on the iterator to find +// the next key. +// This return value is necessary because at the iterator location, the erasure could result in an empty bucket, a +// bucket containing a moved key already visited during the iteration, or a bucket containing a moved key not yet +// visited. +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase_itr_raw )( NAME *table, VT_CAT( NAME, _itr ) itr ) +{ + --table->key_count; + size_t itr_bucket = itr.metadatum - table->metadata; + + // Case 1: The key is the only one in its chain, so just remove it. + if( + table->metadata[ itr_bucket ] & VT_IN_HOME_BUCKET_MASK && + ( table->metadata[ itr_bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK + ) + { + #ifdef KEY_DTOR_FN + KEY_DTOR_FN( table->buckets[ itr_bucket ].key ); + #endif + + #ifdef VAL_DTOR_FN + VAL_DTOR_FN( table->buckets[ itr_bucket ].val ); + #endif + + table->metadata[ itr_bucket ] = VT_EMPTY; + return true; + } + + // Case 2 and 3 require that we know the key's home bucket, which the iterator may not have recorded. + if( itr.home_bucket == SIZE_MAX ) + { + if( table->metadata[ itr_bucket ] & VT_IN_HOME_BUCKET_MASK ) + itr.home_bucket = itr_bucket; + else + itr.home_bucket = HASH_FN( table->buckets[ itr_bucket ].key ) & table->buckets_mask; + } + + // The key can now be safely destructed for cases 2 and 3. + #ifdef KEY_DTOR_FN + KEY_DTOR_FN( table->buckets[ itr_bucket ].key ); + #endif + + #ifdef VAL_DTOR_FN + VAL_DTOR_FN( table->buckets[ itr_bucket ].val ); + #endif + + // Case 2: The key is the last in a multi-key chain. + // Traverse the chain from the beginning and find the penultimate key. + // Then disconnect the key and erase. + if( ( table->metadata[ itr_bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK ) + { + size_t bucket = itr.home_bucket; + while( true ) + { + uint16_t displacement = table->metadata[ bucket ] & VT_DISPLACEMENT_MASK; + size_t next = ( itr.home_bucket + vt_quadratic( displacement ) ) & table->buckets_mask; + if( next == itr_bucket ) + { + table->metadata[ bucket ] |= VT_DISPLACEMENT_MASK; + table->metadata[ itr_bucket ] = VT_EMPTY; + return true; + } + + bucket = next; + } + } + + // Case 3: The chain has multiple keys, and the key is not the last one. + // Traverse the chain from the key to be erased and find the last and penultimate keys. + // Disconnect the last key from the chain, and swap it with the key to erase. + size_t bucket = itr_bucket; + while( true ) + { + size_t prev = bucket; + bucket = ( itr.home_bucket + vt_quadratic( table->metadata[ bucket ] & VT_DISPLACEMENT_MASK ) ) & + table->buckets_mask; + + if( ( table->metadata[ bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK ) + { + table->buckets[ itr_bucket ] = table->buckets[ bucket ]; + + table->metadata[ itr_bucket ] = ( table->metadata[ itr_bucket ] & ~VT_HASH_FRAG_MASK ) | ( + table->metadata[ bucket ] & VT_HASH_FRAG_MASK ); + + table->metadata[ prev ] |= VT_DISPLACEMENT_MASK; + table->metadata[ bucket ] = VT_EMPTY; + + // Whether the iterator should be advanced depends on whether the key moved to the iterator bucket came from + // before or after that bucket. + // In the former case, the iteration would already have hit the moved key, so the iterator should still be + // advanced. + if( bucket > itr_bucket ) + return false; + + return true; + } + } +} + +// Erases the specified key, if it exists. +// Returns true if a key was erased. +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase )( NAME *table, KEY_TY key ) +{ + VT_CAT( NAME, _itr ) itr = VT_CAT( NAME, _get)( table, key ); + if( VT_CAT( NAME, _is_end )( itr ) ) + return false; + + VT_CAT( NAME, _erase_itr_raw )( table, itr ); + return true; +} + +// Finds the first occupied bucket at or after the bucket pointed to by itr. +// This function scans four buckets at a time, ideally using intrinsics. +static inline void VT_CAT( NAME, _fast_forward )( VT_CAT( NAME, _itr ) *itr ) +{ + while( true ) + { + uint64_t metadata; + memcpy( &metadata, itr->metadatum, sizeof( uint64_t ) ); + if( metadata ) + { + int offset = vt_first_nonzero_uint16( metadata ); + itr->data += offset; + itr->metadatum += offset; + itr->home_bucket = SIZE_MAX; + return; + } + + itr->data += 4; + itr->metadatum += 4; + } +} + +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _next )( VT_CAT( NAME, _itr ) itr ) +{ + ++itr.data; + ++itr.metadatum; + VT_CAT( NAME, _fast_forward )( &itr ); + return itr; +} + +// Returns the minimum bucket count required to accommodate a certain number of keys, which is governed by the maximum +// load factor. +static inline size_t VT_CAT( NAME, _min_bucket_count_for_size )( size_t size ) +{ + if( size == 0 ) + return 0; + + // Round up to a power of two. + size_t bucket_count = VT_MIN_NONZERO_BUCKET_COUNT; + while( size > bucket_count * MAX_LOAD ) + bucket_count *= 2; + + return bucket_count; +} + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _reserve )( NAME *table, size_t size ) +{ + size_t bucket_count = VT_CAT( NAME, _min_bucket_count_for_size )( size ); + + if( bucket_count <= VT_CAT( NAME, _bucket_count )( table ) ) + return true; + + return VT_CAT( NAME, _rehash )( table, bucket_count ); +} + +VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _shrink )( NAME *table ) +{ + size_t bucket_count = VT_CAT( NAME, _min_bucket_count_for_size )( table->key_count ); + + if( bucket_count == VT_CAT( NAME, _bucket_count )( table ) ) // Shrink unnecessary. + return true; + + if( bucket_count == 0 ) + { + FREE_FN( + table->buckets, + VT_CAT( NAME, _total_alloc_size )( table ) + #ifdef CTX_TY + , &table->ctx + #endif + ); + + table->buckets_mask = 0x0000000000000000ull; + table->metadata = (uint16_t *)&vt_empty_placeholder_metadatum; + return true; + } + + return VT_CAT( NAME, _rehash )( table, bucket_count ); +} + +VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _first )( NAME *table ) +{ + if( !table->key_count ) + return VT_CAT( NAME, _end_itr )(); + + VT_CAT( NAME, _itr ) itr = { table->buckets, table->metadata, table->metadata + table->buckets_mask + 1, SIZE_MAX }; + VT_CAT( NAME, _fast_forward )( &itr ); + return itr; +} + +VT_API_FN_QUALIFIERS void VT_CAT( NAME, _clear )( NAME *table ) +{ + if( !table->key_count ) + return; + + for( size_t i = 0; i < VT_CAT( NAME, _bucket_count )( table ); ++i ) + { + if( table->metadata[ i ] != VT_EMPTY ) + { + #ifdef KEY_DTOR_FN + KEY_DTOR_FN( table->buckets[ i ].key ); + #endif + #ifdef VAL_DTOR_FN + VAL_DTOR_FN( table->buckets[ i ].val ); + #endif + } + + table->metadata[ i ] = VT_EMPTY; + } + + table->key_count = 0; +} + +VT_API_FN_QUALIFIERS void VT_CAT( NAME, _cleanup )( NAME *table ) +{ + if( !table->buckets_mask ) + return; + + #if defined( KEY_DTOR_FN ) || defined( VAL_DTOR_FN ) + VT_CAT( NAME, _clear )( table ); + #endif + + FREE_FN( + table->buckets, + VT_CAT( NAME, _total_alloc_size )( table ) + #ifdef CTX_TY + , &table->ctx + #endif + ); + + VT_CAT( NAME, _init )( + table + #ifdef CTX_TY + , table->ctx + #endif + ); +} + +#endif + +/*--------------------------------------------------------------------------------------------------------------------*/ +/* Wrapper types and functions for the C11 generic API */ +/*--------------------------------------------------------------------------------------------------------------------*/ + +#if defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 201112L && \ + !defined( IMPLEMENTATION_MODE ) && \ + !defined( VT_NO_C11_GENERIC_API ) \ + +typedef NAME VT_CAT( vt_table_, VT_TEMPLATE_COUNT ); +typedef VT_CAT( NAME, _itr ) VT_CAT( vt_table_itr_, VT_TEMPLATE_COUNT ); + +static inline void VT_CAT( vt_init_, VT_TEMPLATE_COUNT )( + NAME *table + #ifdef CTX_TY + , CTX_TY ctx + #endif +) +{ + VT_CAT( NAME, _init )( + table + #ifdef CTX_TY + , ctx + #endif + ); +} + +static inline bool VT_CAT( vt_init_clone_, VT_TEMPLATE_COUNT )( + NAME *table, + NAME* source + #ifdef CTX_TY + , CTX_TY ctx + #endif +) +{ + return VT_CAT( NAME, _init_clone )( + table, + source + #ifdef CTX_TY + , ctx + #endif + ); +} + +static inline size_t VT_CAT( vt_size_, VT_TEMPLATE_COUNT )( NAME *table ) +{ + return VT_CAT( NAME, _size )( table ); +} + +static inline size_t VT_CAT( vt_bucket_count_, VT_TEMPLATE_COUNT )( NAME *table ) +{ + return VT_CAT( NAME, _bucket_count )( table ); +} + +static inline bool VT_CAT( vt_is_end_, VT_TEMPLATE_COUNT )( VT_CAT( NAME, _itr ) itr ) +{ + return VT_CAT( NAME, _is_end )( itr ); +} + +static inline VT_CAT( NAME, _itr ) VT_CAT( vt_insert_, VT_TEMPLATE_COUNT )( + NAME *table, + KEY_TY key + #ifdef VAL_TY + , VAL_TY val + #endif +) +{ + return VT_CAT( NAME, _insert )( + table, + key + #ifdef VAL_TY + , val + #endif + ); +} + +static inline VT_CAT( NAME, _itr ) VT_CAT( vt_get_or_insert_, VT_TEMPLATE_COUNT )( + NAME *table, + KEY_TY key + #ifdef VAL_TY + , VAL_TY val + #endif +) +{ + return VT_CAT( NAME, _get_or_insert )( + table, + key + #ifdef VAL_TY + , val + #endif + ); +} + +static inline VT_CAT( NAME, _itr ) VT_CAT( vt_get_, VT_TEMPLATE_COUNT )( NAME *table, KEY_TY key ) +{ + return VT_CAT( NAME, _get )( table, key ); +} + +static inline bool VT_CAT( vt_erase_, VT_TEMPLATE_COUNT )( NAME *table, KEY_TY key ) +{ + return VT_CAT( NAME, _erase )( table, key ); +} + +static inline VT_CAT( NAME, _itr ) VT_CAT( vt_next_, VT_TEMPLATE_COUNT )( VT_CAT( NAME, _itr ) itr ) +{ + return VT_CAT( NAME, _next )( itr ); +} + +static inline VT_CAT( NAME, _itr ) VT_CAT( vt_erase_itr_, VT_TEMPLATE_COUNT )( NAME *table, VT_CAT( NAME, _itr ) itr ) +{ + return VT_CAT( NAME, _erase_itr )( table, itr ); +} + +static inline bool VT_CAT( vt_reserve_, VT_TEMPLATE_COUNT )( NAME *table, size_t bucket_count ) +{ + return VT_CAT( NAME, _reserve )( table, bucket_count ); +} + +static inline bool VT_CAT( vt_shrink_, VT_TEMPLATE_COUNT )( NAME *table ) +{ + return VT_CAT( NAME, _shrink )( table ); +} + +static inline VT_CAT( NAME, _itr ) VT_CAT( vt_first_, VT_TEMPLATE_COUNT )( NAME *table ) +{ + return VT_CAT( NAME, _first )( table ); +} + +static inline void VT_CAT( vt_clear_, VT_TEMPLATE_COUNT )( NAME *table ) +{ + VT_CAT( NAME, _clear )( table ); +} + +static inline void VT_CAT( vt_cleanup_, VT_TEMPLATE_COUNT )( NAME *table ) +{ + VT_CAT( NAME, _cleanup )( table ); +} + +// Increment the template counter. +#if VT_TEMPLATE_COUNT_D1 == 0 +#undef VT_TEMPLATE_COUNT_D1 +#define VT_TEMPLATE_COUNT_D1 1 +#elif VT_TEMPLATE_COUNT_D1 == 1 +#undef VT_TEMPLATE_COUNT_D1 +#define VT_TEMPLATE_COUNT_D1 2 +#elif VT_TEMPLATE_COUNT_D1 == 2 +#undef VT_TEMPLATE_COUNT_D1 +#define VT_TEMPLATE_COUNT_D1 3 +#elif VT_TEMPLATE_COUNT_D1 == 3 +#undef VT_TEMPLATE_COUNT_D1 +#define VT_TEMPLATE_COUNT_D1 4 +#elif VT_TEMPLATE_COUNT_D1 == 4 +#undef VT_TEMPLATE_COUNT_D1 +#define VT_TEMPLATE_COUNT_D1 5 +#elif VT_TEMPLATE_COUNT_D1 == 5 +#undef VT_TEMPLATE_COUNT_D1 +#define VT_TEMPLATE_COUNT_D1 6 +#elif VT_TEMPLATE_COUNT_D1 == 6 +#undef VT_TEMPLATE_COUNT_D1 +#define VT_TEMPLATE_COUNT_D1 7 +#elif VT_TEMPLATE_COUNT_D1 == 7 +#undef VT_TEMPLATE_COUNT_D1 +#define VT_TEMPLATE_COUNT_D1 0 +#if VT_TEMPLATE_COUNT_D2 == 0 +#undef VT_TEMPLATE_COUNT_D2 +#define VT_TEMPLATE_COUNT_D2 1 +#elif VT_TEMPLATE_COUNT_D2 == 1 +#undef VT_TEMPLATE_COUNT_D2 +#define VT_TEMPLATE_COUNT_D2 2 +#elif VT_TEMPLATE_COUNT_D2 == 2 +#undef VT_TEMPLATE_COUNT_D2 +#define VT_TEMPLATE_COUNT_D2 3 +#elif VT_TEMPLATE_COUNT_D2 == 3 +#undef VT_TEMPLATE_COUNT_D2 +#define VT_TEMPLATE_COUNT_D2 4 +#elif VT_TEMPLATE_COUNT_D2 == 4 +#undef VT_TEMPLATE_COUNT_D2 +#define VT_TEMPLATE_COUNT_D2 5 +#elif VT_TEMPLATE_COUNT_D2 == 5 +#undef VT_TEMPLATE_COUNT_D2 +#define VT_TEMPLATE_COUNT_D2 6 +#elif VT_TEMPLATE_COUNT_D2 == 6 +#undef VT_TEMPLATE_COUNT_D2 +#define VT_TEMPLATE_COUNT_D2 7 +#elif VT_TEMPLATE_COUNT_D2 == 7 +#undef VT_TEMPLATE_COUNT_D2 +#define VT_TEMPLATE_COUNT_D2 0 +#if VT_TEMPLATE_COUNT_D3 == 0 +#undef VT_TEMPLATE_COUNT_D3 +#define VT_TEMPLATE_COUNT_D3 1 +#elif VT_TEMPLATE_COUNT_D3 == 1 +#undef VT_TEMPLATE_COUNT_D3 +#define VT_TEMPLATE_COUNT_D3 2 +#elif VT_TEMPLATE_COUNT_D3 == 2 +#undef VT_TEMPLATE_COUNT_D3 +#define VT_TEMPLATE_COUNT_D3 3 +#elif VT_TEMPLATE_COUNT_D3 == 3 +#undef VT_TEMPLATE_COUNT_D3 +#define VT_TEMPLATE_COUNT_D3 4 +#elif VT_TEMPLATE_COUNT_D3 == 4 +#undef VT_TEMPLATE_COUNT_D3 +#define VT_TEMPLATE_COUNT_D3 5 +#elif VT_TEMPLATE_COUNT_D3 == 5 +#undef VT_TEMPLATE_COUNT_D3 +#define VT_TEMPLATE_COUNT_D3 6 +#elif VT_TEMPLATE_COUNT_D3 == 6 +#undef VT_TEMPLATE_COUNT_D3 +#define VT_TEMPLATE_COUNT_D3 7 +#elif VT_TEMPLATE_COUNT_D3 == 7 +#error Sorry, the number of template instances is limited to 511. Define VT_NO_C11_GENERIC_API globally and use the \ +C99 prefixed function API to circumvent this restriction. +#endif +#endif +#endif + +#endif + +#undef NAME +#undef KEY_TY +#undef VAL_TY +#undef HASH_FN +#undef CMPR_FN +#undef MAX_LOAD +#undef KEY_DTOR_FN +#undef VAL_DTOR_FN +#undef CTX_TY +#undef MALLOC_FN +#undef FREE_FN +#undef HEADER_MODE +#undef IMPLEMENTATION_MODE +#undef VT_API_FN_QUALIFIERS diff --git a/vere/pkg/noun/vortex.c b/vere/pkg/noun/vortex.c new file mode 100644 index 0000000..8496307 --- /dev/null +++ b/vere/pkg/noun/vortex.c @@ -0,0 +1,411 @@ +/// @file + +#include "vortex.h" + +#include "allocate.h" +#include "imprison.h" +#include "jets/k.h" +#include "jets/q.h" +#include "log.h" +#include "manage.h" +#include "nock.h" +#include "retrieve.h" +#include "trace.h" +#include "xtract.h" + +#define _CVX_LOAD 4 +#define _CVX_PEEK 22 +#define _CVX_POKE 23 +#define _CVX_WISH 10 + +u3v_home* u3v_Home; + +/* u3v_life(): execute initial lifecycle, producing Arvo core. +*/ +u3_noun +u3v_life(u3_noun eve) +{ + u3_noun lyf = u3nt(2, u3nc(0, 3), u3nc(0, 2)); + u3_noun gat = u3n_nock_on(eve, lyf); + u3_noun cor = u3k(u3x_at(7, gat)); + + u3z(gat); + return cor; +} + +/* u3v_boot(): evaluate boot sequence, making a kernel +*/ +c3_o +u3v_boot(u3_noun eve) +{ + c3_d len_d; + { + u3_noun len = u3qb_lent(eve); + u3_assert( c3y == u3r_safe_chub(len, &len_d) ); + u3z(len); + } + + { + u3_noun pro = u3m_soft(0, u3v_life, eve); + + if ( u3_blip != u3h(pro) ) { + u3z(pro); + return c3n; + } + + u3z(u3A->roc); + u3A->roc = u3k(u3t(pro)); + u3A->eve_d = len_d; + u3z(pro); + } + + return c3y; +} + +/* _cv_lite(): load lightweight, core-only pill. +*/ +static u3_noun +_cv_lite(u3_noun pil) +{ + u3_noun eve, pro; + + { + u3_noun hed, tal; + u3x_cell(pil, &hed, &tal); + if ( !_(u3r_sing_c("ivory", hed)) ) { + u3m_bail(c3__exit); + } + eve = tal; + } + + u3l_log("lite: arvo formula %x", u3r_mug(pil)); + pro = u3v_life(u3k(eve)); + u3l_log("lite: core %x", u3r_mug(pro)); + + u3z(pil); + return pro; +} + +/* u3v_boot_lite(): light bootstrap sequence, just making a kernel. +*/ +c3_o +u3v_boot_lite(u3_noun pil) +{ + // ensure zero-initialized kernel + // + u3A->roc = 0; + + { + u3_noun pro = u3m_soft(0, _cv_lite, pil); + + if ( u3_blip != u3h(pro) ) { + u3z(pro); + return c3n; + } + + u3A->roc = u3k(u3t(pro)); + u3z(pro); + } + + u3l_log("lite: final state %x", u3r_mug(u3A->roc)); + + return c3y; +} + +/* _cv_nock_wish(): call wish through hardcoded interface. +*/ +static u3_noun +_cv_nock_wish(u3_noun txt) +{ + u3_noun fun, pro; + + fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_WISH, u3A->roc))); + pro = u3n_slam_on(fun, txt); + + return pro; +} + +/* u3v_wish_n(): text expression with cache. with the input as a u3_noun. +*/ +u3_noun +u3v_wish_n(u3_noun txt) +{ + u3t_event_trace("u3v_wish", 'b'); + u3_weak exp = u3kdb_get(u3k(u3A->yot), u3k(txt)); + + if ( u3_none == exp ) { + exp = _cv_nock_wish(u3k(txt)); + + // It's probably not a good idea to use u3v_wish() + // outside the top level... (as the result is uncached) + // + if ( u3R == &u3H->rod_u ) { + u3A->yot = u3kdb_put(u3A->yot, u3k(txt), u3k(exp)); + } + } + + u3t_event_trace("u3v_wish", 'e'); + + u3z(txt); + return exp; +} + +/* u3v_wish(): text expression with cache. +*/ +u3_noun +u3v_wish(const c3_c* str_c) +{ + u3t_event_trace("u3v_wish", 'b'); + u3_noun txt = u3i_string(str_c); + u3_weak exp = u3kdb_get(u3k(u3A->yot), u3k(txt)); + + if ( u3_none == exp ) { + exp = _cv_nock_wish(u3k(txt)); + + // It's probably not a good idea to use u3v_wish() + // outside the top level... (as the result is uncached) + // + if ( u3R == &u3H->rod_u ) { + u3A->yot = u3kdb_put(u3A->yot, u3k(txt), u3k(exp)); + } + } + + u3t_event_trace("u3v_wish", 'e'); + + u3z(txt); + return exp; +} + +/* u3v_do(): use a kernel gate. +*/ +u3_noun +u3v_do(const c3_c* txt_c, u3_noun sam) +{ + u3_noun gat = u3v_wish(txt_c); + u3_noun pro; + +#if 0 + if ( &u3H->rod_u == u3R ) { + pro = u3m_soft_slam(gat, sam); + } + else { + pro = u3n_slam_on(gat, sam); + } +#else + pro = u3n_slam_on(gat, sam); +#endif + + return pro; +} + +/* u3v_lily(): parse little atom. +*/ +c3_o +u3v_lily(u3_noun fot, u3_noun txt, c3_l* tid_l) +{ + c3_w wad_w; + u3_noun uco = u3dc("slaw", fot, u3k(txt)); + u3_noun p_uco, q_uco; + + if ( (c3n == u3r_cell(uco, &p_uco, &q_uco)) || + (u3_nul != p_uco) || + (c3n == u3r_safe_word(q_uco, &wad_w)) || + (wad_w & 0x80000000) ) + { + c3_c* txt_c = u3r_string(txt); + u3l_log("strange lily %s", txt_c); + c3_free(txt_c); + u3z(txt); u3z(uco); + return c3n; + } + else { + *tid_l = (c3_l)wad_w; + u3z(txt); u3z(uco); + return c3y; + } +} + +/* u3v_peek(): query the reck namespace (protected). +*/ +u3_noun +u3v_peek(u3_noun sam) +{ + u3_noun fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_PEEK, u3A->roc))); + return u3n_slam_on(fun, sam); +} + +/* u3v_soft_peek(): softly query the reck namespace. +*/ +u3_noun +u3v_soft_peek(c3_w mil_w, u3_noun sam) +{ + u3_noun gon = u3m_soft(mil_w, u3v_peek, sam); + u3_noun tag, dat; + u3x_cell(gon, &tag, &dat); + + // read failed, produce trace + // + // NB, reads *should not* fail deterministically + // + if ( u3_blip != tag ) { + return u3nc(c3n, gon); + } + + // read succeeded, produce result + // + { + u3_noun pro = u3nc(c3y, u3k(dat)); + u3z(gon); + return pro; + } +} + +/* u3v_poke(): compute a timestamped ovum. +*/ +u3_noun +u3v_poke(u3_noun sam) +{ + u3_noun fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_POKE, u3A->roc))); + u3_noun pro; + + { +# ifdef U3_MEMORY_DEBUG + c3_w cod_w = u3a_lush(u3h(u3t(u3t(sam)))); +# endif + + pro = u3n_slam_on(fun, sam); + +# ifdef U3_MEMORY_DEBUG + u3a_lop(cod_w); +# endif + } + + return pro; +} + +/* u3v_poke_sure(): inject an event, saving new state if successful. +*/ +c3_o +u3v_poke_sure(c3_w mil_w, u3_noun eve, u3_noun* pro) +{ + u3_noun gon = u3m_soft(mil_w, u3v_poke, eve); + u3_noun tag, dat; + u3x_cell(gon, &tag, &dat); + + // event failed, produce trace + // + if ( u3_blip != tag ) { + *pro = gon; + return c3n; + } + + // event succeeded, persist state and produce effects + // + { + u3_noun vir, cor; + u3x_cell(dat, &vir, &cor); + + u3z(u3A->roc); + u3A->roc = u3k(cor); + u3A->eve_d++; + + *pro = u3k(vir); + u3z(gon); + return c3y; + } +} + +/* u3v_tank(): dump single tank. +*/ +void +u3v_tank(u3_noun blu, c3_l tab_l, u3_noun tac) +{ + u3v_punt(blu, tab_l, u3nc(tac, u3_nul)); +} + +/* u3v_punt(): dump tank list. +*/ +void +u3v_punt(u3_noun blu, c3_l tab_l, u3_noun tac) +{ +#if 0 + u3_noun blu = u3_term_get_blew(0); +#endif + c3_l col_l = u3h(blu); + u3_noun cat = tac; + + // We are calling nock here, but hopefully need no protection. + // + while ( c3y == u3du(cat) ) { + u3_noun wol = u3dc("wash", u3nc(tab_l, col_l), u3k(u3h(cat))); + + u3m_wall(wol); + cat = u3t(cat); + } + u3z(tac); + u3z(blu); +} + +/* u3v_sway(): print trace. +*/ +void +u3v_sway(u3_noun blu, c3_l tab_l, u3_noun tax) +{ + u3_noun mok = u3dc("mook", 2, tax); + + u3v_punt(blu, tab_l, u3k(u3t(mok))); + u3z(mok); +} + +/* u3v_mark(): mark arvo kernel. +*/ +u3m_quac* +u3v_mark() +{ + u3v_arvo* arv_u = &(u3H->arv_u); + + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 3); + + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("kernel"); + qua_u[0]->siz_w = u3a_mark_noun(arv_u->roc) * 4; + + qua_u[1] = c3_calloc(sizeof(*qua_u[2])); + qua_u[1]->nam_c = strdup("wish cache"); + qua_u[1]->siz_w = u3a_mark_noun(arv_u->yot) * 4; + + qua_u[2] = NULL; + + u3m_quac* tot_u = c3_malloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total arvo stuff"); + tot_u->siz_w = qua_u[0]->siz_w + qua_u[1]->siz_w; + tot_u->qua_u = qua_u; + + return tot_u; +} + +/* u3v_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3v_reclaim(void) +{ + // clear the u3v_wish cache + // + // NB: this would leak if not on the home road + // + if ( &(u3H->rod_u) == u3R ) { + u3z(u3A->yot); + u3A->yot = u3_nul; + } +} + +/* u3v_rewrite_compact(): rewrite arvo kernel for compaction. +*/ +void +u3v_rewrite_compact(void) +{ + // XX fix these to correctly no-op on inner roads + // + u3a_relocate_noun(&(u3A->roc)); + u3a_relocate_noun(&(u3A->yot)); +} diff --git a/vere/pkg/noun/vortex.h b/vere/pkg/noun/vortex.h new file mode 100644 index 0000000..9b48ba5 --- /dev/null +++ b/vere/pkg/noun/vortex.h @@ -0,0 +1,135 @@ +/// @file + +#ifndef U3_VORTEX_H +#define U3_VORTEX_H + +#include "allocate.h" +#include "c3/c3.h" +#include "imprison.h" +#include "version.h" + + /** Data structures. + **/ + /* u3v_arvo: modern arvo structure. + */ + typedef struct _u3v_arvo { + c3_d eve_d; // event number + u3_noun roc; // kernel core + u3_noun yot; // cached gates + } u3v_arvo; + + /* u3v_home: all internal (within image) state. + ** NB: version must first for ease of migration. + */ + typedef struct _u3v_home { + u3v_version ver_d; // version number + c3_d pam_d; // parameters + u3v_arvo arv_u; // arvo state + u3a_road rod_u; // storage state + } u3v_home; + + + /** Globals. + **/ + /// Arvo internal state. + extern u3v_home* u3v_Home; +# define u3H u3v_Home +# define u3A (&(u3v_Home->arv_u)) + + /** Functions. + **/ + /* u3v_life(): execute initial lifecycle, producing Arvo core. + */ + u3_noun + u3v_life(u3_noun eve); + + /* u3v_boot(): evaluate boot sequence, making a kernel + */ + c3_o + u3v_boot(u3_noun eve); + + /* u3v_boot_lite(): light bootstrap sequence, just making a kernel. + */ + c3_o + u3v_boot_lite(u3_noun lit); + + /* u3v_wish_n(): text expression with cache. + */ + u3_noun + u3v_wish_n(const u3_noun txt); + + /* u3v_do(): use a kernel function. + */ + u3_noun + u3v_do(const c3_c* txt_c, u3_noun arg); +# define u3do(txt_c, a) u3v_do(txt_c, a) +# define u3dc(txt_c, a, b) u3v_do(txt_c, u3nc(a, b)) +# define u3dt(txt_c, a, b, c) u3v_do(txt_c, u3nt(a, b, c)) +# define u3dq(txt_c, a, b, c, d) u3v_do(txt_c, u3nq(a, b, c, d)) + + /* u3v_wish(): text expression with cache. + */ + u3_noun + u3v_wish(const c3_c* str_c); + + /* u3v_lily(): parse little atom. + */ + c3_o + u3v_lily(u3_noun fot, u3_noun txt, c3_l* tid_l); + + /* u3v_peek(): query the reck namespace. + */ + u3_noun + u3v_peek(u3_noun hap); + + /* u3v_soft_peek(): softly query the reck namespace. + */ + u3_noun + u3v_soft_peek(c3_w mil_w, u3_noun sam); + + /* u3v_poke(): compute a timestamped ovum. + */ + u3_noun + u3v_poke(u3_noun sam); + + /* u3v_poke_sure(): inject an event, saving new state if successful. + */ + c3_o + u3v_poke_sure(c3_w mil_w, u3_noun eve, u3_noun* pro); + + /* u3v_tank(): dump single tank. + */ + void + u3v_tank(u3_noun blu, c3_l tab_l, u3_noun tac); + + /* u3v_punt(): dump tank list. + */ + void + u3v_punt(u3_noun blu, c3_l tab_l, u3_noun tac); + + /* u3v_sway(): print trace. + */ + void + u3v_sway(u3_noun blu, c3_l tab_l, u3_noun tax); + + /* u3v_plan(): queue ovum (external). + */ + void + u3v_plan(u3_noun pax, u3_noun fav); + + /* u3v_mark(): mark arvo kernel. + */ + u3m_quac* + u3v_mark(); + + /* u3v_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3v_reclaim(void); + + /* u3v_rewrite_compact(): rewrite arvo kernel for compaction. + */ + void + u3v_rewrite_compact(void); + +#endif /* ifndef U3_VORTEX_H */ diff --git a/vere/pkg/noun/xtract.c b/vere/pkg/noun/xtract.c new file mode 100644 index 0000000..f18aa68 --- /dev/null +++ b/vere/pkg/noun/xtract.c @@ -0,0 +1,33 @@ +/// @file + +#include "xtract.h" + +#include "manage.h" +#include "retrieve.h" + +u3_atom +u3x_atom(u3_noun a); +u3_noun +u3x_good(u3_weak som); +c3_o +u3x_loob(u3_noun a); + +/* u3x_mean(): +** +** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates. +** Axes must be sorted in tree order. +*/ +void +u3x_mean(u3_noun som, ...) +{ + c3_o ret_o; + va_list ap; + + va_start(ap, som); + ret_o = u3r_vmean(som, ap); + va_end(ap); + + if ( c3n == ret_o ) { + u3m_bail(c3__exit); + } +} diff --git a/vere/pkg/noun/xtract.h b/vere/pkg/noun/xtract.h new file mode 100644 index 0000000..c527a43 --- /dev/null +++ b/vere/pkg/noun/xtract.h @@ -0,0 +1,162 @@ +/// @file + +#ifndef U3_XTRACT_H +#define U3_XTRACT_H + +#include "c3/c3.h" +#include "types.h" +#include "allocate.h" +#include "manage.h" + + /** Constants. + **/ + /* Conventional axes for gate call. + */ +# define u3x_pay 3 // payload +# define u3x_sam 6 // sample +# define u3x_sam_1 6 +# define u3x_sam_2 12 +# define u3x_sam_3 13 +# define u3x_sam_4 24 +# define u3x_sam_5 25 +# define u3x_sam_6 26 +# define u3x_sam_12 52 +# define u3x_sam_13 53 +# define u3x_sam_7 27 +# define u3x_sam_14 54 +# define u3x_sam_15 55 +# define u3x_sam_30 110 +# define u3x_sam_31 111 +# define u3x_sam_62 222 +# define u3x_sam_63 223 +# define u3x_con 7 // context +# define u3x_con_2 14 // context +# define u3x_con_3 15 // context +# define u3x_con_sam 30 // sample in gate context +# define u3x_con_sam_2 60 +# define u3x_con_sam_3 61 +# define u3x_bat 2 // battery + + + /** Macros. + **/ + /* Word axis macros. For 31-bit axes only. + */ + + /* u3x_at (u3at): fragment. + */ +# define u3x_at(a, b) u3x_good(u3r_at(a, b)) +# define u3at(a, b) u3x_at(a, b) + + /* u3x_bite(): xtract/default $bloq and $step from $bite. + */ +# define u3x_bite(a, b, c) \ + do { \ + if ( c3n == u3r_bite(a, b, c) ) { \ + u3m_bail(c3__exit); \ + } \ + } while (0) + + /* u3x_dep(): number of axis bits. + */ +# define u3x_dep(a_w) (c3_bits_word(a_w) - 1) + + /* u3x_cap(): root axis, 2 or 3. + */ +# define u3x_cap(a_w) ({ \ + u3_assert( 1 < a_w ); \ + (0x2 | (a_w >> (u3x_dep(a_w) - 1))); }) + + /* u3x_mas(): remainder after cap. + */ +# define u3x_mas(a_w) ({ \ + u3_assert( 1 < a_w ); \ + ( (a_w & ~(1 << u3x_dep(a_w))) | (1 << (u3x_dep(a_w) - 1)) ); }) + + /* u3x_peg(): connect two axes. + */ +# define u3x_peg(a_w, b_w) \ + ( (a_w << u3x_dep(b_w)) | (b_w &~ (1 << u3x_dep(b_w))) ) + + /* u3x_cell(): divide `a` as a cell `[b c]`. + */ +# define u3x_cell(a, b, c) \ + do { \ + if ( c3n == u3r_cell(a, b, c) ) { \ + u3m_bail(c3__exit); \ + } \ + } while (0) + + /* u3x_trel(): divide `a` as a trel `[b c d]`, or bail. + */ +# define u3x_trel(a, b, c, d) \ + do { \ + if ( c3n == u3r_trel(a, b, c, d) ) { \ + u3m_bail(c3__exit); \ + } \ + } while (0) + + /* u3x_qual(): divide `a` as a quadruple `[b c d e]`. + */ +# define u3x_qual(a, b, c, d, e) \ + do { \ + if ( c3n == u3r_qual(a, b, c, d, e) ) { \ + u3m_bail(c3__exit); \ + } \ + } while (0) + + /* u3x_quil(): divide `a` as a quintuple `[b c d e f]`. + */ +# define u3x_quil(a, b, c, d, e, f) \ + do { \ + if ( c3n == u3r_quil(a, b, c, d, e, f) ) { \ + u3m_bail(c3__exit); \ + } \ + } while (0) + + /* u3x_hext(): divide `a` as a hextuple `[b c d e f g]`. + */ +# define u3x_hext(a, b, c, d, e, f, g) \ + do { \ + if ( c3n == u3r_hext(a, b, c, d, e, f, g) ) { \ + u3m_bail(c3__exit); \ + } \ + } while (0) + + /** Functions. + **/ + /** u3x_*: read, but bail with c3__exit on a crash. + **/ + /* u3x_atom(): atom or exit. + */ + inline u3_atom + u3x_atom(u3_noun a) + { + return ( c3y == u3a_is_cell(a) ) ? u3m_bail(c3__exit) : a; + } + + /* u3x_good(): test for u3_none. + */ + inline u3_noun + u3x_good(u3_weak som) + { + return ( u3_none == som ) ? u3m_bail(c3__exit) : som; + } + + /* u3x_loob(): loobean or exit. + */ + inline c3_o + u3x_loob(u3_noun a) + { + return ( a > 1 ) ? u3m_bail(c3__exit) : a; + } + + /* u3x_mean(): + ** + ** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates. + ** Axes must be sorted in tree order. + */ + void + u3x_mean(u3_noun a, ...); + +#endif /* ifndef U3_XTRACT_H */ diff --git a/vere/pkg/noun/zave.c b/vere/pkg/noun/zave.c new file mode 100644 index 0000000..2530718 --- /dev/null +++ b/vere/pkg/noun/zave.c @@ -0,0 +1,157 @@ +/// @file + +#include "zave.h" + +#include "allocate.h" +#include "hashtable.h" +#include "imprison.h" +#include "options.h" +#include "vortex.h" + +/* u3z_key(): construct a memo cache-key. Arguments retained. +*/ +u3_noun +u3z_key(c3_m fun, u3_noun one) +{ + return u3nc(fun, u3k(one)); +} +u3_noun +u3z_key_2(c3_m fun, u3_noun one, u3_noun two) +{ + return u3nt(fun, u3k(one), u3k(two)); +} +u3_noun +u3z_key_3(c3_m fun, u3_noun one, u3_noun two, u3_noun tri) +{ + return u3nq(fun, u3k(one), u3k(two), u3k(tri)); +} +u3_noun +u3z_key_4(c3_m fun, u3_noun one, u3_noun two, u3_noun tri, u3_noun qua) +{ + return u3nc(fun, u3nq(u3k(one), u3k(two), u3k(tri), u3k(qua))); +} +u3_noun +u3z_key_5(c3_m fun, u3_noun one, u3_noun two, u3_noun tri, u3_noun qua, u3_noun qin) +{ + return u3nc(fun, u3nq(u3k(one), u3k(two), u3k(tri), u3nc(u3k(qua), u3k(qin)))); +} + +/* _har(): get the memo cache for the given cid. +*/ +static u3p(u3h_root) +_har(u3a_road* rod_u, u3z_cid cid) +{ + switch ( cid ) { + case u3z_memo_toss: + return rod_u->cax.har_p; + case u3z_memo_keep: + return rod_u->cax.per_p; + } + u3_assert(0); +} + +/* u3z_find(): find in memo cache. Arguments retained. +*/ +u3_weak +u3z_find(u3z_cid cid, u3_noun key) +{ + if ( (u3z_memo_toss == cid) || (u3C.wag_w & u3o_cash) ) { + // XX under cash lookup in parent roads, + // copying cache hits into the current road + return u3h_get(_har(u3R, cid), key); + } + else { + // XX needs to be benchmarked (up vs. down search) + u3a_road* rod_u = &(u3H->rod_u); + while ( 1 ) { + u3_weak got = u3h_get(_har(rod_u, cid), key); + if ( u3_none != got ) { + return got; + } + if ( 0 == rod_u->kid_p ) { + return u3_none; + } + rod_u = u3to(u3a_road, rod_u->kid_p); + }; + } +} + +/* u3z_find_up(): find in persistent memo cache, + starting from the current road. Arguments retained +*/ +u3_weak +u3z_find_up(u3_noun key) +{ + u3a_road* rod_u = u3R; + while ( 1 ) { + u3_weak got = u3h_get(_har(rod_u, u3z_memo_keep), key); + if ( u3_none != got ) { + return got; + } + if ( rod_u == &(u3H->rod_u) ) { + return u3_none; + } + rod_u = u3to(u3a_road, rod_u->par_p); + } +} + +u3_weak +u3z_find_m(u3z_cid cid, c3_m fun, u3_noun one) +{ + u3_noun key = u3nc(fun, u3k(one)); + u3_weak val; + val = u3z_find(cid, key); + u3z(key); + + return val; +} + +/* u3z_save(): save in memo cache. TRANSFER key; RETAIN val +*/ +u3_noun +u3z_save(u3z_cid cid, u3_noun key, u3_noun val) +{ + u3h_put(_har(u3R, cid), key, u3k(val)); + u3z(key); + return val; +} + +/* u3z_save_m(): save in memo cache. Arguments retained. +*/ +u3_noun +u3z_save_m(u3z_cid cid, c3_m fun, u3_noun one, u3_noun val) +{ + u3_noun key = u3nc(fun, u3k(one)); + + u3h_put(_har(u3R, cid), key, u3k(val)); + u3z(key); + return val; +} + +/* u3z_uniq(): uniquify with memo cache. XX not used. +*/ +u3_noun +u3z_uniq(u3z_cid cid, u3_noun som) +{ + u3_noun key = u3nc(c3__uniq, u3k(som)); + u3_noun val = u3h_get(_har(u3R, cid), key); + + if ( u3_none != val ) { + u3z(key); u3z(som); return val; + } + else { + u3h_put(_har(u3R, cid), key, u3k(som)); + return som; + } +} + +/* u3z_reap(): promote memoization cache state. +*/ +void +u3z_reap(u3z_cid cid, u3p(u3h_root) har_p) +{ + u3_assert(u3z_memo_toss != cid); + + u3h_uni(_har(u3R, cid), har_p); + u3h_free(har_p); +} diff --git a/vere/pkg/noun/zave.h b/vere/pkg/noun/zave.h new file mode 100644 index 0000000..f7e2be9 --- /dev/null +++ b/vere/pkg/noun/zave.h @@ -0,0 +1,69 @@ +/// @file + +#ifndef U3_ZAVE_H +#define U3_ZAVE_H + +#include "c3/c3.h" +#include "types.h" + + /** Memoization. + *** + *** The memo cache is keyed by an arbitrary symbolic function + *** and a noun argument to that (logical) function. Functions + *** are predefined by C-level callers, but 0 means nock. + *** + *** Memo functions RETAIN keys and transfer values. + **/ + /* u3z_cid: cache id + */ + typedef enum { + u3z_memo_toss = 0, + u3z_memo_keep = 1, + // u3z_memo_ford = 2, + // u3z_memo_ames = 3, + // ... + } u3z_cid; + + /* u3z_key*(): construct a memo cache-key. Arguments retained. + */ + u3_noun u3z_key(c3_m, u3_noun); + u3_noun u3z_key_2(c3_m, u3_noun, u3_noun); + u3_noun u3z_key_3(c3_m, u3_noun, u3_noun, u3_noun); + u3_noun u3z_key_4(c3_m, u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3z_key_5(c3_m, u3_noun, u3_noun, u3_noun, u3_noun, u3_noun); + + /* u3z_find*(): find in memo cache. Arguments retained + */ + u3_weak u3z_find(u3z_cid cid, u3_noun key); + u3_weak u3z_find_m(u3z_cid cid, c3_m fun_m, u3_noun one); + u3_weak u3z_find_up(u3_noun key); + + /* u3z_save(): save in memo cache. TRANSFER key; RETAIN val; + */ + u3_noun u3z_save(u3z_cid cid, u3_noun key, u3_noun val); + + /* u3z_save_m(): save in memo cache. Arguments retained + */ + u3_noun u3z_save_m(u3z_cid cid, c3_m fun_m, u3_noun one, u3_noun val); + + /* u3z_uniq(): uniquify with memo cache. + */ + u3_noun + u3z_uniq(u3z_cid cid, u3_noun som); + + /* u3z_reap(): promote memoization cache state. + */ + void + u3z_reap(u3z_cid cid, u3p(u3h_root) har_p); + + /* u3z_free(): free memoization cache. + */ + void + u3z_free(u3z_cid cid); + + /* u3z_ream(): refresh after restoring from checkpoint. + */ + void + u3z_ream(u3z_cid cid); + +#endif /* ifndef U3_ZAVE_H */ |