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 3 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
142 changes: 135 additions & 7 deletions pkg/noun/hashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,134 @@ u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val)
}
}

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

/* _ch_buck_del(): delete from bucket
*/
static c3_o
_ch_buck_del(u3h_slot* sot_w, u3_noun key, c3_w *use_w)
{
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]));
//u3z(u3h_slot_to_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];
}

*use_w -= 1;
return c3y;
}
}

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

static c3_o
_ch_slot_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w, c3_w* use_w) {
if ( c3y == u3h_slot_is_noun(*sot_w) ) {
u3_noun kev = u3h_slot_to_noun(*sot_w);
*sot_w = 0;
u3z(kev);
*use_w -= 1;
return c3y;
} else {
return _ch_some_del(sot_w, key, lef_w, rem_w, use_w);
}
}

static c3_o
_ch_node_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w, c3_w* use_w)
{
u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_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));

// nothing at slot, no-op
if ( !BIT_SET(map_w, bit_w) ) {
return c3n;
}
c3_w ken_w;
u3h_slot kes_w;
u3h_slot don_w = han_u->sot_w[inx_w];
c3_w len_w = _ch_popcount(map_w);
if ( len_w == 2 && ((ken_w = (0 == inx_w) ? 1 : 0),
(kes_w = han_u->sot_w[ken_w]),
(c3y == u3h_slot_is_noun(don_w) && c3y == u3h_slot_is_noun(kes_w))) ) {
*sot_w = kes_w;
u3z(u3h_slot_to_noun(don_w));
*use_w -= 1;
u3a_wfree(han_u);
return c3y;
}
c3_o ret_o = _ch_slot_del(&han_u->sot_w[inx_w], key, lef_w, rem_w, use_w);
if ( c3y == ret_o && c3y == u3h_slot_is_null(han_u->sot_w[inx_w]) ) {
han_u->map_w &= ~(1 << bit_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 ret_o;
}


static c3_o
_ch_some_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w, c3_w* use_w)
{
if ( 0 == lef_w ) {
return _ch_buck_del(sot_w, key, use_w);
}
//u3h_node* han_u = (u3h_node*)han_v;
//if ( _ch_popcount(han_u))
return _ch_node_del(sot_w, key, lef_w, rem_w, use_w);
}



/** TODO: this has a bug where the freeing a hamt that this has been called with failes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joemfb This seems like something that should be addressed before merging.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's obsolete, but need to confirm before removing it. These changes need a full review, didn't want them to sneak in.

* most likelly memroy mgmt
*/
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 ( c3y == u3h_slot_is_null(*sot_w) ) {
return;
} else {
_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 +795,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 +807,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 +816,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 +849,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