shrub/noun/hashtable.c

932 lines
20 KiB
C
Raw Normal View History

2014-09-11 04:01:32 +04:00
/* g/h.c
2014-09-05 23:55:16 +04:00
**
*/
#include "all.h"
2017-11-08 02:32:35 +03:00
static void
_ch_slot_put(u3h_slot* sot_w, u3_noun kev, c3_w lef_w, c3_w rem_w, c3_w* use_w);
static c3_o
_ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w);
2014-09-05 23:55:16 +04:00
c3_w
_ch_skip_slot(c3_w mug_w, c3_w lef_w);
2017-11-03 01:39:57 +03:00
/* u3h_new_cache(): create hashtable with bounded size.
*/
2014-11-06 03:20:01 +03:00
u3p(u3h_root)
2017-11-08 02:32:35 +03:00
u3h_new_cache(c3_w max_w)
2014-09-05 23:55:16 +04:00
{
2014-11-06 03:20:01 +03:00
u3h_root* har_u = u3a_walloc(c3_wiseof(u3h_root));
u3p(u3h_root) har_p = u3of(u3h_root, har_u);
2014-09-05 23:55:16 +04:00
c3_w i_w;
2017-11-08 02:32:35 +03:00
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;
har_u->arm_u.buc_o = c3n;
2014-09-05 23:55:16 +04:00
for ( i_w = 0; i_w < 64; i_w++ ) {
har_u->sot_w[i_w] = 0;
}
2014-11-04 04:02:55 +03:00
return har_p;
2014-09-05 23:55:16 +04:00
}
/* u3h_new(): create hashtable.
*/
u3p(u3h_root)
u3h_new(void)
{
return u3h_new_cache(0);
}
2014-09-05 23:55:16 +04:00
/* _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.
*/
2014-11-06 03:20:01 +03:00
static u3h_buck*
2014-09-05 23:55:16 +04:00
_ch_buck_new(void)
{
2014-11-06 03:20:01 +03:00
u3h_buck* hab_u = u3a_walloc(c3_wiseof(u3h_buck));
2014-09-05 23:55:16 +04:00
hab_u->len_w = 0;
return hab_u;
}
/* _ch_node_new(): create new, empty node.
*/
2014-11-06 03:20:01 +03:00
static u3h_node*
2014-09-05 23:55:16 +04:00
_ch_node_new(void)
{
2014-11-06 03:20:01 +03:00
u3h_node* han_u = u3a_walloc(c3_wiseof(u3h_node));
2014-09-05 23:55:16 +04:00
han_u->map_w = 0;
return han_u;
}
2017-11-07 02:44:32 +03:00
/* _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();
}
}
2014-09-05 23:55:16 +04:00
/* _ch_node_add(): add to node.
*/
2014-11-06 03:20:01 +03:00
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)
2014-09-05 23:55:16 +04:00
{
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) ) {
2017-11-07 02:44:32 +03:00
_ch_slot_put(&(han_u->sot_w[inx_w]), kev, lef_w, rem_w, use_w);
return han_u;
2014-09-05 23:55:16 +04:00
}
else {
// nothing was at this slot.
2014-11-06 03:20:01 +03:00
// Optimize: use u3a_wealloc.
2014-09-05 23:55:16 +04:00
//
c3_w len_w = _ch_popcount(map_w);
u3h_node* nah_u = u3a_walloc(c3_wiseof(u3h_node) +
((len_w + 1) * c3_wiseof(u3h_slot)));
2014-09-05 23:55:16 +04:00
nah_u->map_w = han_u->map_w | (1 << bit_w);
2014-09-05 23:55:16 +04:00
for ( i_w = 0; i_w < inx_w; i_w++ ) {
nah_u->sot_w[i_w] = han_u->sot_w[i_w];
2014-09-05 23:55:16 +04:00
}
2017-11-07 02:44:32 +03:00
nah_u->sot_w[inx_w] = u3h_noun_be_warm(u3h_noun_to_slot(kev));
2014-09-05 23:55:16 +04:00
for ( i_w = inx_w; i_w < len_w; i_w++ ) {
nah_u->sot_w[i_w + 1] = han_u->sot_w[i_w];
}
2017-11-04 07:04:24 +03:00
u3a_wfree(han_u);
*use_w += 1;
2014-09-05 23:55:16 +04:00
return nah_u;
}
}
2017-11-08 02:32:35 +03:00
/* 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)) ) {
u3a_lose(kov);
hab_u->sot_w[i_w] = u3h_noun_to_slot(kev);
return hab_u;
}
}
// create mutant bucket with added key-value pair.
{
c3_w len_w = hab_u->len_w;
u3h_buck* bah_u = u3a_walloc(c3_wiseof(u3h_buck) +
(len_w + 1) * c3_wiseof(u3h_slot));
bah_u->len_w = len_w + 1;
bah_u->sot_w[0] = u3h_noun_to_slot(kev);
// Optimize: use u3a_wealloc().
//
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;
}
}
2014-09-05 23:55:16 +04:00
/* _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)
2014-09-05 23:55:16 +04:00
{
if ( 0 == lef_w ) {
return _ch_buck_add((u3h_buck*)han_v, kev, use_w);
2014-09-05 23:55:16 +04:00
}
else return _ch_node_add((u3h_node*)han_v, lef_w, rem_w, kev, use_w);
2014-09-05 23:55:16 +04:00
}
2017-11-14 07:35:34 +03:00
/* _ch_slot_put(): store a key-value pair in a u3h_slot (root or node)
*/
2017-11-04 19:41:45 +03:00
static void
2017-11-07 02:44:32 +03:00
_ch_slot_put(u3h_slot* sot_w, u3_noun kev, c3_w lef_w, c3_w rem_w, c3_w* use_w)
2017-11-04 19:41:45 +03:00
{
2017-11-07 02:44:32 +03:00
if ( c3y == u3h_slot_is_null(*sot_w) ) {
*sot_w = u3h_noun_be_warm(u3h_noun_to_slot(kev));
*use_w += 1;
2017-11-04 19:41:45 +03:00
}
2017-11-07 02:44:32 +03:00
else if ( c3y == u3h_slot_is_noun(*sot_w) ) {
u3_noun kov = u3h_slot_to_noun(*sot_w);
if ( c3y == u3r_sing(u3h(kev), u3h(kov)) ) {
*sot_w = u3h_noun_be_warm(u3h_noun_to_slot(kev));
u3z(kov);
2017-11-04 19:41:45 +03:00
}
2017-11-07 02:44:32 +03:00
else {
c3_w rom_w = u3r_mug(u3h(kov)) & ((1 << lef_w) - 1);
void* hav_v = _ch_some_new(lef_w);
*use_w -= 1; // take one out, add two
hav_v = _ch_some_add(hav_v, lef_w, rom_w, kov, use_w);
2017-11-07 08:05:25 +03:00
hav_v = _ch_some_add(hav_v, lef_w, rem_w, kev, use_w);
2017-11-07 02:44:32 +03:00
*sot_w = u3h_node_to_slot(hav_v);
2017-11-04 19:41:45 +03:00
}
}
2017-11-07 02:44:32 +03:00
else {
2017-11-14 07:35:34 +03:00
void* hav_v = _ch_some_add(u3h_slot_to_node(*sot_w),
lef_w,
rem_w,
kev,
use_w);
2017-11-07 02:44:32 +03:00
c3_assert( c3y == u3h_slot_is_node(*sot_w) );
*sot_w = u3h_node_to_slot(hav_v);
}
}
2017-11-04 19:41:45 +03:00
2017-11-14 07:35:34 +03:00
/* _ch_trim_node(): trim one entry from a node slot or its children
*/
2017-11-07 02:44:32 +03:00
static c3_o
2017-11-08 02:32:35 +03:00
_ch_trim_node(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w)
2017-11-07 02:44:32 +03:00
{
c3_w bit_w, map_w, inx_w;
u3h_slot* tos_w;
2017-11-08 02:32:35 +03:00
u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w);
2017-11-07 02:44:32 +03:00
lef_w -= 5;
bit_w = (rem_w >> lef_w);
map_w = han_u->map_w;
if ( 0 == (map_w & (1 << bit_w)) ) {
har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w);
return c3n;
}
rem_w = (rem_w & ((1 << lef_w) - 1));
inx_w = _ch_popcount(map_w & ((1 << bit_w) - 1));
tos_w = &(han_u->sot_w[inx_w]);
2017-11-03 01:39:57 +03:00
2017-11-08 02:32:35 +03:00
if ( c3n == _ch_trim_slot(har_u, tos_w, lef_w, rem_w) ) {
// nothing trimmed
return c3n;
}
else if ( 0 != *tos_w ) {
// something trimmed, but slot still has value
return c3y;
}
else {
// shrink!
c3_w i_w, len_w = _ch_popcount(map_w);
if ( 2 == len_w ) {
// only one left, pick the other
*sot_w = han_u->sot_w[ 0 == inx_w ? 1 : 0 ];
u3a_wfree(han_u);
}
else {
// shrink node in place; don't reallocate, we could be low on memory
//
han_u->map_w = han_u->map_w & ~(1 << bit_w);
for ( i_w = inx_w; i_w < (len_w - 1); i_w++ ) {
han_u->sot_w[i_w] = han_u->sot_w[i_w + 1];
}
2017-11-07 02:44:32 +03:00
}
return c3y;
2014-09-05 23:55:16 +04:00
}
2017-11-07 02:44:32 +03:00
}
2014-09-05 23:55:16 +04:00
2017-11-14 07:35:34 +03:00
/* _ch_trim_node(): trim one entry from a bucket slot
*/
2017-11-07 02:44:32 +03:00
static c3_o
2017-11-08 02:32:35 +03:00
_ch_trim_buck(u3h_root* har_u, u3h_slot* sot_w)
2017-11-07 02:44:32 +03:00
{
c3_w i_w, len_w;
u3h_buck* hab_u = u3h_slot_to_node(*sot_w);
2017-11-08 02:32:35 +03:00
for ( har_u->arm_u.buc_o = c3y, len_w = hab_u->len_w;
har_u->arm_u.inx_w < len_w;
har_u->arm_u.inx_w += 1 )
{
u3h_slot* tos_w = &(hab_u->sot_w[har_u->arm_u.inx_w]);
if ( c3y == _ch_trim_slot(har_u, tos_w, 0, 0) ) {
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)
2017-11-08 02:32:35 +03:00
*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;
har_u->arm_u.buc_o = c3n;
}
else {
// shrink bucket in place; don't reallocate, we could be low on memory
//
hab_u->len_w = len_w - 1;
for ( i_w = har_u->arm_u.inx_w; i_w < (len_w - 1); ++i_w ) {
hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1];
2017-11-07 02:44:32 +03:00
}
}
return c3y;
2014-09-05 23:55:16 +04:00
}
}
2017-11-08 02:32:35 +03:00
har_u->arm_u.mug_w = (har_u->arm_u.mug_w + 1) & 0x7FFFFFFF; // modulo 2^31
2017-11-15 00:38:02 +03:00
har_u->arm_u.inx_w = 0;
har_u->arm_u.buc_o = c3n;
2017-11-07 02:44:32 +03:00
return c3n;
}
2017-11-04 19:41:45 +03:00
2017-11-14 07:35:34 +03:00
/* _ch_trim_some(): trim one entry from a bucket or node slot
*/
2017-11-07 02:44:32 +03:00
static c3_o
2017-11-08 02:32:35 +03:00
_ch_trim_some(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w)
2017-11-07 02:44:32 +03:00
{
if ( 0 == lef_w ) {
2017-11-08 02:32:35 +03:00
return _ch_trim_buck(har_u, sot_w);
2017-11-07 02:44:32 +03:00
}
else {
2017-11-08 02:32:35 +03:00
return _ch_trim_node(har_u, sot_w, lef_w, rem_w);
2017-11-07 02:44:32 +03:00
}
2014-09-05 23:55:16 +04:00
}
/* _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 = (hig_w + 1) & ((1 << (31 - lef_w)) - 1); // modulo 2^(31 - lef_w)
return new_w << lef_w;
}
2017-11-14 07:35:34 +03:00
/* _ch_trim_slot(): trim one entry from a slot
*/
2017-11-07 02:44:32 +03:00
static c3_o
2017-11-08 02:32:35 +03:00
_ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w)
{
if ( _(u3h_slot_is_null(*sot_w)) ) {
har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w);
return c3n;
}
else if ( _(u3h_slot_is_node(*sot_w)) ) {
2017-11-08 02:32:35 +03:00
return _ch_trim_some(har_u, sot_w, lef_w, rem_w);
}
else if ( _(u3h_slot_is_warm(*sot_w)) ) {
*sot_w = u3h_noun_be_cold(*sot_w);
if ( c3n == har_u->arm_u.buc_o ) {
har_u->arm_u.mug_w = (har_u->arm_u.mug_w + 1) & 0x7FFFFFFF; // modulo 2^31
}
return c3n;
}
else {
u3_noun kev = u3h_slot_to_noun(*sot_w);
*sot_w = 0;
2017-11-14 07:35:34 +03:00
// uL(fprintf(uH, "trim: freeing %x, use count %d\r\n", kev, u3a_use(kev)));
u3z(kev);
har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w);
return c3y;
}
}
2017-11-14 07:35:34 +03:00
/* _ch_trim_slot(): trim one entry from a hashtable
*/
static c3_o
2017-11-08 02:32:35 +03:00
_ch_trim_root(u3h_root* har_u)
{
2017-11-08 02:32:35 +03:00
c3_w mug_w = har_u->arm_u.mug_w;
c3_w inx_w = mug_w >> 25; // 6 bits
c3_w rem_w = mug_w & ((1 << 25) - 1);
u3h_slot* sot_w = &(har_u->sot_w[inx_w]);
2017-11-08 02:32:35 +03:00
return _ch_trim_slot(har_u, sot_w, 25, rem_w);
}
2017-11-08 02:32:35 +03:00
/* u3h_trim_to(): trim to n key-value pairs
*/
void
2017-11-08 02:32:35 +03:00
u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w)
{
u3h_root* har_u = u3to(u3h_root, har_p);
2017-11-08 02:32:35 +03:00
while ( har_u->use_w > n_w ) {
if ( c3y == _ch_trim_root(har_u) ) {
har_u->use_w -= 1;
}
/* TODO: remove
2017-11-08 02:32:35 +03:00
if ( c3n == har_u->arm_u.buc_o ) {
// lower 31 bits of increment (next mug)
har_u->arm_u.mug_w = (har_u->arm_u.mug_w + 1) & 0x7FFFFFFF;
2017-11-08 02:32:35 +03:00
har_u->arm_u.inx_w = 0;
}
*/
2017-11-08 02:32:35 +03:00
}
}
2017-11-08 02:32:35 +03:00
/* u3h_put(): insert in hashtable.
**
** `key` is RETAINED; `val` is transferred.
*/
2017-11-07 02:44:32 +03:00
void
2017-11-08 02:32:35 +03:00
u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val)
{
2017-11-08 02:32:35 +03:00
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 = (mug_w & ((1 << 25) - 1));
_ch_slot_put(&(har_u->sot_w[inx_w]), kev, 25, rem_w, &(har_u->use_w));
if ( har_u->max_w > 0 ) {
u3h_trim_to(har_p, har_u->max_w);
}
}
2014-09-25 22:32:07 +04:00
/* _ch_buck_hum(): read in bucket.
*/
static c3_o
2014-11-06 03:20:01 +03:00
_ch_buck_hum(u3h_buck* hab_u, c3_w mug_w)
2014-09-25 22:32:07 +04:00
{
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]))) ) {
2014-11-05 04:18:47 +03:00
return c3y;
2014-09-25 22:32:07 +04:00
}
}
2014-11-05 04:18:47 +03:00
return c3n;
2014-09-25 22:32:07 +04:00
}
/* _ch_node_hum(): read in node.
*/
static c3_o
2014-11-06 03:20:01 +03:00
_ch_node_hum(u3h_node* han_u, c3_w lef_w, c3_w rem_w, c3_w mug_w)
2014-09-25 22:32:07 +04:00
{
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)) ) {
2014-11-05 04:18:47 +03:00
return c3n;
2014-09-25 22:32:07 +04:00
}
else {
c3_w inx_w = _ch_popcount(map_w & ((1 << bit_w) - 1));
c3_w sot_w = han_u->sot_w[inx_w];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-09-25 22:32:07 +04:00
2014-11-06 03:20:01 +03:00
if ( mug_w == u3r_mug(u3h(kev)) ) {
2014-11-05 04:18:47 +03:00
return c3y;
}
2014-09-25 22:32:07 +04:00
else {
2014-11-05 04:18:47 +03:00
return c3n;
2014-09-25 22:32:07 +04:00
}
}
else {
2014-11-06 03:20:01 +03:00
void* hav_v = u3h_slot_to_node(sot_w);
2014-09-25 22:32:07 +04:00
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.
2014-09-25 22:32:07 +04:00
**
** `key` is RETAINED.
*/
c3_o
2014-11-06 03:20:01 +03:00
u3h_hum(u3p(u3h_root) har_p, c3_w mug_w)
2014-09-25 22:32:07 +04:00
{
2014-11-06 03:20:01 +03:00
u3h_root* har_u = u3to(u3h_root, har_p);
2014-11-04 04:02:55 +03:00
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];
2014-09-25 22:32:07 +04:00
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_null(sot_w)) ) {
2014-11-05 04:18:47 +03:00
return c3n;
2014-09-25 22:32:07 +04:00
}
2014-11-06 03:20:01 +03:00
else if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-09-25 22:32:07 +04:00
2014-11-06 03:20:01 +03:00
if ( mug_w == u3r_mug(u3h(kev)) ) {
2014-11-05 04:18:47 +03:00
return c3y;
}
2014-09-25 22:32:07 +04:00
else {
2014-11-05 04:18:47 +03:00
return c3n;
2014-09-25 22:32:07 +04:00
}
}
else {
2014-11-06 03:20:01 +03:00
u3h_node* han_u = u3h_slot_to_node(sot_w);
2014-09-25 22:32:07 +04:00
return _ch_node_hum(han_u, 25, rem_w, mug_w);
}
}
2014-12-01 03:06:08 +03:00
/* _ch_buck_git(): read in bucket.
2014-09-05 23:55:16 +04:00
*/
2014-09-06 00:13:24 +04:00
static u3_weak
2014-12-01 03:06:08 +03:00
_ch_buck_git(u3h_buck* hab_u, u3_noun key)
2014-09-05 23:55:16 +04:00
{
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);
2014-09-05 23:55:16 +04:00
}
}
2014-11-06 02:36:30 +03:00
return u3_none;
2014-09-05 23:55:16 +04:00
}
2014-12-01 03:06:08 +03:00
/* _ch_node_git(): read in node.
2014-09-05 23:55:16 +04:00
*/
2014-09-06 00:13:24 +04:00
static u3_weak
2014-12-01 03:06:08 +03:00
_ch_node_git(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun key)
2014-09-05 23:55:16 +04:00
{
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)) ) {
2014-11-06 02:36:30 +03:00
return u3_none;
2014-09-05 23:55:16 +04:00
}
else {
c3_w inx_w = _ch_popcount(map_w & ((1 << bit_w) - 1));
c3_w sot_w = han_u->sot_w[inx_w];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-09-05 23:55:16 +04:00
2014-11-06 03:20:01 +03:00
if ( _(u3r_sing(key, u3h(kev))) ) {
2014-12-01 03:06:08 +03:00
return u3t(kev);
}
2014-09-05 23:55:16 +04:00
else {
2014-11-06 02:36:30 +03:00
return u3_none;
2014-09-05 23:55:16 +04:00
}
}
else {
2014-11-06 03:20:01 +03:00
void* hav_v = u3h_slot_to_node(sot_w);
2014-09-05 23:55:16 +04:00
if ( 0 == lef_w ) {
2014-12-01 03:06:08 +03:00
return _ch_buck_git(hav_v, key);
2014-09-05 23:55:16 +04:00
}
2014-12-01 03:06:08 +03:00
else return _ch_node_git(hav_v, lef_w, rem_w, key);
2014-09-05 23:55:16 +04:00
}
}
}
2014-12-01 03:06:08 +03:00
/* u3h_git(): read from hashtable.
2014-09-07 02:39:28 +04:00
**
2014-12-01 03:06:08 +03:00
** `key` is RETAINED; result is RETAINED.
2014-09-05 23:55:16 +04:00
*/
2014-09-06 00:13:24 +04:00
u3_weak
2014-12-01 03:06:08 +03:00
u3h_git(u3p(u3h_root) har_p, u3_noun key)
2014-09-05 23:55:16 +04:00
{
2014-11-06 03:20:01 +03:00
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 = (mug_w & ((1 << 25) - 1));
c3_w sot_w = har_u->sot_w[inx_w];
2014-09-05 23:55:16 +04:00
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_null(sot_w)) ) {
2014-11-06 02:36:30 +03:00
return u3_none;
2014-09-05 23:55:16 +04:00
}
2014-11-06 03:20:01 +03:00
else if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-09-05 23:55:16 +04:00
2014-11-06 03:20:01 +03:00
if ( _(u3r_sing(key, u3h(kev))) ) {
har_u->sot_w[inx_w] = u3h_noun_be_warm(sot_w);
2014-12-01 03:06:08 +03:00
return u3t(kev);
}
2014-09-05 23:55:16 +04:00
else {
2014-11-06 02:36:30 +03:00
return u3_none;
2014-09-05 23:55:16 +04:00
}
}
else {
2014-11-06 03:20:01 +03:00
u3h_node* han_u = u3h_slot_to_node(sot_w);
2014-09-05 23:55:16 +04:00
2014-12-01 03:06:08 +03:00
return _ch_node_git(han_u, 25, rem_w, key);
}
}
/* u3h_get(): read from hashtable, incrementing refcount.
2014-12-01 03:06:08 +03:00
**
** `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 ) {
u3a_gain(pro);
2014-09-05 23:55:16 +04:00
}
2014-12-01 03:06:08 +03:00
return pro;
2014-09-05 23:55:16 +04:00
}
2014-10-09 02:16:24 +04:00
/* _ch_buck_gut(): read in bucket, unifying key nouns.
*/
static u3_weak
2014-11-06 03:20:01 +03:00
_ch_buck_gut(u3h_buck* hab_u, u3_noun key)
2014-10-09 02:16:24 +04:00
{
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_sung(key, u3h(kev))) ) {
return u3a_gain(u3t(kev));
2014-10-09 02:16:24 +04:00
}
}
2014-11-06 02:36:30 +03:00
return u3_none;
2014-10-09 02:16:24 +04:00
}
/* _ch_node_gut(): read in node, unifying key nouns.
*/
static u3_weak
2014-11-06 03:20:01 +03:00
_ch_node_gut(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun key)
2014-10-09 02:16:24 +04:00
{
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)) ) {
2014-11-06 02:36:30 +03:00
return u3_none;
2014-10-09 02:16:24 +04:00
}
else {
c3_w inx_w = _ch_popcount(map_w & ((1 << bit_w) - 1));
c3_w sot_w = han_u->sot_w[inx_w];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-10-09 02:16:24 +04:00
2014-11-06 03:20:01 +03:00
if ( _(u3r_sung(key, u3h(kev))) ) {
return u3a_gain(u3t(kev));
}
2014-10-09 02:16:24 +04:00
else {
2014-11-06 02:36:30 +03:00
return u3_none;
2014-10-09 02:16:24 +04:00
}
}
else {
2014-11-06 03:20:01 +03:00
void* hav_v = u3h_slot_to_node(sot_w);
2014-10-09 02:16:24 +04:00
if ( 0 == lef_w ) {
return _ch_buck_gut(hav_v, key);
}
else return _ch_node_gut(hav_v, lef_w, rem_w, key);
}
}
}
2014-11-06 03:20:01 +03:00
/* u3h_gut(): read from hashtable, unifying key nouns.
2014-10-09 02:16:24 +04:00
**
** `key` is RETAINED.
*/
u3_weak
2014-11-06 03:20:01 +03:00
u3h_gut(u3p(u3h_root) har_p, u3_noun key)
2014-10-09 02:16:24 +04:00
{
2014-11-06 03:20:01 +03:00
u3h_root* har_u = u3to(u3h_root, har_p);
c3_w mug_w = u3r_mug(key);
2014-11-04 04:02:55 +03:00
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];
2014-10-09 02:16:24 +04:00
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_null(sot_w)) ) {
2014-11-06 02:36:30 +03:00
return u3_none;
2014-10-09 02:16:24 +04:00
}
2014-11-06 03:20:01 +03:00
else if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-10-09 02:16:24 +04:00
2014-11-06 03:20:01 +03:00
if ( _(u3r_sung(key, u3h(kev))) ) {
har_u->sot_w[inx_w] = u3h_noun_be_warm(sot_w);
return u3a_gain(u3t(kev));
}
2014-10-09 02:16:24 +04:00
else {
2014-11-06 02:36:30 +03:00
return u3_none;
2014-10-09 02:16:24 +04:00
}
}
else {
2014-11-06 03:20:01 +03:00
u3h_node* han_u = u3h_slot_to_node(sot_w);
2014-10-09 02:16:24 +04:00
return _ch_node_gut(han_u, 25, rem_w, key);
}
}
2014-09-05 23:55:16 +04:00
/* _ch_free_buck(): free bucket
*/
static void
2014-11-06 03:20:01 +03:00
_ch_free_buck(u3h_buck* hab_u)
2014-09-05 23:55:16 +04:00
{
c3_w i_w;
2014-09-05 23:55:16 +04:00
for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
u3a_lose(u3h_slot_to_noun(hab_u->sot_w[i_w]));
2014-09-05 23:55:16 +04:00
}
u3a_wfree(hab_u);
2014-09-05 23:55:16 +04:00
}
/* _ch_free_node(): free node.
*/
static void
2014-11-06 03:20:01 +03:00
_ch_free_node(u3h_node* han_u, c3_w lef_w)
2014-09-05 23:55:16 +04:00
{
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];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-09-05 23:55:16 +04:00
2014-11-06 03:20:01 +03:00
u3a_lose(kev);
2014-09-05 23:55:16 +04:00
}
else {
2014-11-06 03:20:01 +03:00
void* hav_v = u3h_slot_to_node(sot_w);
2014-09-05 23:55:16 +04:00
if ( 0 == lef_w ) {
_ch_free_buck(hav_v);
} else {
_ch_free_node(hav_v, lef_w);
}
}
}
u3a_wfree(han_u);
2014-09-05 23:55:16 +04:00
}
2014-11-06 03:20:01 +03:00
/* u3h_free(): free hashtable.
2014-09-05 23:55:16 +04:00
*/
void
2014-11-06 03:20:01 +03:00
u3h_free(u3p(u3h_root) har_p)
2014-09-05 23:55:16 +04:00
{
2014-11-06 03:20:01 +03:00
u3h_root* har_u = u3to(u3h_root, har_p);
2014-11-04 04:02:55 +03:00
c3_w i_w;
2014-09-05 23:55:16 +04:00
for ( i_w = 0; i_w < 64; i_w++ ) {
c3_w sot_w = har_u->sot_w[i_w];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-09-05 23:55:16 +04:00
2014-11-06 03:20:01 +03:00
u3a_lose(kev);
2014-09-05 23:55:16 +04:00
}
2014-11-06 03:20:01 +03:00
else if ( _(u3h_slot_is_node(sot_w)) ) {
u3h_node* han_u = u3h_slot_to_node(sot_w);
2014-09-05 23:55:16 +04:00
_ch_free_node(han_u, 25);
}
}
u3a_wfree(har_u);
2014-09-05 23:55:16 +04:00
}
2014-10-31 00:40:05 +03:00
/* _ch_walk_buck(): walk bucket for gc.
*/
static void
2018-04-03 00:08:28 +03:00
_ch_walk_buck(u3h_buck* hab_u, void (*fun_f)(u3_noun, void*), void* wit)
2014-10-31 00:40:05 +03:00
{
c3_w i_w;
2014-10-31 00:40:05 +03:00
for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
2018-04-03 00:08:28 +03:00
fun_f(u3h_slot_to_noun(hab_u->sot_w[i_w]), wit);
2014-10-31 00:40:05 +03:00
}
}
/* _ch_walk_node(): walk node for gc.
*/
static void
2018-04-03 00:08:28 +03:00
_ch_walk_node(u3h_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), void* wit)
2014-10-31 00:40:05 +03:00
{
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];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-10-31 00:40:05 +03:00
2018-04-03 00:08:28 +03:00
fun_f(kev, wit);
2014-10-31 00:40:05 +03:00
}
else {
2014-11-06 03:20:01 +03:00
void* hav_v = u3h_slot_to_node(sot_w);
2014-10-31 00:40:05 +03:00
if ( 0 == lef_w ) {
2018-04-03 00:08:28 +03:00
_ch_walk_buck(hav_v, fun_f, wit);
2014-10-31 00:40:05 +03:00
} else {
2018-04-03 00:08:28 +03:00
_ch_walk_node(hav_v, lef_w, fun_f, wit);
2014-10-31 00:40:05 +03:00
}
}
}
}
2018-04-03 00:08:28 +03:00
/* u3h_walk_with(): traverse hashtable with key, value fn and data
* argument; RETAINS.
2014-10-31 00:40:05 +03:00
*/
void
2018-04-03 00:08:28 +03:00
u3h_walk_with(u3p(u3h_root) har_p,
void (*fun_f)(u3_noun, void*),
void* wit)
2014-10-31 00:40:05 +03:00
{
2014-11-06 03:20:01 +03:00
u3h_root* har_u = u3to(u3h_root, har_p);
2014-11-04 04:02:55 +03:00
c3_w i_w;
2014-10-31 00:40:05 +03:00
for ( i_w = 0; i_w < 64; i_w++ ) {
c3_w sot_w = har_u->sot_w[i_w];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-10-31 00:40:05 +03:00
2018-04-03 00:08:28 +03:00
fun_f(kev, wit);
2014-10-31 00:40:05 +03:00
}
2014-11-06 03:20:01 +03:00
else if ( _(u3h_slot_is_node(sot_w)) ) {
u3h_node* han_u = u3h_slot_to_node(sot_w);
2014-10-31 00:40:05 +03:00
2018-04-03 00:08:28 +03:00
_ch_walk_node(han_u, 25, fun_f, wit);
2014-10-31 00:40:05 +03:00
}
}
}
2018-04-03 00:08:28 +03:00
/* _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) = 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, fun_f);
}
2014-10-31 00:40:05 +03:00
2014-10-09 06:20:57 +04:00
/* _ch_mark_buck(): mark bucket for gc.
*/
2015-05-08 02:16:54 +03:00
c3_w
2014-11-06 03:20:01 +03:00
_ch_mark_buck(u3h_buck* hab_u)
2014-10-09 06:20:57 +04:00
{
c3_w tot_w = 0;
2015-05-08 02:16:54 +03:00
c3_w i_w;
2014-10-09 06:20:57 +04:00
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]));
2014-10-09 06:20:57 +04:00
}
2015-05-08 02:16:54 +03:00
tot_w += u3a_mark_ptr(hab_u);
return tot_w;
2014-10-09 06:20:57 +04:00
}
/* _ch_mark_node(): mark node for gc.
*/
2015-05-08 02:16:54 +03:00
c3_w
2014-11-06 03:20:01 +03:00
_ch_mark_node(u3h_node* han_u, c3_w lef_w)
2014-10-09 06:20:57 +04:00
{
2015-05-08 02:16:54 +03:00
c3_w tot_w = 0;
2014-10-09 06:20:57 +04:00
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];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-10-09 06:20:57 +04:00
2015-05-08 02:16:54 +03:00
tot_w += u3a_mark_noun(kev);
2014-10-09 06:20:57 +04:00
}
else {
2014-11-06 03:20:01 +03:00
void* hav_v = u3h_slot_to_node(sot_w);
2014-10-09 06:20:57 +04:00
if ( 0 == lef_w ) {
2015-05-08 02:16:54 +03:00
tot_w += _ch_mark_buck(hav_v);
2014-10-09 06:20:57 +04:00
} else {
2015-05-08 02:16:54 +03:00
tot_w += _ch_mark_node(hav_v, lef_w);
2014-10-09 06:20:57 +04:00
}
}
}
2015-05-08 02:16:54 +03:00
tot_w += u3a_mark_ptr(han_u);
return tot_w;
2014-10-09 06:20:57 +04:00
}
2014-11-06 03:20:01 +03:00
/* u3h_mark(): mark hashtable for gc.
2014-10-09 06:20:57 +04:00
*/
2015-05-08 02:16:54 +03:00
c3_w
2014-11-06 03:20:01 +03:00
u3h_mark(u3p(u3h_root) har_p)
2014-10-09 06:20:57 +04:00
{
2015-05-08 02:16:54 +03:00
c3_w tot_w = 0;
2014-11-06 03:20:01 +03:00
u3h_root* har_u = u3to(u3h_root, har_p);
2014-11-04 04:02:55 +03:00
c3_w i_w;
2014-10-09 06:20:57 +04:00
for ( i_w = 0; i_w < 64; i_w++ ) {
c3_w sot_w = har_u->sot_w[i_w];
2014-11-06 03:20:01 +03:00
if ( _(u3h_slot_is_noun(sot_w)) ) {
u3_noun kev = u3h_slot_to_noun(sot_w);
2014-10-09 06:20:57 +04:00
2015-05-08 02:16:54 +03:00
tot_w += u3a_mark_noun(kev);
2014-10-09 06:20:57 +04:00
}
2014-11-06 03:20:01 +03:00
else if ( _(u3h_slot_is_node(sot_w)) ) {
u3h_node* han_u = u3h_slot_to_node(sot_w);
2014-10-09 06:20:57 +04:00
2015-05-08 02:16:54 +03:00
tot_w += _ch_mark_node(han_u, 25);
2014-10-09 06:20:57 +04:00
}
}
2015-05-08 02:16:54 +03:00
tot_w += u3a_mark_ptr(har_u);
return tot_w;
2014-10-09 06:20:57 +04:00
}