Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

u3: adds deletion to HAMT #629

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 149 additions & 7 deletions pkg/noun/hashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,148 @@ u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val)
}
}

/* _ch_buck_del(): delete from bucket
*/
static c3_o
_ch_buck_del(u3h_slot* sot_w, u3_noun key)
{
u3h_buck* hab_u = u3h_slot_to_node(*sot_w);
c3_w fin_w = hab_u->len_w;
c3_w i_w;
//
// find index of key to be deleted
//
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(key, u3h(kov)) ) {
fin_w = i_w;
u3z(kov);
break;
}
}

// no key found, no-op
if ( fin_w == hab_u->len_w ) {
return c3n;
}

{
hab_u->len_w--;
// u3_assert(c3y == u3h_slot_is_noun(hab_u->sot_w[fin_w]));
for ( i_w = fin_w; i_w < hab_u->len_w; i_w++ ) {
hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1];
}

return c3y;
}
}

static c3_o _ch_some_del(u3h_slot*, u3_noun, c3_w, c3_w);

/* _ch_slot_del(): delete from slot
*/
static c3_o
_ch_slot_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w)
{
if ( c3y == u3h_slot_is_noun(*sot_w) ) {
u3_noun kev = u3h_slot_to_noun(*sot_w);
*sot_w = 0;
u3z(kev);
return c3y;
}
else {
return _ch_some_del(sot_w, key, lef_w, rem_w);
}
}

/* _ch_slot_del(): delete from node
*/
static c3_o
_ch_node_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w)
{
u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w);
u3h_slot* tos_w;

c3_w bit_w, inx_w, map_w, i_w;

lef_w -= 5;
bit_w = (rem_w >> lef_w);
rem_w = CUT_END(rem_w, lef_w);
map_w = han_u->map_w;
inx_w = _ch_popcount(CUT_END(map_w, bit_w));

tos_w = &(han_u->sot_w[inx_w]);

// nothing at slot, no-op
if ( !BIT_SET(map_w, bit_w) ) {
return c3n;
}

if ( c3n == _ch_slot_del(tos_w, key, lef_w, rem_w) ) {
// nothing deleted
return c3n;
}
else if ( 0 != *tos_w ) {
// something deleted, but slot still has value
return c3y;
}
else {
// shrink!
c3_w i_w, ken_w, len_w = _ch_popcount(map_w);
u3h_slot kes_w;

if ( 2 == len_w && ((ken_w = (0 == inx_w) ? 1 : 0),
(kes_w = han_u->sot_w[ken_w]),
(c3y == u3h_slot_is_noun(kes_w))) )
{
// only one side left, and the other is a noun. debucketize.
*sot_w = kes_w;
u3a_wfree(han_u);
}
else {
// shrink node in place; don't reallocate, we could be low on memory
//
han_u->map_w &= ~(1 << bit_w);
--len_w;

for ( i_w = inx_w; i_w < len_w; i_w++ ) {
han_u->sot_w[i_w] = han_u->sot_w[i_w + 1];
}
}
return c3y;
}
}

/* _ch_some_del(): delete from node or buck
*/
static c3_o
_ch_some_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w)
{
if ( 0 == lef_w ) {
return _ch_buck_del(sot_w, key);
}

return _ch_node_del(sot_w, key, lef_w, rem_w);
}

/* u3h_del(); delete from hashtable.
*/
void
u3h_del(u3p(u3h_root) har_p, u3_noun key)
{
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 = CUT_END(mug_w, 25);
u3h_slot* sot_w = &(har_u->sot_w[inx_w]);

if ( (c3n == u3h_slot_is_null(*sot_w))
&& (c3y == _ch_slot_del(sot_w, key, 25, rem_w)) )
{
har_u->use_w--;
}
}

