diff --git a/noun/hashtable.c b/noun/hashtable.c index a30adc6d77..30cc70d311 100644 --- a/noun/hashtable.c +++ b/noun/hashtable.c @@ -3,14 +3,17 @@ */ #include "all.h" -static void* _ch_some_add(void* han_v, c3_w, c3_w, u3_noun, c3_w*); +static void _ch_free_node(u3h_node*, c3_w); +static void _ch_node_deflate(u3h_slot*, c3_w); +static c3_c* _ch_pre(c3_w); +static void _ch_print_node(u3h_node*, c3_w); +static void* _ch_some_add(void*, c3_w, c3_w, u3_noun, c3_w*); static void* _ch_some_new(c3_w lef_w); -static void _ch_trim_one(u3h_root*); -static c3_o _ch_trim_one_some(u3h_slot*, c3_w); -static c3_o _ch_trim_one_buck(u3h_slot*); -static c3_o _ch_trim_one_node(u3h_slot*, c3_w); -static void _ch_print_node(u3h_node*, c3_w); -static void _ch_walk_node(u3h_node*, c3_w, void (*fun_f)(u3_noun)); +static void _ch_trim_one(u3h_root*); +static c3_o _ch_trim_one_some(u3h_slot*, c3_w); +static c3_o _ch_trim_one_buck(u3h_slot*); +static c3_o _ch_trim_one_node(u3h_slot*, c3_w); +static void _ch_walk_node(u3h_node*, c3_w, void (*fun_f)(u3_noun)); /* u3h_new_cache(): create hashtable with bounded size. */ @@ -118,6 +121,7 @@ static u3h_node* _ch_node_add(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) { c3_w bit_w, inx_w, map_w, i_w; + c3_c* pre = _ch_pre(lef_w); lef_w -= 5; bit_w = (rem_w >> lef_w); @@ -133,7 +137,7 @@ _ch_node_add(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) // this slot contains a node, so recurse into that node. // if ( _(u3h_slot_is_node(sot_w)) ) { - fprintf(stderr, "nod recurse\r\n"); + fprintf(stderr, "%snod recurse\r\n", pre); void* hav_v = u3h_slot_to_node(sot_w); hav_v = _ch_some_add(hav_v, lef_w, rem_w, kev, use_w); @@ -149,7 +153,7 @@ _ch_node_add(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) // the key is the same, so replace the value // if ( c3y == u3r_sing(u3h(kev), u3h(kov)) ) { - fprintf(stderr, "nod replace\r\n"); + fprintf(stderr, "%snod replace\r\n", pre); u3m_p("nod kev", kev); u3m_p("nod kov", kov); u3a_lose(kov); @@ -165,13 +169,13 @@ _ch_node_add(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) // Optimize: need a custom collision create. // - fprintf(stderr, "nod pre-kev use_w: %d\r\n", *use_w); + fprintf(stderr, "%snod pre-kev use_w: %d\r\n", pre, *use_w); hav_v = _ch_some_add(hav_v, lef_w, rem_w, kev, use_w); - fprintf(stderr, "nod pre-kov use_w: %d\r\n", *use_w); + fprintf(stderr, "%snod pre-kov use_w: %d\r\n", pre, *use_w); hav_v = _ch_some_add(hav_v, lef_w, rom_w, kov, use_w); - fprintf(stderr, "nod post-kev use_w: %d\r\n", *use_w); + fprintf(stderr, "%snod post-kev use_w: %d\r\n", pre, *use_w); (*use_w)--; - fprintf(stderr, "nod post-dec use_w: %d\r\n", *use_w); + fprintf(stderr, "%snod post-dec use_w: %d\r\n", pre, *use_w); han_u->sot_w[inx_w] = u3h_node_to_slot(hav_v); return han_u; @@ -186,29 +190,36 @@ _ch_node_add(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) u3h_node* nah_u = u3a_walloc(c3_wiseof(u3h_node) + ((len_w + 1) * c3_wiseof(u3h_slot))); nah_u->map_w = han_u->map_w | (1 << bit_w); + fprintf(stderr, "%snod len_w %d -> %d\r\n", pre, len_w, len_w + 1); for ( i_w = 0; i_w < inx_w; i_w++ ) { nah_u->sot_w[i_w] = han_u->sot_w[i_w]; + if ( _(u3h_slot_is_noun(nah_u->sot_w[i_w])) ) { + fprintf(stderr, "%snod sot_w[%d]: {%d: %d}\r\n", pre, + i_w, u3h(u3h_slot_to_noun(nah_u->sot_w[i_w])), + u3t(u3h_slot_to_noun(nah_u->sot_w[i_w]))); + } + else { + fprintf(stderr, "%snod sot_w[%d]: \r\n", pre, i_w); + } } nah_u->sot_w[inx_w] = u3h_noun_to_slot(kev); + fprintf(stderr, "%snod sot_w[%d]: {%d: %d} (inx_w)\r\n", pre, + inx_w, u3h(u3h_slot_to_noun(nah_u->sot_w[inx_w])), + u3t(u3h_slot_to_noun(nah_u->sot_w[inx_w]))); for ( i_w = inx_w; i_w < len_w; i_w++ ) { nah_u->sot_w[i_w + 1] = han_u->sot_w[i_w]; + fprintf(stderr, "%snod sot_w[%d]: {%d: %d}\r\n", pre, + i_w + 1, u3h(u3h_slot_to_noun(nah_u->sot_w[i_w + 1])), + u3t(u3h_slot_to_noun(nah_u->sot_w[i_w + 1]))); } nah_u->arm_w = han_u->arm_w; u3a_wfree(han_u); - /* TODO: remove - // make sure we don't immediately trim off the new value. - // - if ( nah_u->arm_w == inx_w ) { - nah_u->arm_w++; - } - */ - *use_w += 1; - fprintf(stderr, "nod post-inc use_w: %d\r\n", *use_w); + fprintf(stderr, "%snod post-inc use_w: %d\r\n", pre, *use_w); return nah_u; } } @@ -269,15 +280,13 @@ _ch_print_node(u3h_node* han_u, c3_w lef_w) { c3_w len_w = _ch_popcount(han_u->map_w); c3_w i_w; - c3_c* pre; + c3_c* pre = _ch_pre(lef_w); lef_w -= 5; - if ( 20 == lef_w ) { pre = " "; } - else if ( 15 == lef_w ) { pre = " "; } - else if ( 10 == lef_w ) { pre = " "; } - else if ( 5 == lef_w ) { pre = " "; } - else { - pre = " "; + + fprintf(stderr, "%snode @%08x\r\n", pre, han_u); + + if ( 0 == lef_w ) { fprintf(stderr, "%s\r\n", pre); } @@ -295,6 +304,18 @@ _ch_print_node(u3h_node* han_u, c3_w lef_w) } } +/* _ch_pre(): get printing whitepsace prefix based on recursion depth. +*/ +static c3_c* +_ch_pre(c3_w lef_w) +{ + if ( 25 == lef_w ) { return " "; } + else if ( 20 == lef_w ) { return " "; } + else if ( 15 == lef_w ) { return " "; } + else if ( 10 == lef_w ) { return " "; } + else if ( 5 == lef_w ) { return " "; } + else { return " "; } +} /* u3h_put(): insert in hashtable. ** @@ -321,23 +342,6 @@ u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val) har_u->use_w++; fprintf(stderr, "post-nul use_w: %d\r\n", har_u->use_w); - // make sure we don't immediately trim off the new value. - // cycle arm_w around until it points to a non-null slot. - // if it landed on a null value, the next value inserted might - // be the first one to be evicted, which would break the semantics. - // if we're adding the first non-null element, arm_w will end up - // pointing at the new element. this is ok. - // - /* TODO: remove - if ( har_u->arm_w == inx_w ) { - fprintf(stderr, "put arm_w %d -> ", har_u->arm_w); - do { - har_u->arm_w = (har_u->arm_w + 1) % 64; - } - while ( _(u3h_slot_is_null(har_u->sot_w[har_u->arm_w])) ); - fprintf(stderr, "%d\r\n", har_u->arm_w); - } - */ } else { u3h_node* han_u; @@ -349,11 +353,8 @@ u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val) u3_noun kov = u3h_slot_to_noun(sot_w); c3_w rom_w = u3r_mug(u3h(kov)) & ((1 << 25) - 1); - fprintf(stderr, "sot_w: %08x kev: %08x kov: %08x\r\n", sot_w, kev, kov); - u3m_p("put kov", u3h(kov)); - u3m_p("put kov", u3t(kov)); - u3m_p("put kev", u3h(kev)); - u3m_p("put kev", u3t(kev)); + u3m_p("put kov", kov); + u3m_p("put kev", kev); han_u = _ch_node_new(); fprintf(stderr, "put: pre-kev use_w: %d\r\n", har_u->use_w); @@ -409,6 +410,7 @@ _ch_trim_one(u3h_root *har_u) else if ( _(u3h_slot_is_node(root_sot_w)) ) { c3_o trimmed = _ch_trim_one_some(&root_sot_w, 25); if ( _(trimmed) ) { + fprintf(stderr, "trimmed: c3y\r\n"); har_u->use_w--; return; } @@ -421,6 +423,7 @@ _ch_trim_one(u3h_root *har_u) c3_assert(_(u3h_slot_is_noun(root_sot_w))); u3_noun kev = u3h_slot_to_noun(root_sot_w); + fprintf(stderr, "removing sot_w[%d]: {%d: %d}\r\n", har_u->arm_w, u3h(kev), u3t(kev)); u3a_lose(kev); har_u->sot_w[har_u->arm_w] = 0; @@ -442,11 +445,32 @@ _ch_trim_one(u3h_root *har_u) static c3_o _ch_trim_one_some(u3h_slot* hal_w, c3_w lef_w) { + c3_c* pre = _ch_pre(lef_w); + if ( 0 == lef_w ) { + // TODO: _ch_buck_deflate() return _ch_trim_one_buck(hal_w); } else { - return _ch_trim_one_node(hal_w, lef_w); + u3h_slot old_w = *hal_w; + + fprintf(stderr, "%strim_one_some \r\n", pre); + _ch_print_node(u3h_slot_to_node(*hal_w), lef_w); + fprintf(stderr, "%strim_one_some \r\n", pre); + + c3_o del_o = _ch_trim_one_node(hal_w, lef_w); + + if ( _(del_o) ) { + _ch_node_deflate(hal_w, lef_w); + c3_assert(old_w != *hal_w); + + u3_noun kev = u3h_slot_to_noun(*hal_w); + fprintf(stderr, "%strim_one_some deflated: {%d: %d}\r\n", pre, u3h(kev), u3t(kev)); + } + else { + fprintf(stderr, "%strim_one_some did not trim node\r\n", pre); + } + return del_o; } } @@ -533,6 +557,8 @@ _ch_trim_one_node(u3h_slot* hal_w, c3_w lef_w) c3_assert(len_w != 1); + fprintf(stderr, "trim_one_node arm_w: %d\r\n", han_u->arm_w); + while (han_u->arm_w < len_w) { sot_w = han_u->sot_w[han_u->arm_w]; @@ -551,16 +577,6 @@ _ch_trim_one_node(u3h_slot* hal_w, c3_w lef_w) else { c3_w bit_w, i_w, inx_w; - if ( len_w == 2) { - c3_assert(c3n == u3h_slot_is_null(sot_w)); - u3a_lose(u3h_slot_to_noun(sot_w)); - - // if arm_w is 0, assign han_u->sot_w[1] and vice versa. - // - *hal_w = u3h_slot_to_noun(han_u->sot_w[!han_u->arm_w]); - return c3y; - } - u3h_node* nah_u = u3a_walloc(c3_wiseof(u3h_node) + ((len_w - 1) * c3_wiseof(u3h_slot))); @@ -588,6 +604,34 @@ _ch_trim_one_node(u3h_slot* hal_w, c3_w lef_w) return c3n; } +/* _ch_node_deflate(); convert singleton node to key-value pair. +*/ +static void +_ch_node_deflate(u3h_slot* sot_w, c3_w lef_w) +{ + u3h_node* han_u = (u3h_node*)u3h_slot_to_node(*sot_w); + c3_w len_w = _ch_popcount(han_u->map_w); + c3_c* pre = _ch_pre(lef_w); + + if ( 1 == len_w ) { + fprintf(stderr, "%snode_deflate: deflating\r\n", pre); + + if ( _(u3h_slot_is_node(han_u->sot_w[0])) ) { + fprintf(stderr, "%snode_deflate: recursing\r\n", pre); + _ch_node_deflate(&han_u->sot_w[0], lef_w); + } + + // bump refcount before freeing node to make sure kev + // doesn't get freed. + // + u3_noun kev = u3k(u3h_slot_to_noun(han_u->sot_w[0])); + + _ch_free_node(han_u, lef_w); + + *sot_w = u3h_noun_to_slot(kev); + } +} + /* _ch_buck_hum(): read in bucket. */ static c3_o diff --git a/tests/hashtable_tests.c b/tests/hashtable_tests.c index 6e65d0b302..54a63ff2c6 100644 --- a/tests/hashtable_tests.c +++ b/tests/hashtable_tests.c @@ -57,7 +57,6 @@ _ch_test_cache_trimming(void) u3p(u3h_root) har_p = u3h_new_cache(1); for ( i_w = 0; i_w < max_w; i_w++ ) { - fprintf(stderr, "****putting %d: %d******\r\n", i_w, i_w + max_w); u3h_put(har_p, i_w, i_w + max_w); fprintf(stderr, "********************************\r\n"); }