/* f/meme.c ** ** This file is in the public domain. */ #define C3_GLOBAL #include "f/meme.h" /* _boot_north(): install a north road. */ static u2_road* _boot_north(c3_w* mem_w, c3_w len_w) { c3_w* rut_w = mem_w; c3_w* hat_w = rut_w; c3_w* mat_w = ((mem_w + len_w) - c3_wiseof(u2_road)); c3_w* cap_w = mat_w; u2_road* rod_u = (void*) mat_w; memset(rod_u, 0, sizeof(u2_road)); rod_u->rut_w = rut_w; rod_u->hat_w = hat_w; rod_u->mat_w = mat_w; rod_u->cap_w = cap_w; return rod_u; } /* _boot_south(): install a south road. */ static u2_road* _boot_south(c3_w* mem_w, c3_w len_w) { c3_w* rut_w = mem_w; c3_w* hat_w = rut_w; c3_w* mat_w = ((mem_w + len_w) - c3_wiseof(u2_road)); c3_w* cap_w = mat_w; u2_road* rod_u = (void*) mat_w; memset(rod_u, 0, sizeof(u2_road)); rod_u->rut_w = rut_w; rod_u->hat_w = hat_w; rod_u->mat_w = mat_w; rod_u->cap_w = cap_w; return rod_u; } /* u2_cm_boot(): make u2R and u2H from nothing. */ void u2_cm_boot(c3_p adr_p, c3_w len_w) { void* map_v; map_v = mmap((void *)(c3_p)adr_p, (len_w << 2), PROT_READ | PROT_WRITE, (MAP_ANON | MAP_FIXED | MAP_PRIVATE), -1, 0); if ( -1 == (c3_ps)map_v ) { map_v = mmap((void *)0, (len_w << 2), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if ( -1 == (c3_ps)map_v ) { fprintf(stderr, "map failed twice\n"); } else { fprintf(stderr, "map failed - try U2_OS_LoomBase %p\n", map_v); } exit(1); } printf("loom: mapped %dMB\n", (len_w >> 18)); u2L = map_v; u2H = u2R = _boot_north(map_v, len_w); } /* _me_road_all_hat(): in u2R, allocate directly on the hat_w. */ static c3_w* _me_road_all_hat(c3_w len_w) { if ( len_w > u2_co_open ) { u2_cm_bail(c3__meme); return 0; } if ( u2_yes == u2_co_is_north ) { c3_w* all_w; all_w = u2R->hat_w; u2R->hat_w += len_w; return all_w; } else { u2R->hat_w -= len_w; return u2R->hat_w; } } #if 0 // not yet used /* _me_road_all_cap(): in u2R, allocate directly on the cap. */ static c3_w* _me_road_all_cap(c3_w len_w) { if ( len_w > u2_co_open ) { u2_cm_bail(c3__meme); return 0; } if ( u2_yes == u2_co_is_north ) { u2R->cap_w -= len_w; return u2R->cap_w; } else { c3_w* all_w; all_w = u2R->cap_w; u2R->cap_w += len_w; return all_w; } } #endif #if 1 static void _road_sane(void) { c3_w i_w; for ( i_w = 0; i_w < u2_cc_fbox_no; i_w++ ) { u2_cs_fbox* fre_u = u2R->all.fre_u[i_w]; while ( fre_u ) { if ( fre_u == u2R->all.fre_u[i_w] ) { c3_assert(fre_u->pre_u == 0); } else { c3_assert(fre_u->pre_u != 0); c3_assert(fre_u->pre_u->nex_u == fre_u); if ( fre_u->nex_u != 0 ) { c3_assert(fre_u->nex_u->pre_u == fre_u); } } fre_u = fre_u->nex_u; } } } #endif /* u2_cm_bail(): bail out. Does not return. ** ** Bail motes: ** ** %evil :: erroneous cryptography ** %exit :: semantic failure ** %oops :: assertion failure ** %intr :: interrupt ** %fail :: computability failure ** %need :: namespace block ** %meme :: out of memory */ c3_i u2_cm_bail(c3_m how_m) { c3_c str_c[5]; str_c[0] = ((how_m >> 0) & 0xff); str_c[1] = ((how_m >> 8) & 0xff); str_c[2] = ((how_m >> 16) & 0xff); str_c[3] = ((how_m >> 24) & 0xff); str_c[4] = 0; printf("bail: %s\n", str_c); assert(0); if ( c3__meme == how_m ) { _road_dump(); } _longjmp(u2R->esc.buf, how_m); return how_m; } /* u2_cm_error(): bail out with %exit, ct_pushing error. */ c3_i u2_cm_error(c3_c* str_c) { printf("error: %s\n", str_c); // rong return u2_cm_bail(c3__exit); } /* u2_cm_leap(): in u2R, create a new road within the existing one. */ void u2_cm_leap() { u2_road* rod_u; if ( u2_yes == u2_co_is_north ) { rod_u = _boot_south(u2R->hat_w, (u2R->cap_w - u2R->hat_w)); } else { rod_u = _boot_north(u2R->cap_w, (u2R->hat_w - u2R->cap_w)); } c3_assert(0 == u2R->kid_u); rod_u->par_u = u2R; u2R->kid_u = rod_u; u2R = rod_u; } /* u2_cm_fall(): in u2R, return an inner road to its parent. */ void u2_cm_fall() { c3_assert(0 != u2R->par_u); u2R->par_u->cap_w = u2R->hat_w; u2R = u2R->par_u; } /* u2_cm_golf(): record cap_w length for u2_flog(). */ c3_w u2_cm_golf(void) { if ( u2_yes == u2_co_is_north ) { return u2R->mat_w - u2R->cap_w; } else { return u2R->cap_w - u2R->mat_w; } } /* u2_cm_flog(): reset cap_w. */ void u2_cm_flog(c3_w gof_w) { if ( u2_yes == u2_co_is_north ) { u2R->cap_w = u2R->mat_w - gof_w; } else { u2R->cap_w = u2R->mat_w + gof_w; } } /* u2_cm_water(): produce watermarks. */ void u2_cm_water(c3_w* low_w, c3_w* hig_w) { c3_assert(u2R == u2H); *low_w = (u2H->hat_w - u2H->rut_w); *hig_w = (u2H->mat_w - u2H->cap_w) + c3_wiseof(u2_road); } /* _box_slot(): select the right free list to search for a block. */ c3_w _box_slot(c3_w siz_w) { if ( siz_w < 8 ) { return 0; } else { c3_w i_w = 1; while ( 1 ) { if ( i_w == u2_cc_fbox_no ) { return (i_w - 1); } if ( siz_w < 16 ) { return i_w; } siz_w = (siz_w + 1) >> 1; i_w += 1; } } } /* _box_make(): construct a box. */ u2_cs_box* _box_make(void* box_v, c3_w siz_w, c3_w use_w) { u2_cs_box* box_u = box_v; c3_w* box_w = box_v; box_w[0] = siz_w; box_w[siz_w - 1] = siz_w; box_u->use_w = use_w; # ifdef U2_MEMORY_DEBUG box_u->cod_w = COD_w; # endif return box_u; } /* _box_attach(): attach a box to the free list. */ void _box_attach(u2_cs_box* box_u) { c3_assert(box_u->siz_w >= (1 + c3_wiseof(u2_cs_fbox))); { c3_w sel_w = _box_slot(box_u->siz_w); u2_cs_fbox* fre_u = (void *)box_u; u2_cs_fbox** pfr_u = &u2R->all.fre_u[sel_w]; u2_cs_fbox* nex_u = *pfr_u; fre_u->pre_u = 0; fre_u->nex_u = nex_u; if ( fre_u->nex_u ) { fre_u->nex_u->pre_u = fre_u; } (*pfr_u) = fre_u; } } /* _box_detach(): detach a box from the free list. */ void _box_detach(u2_cs_box* box_u) { u2_cs_fbox* fre_u = (void*) box_u; u2_cs_fbox* pre_u = fre_u->pre_u; u2_cs_fbox* nex_u = fre_u->nex_u; if ( nex_u ) { c3_assert(nex_u->pre_u == fre_u); nex_u->pre_u = pre_u; } if ( pre_u ) { c3_assert(pre_u->nex_u == fre_u); pre_u->nex_u = nex_u; } else { c3_w sel_w = _box_slot(box_u->siz_w); c3_assert(fre_u == u2R->all.fre_u[sel_w]); u2R->all.fre_u[sel_w] = nex_u; } } /* u2_ca_walloc(): allocate storage words on hat_w. */ void* u2_ca_walloc(c3_w len_w) { c3_w siz_w = c3_max(u2_cc_minimum, u2_co_boxed(len_w)); c3_w sel_w = _box_slot(siz_w); // XX: this logic is totally bizarre, but preserve it. // if ( (sel_w != 0) && (sel_w != u2_cc_fbox_no - 1) ) { sel_w += 1; } while ( 1 ) { u2_cs_fbox** pfr_u = &u2R->all.fre_u[sel_w]; while ( 1 ) { if ( 0 == *pfr_u ) { if ( sel_w < (u2_cc_fbox_no - 1) ) { sel_w += 1; break; } else { /* Nothing in top free list. Chip away at the hat_w. */ return u2_co_boxto(_box_make(_me_road_all_hat(siz_w), siz_w, 1)); } } else { if ( siz_w > (*pfr_u)->box_u.siz_w ) { /* This free block is too small. Continue searching. */ pfr_u = &((*pfr_u)->nex_u); continue; } else { u2_cs_box* box_u = &((*pfr_u)->box_u); /* We have found a free block of adequate size. Remove it ** from the free list. */ { { c3_assert((0 == (*pfr_u)->pre_u) || (*pfr_u)->pre_u->nex_u == (*pfr_u)); c3_assert((0 == (*pfr_u)->nex_u) || (*pfr_u)->nex_u->pre_u == (*pfr_u)); } if ( 0 != (*pfr_u)->nex_u ) { (*pfr_u)->nex_u->pre_u = (*pfr_u)->pre_u; } *pfr_u = (*pfr_u)->nex_u; } /* If we can chop off another block, do it. */ if ( (siz_w + c3_wiseof(u2_cs_fbox) + 1) <= box_u->siz_w ) { /* Split the block. */ c3_w* box_w = ((c3_w *)(void *)box_u); c3_w* end_w = box_w + siz_w; c3_w lef_w = (box_u->siz_w - siz_w); _box_attach(_box_make(end_w, lef_w, 0)); return u2_co_boxto(_box_make(box_w, siz_w, 1)); } else { c3_assert(0 == box_u->use_w); box_u->use_w = 1; #ifdef U2_MEMORY_DEBUG box_u->cod_w = COD_w; #endif return u2_co_boxto(box_u); } } } } } } /* u2_ca_malloc(): allocate storage measured in bytes. */ void* u2_ca_malloc(c3_w len_w) { return u2_ca_walloc((len_w + 3) >> 2); } /* u2_ca_wealloc(): realloc in words. */ void* u2_ca_wealloc(void* lag_v, c3_w len_w) { if ( !lag_v ) { return u2_ca_malloc(len_w); } else { u2_cs_box* box_u = u2_co_botox(lag_v); c3_w* old_w = lag_v; c3_w tiz_w = c3_min(box_u->siz_w, len_w); { c3_w* new_w = u2_ca_walloc(len_w); c3_w i_w; for ( i_w = 0; i_w < tiz_w; i_w++ ) { new_w[i_w] = old_w[i_w]; } u2_ca_free(lag_v); return new_w; } } } /* u2_ca_realloc(): realloc in bytes. */ void* u2_ca_realloc(void* lag_v, c3_w len_w) { return u2_ca_wealloc(lag_v, (len_w + 3) >> 2); } /* u2_ca_free(): free storage. */ void u2_ca_free(void* tox_v) { u2_cs_box* box_u = u2_co_botox(tox_v); c3_w* box_w = (c3_w *)(void *)box_u; c3_assert(box_u->use_w != 0); box_u->use_w -= 1; if ( 0 != box_u->use_w ) return; c3_assert(u2_yes == u2_co_is_north); #if 0 /* Clear the contents of the block, for debugging. */ { c3_w i_w; for ( i_w = c3_wiseof(u2_cs_box); (i_w + 1) < box_u->siz_w; i_w++ ) { box_w[i_w] = 0xdeadbeef; } } #endif if ( u2_yes == u2_co_is_north ) { /* Try to coalesce with the block below. */ if ( box_w != u2R->rut_w ) { c3_w laz_w = *(box_w - 1); u2_cs_box* pox_u = (u2_cs_box*)(void *)(box_w - laz_w); if ( 0 == pox_u->use_w ) { _box_detach(pox_u); _box_make(pox_u, (laz_w + box_u->siz_w), 0); box_u = pox_u; box_w = (c3_w*)(void *)pox_u; } } /* Try to coalesce with the block above, or the wilderness. */ if ( (box_w + box_u->siz_w) == u2R->hat_w ) { u2R->hat_w = box_w; } else { u2_cs_box* nox_u = (u2_cs_box*)(void *)(box_w + box_u->siz_w); if ( 0 == nox_u->use_w ) { _box_detach(nox_u); _box_make(box_u, (box_u->siz_w + nox_u->siz_w), 0); } _box_attach(box_u); } } else { /* Try to coalesce with the block above. */ if ( (box_w + box_u->siz_w) != u2R->rut_w ) { u2_cs_box* nox_u = (u2_cs_box*)(void *)(box_w + box_u->siz_w); if ( 0 == nox_u->use_w ) { _box_detach(nox_u); _box_make(box_u, (box_u->siz_w + nox_u->siz_w), 0); box_u = nox_u; box_w = (c3_w*)(void *)nox_u; } } /* Try to coalesce with the block below, or with the wilderness. */ if ( box_w == u2R->hat_w ) { u2R->hat_w = (box_w + box_u->siz_w); } else { c3_w laz_w = *(box_w - 1); u2_cs_box* pox_u = (u2_cs_box*)(void *)(box_w - laz_w); if ( 0 == pox_u->use_w ) { _box_detach(pox_u); _box_make(pox_u, (laz_w + box_u->siz_w), 0); } _box_attach(box_u); } } } /* _me_north_is_senior(): yes iff only in the senior region. */ static u2_bean _me_north_is_senior(u2_noun dog) { c3_w* dog_w = u2_co_to_ptr(dog); return u2_say((dog_w < u2R->rut_w) || (dog_w >= u2R->mat_w)); } /* _me_north_is_junior(): yes iff only in the junior section. */ static u2_bean _me_north_is_junior(u2_noun dog) { c3_w* dog_w = u2_co_to_ptr(dog); return u2_say((dog_w >= u2R->cap_w) && (dog_w < u2R->mat_w)); } /* _me_north_is_normal(): yes iff only in the normal heap. */ static u2_bean _me_north_is_normal(u2_noun dog) { return u2_and(u2_not(_me_north_is_senior(dog)), u2_not(_me_north_is_junior(dog))); } /* _me_south_is_senior(): yes iff only in the senior region. */ static u2_bean _me_south_is_senior(u2_noun dog) { c3_w* dog_w = u2_co_to_ptr(dog); return u2_say((dog_w >= u2R->mat_w) || (dog_w < u2R->cap_w)); } /* _me_south_is_junior(): yes iff only in the junior section. */ static u2_bean _me_south_is_junior(u2_noun dog) { c3_w* dog_w = u2_co_to_ptr(dog); return u2_say((dog_w >= u2R->cap_w) && (dog_w < u2R->mat_w)); } /* _me_south_is_normal(): yes iff only in the normal heap. */ static u2_bean _me_south_is_normal(u2_noun dog) { return u2_and(u2_not(_me_south_is_senior(dog)), u2_not(_me_south_is_junior(dog))); } /* u2_co_is_junior(): yes iff (som) is junior. */ u2_bean u2_co_is_junior(u2_noun som) { if ( u2_so(u2_co_is_cat(som)) ) { return u2_no; } else { if ( u2_so(u2_co_is_north) ) { return _me_north_is_junior(som); } else { return _me_south_is_junior(som); } } } /* _me_wash_north(): clean up mug slots after copy. */ static void _me_wash_north(u2_noun dog); static void _me_wash_north_in(u2_noun som) { if ( u2_so(u2_co_is_cat(som)) ) return; if ( u2_ne(_me_north_is_junior(som)) ) return; _me_wash_north(som); } static void _me_wash_north(u2_noun dog) { c3_assert(u2_co_is_dog(dog)); c3_assert(u2_yes == _me_north_is_junior(dog)); { u2_cs_noun* dog_u = u2_co_to_ptr(dog); if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; } if ( u2_so(u2_co_is_pom(dog)) ) { u2_cs_cell* god_u = (u2_cs_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(u2_noun dog); static void _me_wash_south_in(u2_noun som) { if ( u2_so(u2_co_is_cat(som)) ) return; if ( u2_ne(_me_south_is_junior(som)) ) return; _me_wash_south(som); } static void _me_wash_south(u2_noun dog) { c3_assert(u2_co_is_dog(dog)); c3_assert(u2_yes == _me_south_is_junior(dog)); { u2_cs_noun* dog_u = u2_co_to_ptr(dog); if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; } if ( u2_so(u2_co_is_pom(dog)) ) { u2_cs_cell* god_u = (u2_cs_cell *)(void *)dog_u; _me_wash_south_in(god_u->hed); _me_wash_south_in(god_u->tel); } } } /* _me_gain_use(): increment use count. */ static void _me_gain_use(u2_noun dog) { c3_w* dog_w = u2_co_to_ptr(dog); u2_cs_box* box_u = u2_co_botox(dog_w); if ( 0xffffffff == box_u->use_w ) { u2_cm_bail(c3__fail); } else { box_u->use_w += 1; } } /* _me_copy_north_in(): copy subjuniors on a north road. */ static u2_noun _me_copy_north(u2_noun); static u2_noun _me_copy_north_in(u2_noun som) { c3_assert(u2_none != som); if ( u2_so(u2_co_is_cat(som)) ) { return som; } else { u2_noun dog = som; if ( u2_so(_me_north_is_senior(dog)) ) { return dog; } else if ( u2_so(_me_north_is_junior(dog)) ) { return _me_copy_north(dog); } else { _me_gain_use(dog); return dog; } } } /* _me_copy_north(): copy juniors on a north road. */ static u2_noun _me_copy_north(u2_noun dog) { c3_assert(u2_yes == _me_north_is_junior(dog)); if ( u2_ne(_me_north_is_junior(dog)) ) { if ( u2_ne(_me_north_is_senior(dog)) ) { _me_gain_use(dog); } return dog; } else { u2_cs_noun* dog_u = u2_co_to_ptr(dog); /* Borrow mug slot to record new destination. */ if ( dog_u->mug_w >> 31 ) { u2_noun nov = (u2_noun) dog_u->mug_w; c3_assert(u2_so(_me_north_is_normal(nov))); _me_gain_use(nov); return nov; } else { if ( u2_yes == u2_co_is_pom(dog) ) { u2_cs_cell* old_u = u2_co_to_ptr(dog); c3_w* new_w = u2_ca_walloc(c3_wiseof(u2_cs_cell)); u2_noun new = u2_co_de_twin(dog, new_w); u2_cs_cell* new_u = (u2_cs_cell*)(void *)new_w; new_u->mug_w = old_u->mug_w; new_u->hed = _me_copy_north_in(old_u->hed); new_u->tel = _me_copy_north_in(old_u->tel); /* Borrow mug slot to record new destination. */ old_u->mug_w = new; return new; } else { u2_cs_atom* old_u = u2_co_to_ptr(dog); c3_w* new_w = u2_ca_walloc(old_u->len_w + c3_wiseof(u2_cs_atom)); u2_noun new = u2_co_de_twin(dog, new_w); u2_cs_atom* new_u = (u2_cs_atom*)(void *)new_w; 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. */ old_u->mug_w = new; return new; } } } } /* _me_copy_south_in(): copy subjuniors on a south road. */ static u2_noun _me_copy_south(u2_noun); static u2_noun _me_copy_south_in(u2_noun som) { c3_assert(u2_none != som); if ( u2_so(u2_co_is_cat(som)) ) { return som; } else { u2_noun dog = som; if ( u2_so(_me_south_is_senior(dog)) ) { return dog; } else if ( u2_so(_me_south_is_junior(dog)) ) { return _me_copy_south(dog); } else { _me_gain_use(dog); return dog; } } } /* _me_copy_south(): copy juniors on a south road. */ static u2_noun _me_copy_south(u2_noun dog) { c3_assert(u2_yes == _me_south_is_junior(dog)); if ( u2_ne(_me_south_is_junior(dog)) ) { if ( u2_ne(_me_south_is_senior(dog)) ) { _me_gain_use(dog); } return dog; } else { u2_cs_noun* dog_u = u2_co_to_ptr(dog); /* Borrow mug slot to record new destination. */ if ( dog_u->mug_w >> 31 ) { u2_noun nov = (u2_noun) dog_u->mug_w; c3_assert(u2_so(_me_south_is_normal(nov))); _me_gain_use(nov); return nov; } else { if ( u2_yes == u2_co_is_pom(dog) ) { u2_cs_cell* old_u = u2_co_to_ptr(dog); c3_w* new_w = u2_ca_walloc(c3_wiseof(u2_cs_cell)); u2_noun new = u2_co_de_twin(dog, new_w); u2_cs_cell* new_u = (u2_cs_cell*)(void *)new_w; new_u->mug_w = old_u->mug_w; new_u->hed = _me_copy_south_in(old_u->hed); new_u->tel = _me_copy_south_in(old_u->tel); /* Borrow mug slot to record new destination. */ old_u->mug_w = new; return new; } else { u2_cs_atom* old_u = u2_co_to_ptr(dog); c3_w* new_w = u2_ca_walloc(old_u->len_w + c3_wiseof(u2_cs_atom)); u2_noun new = u2_co_de_twin(dog, new_w); u2_cs_atom* new_u = (u2_cs_atom*)(void *)new_w; 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. */ old_u->mug_w = new; return new; } } } } /* _me_gain_north(): gain on a north road. */ static u2_noun _me_gain_north(u2_noun dog) { if ( u2_yes == _me_north_is_senior(dog) ) { /* senior pointers are not refcounted */ return dog; } else if ( u2_yes == _me_north_is_junior(dog) ) { /* junior pointers are copied */ u2_noun mos = _me_copy_north(dog); _me_wash_north(dog); return mos; } else { /* normal pointers are refcounted */ _me_gain_use(dog); return dog; } } /* _me_gain_south(): gain on a south road. */ static u2_noun _me_gain_south(u2_noun dog) { if ( u2_yes == _me_south_is_senior(dog) ) { /* senior pointers are not refcounted */ return dog; } else if ( u2_yes == _me_south_is_junior(dog) ) { /* junior pointers are copied */ u2_noun mos = _me_copy_south(dog); _me_wash_south(dog); return mos; } else { /* normal pointers are refcounted */ _me_gain_use(dog); return dog; } } /* _me_lose_north(): lose on a north road. */ static void _me_lose_north(u2_noun dog) { top: if ( u2_yes == _me_north_is_normal(dog) ) { c3_w* dog_w = u2_co_to_ptr(dog); u2_cs_box* box_u = u2_co_botox(dog_w); if ( box_u->use_w > 1 ) { box_u->use_w -= 1; } else { if ( 0 == box_u->use_w ) { u2_cm_bail(c3__foul); } else { if ( u2_so(u2_co_is_pom(dog)) ) { u2_cs_cell* dog_u = (void *)dog_w; u2_noun h_dog = dog_u->hed; u2_noun t_dog = dog_u->tel; if ( u2_ne(u2_co_is_cat(h_dog)) ) { _me_lose_north(h_dog); } u2_ca_free(dog_w); if ( u2_ne(u2_co_is_cat(t_dog)) ) { dog = t_dog; goto top; } } else { u2_ca_free(dog_w); } } } } } /* _me_lose_south(): lose on a south road. */ static void _me_lose_south(u2_noun dog) { top: if ( u2_yes == _me_south_is_normal(dog) ) { c3_w* dog_w = u2_co_to_ptr(dog); u2_cs_box* box_u = u2_co_botox(dog_w); if ( box_u->use_w > 1 ) { box_u->use_w -= 1; } else { if ( 0 == box_u->use_w ) { u2_cm_bail(c3__foul); } else { if ( u2_so(u2_co_is_pom(dog)) ) { u2_cs_cell* dog_u = (void *)dog_w; u2_noun h_dog = dog_u->hed; u2_noun t_dog = dog_u->tel; if ( u2_ne(u2_co_is_cat(h_dog)) ) { _me_lose_south(h_dog); } u2_ca_free(dog_w); if ( u2_ne(u2_co_is_cat(t_dog)) ) { dog = t_dog; goto top; } } else { u2_ca_free(dog_w); } } } } } /* u2_ca_gain(): gain a reference count, and/or copy juniors. */ u2_noun u2_ca_gain(u2_noun som) { c3_assert(u2_none != som); if ( u2_so(u2_co_is_cat(som)) ) { return som; } else { return u2_so(u2_co_is_north) ? _me_gain_north(som) : _me_gain_south(som); } } /* u2_ca_lose(): lose a reference count. */ void u2_ca_lose(u2_noun som) { if ( u2_ne(u2_co_is_cat(som)) ) { if ( u2_so(u2_co_is_north) ) { _me_lose_north(som); } else { _me_lose_south(som); } } } /* u2_ca_use(): reference count. */ c3_w u2_ca_use(u2_noun som) { if ( u2_so(u2_co_is_cat(som)) ) { return 1; } else { c3_w* dog_w = u2_co_to_ptr(som); u2_cs_box* box_u = u2_co_botox(dog_w); return box_u->use_w; } } /* u2_ca_slab(): create a length-bounded proto-atom. */ c3_w* u2_ca_slab(c3_w len_w) { c3_w* nov_w = u2_ca_walloc(len_w + c3_wiseof(u2_cs_atom)); u2_cs_atom* pug_u = (void *)nov_w; pug_u->mug_w = 0; pug_u->len_w = len_w; /* Clear teh slab. */ { c3_w i_w; for ( i_w=0; i_w < len_w; i_w++ ) { pug_u->buf_w[i_w] = 0; } } return pug_u->buf_w; } /* u2_ca_slaq(): u2_ca_slaq() with a defined blocksize. */ c3_w* u2_ca_slaq(c3_g met_g, c3_w len_w) { return u2_ca_slab(((len_w << met_g) + 31) >> 5); } /* u2_ca_malt(): measure and finish a proto-atom. */ u2_noun u2_ca_malt(c3_w* sal_w) { c3_w* nov_w = (sal_w - c3_wiseof(u2_cs_atom)); u2_cs_atom* nov_u = (void *)nov_w; c3_w len_w; for ( len_w = nov_u->len_w; len_w; len_w-- ) { if ( 0 != nov_u->buf_w[len_w - 1] ) { break; } } return u2_ca_mint(sal_w, len_w); } /* u2_ca_moot(): finish a pre-measured proto-atom; dangerous. */ u2_noun u2_ca_moot(c3_w* sal_w) { c3_w* nov_w = (sal_w - c3_wiseof(u2_cs_atom)); u2_cs_atom* nov_u = (void*)nov_w; c3_w len_w = nov_u->len_w; c3_w las_w = nov_u->buf_w[len_w - 1]; c3_assert(0 != len_w); c3_assert(0 != las_w); if ( 1 == len_w ) { if ( u2_so(u2_co_is_cat(las_w)) ) { u2_ca_free(nov_w); return las_w; } } return u2_co_to_pug(u2_co_outa(nov_w)); } /* u2_ca_mint(): finish a measured proto-atom. */ u2_noun u2_ca_mint(c3_w* sal_w, c3_w len_w) { c3_w* nov_w = (sal_w - c3_wiseof(u2_cs_atom)); u2_cs_atom* nov_u = (void*)nov_w; /* See if we can free the slab entirely. */ if ( len_w == 0 ) { u2_ca_free(nov_w); return 0; } else if ( len_w == 1 ) { c3_w low_w = nov_u->buf_w[0]; if ( u2_so(u2_co_is_cat(low_w)) ) { u2_ca_free(nov_w); return low_w; } } /* See if we can strip off a block on the end. */ { c3_w old_w = nov_u->len_w; c3_w dif_w = (old_w - len_w); if ( dif_w >= u2_cc_minimum ) { c3_w* box_w = (void *)u2_co_botox(nov_w); c3_w* end_w = (nov_w + c3_wiseof(u2_cs_atom) + len_w + 1); c3_w asz_w = (end_w - box_w); c3_w bsz_w = box_w[0] - asz_w; _box_attach(_box_make(end_w, bsz_w, 0)); box_w[0] = asz_w; box_w[asz_w - 1] = asz_w; } nov_u->len_w = len_w; } return u2_co_to_pug(u2_co_outa(nov_w)); } /* u2_ci_words(): ** ** Copy [a] words from [b] into an atom. */ u2_noun u2_ci_words(c3_w a_w, const c3_w* b_w) { /* Strip trailing zeroes. */ while ( a_w && !b_w[a_w - 1] ) { a_w--; } /* Check for cat. */ if ( !a_w ) { return 0; } else if ( (a_w == 1) && !(b_w[0] >> 31) ) { return b_w[0]; } /* Allocate, fill, return. */ { c3_w* nov_w = u2_ca_walloc(a_w + c3_wiseof(u2_cs_atom)); u2_cs_atom* nov_u = (void*)nov_w; nov_u->mug_w = 0; nov_u->len_w = a_w; /* Fill the words. */ { c3_w i_w; for ( i_w=0; i_w < a_w; i_w++ ) { nov_u->buf_w[i_w] = b_w[i_w]; } } return u2_co_to_pug(u2_co_outa(nov_w)); } } /* u2_ci_chubs(): ** ** Construct `a` double-words from `b`, LSD first, as an atom. */ u2_atom u2_ci_chubs(c3_w a_w, const c3_d* b_d) { c3_w *b_w = c3_malloc(a_w * 8); c3_w i_w; u2_atom p; for ( i_w = 0; i_w < a_w; i_w++ ) { b_w[(2 * i_w)] = b_d[i_w] & 0xffffffffULL; b_w[(2 * i_w) + 1] = b_d[i_w] >> 32ULL; } p = u2_ci_words((a_w * 2), b_w); free(b_w); return p; } /* u2_ci_bytes(): ** ** Copy `a` bytes from `b` to an LSB first atom. */ u2_noun u2_ci_bytes(c3_w a_w, const c3_y* b_y) { /* Strip trailing zeroes. */ while ( a_w && !b_y[a_w - 1] ) { a_w--; } /* Check for cat. */ if ( a_w <= 4 ) { if ( !a_w ) { return 0; } else if ( a_w == 1 ) { return b_y[0]; } else if ( a_w == 2 ) { return (b_y[0] | (b_y[1] << 8)); } else if ( a_w == 3 ) { return (b_y[0] | (b_y[1] << 8) | (b_y[2] << 16)); } else if ( (b_y[3] <= 0x7f) ) { return (b_y[0] | (b_y[1] << 8) | (b_y[2] << 16) | (b_y[3] << 24)); } } /* Allocate, fill, return. */ { c3_w len_w = (a_w + 3) >> 2; c3_w* nov_w = u2_ca_walloc((len_w + c3_wiseof(u2_cs_atom))); u2_cs_atom* nov_u = (void*)nov_w; nov_u->mug_w = 0; nov_u->len_w = len_w; /* Clear the words. */ { c3_w i_w; for ( i_w=0; i_w < len_w; i_w++ ) { nov_u->buf_w[i_w] = 0; } } /* Fill the bytes. */ { c3_w i_w; for ( i_w=0; i_w < a_w; i_w++ ) { nov_u->buf_w[i_w >> 2] |= (b_y[i_w] << ((i_w & 3) * 8)); } } return u2_co_to_pug(u2_co_outa(nov_w)); } } /* u2_ci_mp(): ** ** Copy the GMP integer `a` into an atom, and clear it. */ u2_noun u2_ci_mp(mpz_t a_mp) { /* Efficiency: unnecessary copy. */ { c3_w pyg_w = mpz_size(a_mp) * ((sizeof(mp_limb_t)) / 4); c3_w *buz_w = alloca(pyg_w * 4); c3_w i_w; for ( i_w = 0; i_w < pyg_w; i_w++ ) { buz_w[i_w] = 0; } mpz_export(buz_w, 0, -1, 4, 0, 0, a_mp); mpz_clear(a_mp); return u2_ci_words(pyg_w, buz_w); } } /* u2_ci_vint(): ** ** Create `a + 1`. */ u2_noun u2_ci_vint(u2_noun a) { c3_assert(u2_none != a); if ( u2_so(u2_co_is_cat(a)) ) { c3_w vin_w = (a + 1); if ( a == 0x7fffffff ) { return u2_ci_words(1, &vin_w); } else return vin_w; } else if ( u2_so(u2_co_is_cell(a)) ) { return u2_cm_bail(c3__exit); } else { mpz_t a_mp; u2_cr_mp(a_mp, a); u2_ca_lose(a); mpz_add_ui(a_mp, a_mp, 1); return u2_ci_mp(a_mp); } } /* u2_ci_cell(): ** ** Produce the cell `[a b]`. */ u2_noun u2_ci_cell(u2_noun a, u2_noun b) { c3_assert(u2_none != a); c3_assert(u2_none != b); c3_assert(u2_ne(u2_co_is_junior(a))); c3_assert(u2_ne(u2_co_is_junior(b))); { c3_w* nov_w = u2_ca_walloc(c3_wiseof(u2_cs_cell)); u2_cs_cell* nov_u = (void *)nov_w; nov_u->mug_w = 0; nov_u->hed = a; nov_u->tel = b; return u2_co_to_pom(u2_co_outa(nov_w)); } } /* u2_ci_trel(): ** ** Produce the triple `[a b c]`. */ u2_noun u2_ci_trel(u2_noun a, u2_noun b, u2_noun c) { return u2_ci_cell(a, u2_ci_cell(b, c)); } /* u2_ci_qual(): ** ** Produce the cell `[a b c d]`. */ u2_noun u2_ci_qual(u2_noun a, u2_noun b, u2_noun c, u2_noun d) { return u2_ci_cell(a, u2_ci_trel(b, c, d)); } /* u2_ci_string(): ** ** Produce an LSB-first atom from the C string `a`. */ u2_noun u2_ci_string(const c3_c* a_c) { return u2_ci_bytes(strlen(a_c), (c3_y *)a_c); } /* u2_ci_tape(): from a C string, to a list of bytes. */ u2_atom u2_ci_tape(const c3_c* txt_c) { if ( !*txt_c ) { return u2_nul; } else return u2_ci_cell(*txt_c, u2_ci_tape(txt_c + 1)); } /* u2_ci_decimal(): ** ** Parse `a` as a list of decimal digits. */ u2_atom u2_ci_decimal(u2_noun a); /* u2_ci_heximal(): ** ** Parse `a` as a list of hex digits. */ u2_noun u2_ci_heximal(u2_noun a); /* u2_ci_list(): ** ** Generate a null-terminated list, with `u2_none` as terminator. */ u2_noun u2_ci_list(u2_weak one, ...); /* u2_ci_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; u2_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 = c3_false; 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 == c3_false) && (3 == u2_ax_cap(axe_w)) ) { cut_t = c3_true; cut_w = i_w; } pms_m[i_w].axe_w = u2_ax_mas(axe_w); } return cut_t ? cut_w : i_w; } static u2_noun // transfer _molt_apply(u2_noun som, // retain c3_w len_w, struct _molt_pair* pms_m) // transfer { if ( len_w == 0 ) { return u2_ca_gain(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 ( u2_no == u2_co_is_cell(som) ) { return u2_cm_bail(c3__exit); } else { return u2_ci_cell (_molt_apply(u2_co_h(som), cut_w, pms_m), _molt_apply(u2_co_t(som), (len_w - cut_w), (pms_m + cut_w))); } } } u2_noun u2_ci_molt(u2_noun som, ...) { va_list ap; c3_w len_w; struct _molt_pair* pms_m; u2_noun pro; /* Count. */ len_w = 0; { va_start(ap, som); while ( 1 ) { if ( 0 == va_arg(ap, c3_w) ) { break; } va_arg(ap, u2_weak*); len_w++; } va_end(ap); } 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, u2_noun); } va_end(ap); } /* Apply. */ pro = _molt_apply(som, len_w, pms_m); u2_ca_lose(som); return pro; } /* u2_cx_good(): test for u2_none. */ u2_noun u2_cx_good(u2_weak som) { if ( u2_none == som ) { return u2_cm_bail(c3__exit); } else return som; } /* u2_cx_at (u2at): fragment. */ u2_noun u2_cx_at(u2_noun axe, u2_noun som) { u2_weak pro = u2_cr_at(axe, som); if ( u2_none == pro ) { return u2_cm_bail(c3__exit); } else return pro; } /* u2_cx_cell(): ** ** Divide `a` as a cell `[b c]`. */ void u2_cx_cell(u2_noun a, u2_noun* b, u2_noun* c) { if ( u2_no == u2_cr_cell(a, b, c) ) { u2_cm_bail(c3__exit); } } /* u2_cx_trel(): ** ** Divide `a` as a trel `[b c d]`, or bail. */ void u2_cx_trel(u2_noun a, u2_noun* b, u2_noun* c, u2_noun* d) { if ( u2_no == u2_cr_trel(a, b, c, d) ) { u2_cm_bail(c3__exit); } } /* u2_cx_qual(): ** ** Divide `a` as a quadruple `[b c d e]`. */ void u2_cx_qual(u2_noun a, u2_noun* b, u2_noun* c, u2_noun* d, u2_noun* e) { if ( u2_no == u2_cr_qual(a, b, c, d, e) ) { u2_cm_bail(c3__exit); } } /* _frag_word(): fast fragment/branch prediction for top word. */ static u2_weak _frag_word(c3_w a_w, u2_noun b) { c3_assert(0 != a_w); { c3_w dep_w = u2_ax_dep(a_w); while ( dep_w ) { if ( u2_no == u2_co_is_cell(b) ) { return u2_none; } else { u2_cs_cell* b_u = u2_co_to_ptr(b); b = *(((u2_noun*)&(b_u->hed)) + (1 & (a_w >> (dep_w - 1)))); dep_w--; } } return b; } } /* _frag_deep(): fast fragment/branch for deep words. */ static u2_weak _frag_deep(c3_w a_w, u2_noun b) { c3_w dep_w = 32; while ( dep_w ) { if ( u2_no == u2_co_is_cell(b) ) { return u2_none; } else { u2_cs_cell* b_u = u2_co_to_ptr(b); b = *(((u2_noun*)&(b_u->hed)) + (1 & (a_w >> (dep_w - 1)))); dep_w--; } } return b; } /* u2_cr_at(): ** ** Return fragment (a) of (b), or u2_none if not applicable. */ u2_weak u2_cr_at(u2_atom a, u2_noun b) { c3_assert(u2_none != a); c3_assert(u2_none != b); if ( 0 == a ) { return u2_none; } if ( u2_so(u2_co_is_cat(a)) ) { return _frag_word(a, b); } else { if ( u2_ne(u2_co_is_pug(a)) ) { return u2_none; } else { u2_cs_atom* a_u = u2_co_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; while ( len_w ) { b = _frag_deep(a_u->buf_w[len_w], b); if ( u2_none == b ) { return b; } else { len_w--; } } return b; } } } /* u2_cr_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; u2_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 = c3_false; 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 == c3_false) && (3 == u2_ax_cap(axe_w)) ) { cut_t = c3_true; cut_w = i_w; } prs_m[i_w].axe_w = u2_ax_mas(axe_w); } return cut_t ? cut_w : i_w; } static u2_bean _mean_extract(u2_noun som, c3_w len_w, struct _mean_pair* prs_m) { if ( len_w == 0 ) { return u2_yes; } else if ( (len_w == 1) && (1 == prs_m[0].axe_w) ) { *prs_m->som = som; return u2_yes; } else { if ( u2_no == u2_co_is_cell(som) ) { return u2_no; } else { c3_w cut_w = _mean_cut(len_w, prs_m); return u2_and (_mean_extract(u2_co_h(som), cut_w, prs_m), _mean_extract(u2_co_t(som), (len_w - cut_w), (prs_m + cut_w))); } } } u2_bean u2_cr_mean(u2_noun som, ...) { va_list ap; c3_w len_w; struct _mean_pair* prs_m; c3_assert(u2_none != som); /* Count. */ len_w = 0; { va_start(ap, som); while ( 1 ) { if ( 0 == va_arg(ap, c3_w) ) { break; } va_arg(ap, u2_noun*); len_w++; } va_end(ap); } prs_m = alloca(len_w * sizeof(struct _mean_pair)); /* Install. */ { c3_w i_w; va_start(ap, som); 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, u2_noun*); } va_end(ap); } /* Extract. */ return _mean_extract(som, len_w, prs_m); } static __inline__ c3_w _mug_fnv(c3_w has_w) { return (has_w * ((c3_w)16777619)); } static __inline__ c3_w _mug_out(c3_w has_w) { return (has_w >> 31) ^ (has_w & 0x7fffffff); } static __inline__ c3_w _mug_both(c3_w lef_w, c3_w rit_w) { c3_w bot_w = _mug_fnv(lef_w ^ _mug_fnv(rit_w)); c3_w out_w = _mug_out(bot_w); if ( 0 != out_w ) { return out_w; } else { return _mug_both(lef_w, ++rit_w); } } /* u2_cr_mug_both(): ** ** Join two mugs. */ c3_w u2_cr_mug_both(c3_w lef_w, c3_w rit_w) { return _mug_both(lef_w, rit_w); } static __inline__ c3_w _mug_bytes_in(c3_w off_w, c3_w nby_w, c3_y* byt_y) { c3_w i_w; for ( i_w = 0; i_w < nby_w; i_w++ ) { off_w = _mug_fnv(off_w ^ byt_y[i_w]); } return off_w; } static c3_w _mug_bytes(c3_w off_w, c3_w nby_w, c3_y* byt_y) { c3_w has_w = _mug_bytes_in(off_w, nby_w, byt_y); c3_w out_w = _mug_out(has_w); if ( 0 != out_w ) { return out_w; } else { return _mug_bytes(++off_w, nby_w, byt_y); } } static __inline__ c3_w _mug_words_in_buf(c3_w off_w, c3_w nwd_w, u2_noun veb) { u2_cs_atom* veb_u = u2_co_to_ptr(veb); if ( 0 == nwd_w ) { return off_w; } else { c3_w i_w, x_w; for ( i_w = 0; i_w < (nwd_w - 1); i_w++ ) { x_w = veb_u->buf_w[i_w]; { c3_y a_y = (x_w & 0xff); c3_y b_y = ((x_w >> 8) & 0xff); c3_y c_y = ((x_w >> 16) & 0xff); c3_y d_y = ((x_w >> 24) & 0xff); off_w = _mug_fnv(off_w ^ a_y); off_w = _mug_fnv(off_w ^ b_y); off_w = _mug_fnv(off_w ^ c_y); off_w = _mug_fnv(off_w ^ d_y); } } x_w = veb_u->buf_w[nwd_w - 1]; if ( x_w ) { off_w = _mug_fnv(off_w ^ (x_w & 0xff)); x_w >>= 8; if ( x_w ) { off_w = _mug_fnv(off_w ^ (x_w & 0xff)); x_w >>= 8; if ( x_w ) { off_w = _mug_fnv(off_w ^ (x_w & 0xff)); x_w >>= 8; if ( x_w ) { off_w = _mug_fnv(off_w ^ (x_w & 0xff)); } } } } } return off_w; } static __inline__ c3_w _mug_words_in(c3_w off_w, c3_w nwd_w, const c3_w* wod_w) { if ( 0 == nwd_w ) { return off_w; } else { c3_w i_w, x_w; for ( i_w = 0; i_w < (nwd_w - 1); i_w++ ) { x_w = wod_w[i_w]; { c3_y a_y = (x_w & 0xff); c3_y b_y = ((x_w >> 8) & 0xff); c3_y c_y = ((x_w >> 16) & 0xff); c3_y d_y = ((x_w >> 24) & 0xff); off_w = _mug_fnv(off_w ^ a_y); off_w = _mug_fnv(off_w ^ b_y); off_w = _mug_fnv(off_w ^ c_y); off_w = _mug_fnv(off_w ^ d_y); } } x_w = wod_w[nwd_w - 1]; if ( x_w ) { off_w = _mug_fnv(off_w ^ (x_w & 0xff)); x_w >>= 8; if ( x_w ) { off_w = _mug_fnv(off_w ^ (x_w & 0xff)); x_w >>= 8; if ( x_w ) { off_w = _mug_fnv(off_w ^ (x_w & 0xff)); x_w >>= 8; if ( x_w ) { off_w = _mug_fnv(off_w ^ (x_w & 0xff)); } } } } } return off_w; } static c3_w _mug_words(c3_w off_w, c3_w nwd_w, const c3_w* wod_w) { c3_w has_w = _mug_words_in(off_w, nwd_w, wod_w); c3_w out_w = _mug_out(has_w); if ( 0 != out_w ) { return out_w; } else { return _mug_words(++off_w, nwd_w, wod_w); } } static c3_w _mug_words_buf(c3_w off_w, c3_w nwd_w, u2_noun veb) { c3_w has_w = _mug_words_in_buf(off_w, nwd_w, veb); c3_w out_w = _mug_out(has_w); if ( 0 != out_w ) { return out_w; } else { return _mug_words_buf(++off_w, nwd_w, veb); } } /* u2_cr_mug(): ** ** Compute and/or recall the mug (31-bit FNV1a hash) of (a). */ c3_w u2_cr_mug(u2_noun veb) { c3_assert(u2_none != veb); if ( u2_so(u2_co_is_cat(veb)) ) { c3_w x_w = veb; return _mug_words(2166136261, (veb ? 1 : 0), &x_w); } else { u2_cs_noun* veb_u = u2_co_to_ptr(veb); if ( veb_u->mug_w ) { return veb_u->mug_w; } else { if ( u2_so(u2_co_is_cell(veb)) ) { u2_cs_cell* veb_u = u2_co_to_ptr(veb); u2_noun hed = veb_u->hed; u2_noun tel = veb_u->tel; veb_u->mug_w = u2_cr_mug_cell(hed, tel); return veb_u->mug_w; } else { u2_cs_atom* veb_u = u2_co_to_ptr(veb); c3_w len_w = veb_u->len_w; veb_u->mug_w = _mug_words_buf(2166136261, len_w, veb); return veb_u->mug_w; } } } } /* u2_cr_mug_words(): ** ** Compute the mug of `buf`, `len`, LSW first. */ c3_w u2_cr_mug_words(const c3_w *buf_w, c3_w len_w) { return _mug_words(2166136261, len_w, buf_w); } /* u2_cr_mug_string(): ** ** Compute the mug of `a`, LSB first. */ c3_w u2_cr_mug_string(const c3_c *a_c) { return _mug_bytes(2166136261, strlen(a_c), (c3_y *)a_c); } /* u2_cr_mug_cell(): ** ** Compute the mug of the cell `[hed tel]`. */ c3_w u2_cr_mug_cell(u2_noun hed, u2_noun tel) { c3_w lus_w = u2_cr_mug(hed); c3_w biq_w = u2_cr_mug(tel); return u2_cr_mug_both(lus_w, biq_w); } /* u2_cr_mug_trel(): ** ** Compute the mug of `[a b c]`. */ c3_w u2_cr_mug_trel(u2_noun a, u2_noun b, u2_noun c) { return u2_cr_mug_both(u2_cr_mug(a), u2_cr_mug_both(u2_cr_mug(b), u2_cr_mug(c))); } /* u2_cr_mug_qual(): ** ** Compute the mug of `[a b c d]`. */ c3_w u2_cr_mug_qual(u2_noun a, u2_noun b, u2_noun c, u2_noun d) { return u2_cr_mug_both (u2_cr_mug(a), u2_cr_mug_both(u2_cr_mug(b), u2_cr_mug_both(u2_cr_mug(c), u2_cr_mug(d)))); } /* _sing_x(): ** ** Yes iff (a) and (b) are the same noun. */ static u2_bean _sing_x(u2_noun a, u2_noun b) { c3_assert(u2_none != a); c3_assert(u2_none != b); if ( a == b ) { return u2_yes; } else { if ( u2_so(u2_co_is_atom(a)) ) { u2_cs_atom* a_u = u2_co_to_ptr(a); if ( !u2_so(u2_co_is_atom(b)) || u2_so(u2_co_is_cat(a)) || u2_so(u2_co_is_cat(b)) ) { return u2_no; } else { u2_cs_atom* b_u = u2_co_to_ptr(b); if ( a_u->mug_w && b_u->mug_w && (a_u->mug_w != b_u->mug_w) ) { return u2_no; } else { c3_w w_rez = a_u->len_w; c3_w w_mox = b_u->len_w; if ( w_rez != w_mox ) { return u2_no; } else { c3_w i_w; for ( i_w = 0; i_w < w_rez; i_w++ ) { if ( a_u->buf_w[i_w] != b_u->buf_w[i_w] ) { return u2_no; } } return u2_yes; } } } } else { if ( u2_so(u2_co_is_atom(b)) ) { return u2_no; } else { u2_cs_cell* a_u = u2_co_to_ptr(a); u2_cs_cell* b_u = u2_co_to_ptr(b); if ( a_u->mug_w && b_u->mug_w && (a_u->mug_w != b_u->mug_w) ) { return u2_no; } else { if ( u2_no == _sing_x(u2_co_h(a), u2_co_h(b)) ) { return u2_no; } else if ( u2_no == _sing_x(u2_co_t(a), u2_co_t(b)) ) { return u2_no; } return u2_yes; } } } } } /* u2_cr_sing(): ** ** Yes iff (a) and (b) are the same noun. */ u2_bean u2_cr_sing(u2_noun a, u2_noun b) { return _sing_x(a, b); } u2_bean u2_cr_fing(u2_noun a, u2_noun b) { return (a == b) ? u2_yes : u2_no; } /* u2_cr_sing_cell(): ** ** Yes iff `[p q]` and `b` are the same noun. */ u2_bean u2_cr_sing_cell(u2_noun p, u2_noun q, u2_noun b) { return u2_and(u2_so(u2_co_is_cell(b)), u2_and(u2_cr_sing(p, u2_co_h(b)), u2_cr_sing(q, u2_co_t(b)))); } u2_bean u2_cr_fing_cell(u2_noun p, u2_noun q, u2_noun b) { return u2_and(u2_so(u2_co_is_cell(b)), u2_and(u2_cr_fing(p, u2_co_h(b)), u2_cr_fing(q, u2_co_t(b)))); } /* u2_cr_sing_mixt(): ** ** Yes iff `[p q]` and `b` are the same noun. */ u2_bean u2_cr_sing_mixt(const c3_c* p_c, u2_noun q, u2_noun b) { return u2_and(u2_so(u2_co_is_cell(b)), u2_and(u2_cr_sing_c(p_c, u2_co_h(b)), u2_cr_sing(q, u2_co_t(b)))); } u2_bean u2_cr_fing_mixt(const c3_c* p_c, u2_noun q, u2_noun b) { return u2_and(u2_so(u2_co_is_cell(b)), u2_and(u2_cr_sing_c(p_c, u2_co_h(b)), u2_cr_fing(q, u2_co_t(b)))); } /* u2_cr_sing_trel(): ** ** Yes iff `[p q r]` and `b` are the same noun. */ u2_bean u2_cr_sing_trel(u2_noun p, u2_noun q, u2_noun r, u2_noun b) { return u2_and(u2_so(u2_co_is_cell(b)), u2_and(u2_cr_sing(p, u2_co_h(b)), u2_cr_sing_cell(q, r, u2_co_t(b)))); } u2_bean u2_cr_fing_trel(u2_noun p, u2_noun q, u2_noun r, u2_noun b) { return u2_and(u2_so(u2_co_is_cell(b)), u2_and(u2_cr_fing(p, u2_co_h(b)), u2_cr_fing_cell(q, r, u2_co_t(b)))); } /* u2_cr_sing_qual(): ** ** Yes iff `[p q r]` and `b` are the same noun. */ u2_bean u2_cr_sing_qual(u2_noun p, u2_noun q, u2_noun r, u2_noun s, u2_noun b) { return u2_and(u2_so(u2_co_is_cell(b)), u2_and(u2_cr_sing(p, u2_co_h(b)), u2_cr_sing_trel(q, r, s, u2_co_t(b)))); } u2_bean u2_cr_fing_qual(u2_noun p, u2_noun q, u2_noun r, u2_noun s, u2_noun b) { return u2_and(u2_so(u2_co_is_cell(b)), u2_and(u2_cr_fing(p, u2_co_h(b)), u2_cr_fing_trel(q, r, s, u2_co_t(b)))); } /* u2_cr_nord(): ** ** Return 0, 1 or 2 if `a` is below, equal to, or above `b`. */ u2_atom u2_cr_nord(u2_noun a, u2_noun b) { c3_assert(u2_none != a); c3_assert(u2_none != b); if ( a == b ) { return 1; } else { if ( u2_so(u2_co_is_atom(a)) ) { if ( !u2_so(u2_co_is_atom(b)) ) { return 0; } else { if ( u2_so(u2_co_is_cat(a)) ) { if ( u2_so(u2_co_is_cat(b)) ) { return (a < b) ? 0 : 2; } else return 0; } else if ( u2_so(u2_co_is_cat(b)) ) { return 2; } else { u2_cs_atom* a_u = u2_co_to_ptr(a); u2_cs_atom* b_u = u2_co_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 ( u2_so(u2_co_is_atom(b)) ) { return 2; } else { u2_atom c = u2_cr_nord(u2_co_h(a), u2_co_h(b)); if ( 1 == c ) { return u2_cr_nord(u2_co_t(a), u2_co_t(b)); } else { return c; } } } } } /* u2_cr_sing_c(): ** ** Yes iff (b) is the same noun as the C string a_c. */ u2_bean u2_cr_sing_c(const c3_c* a_c, u2_noun b) { c3_assert(u2_none != b); if ( !u2_so(u2_co_is_atom(b)) ) { return u2_no; } else { c3_w w_sof = strlen(a_c); c3_w i_w; for ( i_w = 0; i_w < w_sof; i_w++ ) { if ( u2_cr_byte(i_w, b) != a_c[i_w] ) { return u2_no; } } return u2_yes; } } /* u2_cr_bush(): ** ** Factor [a] as a bush [b.[p q] c]. */ u2_bean u2_cr_bush(u2_noun a, u2_noun* b, u2_noun* c) { c3_assert(u2_none != a); if ( u2_so(u2_co_is_atom(a)) ) { return u2_no; } else { *b = u2_co_h(a); if ( u2_so(u2_co_is_atom(*b)) ) { return u2_no; } else { *c = u2_co_t(a); return u2_yes; } } } /* u2_cr_cell(): ** ** Factor (a) as a cell (b c). */ u2_bean u2_cr_cell(u2_noun a, u2_noun* b, u2_noun* c) { c3_assert(u2_none != a); if ( u2_so(u2_co_is_atom(a)) ) { return u2_no; } else { if ( b ) *b = u2_co_h(a); if ( c ) *c = u2_co_t(a); return u2_yes; } } /* u2_cr_p(): ** ** & [0] if [a] is of the form [b *c]. */ u2_bean u2_cr_p(u2_noun a, u2_noun b, u2_noun* c) { u2_noun feg, nux; if ( (u2_yes == u2_cr_cell(a, &feg, &nux)) && (u2_yes == u2_cr_sing(feg, b)) ) { *c = nux; return u2_yes; } else return u2_no; } /* u2_cr_pq(): ** ** & [0] if [a] is of the form [b *c d]. */ u2_bean u2_cr_pq(u2_noun a, u2_noun b, u2_noun* c, u2_noun* d) { u2_noun nux; if ( (u2_yes == u2_cr_p(a, b, &nux)) && (u2_yes == u2_cr_cell(nux, c, d)) ) { return u2_yes; } else return u2_no; } /* u2_cr_pqr(): ** ** & [0] if [a] is of the form [b *c *d *e]. */ u2_bean u2_cr_pqr(u2_noun a, u2_noun b, u2_noun* c, u2_noun* d, u2_noun* e) { u2_noun nux; if ( (u2_yes == u2_cr_p(a, b, &nux)) && (u2_yes == u2_cr_trel(nux, c, d, e)) ) { return u2_yes; } else return u2_no; } /* u2_cr_pqrs(): ** ** & [0] if [a] is of the form [b *c *d *e *f]. */ u2_bean u2_cr_pqrs(u2_noun a, u2_noun b, u2_noun* c, u2_noun* d, u2_noun* e, u2_noun* f) { u2_noun nux; if ( (u2_yes == u2_cr_p(a, b, &nux)) && (u2_yes == u2_cr_qual(nux, c, d, e, f)) ) { return u2_yes; } else return u2_no; } /* u2_cr_trel(): ** ** Factor (a) as a trel (b c d). */ u2_bean u2_cr_trel(u2_noun a, u2_noun *b, u2_noun *c, u2_noun *d) { u2_noun guf; if ( (u2_yes == u2_cr_cell(a, b, &guf)) && (u2_yes == u2_cr_cell(guf, c, d)) ) { return u2_yes; } else { return u2_no; } } /* u2_cr_qual(): ** ** Factor (a) as a qual (b c d e). */ u2_bean u2_cr_qual(u2_noun a, u2_noun* b, u2_noun* c, u2_noun* d, u2_noun* e) { u2_noun guf; if ( (u2_yes == u2_cr_cell(a, b, &guf)) && (u2_yes == u2_cr_trel(guf, c, d, e)) ) { return u2_yes; } else return u2_no; } /* u2_cr_quil(): ** ** Factor (a) as a quil (b c d e f). */ u2_bean u2_cr_quil(u2_noun a, u2_noun* b, u2_noun* c, u2_noun* d, u2_noun* e, u2_noun* f) { u2_noun guf; if ( (u2_yes == u2_cr_cell(a, b, &guf)) && (u2_yes == u2_cr_qual(guf, c, d, e, f)) ) { return u2_yes; } else return u2_no; } /* u2_cr_hext(): ** ** Factor (a) as a hext (b c d e f g) */ u2_bean u2_cr_hext(u2_noun a, u2_noun* b, u2_noun* c, u2_noun* d, u2_noun* e, u2_noun* f, u2_noun* g) { u2_noun guf; if ( (u2_yes == u2_cr_cell(a, b, &guf)) && (u2_yes == u2_cr_quil(guf, c, d, e, f, g)) ) { return u2_yes; } else return u2_no; } /* u2_cr_met(): ** ** Return the size of (b) in bits, rounded up to ** (1 << a_y). ** ** For example, (a_y == 3) returns the size in bytes. */ c3_w u2_cr_met(c3_y a_y, u2_atom b) { c3_assert(u2_none != b); c3_assert(u2_so(u2_co_is_atom(b))); if ( b == 0 ) { return 0; } else { /* 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 ( u2_so(u2_co_is_cat(b)) ) { gal_w = 0; daz_w = b; } else { u2_cs_atom* b_u = u2_co_to_ptr(b); gal_w = (b_u->len_w) - 1; daz_w = b_u->buf_w[gal_w]; } switch ( a_y ) { case 0: case 1: case 2: { /* col_w: number of bits in (daz_w) ** bif_w: number of bits in (b) */ c3_w bif_w, col_w; col_w = c3_bits_word(daz_w); bif_w = col_w + (gal_w << 5); return (bif_w + ((1 << a_y) - 1)) >> a_y; } case 3: { return (gal_w << 2) + ((daz_w >> 24) ? 4 : (daz_w >> 16) ? 3 : (daz_w >> 8) ? 2 : 1); } case 4: { return (gal_w << 1) + ((daz_w >> 16) ? 2 : 1); } default: { c3_y gow_y = (a_y - 5); return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y; } } } } /* u2_cr_bit(): ** ** Return bit (a_w) of (b). */ c3_b u2_cr_bit(c3_w a_w, u2_atom b) { c3_assert(u2_none != b); c3_assert(u2_so(u2_co_is_atom(b))); if ( u2_so(u2_co_is_cat(b)) ) { if ( a_w >= 31 ) { return 0; } else return (1 & (b >> a_w)); } else { u2_cs_atom* b_u = u2_co_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)); } } } /* u2_cr_byte(): ** ** Return byte (a_w) of (b). */ c3_y u2_cr_byte(c3_w a_w, u2_atom b) { c3_assert(u2_none != b); c3_assert(u2_so(u2_co_is_atom(b))); if ( u2_so(u2_co_is_cat(b)) ) { if ( a_w > 3 ) { return 0; } else return (255 & (b >> (a_w << 3))); } else { u2_cs_atom* b_u = u2_co_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))); } } } /* u2_cr_bytes(): ** ** Copy bytes (a_w) through (a_w + b_w - 1) from (d) to (c). */ void u2_cr_bytes(c3_w a_w, c3_w b_w, c3_y* c_y, u2_atom d) { c3_w i_w; c3_assert(u2_none != d); /* Efficiency: don't call u2_cr_byte(). */ for ( i_w = 0; i_w < b_w; i_w++ ) { c_y[i_w] = u2_cr_byte((a_w + i_w), d); } } /* u2_cr_mp(): ** ** Copy (b) into (a_mp). */ void u2_cr_mp(mpz_t a_mp, u2_atom b) { c3_assert(u2_none != b); c3_assert(u2_so(u2_co_is_atom(b))); if ( u2_so(u2_co_is_cat(b)) ) { mpz_init_set_ui(a_mp, b); } else { u2_cs_atom* b_u = u2_co_to_ptr(b); c3_w len_w = b_u->len_w; /* Slight deficiency in the GMP API. */ c3_assert(!(len_w >> 27)); mpz_init2(a_mp, len_w << 5); /* Efficiency: horrible. */ { c3_w *buf_w = alloca(len_w << 2); c3_w i_w; for ( i_w=0; i_w < len_w; i_w++ ) { buf_w[i_w] = b_u->buf_w[i_w]; } mpz_import(a_mp, len_w, -1, 4, 0, 0, buf_w); } } } /* u2_cr_word(): ** ** Return word (a_w) of (b). */ c3_w u2_cr_word(c3_w a_w, u2_atom b) { c3_assert(u2_none != b); c3_assert(u2_so(u2_co_is_atom(b))); if ( u2_so(u2_co_is_cat(b)) ) { if ( a_w > 0 ) { return 0; } else return b; } else { u2_cs_atom* b_u = u2_co_to_ptr(b); if ( a_w >= b_u->len_w ) { return 0; } else return b_u->buf_w[a_w]; } } /* u2_cr_chub(): ** ** Return double-word (a_w) of (b). */ c3_d u2_cr_chub(c3_w a_w, u2_atom b) { c3_w wlo_w = u2_cr_word(a_w * 2, b); c3_w whi_w = u2_cr_word(1 + (a_w * 2), b); return (((uint64_t)whi_w) << 32ULL) | ((uint64_t)wlo_w); } /* u2_cr_words(): ** ** Copy words (a_w) through (a_w + b_w - 1) from (d) to (c). */ void u2_cr_words(c3_w a_w, c3_w b_w, c3_w* c_w, u2_atom d) { c3_w i_w; c3_assert(u2_none != d); /* Efficiency: don't call u2_cr_word(). */ for ( i_w = 0; i_w < b_w; i_w++ ) { c_w[i_w] = u2_cr_word((a_w + i_w), d); } } /* u2_cr_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`. */ void u2_cr_chop(c3_g met_g, c3_w fum_w, c3_w wid_w, c3_w tou_w, c3_w* dst_w, u2_atom src) { c3_w i_w; c3_w len_w; c3_w* buf_w; c3_assert(u2_none != src); c3_assert(u2_so(u2_co_is_atom(src))); if ( u2_so(u2_co_is_cat(src)) ) { len_w = src ? 1 : 0; buf_w = &src; } else { u2_cs_atom* src_u = u2_co_to_ptr(src); len_w = src_u->len_w; buf_w = src_u->buf_w; } if ( met_g < 5 ) { c3_w san_w = (1 << met_g); c3_w mek_w = ((1 << san_w) - 1); c3_w baf_w = (fum_w << met_g); c3_w bat_w = (tou_w << met_g); // XX: efficiency: poor. Iterate by words. // for ( i_w = 0; i_w < wid_w; i_w++ ) { c3_w waf_w = (baf_w >> 5); c3_g raf_g = (baf_w & 31); c3_w wat_w = (bat_w >> 5); c3_g rat_g = (bat_w & 31); c3_w hop_w; hop_w = (waf_w >= len_w) ? 0 : buf_w[waf_w]; hop_w = (hop_w >> raf_g) & mek_w; dst_w[wat_w] ^= (hop_w << rat_g); baf_w += san_w; bat_w += san_w; } } else { c3_g hut_g = (met_g - 5); c3_w san_w = (1 << hut_g); c3_w j_w; for ( i_w = 0; i_w < wid_w; i_w++ ) { c3_w wuf_w = (fum_w + i_w) << hut_g; c3_w wut_w = (tou_w + i_w) << hut_g; for ( j_w = 0; j_w < san_w; j_w++ ) { dst_w[wut_w + j_w] ^= ((wuf_w + j_w) >= len_w) ? 0 : buf_w[wuf_w + j_w]; } } } } /* u2_cr_string(): `a` as malloced C string. */ c3_c* u2_cr_string(u2_atom a) { c3_w met_w = u2_cr_met(3, a); c3_c* str_c = c3_malloc(met_w + 1); u2_cr_bytes(0, met_w, (c3_y*)str_c, a); str_c[met_w] = 0; return str_c; } /* u2_cr_tape(): `a`, a list of bytes, as malloced C string. */ c3_y* u2_cr_tape(u2_noun a) { u2_noun b; c3_w i_w; c3_y *a_y; for ( i_w = 0, b=a; u2_yes == u2_co_is_cell(b); i_w++, b=u2_co_t(b) ) ; a_y = c3_malloc(i_w + 1); for ( i_w = 0, b=a; u2_yes == u2_co_is_cell(b); i_w++, b=u2_co_t(b) ) { a_y[i_w] = u2_co_h(b); } a_y[i_w] = 0; return a_y; } static void* _ch_some_add(void* han_v, c3_w, c3_w, u2_noun); static void* _ch_some_new(c3_w lef_w); /* u2_ch_new(): create hashtable. */ u2_ch_root* u2_ch_new(void) { u2_ch_root* har_u = u2_ca_walloc(c3_wiseof(u2_ch_root)); c3_w i_w; har_u->clk_w = 0; for ( i_w = 0; i_w < 64; i_w++ ) { har_u->sot_w[i_w] = 0; } return har_u; } /* _ch_popcount(): number of bits set in word. A standard intrinsic. */ static c3_w _ch_popcount(c3_w num_w) { return __builtin_popcount(num_w); } /* _ch_buck_new(): create new, empty bucket. */ static u2_ch_buck* _ch_buck_new(void) { u2_ch_buck* hab_u = u2_ca_walloc(c3_wiseof(u2_ch_buck)); hab_u->len_w = 0; return hab_u; } /* ha_buck_add(): add to bucket. */ static u2_ch_buck* _ch_buck_add(u2_ch_buck* hab_u, u2_noun kev) { c3_w i_w; for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { if ( u2_yes == u2_cr_sing(u2h(kev), u2h(hab_u->kev[i_w])) ) { u2_ca_lose(hab_u->kev[i_w]); hab_u->kev[i_w] = kev; return hab_u; } } { c3_w len_w = hab_u->len_w; u2_ch_buck* bah_u = u2_ca_walloc(c3_wiseof(u2_ch_buck) + (len_w + 1) * c3_wiseof(u2_noun)); bah_u->len_w = len_w + 1; bah_u->kev[0] = kev; // Optimize: use u2_ca_wealloc(). // for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { bah_u->kev[i_w + 1] = hab_u->kev[i_w]; } u2_ca_free(hab_u); return bah_u; } } /* _ch_node_new(): create new, empty node. */ static u2_ch_node* _ch_node_new(void) { u2_ch_node* han_u = u2_ca_walloc(c3_wiseof(u2_ch_node)); han_u->map_w = 0; return han_u; } /* _ch_node_add(): add to node. */ static u2_ch_node* _ch_node_add(u2_ch_node* han_u, c3_w lef_w, c3_w rem_w, u2_noun kev) { c3_w bit_w, inx_w, map_w, i_w; lef_w -= 5; bit_w = (rem_w >> lef_w); rem_w = (rem_w & ((1 << lef_w) - 1)); map_w = han_u->map_w; inx_w = _ch_popcount(map_w & ((1 << bit_w) - 1)); if ( map_w & (1 << bit_w) ) { c3_w sot_w = han_u->sot_w[inx_w]; if ( u2_so(u2_ch_slot_is_node(sot_w)) ) { void* hav_v = u2_ch_slot_to_node(sot_w); hav_v = _ch_some_add(hav_v, lef_w, rem_w, kev); han_u->sot_w[inx_w] = u2_ch_node_to_slot(hav_v); return han_u; } else { u2_noun kov = u2_ch_slot_to_noun(sot_w); if ( u2_yes == u2_cr_sing(u2h(kev), u2h(kov)) ) { u2_ca_lose(kov); han_u->sot_w[inx_w] = u2_ch_noun_to_slot(kev); return han_u; } else { c3_w rom_w = u2_cr_mug(u2h(kov)) & ((1 << lef_w) - 1); void* hav_v = _ch_some_new(lef_w); // Optimize: need a custom collision create. // hav_v = _ch_some_add(hav_v, lef_w, rem_w, kev); hav_v = _ch_some_add(hav_v, lef_w, rom_w, kov); han_u->sot_w[inx_w] = u2_ch_node_to_slot(hav_v); return han_u; } } } else { // Optimize: use u2_ca_wealloc. // c3_w len_w = _ch_popcount(map_w); u2_ch_node* nah_u = u2_ca_walloc(c3_wiseof(u2_ch_node) + ((len_w + 1) * c3_wiseof(u2_ch_slot))); nah_u->map_w = han_u->map_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] = u2_ch_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]; } u2_ca_free(han_u); return nah_u; } } /* _ch_some_new(): create node or bucket. */ static void* _ch_some_new(c3_w lef_w) { if ( 0 == lef_w ) { return _ch_buck_new(); } else { return _ch_node_new(); } } /* _ch_some_add(): add to node or bucket. */ static void* _ch_some_add(void* han_v, c3_w lef_w, c3_w rem_w, u2_noun kev) { if ( 0 == lef_w ) { return _ch_buck_add(han_v, kev); } else return _ch_node_add(han_v, lef_w, rem_w, kev); } /* u2_ch_put(): insert in hashtable. */ void u2_ch_put(u2_ch_root* har_u, u2_noun key, u2_noun val) { u2_noun kev = u2nc(u2k(key), val); c3_w mug_w = u2_cr_mug(key); c3_w inx_w = (mug_w >> 25); c3_w rem_w = (mug_w & ((1 << 25) - 1)); c3_w sot_w = har_u->sot_w[inx_w]; if ( u2_so(u2_ch_slot_is_null(sot_w)) ) { har_u->sot_w[inx_w] = u2_ch_noun_to_slot(kev); } else { u2_ch_node* han_u; if ( u2_so(u2_ch_slot_is_noun(sot_w)) ) { u2_noun kov = u2_ch_slot_to_noun(sot_w); c3_w rom_w = u2_cr_mug(u2h(kov)) & ((1 << 25) - 1); han_u = _ch_node_new(); han_u = _ch_node_add(han_u, 25, rem_w, kev); han_u = _ch_node_add(han_u, 25, rom_w, kov); } else { han_u = _ch_node_add(u2_ch_slot_to_node(sot_w), 25, rem_w, kev); } har_u->sot_w[inx_w] = u2_ch_node_to_slot(han_u); } } /* _ch_buck_get(): read in bucket. */ static u2_weak _ch_buck_get(u2_ch_buck* hab_u, u2_noun key) { c3_w i_w; for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { if ( u2_so(u2_cr_sing(key, u2h(hab_u->kev[i_w]))) ) { return u2_ca_gain(u2t(hab_u->kev[i_w])); } } return u2_none; } /* _ch_node_get(): read in node. */ static u2_weak _ch_node_get(u2_ch_node* han_u, c3_w lef_w, c3_w rem_w, u2_noun key) { c3_w bit_w, map_w; lef_w -= 5; bit_w = (rem_w >> lef_w); rem_w = (rem_w & ((1 << lef_w) - 1)); map_w = han_u->map_w; if ( !(map_w & (1 << bit_w)) ) { return u2_none; } else { c3_w inx_w = _ch_popcount(map_w & ((1 << bit_w) - 1)); c3_w sot_w = han_u->sot_w[inx_w]; if ( u2_so(u2_ch_slot_is_noun(sot_w)) ) { u2_noun kev = u2_ch_slot_to_noun(sot_w); if ( u2_so(u2_cr_sing(key, u2h(kev))) ) { return u2_ca_gain(u2t(kev)); } else { return u2_none; } } else { void* hav_v = u2_ch_slot_to_node(sot_w); if ( 0 == lef_w ) { return _ch_buck_get(hav_v, key); } else return _ch_node_get(hav_v, lef_w, rem_w, key); } } } /* u2_ch_get(): read from hashtable. */ u2_weak u2_ch_get(u2_ch_root* har_u, u2_noun key) { c3_w mug_w = u2_cr_mug(key); c3_w inx_w = (mug_w >> 25); c3_w rem_w = (mug_w & ((1 << 25) - 1)); c3_w sot_w = har_u->sot_w[inx_w]; if ( u2_so(u2_ch_slot_is_null(sot_w)) ) { return u2_none; } else if ( u2_so(u2_ch_slot_is_noun(sot_w)) ) { u2_noun kev = u2_ch_slot_to_noun(sot_w); if ( u2_so(u2_cr_sing(key, u2h(kev))) ) { har_u->sot_w[inx_w] = u2_ch_noun_be_warm(sot_w); return u2_ca_gain(u2t(kev)); } else { return u2_none; } } else { u2_ch_node* han_u = u2_ch_slot_to_node(sot_w); return _ch_node_get(han_u, 25, rem_w, key); } } /* _ch_free_buck(): free bucket */ static void _ch_free_buck(u2_ch_buck* hab_u) { c3_w i_w; for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { u2_ca_lose(hab_u->kev[i_w]); } u2_ca_free(hab_u); } /* _ch_free_node(): free node. */ static void _ch_free_node(u2_ch_node* han_u, c3_w lef_w) { 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 ( u2_so(u2_ch_slot_is_noun(sot_w)) ) { u2_noun kev = u2_ch_slot_to_noun(sot_w); u2_ca_lose(kev); } else { void* hav_v = u2_ch_slot_to_node(sot_w); if ( 0 == lef_w ) { _ch_free_buck(hav_v); } else { _ch_free_node(hav_v, lef_w); } } } u2_ca_free(han_u); } /* u2_ch_free(): free hashtable. */ void u2_ch_free(u2_ch_root* har_u) { c3_w i_w; for ( i_w = 0; i_w < 64; i_w++ ) { c3_w sot_w = har_u->sot_w[i_w]; if ( u2_so(u2_ch_slot_is_noun(sot_w)) ) { u2_noun kev = u2_ch_slot_to_noun(sot_w); u2_ca_lose(kev); } else if ( u2_so(u2_ch_slot_is_node(sot_w)) ) { u2_ch_node* han_u = u2_ch_slot_to_node(sot_w); _ch_free_node(han_u, 25); } } u2_ca_free(har_u); } /* u2_cz_find(): find in memo cache. Arguments retained. */ u2_weak u2_cz_find(u2_mote fun, u2_noun one) { u2_noun key = u2nc(fun, u2k(one)); u2_noun val; val = u2_ch_get(u2R->cax.har_u, key); u2z(key); return val; } u2_weak u2_cz_find_2(u2_mote fun, u2_noun one, u2_noun two) { u2_noun key = u2nt(fun, u2k(one), u2k(two)); u2_noun val; val = u2_ch_get(u2R->cax.har_u, key); u2z(key); return val; } u2_weak u2_cz_find_3(u2_mote fun, u2_noun one, u2_noun two, u2_noun tri) { u2_noun key = u2nq(fun, u2k(one), u2k(two), u2k(tri)); u2_noun val; val = u2_ch_get(u2R->cax.har_u, key); u2z(key); return val; } u2_weak u2_cz_find_4(u2_mote fun, u2_noun one, u2_noun two, u2_noun tri, u2_noun qua) { u2_noun key = u2nc(fun, u2nq(u2k(one), u2k(two), u2k(tri), u2k(qua))); u2_noun val; val = u2_ch_get(u2R->cax.har_u, key); u2z(key); return val; } /* u2_cz_save*(): save in memo cache. */ u2_noun u2_cz_save(u2_mote fun, u2_noun one, u2_noun val) { u2_noun key = u2nc(fun, u2k(one)); u2_ch_put(u2R->cax.har_u, key, u2k(val)); u2z(key); return val; } u2_noun u2_cz_save_2(u2_mote fun, u2_noun one, u2_noun two, u2_noun val) { u2_noun key = u2nt(fun, u2k(one), u2k(two)); u2_ch_put(u2R->cax.har_u, key, u2k(val)); u2z(key); return val; } u2_noun u2_cz_save_3(u2_mote fun, u2_noun one, u2_noun two, u2_noun tri, u2_noun val) { u2_noun key = u2nq(fun, u2k(one), u2k(two), u2k(tri)); u2_ch_put(u2R->cax.har_u, key, u2k(val)); u2z(key); return val; } u2_noun u2_cz_save_4(u2_mote fun, u2_noun one, u2_noun two, u2_noun tri, u2_noun qua, u2_noun val) { u2_noun key = u2nc(fun, u2nq(u2k(one), u2k(two), u2k(tri), u2k(qua))); u2_ch_put(u2R->cax.har_u, key, u2k(val)); u2z(key); return val; } /* u2_cz_uniq(): uniquify with memo cache. */ u2_noun u2_cz_uniq(u2_noun som) { u2_noun key = u2nc(c3__uniq, u2k(som)); u2_noun val = u2_ch_get(u2R->cax.har_u, key); if ( u2_none != val ) { u2z(key); u2z(som); return val; } else { u2_ch_put(u2R->cax.har_u, key, u2k(som)); return som; } } /* u2_ct_push(): push on trace stack. */ void u2_ct_push(u2_noun mon) { u2R->bug.tax = u2nc(mon, u2R->bug.tax); } /* u2_ct_mean(): push `[%mean roc]` on trace stack. */ void u2_ct_mean(u2_noun roc) { u2R->bug.tax = u2nc(u2nc(c3__mean, roc), u2R->bug.tax); } /* u2_ct_drop(): drop from meaning stack. */ void u2_ct_drop(void) { c3_assert(u2_so(u2du(u2R->bug.tax))); { u2_noun tax = u2R->bug.tax; u2R->bug.tax = u2k(u2t(tax)); u2z(tax); } } /* u2_ct_slog(): print directly. */ void u2_ct_slog(u2_noun hod) { u2z(hod); } /* _cn_hint(): process hint. */ static u2_noun _cn_hint(u2_noun zep, u2_noun hod, u2_noun bus, u2_noun nex) { switch ( zep ) { default: { u2_ca_lose(zep); u2_ca_lose(hod); return u2_cn_nock_on(bus, nex); } case c3__hunk: case c3__lose: case c3__mean: case c3__spot: { u2_noun tac = u2nc(zep, hod); u2_noun pro; u2_ct_push(tac); #if 0 if ( c3__spot == zep ) { printf("spot %d/%d : %d/%d\n", u2h(u2h(u2t(hod))), u2t(u2h(u2t(hod))), u2h(u2t(u2t(hod))), u2t(u2t(u2t(hod)))); } #endif pro = u2_cn_nock_on(bus, nex); u2_ct_drop(); return pro; } case c3__slog: { u2_ct_slog(hod); return u2_cn_nock_on(bus, nex); } case c3__germ: { u2_noun pro = u2_cn_nock_on(bus, nex); if ( u2_yes == u2_cr_sing(pro, hod) ) { u2z(pro); return hod; } else { u2z(hod); return pro; } } case c3__fast: { u2_noun pro = u2_cn_nock_on(bus, nex); return u2_cj_mine(hod, pro); } case c3__memo: { u2z(hod); { u2_noun pro = u2_cz_find_2(c3__nock, bus, nex); if ( pro != u2_none ) { u2z(bus); u2z(nex); return pro; } pro = u2_cn_nock_on(bus, nex); u2_cz_save_2(c3__nock, bus, nex, pro); u2z(bus); u2z(nex); } } case c3__sole: { u2z(hod); { u2_noun pro = u2_cn_nock_on(bus, nex); return u2_cz_uniq(pro); } } } } /* u2_cn_nock_on(): produce .*(bus fol). Do not virtualize. */ u2_noun u2_cn_nock_on(u2_noun bus, u2_noun fol) { u2_noun hib, gal; while ( 1 ) { hib = u2h(fol); gal = u2t(fol); if ( u2_yes == u2_cr_du(hib) ) { u2_noun poz, riv; poz = u2_cn_nock_on(u2k(bus), u2k(hib)); riv = u2_cn_nock_on(bus, u2k(gal)); u2_ca_lose(fol); return u2_ci_cell(poz, riv); } else switch ( hib ) { default: return u2_cm_bail(c3__exit); case 0: { if ( u2_no == u2_cr_ud(gal) ) { return u2_cm_bail(c3__exit); } else { u2_noun pro = u2k(u2at(gal, bus)); u2_ca_lose(bus); u2_ca_lose(fol); return pro; } } c3_assert(!"not reached"); case 1: { u2_noun pro = u2k(gal); u2_ca_lose(bus); u2_ca_lose(fol); return pro; } c3_assert(!"not reached"); case 2: { u2_noun nex = u2_cn_nock_on(u2k(bus), u2k(u2t(gal))); u2_noun seb = u2_cn_nock_on(bus, u2k(u2h(gal))); u2_ca_lose(fol); bus = seb; fol = nex; continue; } c3_assert(!"not reached"); case 3: { u2_noun gof, pro; gof = u2_cn_nock_on(bus, u2k(gal)); pro = u2_cr_du(gof); u2_ca_lose(gof); u2_ca_lose(fol); return pro; } c3_assert(!"not reached"); case 4: { u2_noun gof, pro; gof = u2_cn_nock_on(bus, u2k(gal)); pro = u2_ci_vint(gof); u2_ca_lose(fol); return pro; } c3_assert(!"not reached"); case 5: { u2_noun wim = u2_cn_nock_on(bus, u2k(gal)); u2_noun pro = u2_cr_sing(u2h(wim), u2t(wim)); u2_ca_lose(wim); u2_ca_lose(fol); return pro; } c3_assert(!"not reached"); case 6: { u2_noun b_gal, c_gal, d_gal; u2_cx_trel(gal, &b_gal, &c_gal, &d_gal); { u2_noun tys = u2_cn_nock_on(u2k(bus), u2k(b_gal)); u2_noun nex; if ( 0 == tys ) { nex = u2k(c_gal); } else if ( 1 == tys ) { nex = u2k(d_gal); } else return u2_cm_bail(c3__exit); u2_ca_lose(fol); fol = nex; continue; } } c3_assert(!"not reached"); case 7: { u2_noun b_gal, c_gal; u2_cx_cell(gal, &b_gal, &c_gal); { u2_noun bod = u2_cn_nock_on(bus, u2k(b_gal)); u2_noun nex = u2k(c_gal); u2_ca_lose(fol); bus = bod; fol = nex; continue; } } c3_assert(!"not reached"); case 8: { u2_noun b_gal, c_gal; u2_cx_cell(gal, &b_gal, &c_gal); { u2_noun heb = u2_cn_nock_on(u2k(bus), u2k(b_gal)); u2_noun bod = u2nc(heb, bus); u2_noun nex = u2k(c_gal); u2_ca_lose(fol); bus = bod; fol = nex; continue; } } c3_assert(!"not reached"); case 9: { u2_noun b_gal, c_gal; u2_cx_cell(gal, &b_gal, &c_gal); { u2_noun seb = u2_cn_nock_on(bus, u2k(c_gal)); u2_noun pro = u2_cj_kick(seb, b_gal); if ( u2_none != pro ) { u2_ca_lose(fol); return pro; } else { if ( u2_no == u2_cr_ud(b_gal) ) { return u2_cm_bail(c3__exit); } else { u2_noun nex = u2k(u2at(b_gal, seb)); u2_ca_lose(fol); bus = seb; fol = nex; continue; } } } } c3_assert(!"not reached"); case 10: { u2_noun p_gal, q_gal; u2_cx_cell(gal, &p_gal, &q_gal); { u2_noun zep, hod, nex; if ( u2_yes == u2_cr_du(p_gal) ) { u2_noun b_gal = u2h(p_gal); u2_noun c_gal = u2t(p_gal); u2_noun d_gal = q_gal; zep = u2k(b_gal); hod = u2_cn_nock_on(u2k(bus), u2k(c_gal)); nex = u2k(d_gal); } else { u2_noun b_gal = p_gal; u2_noun c_gal = q_gal; zep = u2k(b_gal); hod = u2_nul; nex = u2k(c_gal); } u2_ca_lose(fol); return _cn_hint(zep, hod, bus, nex); } } case 11: { c3_assert(!"11 remains stubbed out"); } c3_assert(!"not reached"); } } } /* u2_cn_kick_on(): fire `gat` without changing the sample. */ u2_noun u2_cn_kick_on(u2_noun gat) { return u2_cj_kink(gat, 2); } /* u2_cn_slam_on(): produce (gat sam). */ u2_noun u2_cn_slam_on(u2_noun gat, u2_noun sam) { u2_noun cor = u2nc(u2k(u2h(gat)), u2nc(sam, u2k(u2t(u2t(gat))))); u2z(gat); return u2_cn_kick_on(cor); } /* u2_cn_nock_un(): produce .*(bus fol), as ++toon. */ u2_noun u2_cn_nock_un(u2_noun bus, u2_noun fol) { u2_noun ton; u2_cm_leap(); if ( u2_no == u2_cm_trap() ) { u2_noun ton; if ( 0 != u2R->net.nyd ) { ton = u2nc(1, u2R->net.nyd); } else { ton = u2nc(2, u2R->bug.tax); } u2_cm_fall(); ton = u2_ca_gain(ton); u2_cm_flog(0); } else { u2_noun pro = u2_cn_nock_on(bus, fol); u2_cm_fall(); ton = u2nc(0, u2_ca_gain(pro)); } u2z(bus); u2z(fol); return ton; } /* u2_cn_slam_un(): produce (gat sam), as ++toon. */ u2_noun u2_cn_slam_un(u2_noun gat, u2_noun sam) { u2_noun ton; u2_cm_leap(); if ( u2_no == u2_cm_trap() ) { u2_noun ton; if ( 0 != u2R->net.nyd ) { ton = u2nc(1, u2R->net.nyd); } else { ton = u2nc(2, u2R->bug.tax); } u2_cm_fall(); ton = u2_ca_gain(ton); u2_cm_flog(0); } else { u2_noun pro = u2_cn_slam_on(gat, sam); u2_cm_fall(); ton = u2nc(0, u2_ca_gain(pro)); } u2z(gat); u2z(sam); return ton; } /* u2_cn_nock_in(): produce .*(bus fol), as ++toon, in namespace. */ u2_noun u2_cn_nock_in(u2_noun fly, u2_noun bus, u2_noun fol) { // XX implement 11 // u2z(fly); return u2_cn_nock_un(bus, fol); } /* u2_cn_slam_in(): produce (gat sam), as ++toon, in namespace. */ u2_noun u2_cn_slam_in(u2_noun fly, u2_noun gat, u2_noun sam) { // XX implement 11 // u2z(fly); return u2_cn_slam_un(gat, sam); } /* u2_cn_nock_an(): as slam_in(), but with empty fly. */ u2_noun u2_cn_nock_an(u2_noun bus, u2_noun fol) { return u2_cn_nock_un(bus, fol); }