/* _ch_uni_with(): key/value callback, put into [*wit]
*/
static void
Expand Down Expand Up @@ -667,6 +809,7 @@ u3h_get(u3p(u3h_root) har_p, u3_noun key)
static void
_ch_free_buck(u3h_buck* hab_u)
{
//fprintf(stderr, "free buck\r\n");
c3_w i_w;

for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
Expand All @@ -678,7 +821,7 @@ _ch_free_buck(u3h_buck* hab_u)
/* _ch_free_node(): free node.
*/
static void
_ch_free_node(u3h_node* han_u, c3_w lef_w)
_ch_free_node(u3h_node* han_u, c3_w lef_w, c3_o pin_o)
{
c3_w len_w = _ch_popcount(han_u->map_w);
c3_w i_w;
Expand All @@ -687,17 +830,16 @@ _ch_free_node(u3h_node* han_u, c3_w lef_w)

for ( i_w = 0; i_w < len_w; i_w++ ) {
c3_w sot_w = han_u->sot_w[i_w];

if ( _(u3h_slot_is_noun(sot_w)) ) {
if ( _(u3h_slot_is_null(sot_w))) {
} else if ( _(u3h_slot_is_noun(sot_w)) ) {
u3z(u3h_slot_to_noun(sot_w));
}
else {
} else {
void* hav_v = u3h_slot_to_node(sot_w);

if ( 0 == lef_w ) {
_ch_free_buck(hav_v);
} else {
_ch_free_node(hav_v, lef_w);
_ch_free_node(hav_v, lef_w, pin_o);
}
}
}
Expand All @@ -721,7 +863,7 @@ u3h_free(u3p(u3h_root) har_p)
else if ( _(u3h_slot_is_node(sot_w)) ) {
u3h_node* han_u = u3h_slot_to_node(sot_w);

_ch_free_node(han_u, 25);
_ch_free_node(han_u, 25, i_w == 57);
}
}
u3a_wfree(har_u);
Expand Down
7 changes: 7 additions & 0 deletions pkg/noun/hashtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@
u3_weak
u3h_git(u3p(u3h_root) har_p, u3_noun key);

/* u3h_del(); delete from hashtable.
**
** `key` is RETAINED
*/
void
u3h_del(u3p(u3h_root) har_p, u3_noun key);

/* u3h_trim_to(): trim to n key-value pairs
*/
void
Expand Down
71 changes: 71 additions & 0 deletions pkg/noun/hashtable_tests.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// @file

#include "noun.h"
#define TEST_SIZE 100000

// defined in noun/hashtable.c
c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w);
Expand All @@ -14,6 +15,75 @@ _setup(void)
u3m_pave(c3y);
}

/* _test_put_del():
*/
static c3_i
_test_put_del()
{
u3p(u3h_root) har_p = u3h_new();
c3_w i_w, j_w;
c3_i ret_i = 1;

for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) {
u3_noun key = u3i_word(i_w);
u3_noun val = u3nc(u3_nul, u3k(key));
u3h_put(har_p, key, val);
u3z(key);
}
fprintf(stderr, "inserted\r\n");

for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) {
u3_noun key = u3i_word(i_w);
u3_weak val = u3h_git(har_p, key);
if ( val == u3_none ) {
fprintf(stderr, "failed insert\r\n");
ret_i = 0;
}
u3z(key);
}
fprintf(stderr, "presence\r\n");

c3_w del_w[4] = {30, 82, 4921, 535};

for ( i_w = 0; i_w < 4; i_w++ ) {
u3_noun key = u3i_word(del_w[i_w]);
u3h_del(har_p, key);
u3z(key);
}
fprintf(stderr, "deleted\r\n");

for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) {
u3_noun key = u3i_word(i_w);
u3_weak val = u3h_git(har_p, key);
c3_o mis_o = __( val == u3_none );
c3_o del_o = c3n;

for ( j_w = 0; j_w < 4; j_w++ ) {
if ( i_w == del_w[j_w] ) {
del_o = c3y;
}
}

if ( mis_o != del_o ) {
if ( c3n == del_o ) {
fprintf(stderr, "delete collateral damage %u\r\n", i_w);
}
else {
fprintf(stderr, "failed delete %u\r\n", i_w);
}
ret_i = 0;
}

u3z(key);
}
fprintf(stderr, "presence two\r\n");

u3h_free(har_p);
fprintf(stderr, "freed\r\n");

return ret_i;
}

/* _test_bit_manipulation():
*/
static c3_i
Expand Down Expand Up @@ -220,6 +290,7 @@ _test_hashtable(void)
ret_i &= _test_skip_slot();
ret_i &= _test_cache_trimming();
ret_i &= _test_cache_replace_value();
ret_i &= _test_put_del();

return ret_i;
}
Expand Down
Loading