From ac7d0731f66499e40e657491fa354bcbb31775d0 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 27 Aug 2020 12:46:55 -0700 Subject: [PATCH] u3: adds u3s_cue_smol/full/bytes/atom --- pkg/urbit/include/noun/serial.h | 20 ++ pkg/urbit/noun/serial.c | 368 +++++++++++++++++++++++++++++++- 2 files changed, 387 insertions(+), 1 deletion(-) diff --git a/pkg/urbit/include/noun/serial.h b/pkg/urbit/include/noun/serial.h index 2e07378a4e..53883e95a6 100644 --- a/pkg/urbit/include/noun/serial.h +++ b/pkg/urbit/include/noun/serial.h @@ -39,3 +39,23 @@ */ u3_noun u3s_cue_xeno(c3_d len_d, const c3_y* byt_y); + + /* u3s_cue_smol(): cue onto the loom, bitwidth fits in a direct atom. + */ + u3_noun + u3s_cue_smol(c3_w len_w, const c3_y* byt_y); + + /* u3s_cue_full(): cue onto the loom. + */ + u3_noun + u3s_cue_full(c3_d len_d, const c3_y* byt_y); + + /* u3s_cue_bytes(): cue bytes. + */ + 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); diff --git a/pkg/urbit/noun/serial.c b/pkg/urbit/noun/serial.c index 589fd0bfc5..be51e314e9 100644 --- a/pkg/urbit/noun/serial.c +++ b/pkg/urbit/noun/serial.c @@ -826,7 +826,7 @@ _cs_cue_xeno_next(_cue_stack_t* tac_u, c3_y* byt_y; // XX check that byt_d fits in a c3_w; - + // byt_y = c3_calloc(byt_d); ur_bsr_bytes_any(red_u, len_d, byt_y); @@ -932,3 +932,369 @@ u3s_cue_xeno(c3_d len_d, const c3_y* byt_y) ur_dict_free((ur_dict_t*)&dic_u); return pro; } + +/* _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_smol_next(): read next value from bitstream, direct-atom cursors. +*/ +static inline u3_noun +_cs_cue_smol_next(c3_ys mov, + c3_ys off, + 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: c3_assert(0); + + case ur_jam_cell: { + // wind the stack + // + u3R->cap_p += mov; + + // ensure we haven't overflowed (ie, run into the heap) + // (off==0 means we're on a north road) + // + 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); + } + } + + // save a head-frame and read the head from the stream + // + { + _cue_frame_t* fam_u = u3to(_cue_frame_t, u3R->cap_p + off); + 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)); + + // XX review, s/b deterministic error + // + c3_assert( 32 > len_d ); + + { + c3_w bak_w = ur_bsr32_any(red_u, len_d); + u3_weak bak = u3h_get(har_p, (u3_noun)bak_w); + 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 { + c3_w byt_w = (len_d >> 3) + !!ur_mask_3(len_d); + c3_w* wor_w = u3a_slaq(3, byt_w); + // XX assumes little-endian + // XX need a ur_bsr_words_any() + // + c3_y* byt_y = (c3_y*)wor_w; + + ur_bsr_bytes_any(red_u, len_d, byt_y); + vat = u3a_malt(wor_w); + } + + u3h_put(har_p, (u3_noun)(c3_w)bit_d, u3k(vat)); + + return vat; + } + } + } +} + +/* u3s_cue_smol(): cue onto the loom, bitwidth fits in a direct atom. +*/ +u3_noun +u3s_cue_smol(c3_w len_w, const c3_y* byt_y) +{ + ur_bsr_t red_u = {0}; + u3_noun ref; + + c3_assert( 0x10000000 >= len_w ); + + // initialize a hash table for dereferencing backrefs + // + u3p(u3h_root) har_p = u3h_new(); + const u3_post top_p = u3R->cap_p; + + // initialize signed stack offsets (relative to north/south road) + // + c3_ys mov, off; + { + c3_o nor_o = u3a_is_north(u3R); + c3_y wis_y = c3_wiseof(_cue_frame_t); + mov = ( c3y == nor_o ? -wis_y : wis_y ); + off = ( c3y == nor_o ? 0 : -wis_y ); + } + + // init bitstream-reader + // + red_u.left = len_w; + red_u.bytes = byt_y; + + // advance into stream + // + ref = _cs_cue_smol_next(mov, off, har_p, &red_u); + + // process result + // + while ( top_p != u3R->cap_p ) { + // peek at the top of the stack + // + _cue_frame_t* fam_u = u3to(_cue_frame_t, u3R->cap_p + off); + + // 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_smol_next(mov, off, har_p, &red_u); + } + // f is a tail-frame; pop the stack and continue + // + else { + ref = u3nc(fam_u->ref, ref); + u3h_put(har_p, (u3_noun)(c3_w)fam_u->bit_d, u3k(ref)); + u3R->cap_p -= mov; + } + } + + u3h_free(har_p); + + return ref; +} + +/* _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 = u3i_chubs(1, &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 = u3i_chubs(1, &key_d); + u3h_put(har_p, key, u3k(val)); + u3z(key); + return val; +} + +/* _cs_cue_full_next(): read next value from bitstream. +*/ +static inline u3_noun +_cs_cue_full_next(c3_ys mov, + c3_ys off, + 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: c3_assert(0); + + case ur_jam_cell: { + // wind the stack + // + u3R->cap_p += mov; + + // ensure we haven't overflowed (ie, run into the heap) + // (off==0 means we're on a north road) + // + 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); + } + } + + // save a head-frame and read the head from the stream + // + { + _cue_frame_t* fam_u = u3to(_cue_frame_t, u3R->cap_p + off); + 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); + } + // XX need a ur_bsr_words_any() + // + else { + // XX check that byt_d fits in a c3_w; + // + c3_d byt_d = (len_d >> 3) + !!ur_mask_3(len_d); + c3_w* wor_w = u3a_slaq(3, byt_d); + // XX assumes little-endian + // + c3_y* byt_y = (c3_y*)wor_w; + + ur_bsr_bytes_any(red_u, len_d, byt_y); + + vat = u3a_malt(wor_w); + } + + return _cs_cue_put(har_p, bit_d, vat); + } + } + } +} + +/* u3s_cue_full(): cue onto the loom. +*/ +u3_noun +u3s_cue_full(c3_d len_d, const c3_y* byt_y) +{ + ur_bsr_t red_u = {0}; + u3_noun ref; + + // initialize a hash table for dereferencing backrefs + // + u3p(u3h_root) har_p = u3h_new(); + const u3_post top_p = u3R->cap_p; + + // initialize signed stack offsets (relative to north/south road) + // + c3_ys mov, off; + { + c3_o nor_o = u3a_is_north(u3R); + c3_y wis_y = c3_wiseof(_cue_frame_t); + mov = ( c3y == nor_o ? -wis_y : wis_y ); + off = ( c3y == nor_o ? 0 : -wis_y ); + } + + // init bitstream-reader + // + red_u.left = len_d; + red_u.bytes = byt_y; + + // advance into stream + // + ref = _cs_cue_full_next(mov, off, har_p, &red_u); + + // process result + // + while ( top_p != u3R->cap_p ) { + // peek at the top of the stack + // + _cue_frame_t* fam_u = u3to(_cue_frame_t, u3R->cap_p + off); + + // 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_full_next(mov, off, har_p, &red_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); + u3R->cap_p -= mov; + } + } + + u3h_free(har_p); + + return ref; +} + +/* u3s_cue_bytes(): cue bytes. +*/ +u3_noun +u3s_cue_bytes(c3_d len_d, const c3_y* byt_y) +{ + // check if we can bitwise-index [len_d] bytes in a direct atom + // + return ( 0x10000000ULL >= len_d ) + ? u3s_cue_smol(len_d, byt_y) + : u3s_cue_full(len_d, byt_y); +} + +/* 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); +}