u3: adds u3s_cue_smol/full/bytes/atom

This commit is contained in:
Joe Bryan 2020-08-27 12:46:55 -07:00
parent dd8a74cea2
commit ac7d0731f6
2 changed files with 387 additions and 1 deletions

View File

@ -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);

View File

@ -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);
}