Incorporate HAMT into meme.c; delete old BPT.

This commit is contained in:
C. Guy Yarvin 2014-08-25 14:35:37 -07:00
parent 66bd19ed0a
commit af5352fc1a
9 changed files with 499 additions and 894 deletions

View File

@ -330,7 +330,7 @@ $(BIN)/vere: $(LIBCRE) $(VERE_OFILES) $(LIBUV) $(LIBRE2) $(LIBED25519) $(BPT_O)
meme: $(BIN)/meme meme: $(BIN)/meme
MEME_OFILES=f/meme.o $(BPT_O) f/nash.o f/pork.o \ MEME_OFILES=f/meme.o \
gen164/1/add.o \ gen164/1/add.o \
gen164/1/dec.o \ gen164/1/dec.o \
gen164/1/gth.o \ gen164/1/gth.o \

385
f/meme.c
View File

@ -22,7 +22,6 @@
#include <errno.h> #include <errno.h>
#include "f/meme.h" #include "f/meme.h"
#include "f/pork.h"
#include "../gen164/pit.h" #include "../gen164/pit.h"
/** Jet dependencies. Minimize these. /** Jet dependencies. Minimize these.
@ -3053,6 +3052,374 @@ u2_cr_tape(u2_noun a)
return a_y; 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(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]))) ) {
u2_ca_lose(key);
return u2_ca_gain(u2t(hab_u->kev[i_w]));
}
}
u2_ca_lose(key);
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)) ) {
u2_ca_lose(key);
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))) ) {
u2_ca_lose(key);
return u2_ca_gain(u2t(kev));
}
else {
u2_ca_lose(key);
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)) ) {
u2_ca_lose(key);
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);
u2_ca_lose(key);
return u2_ca_gain(u2t(kev));
}
else {
u2_ca_lose(key);
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);
}
#if 0 #if 0
static c3_w* static c3_w*
_test_walloc(c3_w siz_w) _test_walloc(c3_w siz_w)
@ -3503,15 +3870,15 @@ _test_hash_bad(void)
{ {
_road_dump(); _road_dump();
{ {
u2_ha_root* har_u = u2_ha_new(); u2_ch_root* har_u = u2_ch_new();
c3_w i_w; c3_w i_w;
c3_w max_w = (1 << 20); c3_w max_w = (1 << 20);
for ( i_w = 0; i_w < max_w; i_w++ ) { for ( i_w = 0; i_w < max_w; i_w++ ) {
u2_ha_put(har_u, u2nc(0, i_w), u2nc(0, (i_w + 1))); u2_ch_put(har_u, u2nc(0, i_w), u2nc(0, (i_w + 1)));
} }
for ( i_w = 0; i_w < max_w; i_w++ ) { for ( i_w = 0; i_w < max_w; i_w++ ) {
u2_noun val = u2_ha_get(har_u, u2nc(0, i_w)); u2_noun val = u2_ch_get(har_u, u2nc(0, i_w));
if ( u2_none == val ) { if ( u2_none == val ) {
printf("at %d, nothing\n", i_w); printf("at %d, nothing\n", i_w);
@ -3523,7 +3890,7 @@ _test_hash_bad(void)
} }
u2_ca_lose(val); u2_ca_lose(val);
} }
u2_ha_free(har_u); u2_ch_free(har_u);
} }
_road_dump(); _road_dump();
} }
@ -3533,15 +3900,15 @@ _test_hash(void)
{ {
_road_dump(); _road_dump();
{ {
u2_ha_root* har_u = u2_ha_new(); u2_ch_root* har_u = u2_ch_new();
c3_w i_w; c3_w i_w;
c3_w max_w = (1 << 20); c3_w max_w = (1 << 20);
for ( i_w = 0; i_w < max_w; i_w++ ) { for ( i_w = 0; i_w < max_w; i_w++ ) {
u2_ha_put(har_u, u2nc(0, i_w), (i_w + 1)); u2_ch_put(har_u, u2nc(0, i_w), (i_w + 1));
} }
for ( i_w = 0; i_w < max_w; i_w++ ) { for ( i_w = 0; i_w < max_w; i_w++ ) {
u2_noun val = u2_ha_get(har_u, u2nc(0, i_w)); u2_noun val = u2_ch_get(har_u, u2nc(0, i_w));
if ( val != (i_w + 1) ) { if ( val != (i_w + 1) ) {
if ( u2_none == val ) { if ( u2_none == val ) {
@ -3551,7 +3918,7 @@ _test_hash(void)
c3_assert(0); c3_assert(0);
} }
} }
u2_ha_free(har_u); u2_ch_free(har_u);
} }
_road_dump(); _road_dump();
} }

194
f/nash.c
View File

@ -1,194 +0,0 @@
/* f/nash.c
**
** This file is in the public domain.
*/
#include "all.h"
#include "f/nash.h"
#include <bitmapped_patricia_tree.h>
/* structures
*/
/* u2_nair: bucket node.
*/
struct u2_nair {
u2_noun key;
void* val;
};
/* u2_buck: realloced bucket.
*/
struct u2_buck {
c3_w con_w;
struct u2_nair* sto_u;
};
/* u2_nash: wrapper around Patricia trie.
*/
struct u2_nash {
bpt_t sto;
};
void u2_na_dump(struct u2_nash* nas_u);
/* u2_na_make(): create a new nounhash-table.
**
** nashtables live in C memory and do not take refs.
*/
struct u2_nash*
u2_na_make()
{
struct u2_nash* nas_u = calloc(1, sizeof(*nas_u));
c3_assert(nas_u);
// fprintf(stderr, "[%%nash-make %p]\r\n", nas_u);
return nas_u;
}
/* u2_na_put(): put into nash, replacing.
*/
void
u2_na_put(struct u2_nash* nas_u, u2_noun key, void* val)
{
struct u2_buck* buc_u = 0;
struct u2_nair* nuu_u = 0;
c3_w sot_w = 0;
c3_w i = 0;
u2_noun tom = u2_cr_mug(key);
if ( !bpt_has_key(nas_u->sto, tom)) {
bpt_t ots;
buc_u = calloc(1, sizeof(*buc_u));
c3_assert(buc_u);
ots = bpt_assoc(nas_u->sto, tom, buc_u);
bpt_release(nas_u->sto);
nas_u->sto = ots;
#if 0
fprintf(stderr, "[%%nash-sto %p %p]\r\n", nas_u->sto, tom);
if (!bpt_has_key(nas_u->sto, tom)) {
u2_na_dump(nas_u);
assert(0);
}
#endif
}
buc_u = bpt_get(nas_u->sto, tom);
if ( 0 == buc_u->con_w ) {
c3_assert(buc_u->sto_u == 0);
}
else {
for(i = 0; i < buc_u->con_w; i++) {
if (u2_cr_sing(buc_u->sto_u[i].key, key) == u2_yes) {
buc_u->sto_u[i].val = val;
#if 0
fprintf(stderr, "[%%nash-rep %p %p %d]\r\n",
(void*)key, (void*)val, i);
#endif
return;
}
}
}
sot_w = buc_u->con_w;
buc_u->con_w++;
nuu_u = realloc(buc_u->sto_u, buc_u->con_w * sizeof(struct u2_nair));
c3_assert(nuu_u);
nuu_u[sot_w].key = key;
nuu_u[sot_w].val = val;
buc_u->sto_u = nuu_u;
#if 0
fprintf(stderr, "[%%nash-put %p %p %d]\r\n",
(void*)key, (void*)val, sot_w);
#endif
}
/* u2_na_get(): get a noun from a nounhash table.
*/
u2_weak
u2_na_get(struct u2_nash* nas_u, u2_noun key)
{
u2_weak may;
c3_b fon;
may = (u2_noun)u2_na_get_ptr(nas_u, key, &fon);
if (fon == u2_no) {
return u2_none;
}
return (u2_noun)may;
}
/* u2_na_get_ptr(): get a pointer from a nounhash table, along with a
** bean indicating found status.
*/
void*
u2_na_get_ptr(struct u2_nash* nas_u, u2_noun key, c3_b* found)
{
struct u2_buck* buc_u = 0;
c3_w i;
u2_noun tom = u2_cr_mug(key);
*found = u2_no;
if ( !bpt_has_key(nas_u->sto, tom) ) {
// fprintf(stderr, "[%%nash-get-none %p %p]\r\n", nas_u->sto, tom);
return 0;
}
buc_u = bpt_get(nas_u->sto, tom);
for(i = 0; i < buc_u->con_w; i++) {
if (u2_cr_sing(buc_u->sto_u[i].key, key) == u2_yes) {
#if 0
fprintf(stderr, "[%%nash-get %p %p %d]\r\n",
(void*)key, (void*)buc_u->sto_u[i].val, i);
#endif
*found = u2_yes;
return buc_u->sto_u[i].val;
}
}
return 0;
}
/* _na_drop(): deallocate a node.
*/
static void
_na_drop(bpt_key_t x, void* a, void* b)
{
struct u2_buck* buc = a;
free(buc->sto_u);
free(buc);
}
/* _na_dump(): debugging dump.
*/
void
_na_dump(bpt_key_t x, void* a, void* b)
{
struct u2_buck* buc = a;
int i;
fprintf(stderr, "[%%nash-dump %x ", x);
for(i=0;i<buc->con_w;i++) {
fprintf(stderr, "%x->%p%s", buc->sto_u[i].key, buc->sto_u[i].val,
i+1==buc->con_w?"":" ");
}
fprintf(stderr, "]\r\n");
}
/* u2_na_dump(): debugging dump.
*/
void u2_na_dump(struct u2_nash* nas_u)
{
if(nas_u->sto) bpt_for_mappings(nas_u->sto, _na_dump, 0);
}
/* u2_na_take(): destroy a nounhash table.
*/
void
u2_na_take(struct u2_nash* nas_u)
{
if (nas_u->sto) bpt_for_mappings(nas_u->sto, _na_drop, 0);
bpt_release(nas_u->sto);
free(nas_u);
// fprintf(stderr, "[%%nash-take %p]\r\n", nash);
}

View File

@ -4,10 +4,9 @@
*/ */
#include "all.h" #include "all.h"
#include "../pit.h" #include "../pit.h"
#include "f/pork.h"
static u2_noun // produce static u2_noun // produce
_cue_in(u2_ha_root* har_u, _cue_in(u2_ch_root* har_u,
u2_atom a, // retain u2_atom a, // retain
u2_atom b) // retain u2_atom b) // retain
{ {
@ -20,7 +19,7 @@
p = j2_mbc(Pt1, inc)(u2k(u2h(c))); p = j2_mbc(Pt1, inc)(u2k(u2h(c)));
q = u2k(u2t(c)); q = u2k(u2t(c));
u2_ha_put(har_u, u2k(b), u2k(q)); u2_ch_put(har_u, u2k(b), u2k(q));
u2z(c); u2z(c);
u2z(x); u2z(x);
@ -42,13 +41,13 @@
p = j2_mbc(Pt1, add)(2, y); p = j2_mbc(Pt1, add)(2, y);
q = w; q = w;
u2_ha_put(har_u, u2k(b), u2k(q)); u2_ch_put(har_u, u2k(b), u2k(q));
u2z(u); u2z(v); u2z(x); u2z(y); u2z(u); u2z(v); u2z(x); u2z(y);
} }
else { else {
u2_noun d = j2_mby(Pt5, rub)(c, a); u2_noun d = j2_mby(Pt5, rub)(c, a);
u2_noun x = u2_ha_get(har_u, u2k(u2t(d))); u2_noun x = u2_ch_get(har_u, u2k(u2t(d)));
p = j2_mbc(Pt1, add)(2, u2h(d)); p = j2_mbc(Pt1, add)(2, u2h(d));
if ( u2_none == x ) { if ( u2_none == x ) {
@ -66,12 +65,12 @@
u2_noun // transfer u2_noun // transfer
j2_mby(Pt5, cue)(u2_atom a) // retain j2_mby(Pt5, cue)(u2_atom a) // retain
{ {
u2_ha_root* har_u = u2_ha_new(); u2_ch_root* har_u = u2_ch_new();
u2_noun x = _cue_in(har_u, a, 0); u2_noun x = _cue_in(har_u, a, 0);
u2_noun y = u2k(u2h(u2t(x))); u2_noun y = u2k(u2h(u2t(x)));
u2_ha_free(har_u); u2_ch_free(har_u);
u2z(x); u2z(x);
return y; return y;

View File

@ -4,15 +4,14 @@
*/ */
#include "all.h" #include "all.h"
#include "../pit.h" #include "../pit.h"
#include "f/pork.h"
/* functions /* functions
*/ */
static u2_noun static u2_noun
_jam_in(u2_ha_root* har_u, u2_atom, u2_atom, u2_noun); _jam_in(u2_ch_root* har_u, u2_atom, u2_atom, u2_noun);
static u2_noun // produce static u2_noun // produce
_jam_in_pair(u2_ha_root* har_u, _jam_in_pair(u2_ch_root* har_u,
u2_atom h_a, // retain u2_atom h_a, // retain
u2_atom t_a, // retain u2_atom t_a, // retain
u2_atom b, // retain u2_atom b, // retain
@ -49,7 +48,7 @@
} }
static u2_noun // produce static u2_noun // produce
_jam_in_flat(u2_ha_root* har_u, _jam_in_flat(u2_ch_root* har_u,
u2_atom a, // retain u2_atom a, // retain
u2_noun l) // retain u2_noun l) // retain
{ {
@ -64,7 +63,7 @@
} }
static u2_noun // produce static u2_noun // produce
_jam_in_ptr(u2_ha_root* har_u, _jam_in_ptr(u2_ch_root* har_u,
u2_atom u_c, // retain u2_atom u_c, // retain
u2_noun l) // retain u2_noun l) // retain
{ {
@ -81,16 +80,16 @@
} }
static u2_noun // produce static u2_noun // produce
_jam_in(u2_ha_root* har_u, _jam_in(u2_ch_root* har_u,
u2_noun a, // retain u2_noun a, // retain
u2_atom b, // retain u2_atom b, // retain
u2_noun l) // retain u2_noun l) // retain
{ {
u2_noun c = u2_ha_get(har_u, u2k(a)); u2_noun c = u2_ch_get(har_u, u2k(a));
u2_noun x; u2_noun x;
if ( u2_none == c ) { if ( u2_none == c ) {
u2_ha_put(har_u, u2k(a), u2k(b)); u2_ch_put(har_u, u2k(a), u2k(b));
if ( u2_yes == u2ud(a) ) { if ( u2_yes == u2ud(a) ) {
x = _jam_in_flat(har_u, a, l); x = _jam_in_flat(har_u, a, l);
@ -112,7 +111,7 @@
u2_noun // transfer u2_noun // transfer
j2_mby(Pt5, jam)(u2_atom a) // retain j2_mby(Pt5, jam)(u2_atom a) // retain
{ {
u2_ha_root* har_u = u2_ha_new(); u2_ch_root* har_u = u2_ch_new();
u2_noun x = _jam_in(har_u, a, 0, u2_nul); u2_noun x = _jam_in(har_u, a, 0, u2_nul);
u2_noun q = j2_mbc(Pt2, flop)(u2h(u2t(x))); u2_noun q = j2_mbc(Pt2, flop)(u2h(u2t(x)));
@ -120,7 +119,7 @@
u2z(x); u2z(x);
u2z(q); u2z(q);
u2_ha_free(har_u); u2_ch_free(har_u);
return r; return r;
} }
u2_noun // transfer u2_noun // transfer

View File

@ -6,7 +6,7 @@
*** ***
*** u2_ca_: fundamental allocators. *** u2_ca_: fundamental allocators.
*** u2_cc_: constants. *** u2_cc_: constants.
*** u2_ch_: memoization. *** u2_ch_: HAMT hash tables.
*** u2_ci_: noun constructors *** u2_ci_: noun constructors
*** u2_cj_: jets. *** u2_cj_: jets.
*** u2_ck_: direct jet calls. *** u2_ck_: direct jet calls.
@ -17,6 +17,7 @@
*** u2_cs_: structures and definitions. *** u2_cs_: structures and definitions.
*** u2_ct_: tracing. *** u2_ct_: tracing.
*** u2_cx_: read functions which do bail out. *** u2_cx_: read functions which do bail out.
*** u2_cz_: memoization.
*** ***
*** u2_cr_ and u2_cx_ functions use retain conventions; the caller *** u2_cr_ and u2_cx_ functions use retain conventions; the caller
*** retains ownership of passed-in nouns, the callee preserves *** retains ownership of passed-in nouns, the callee preserves
@ -199,6 +200,75 @@
? ( ((u2_cs_cell *)u2_co_to_ptr(som))->tel )\ ? ( ((u2_cs_cell *)u2_co_to_ptr(som))->tel )\
: u2_cm_bail(c3__exit) ) : u2_cm_bail(c3__exit) )
/** Straightforward implementation of the classic Bagwell
*** HAMT (hash array mapped trie), using a mug hash.
***
*** Because a mug is 31 bits, the root table is 64 wide.
*** Thereupon 5 bits each are warm for each layer. The
*** final leaf is simply a linear search.
***
*** We store an extra "freshly warm" bit for a simple
*** clock-algorithm reclamation policy, not yet implemented.
*** Search "clock algorithm" to figure it out.
**/
/* u2_ch_slot: map slot.
**
** Either a key-value cell or a loom offset, decoded as a pointer
** to a u2_ch_node. Matches the u2_noun format - coordinate with
** meme.h. The top two bits are:
**
** 00 - empty (in the root table only)
** 01 - table
** 02 - entry, stale
** 03 - entry, fresh
*/
typedef c3_w u2_ch_slot;
/* u2_ch_node: map node.
*/
typedef struct {
c3_w map_w;
u2_ch_slot sot_w[0];
} u2_ch_node;
/* u2_ch_root: hash root table, with future-proof clock.
*/
typedef struct {
c3_w clk_w;
u2_ch_slot sot_w[64];
} u2_ch_root;
/* u2_ch_buck: bottom bucket.
*/
typedef struct {
c3_w len_w;
u2_noun kev[0];
} u2_ch_buck;
/** HAMT macros.
***
*** Coordinate with u2_noun definition!
**/
/* u2_ch_slot_is_null(): yes iff slot is empty
** u2_ch_slot_is_noun(): yes iff slot contains a key/value cell
** u2_ch_slot_is_node(): yes iff slot contains a subtable/bucket
** u2_ch_slot_is_warm(): yes iff fresh bit is set
** u2_ch_slot_to_node(): slot to node pointer
** u2_ch_node_to_slot(): node pointer to slot
** u2_ch_slot_to_noun(): slot to cell
** u2_ch_noun_to_slot(): cell to slot
*/
# define u2_ch_slot_is_null(sot) ((0 == ((sot) >> 30)) ? u2_yes : u2_no)
# define u2_ch_slot_is_node(sot) ((1 == ((sot) >> 30)) ? u2_yes : u2_no)
# define u2_ch_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? u2_yes : u2_no)
# define u2_ch_slot_is_warm(sot) (((sot) & 0x40000000) ? u2_yes : u2_no)
# define u2_ch_slot_to_node(sot) (u2_co_into((sot) & 0x3fffffff))
# define u2_ch_node_to_slot(ptr) (u2_co_outa(ptr) | 0x40000000)
# define u2_ch_slot_to_noun(sot) (0x40000000 | (sot))
# define u2_ch_noun_to_slot(som) (som)
# define u2_ch_noun_be_warm(sot) ((sot) | 0x40000000)
# define u2_ch_noun_be_cold(sot) ((sot) & ~0x40000000)
/* u2_cs_box: classic allocation box. /* u2_cs_box: classic allocation box.
** **
** The box size is also stored at the end of the box in classic ** The box size is also stored at the end of the box in classic
@ -1134,6 +1204,30 @@
u2_noun u2_noun
u2_cn_nock_an(u2_noun bus, u2_noun fol); u2_cn_nock_an(u2_noun bus, u2_noun fol);
/** Functions.
***
*** Needs: delete and merge functions; clock reclamation function.
**/
/* u2_ch_new(): create hashtable.
*/
u2_ch_root*
u2_ch_new(void);
/* u2_ch_put(): insert in hashtable.
*/
void
u2_ch_put(u2_ch_root* har_u, u2_noun key, u2_noun val);
/* u2_ch_get(): read from hashtable.
*/
u2_weak
u2_ch_get(u2_ch_root* har_u, u2_noun key);
/* u2_ch_free(): free hashtable.
*/
void
u2_ch_free(u2_ch_root* har_u);
/** Jet firing. (Change retain protocols!) /** Jet firing. (Change retain protocols!)
**/ **/
@ -1185,25 +1279,25 @@
*** ***
*** The memo cache is within its road and dies when it falls. *** The memo cache is within its road and dies when it falls.
**/ **/
/* u2_ch_find*(): find in memo cache. /* u2_cz_find*(): find in memo cache.
*/ */
u2_weak u2_ch_find(u2_mote, u2_noun); u2_weak u2_cz_find(u2_mote, u2_noun);
u2_weak u2_ch_find_2(u2_mote, u2_noun, u2_noun); u2_weak u2_cz_find_2(u2_mote, u2_noun, u2_noun);
u2_weak u2_ch_find_3(u2_mote, u2_noun, u2_noun, u2_noun); u2_weak u2_cz_find_3(u2_mote, u2_noun, u2_noun, u2_noun);
u2_weak u2_ch_find_4(u2_mote, u2_noun, u2_noun, u2_noun, u2_noun); u2_weak u2_cz_find_4(u2_mote, u2_noun, u2_noun, u2_noun, u2_noun);
/* u2_ch_save*(): save in memo cache. /* u2_cz_save*(): save in memo cache.
*/ */
u2_weak u2_ch_save(u2_mote, u2_noun, u2_noun); u2_weak u2_cz_save(u2_mote, u2_noun, u2_noun);
u2_weak u2_ch_save_2(u2_mote, u2_noun, u2_noun, u2_noun); u2_weak u2_cz_save_2(u2_mote, u2_noun, u2_noun, u2_noun);
u2_weak u2_ch_save_3(u2_mote, u2_noun, u2_noun, u2_noun, u2_noun); u2_weak u2_cz_save_3(u2_mote, u2_noun, u2_noun, u2_noun, u2_noun);
u2_weak u2_ch_save_4 u2_weak u2_cz_save_4
(u2_mote, u2_noun, u2_noun, u2_noun, u2_noun, u2_noun); (u2_mote, u2_noun, u2_noun, u2_noun, u2_noun, u2_noun);
/* u2_ch_uniq(): uniquify with memo cache. /* u2_cz_uniq(): uniquify with memo cache.
*/ */
u2_weak u2_weak
u2_ch_uniq(u2_noun som); u2_cz_uniq(u2_noun som);
/* u2_ck: kernel and related functions /* u2_ck: kernel and related functions

View File

@ -1,46 +0,0 @@
/* include/f/nash.h
**
** This file is in the public domain.
*/
/** Hash-table design:
***
*** u2_nash is a non-noun hash-table, meant for ephemeral usage such as
*** in jam and cue.
***
*** It uses a Patricia trie keyed on the mug of the actual key, and then
*** a vector of key-value pairs to resolve collisions.
**/
/* Opaque structure holding hash table.
*/
struct u2_nash;
/* Functions
*/
/* u2_na_make(): create a new nash.
*/
struct u2_nash*
u2_na_make();
/* u2_na_put(): put an entry in the hash table.
*/
void
u2_na_put(struct u2_nash* nash, u2_noun key, void* val);
/* u2_na_get(): retrieve an entry from the hash table, or u2_none.
*/
u2_weak
u2_na_get(struct u2_nash* nash, u2_noun key);
/* u2_na_get_ptr(): retrieve a pointer entry from the hash table, or u2_none.
*/
void*
u2_na_get_ptr(struct u2_nash* nash, u2_noun key, c3_b* fon);
/* u2_na_take(): destroy a nash.
*/
void
u2_na_take(struct u2_nash* nash);

View File

@ -1,543 +0,0 @@
// -*- mode: c; coding: utf-8 -*- */
//
// Copyright 2010, 2011, Matthias Andreas Benkard.
//
//-----------------------------------------------------------------------------
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//-----------------------------------------------------------------------------
//
// An implementation of a bitmapped Patricia tree.
//// Purpose ////
//
// The idea is to use a locally mutable, bitmapped Patricia tree as a
// variable binding store (i.e. environment) in compiled code. In this
// way, there is no need for excessive copying when an independent
// environment must be set up (such as when initiating the processing of
// a new node in the search space). Instead, significant amounts of
// structure can be shared between child and parent environments.
//// Motivation ////
//
// 1. Patricia trees are very amenable to structure sharing.
//
// 2. Furthermore, big-endian Patricia trees are especially efficient
// when indices are allocated sequentially, as is the case for
// variables in code emitted by our compiler.
//
// 3. Finally, bitmapping improves the performance of copying because
// copying an array is much cheaper than copying an equivalent branch
// in a tree. As we need to shallow-copy the tree at potentially
// each choice point, copying needs to be fast.
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "bitmapped_patricia_tree.h"
#if 1
/* u2_ca_malloc(): allocate storage measured in bytes.
*/
void*
u2_ca_malloc(uint32_t len_w);
/* u2_ca_free(): free storage.
*/
void
u2_ca_free(void* lag_v);
/* u2_ca_realloc(): crude realloc.
*/
void*
u2_ca_realloc(void* lag_v, uint32_t len_w);
#define malloc u2_ca_malloc
#define realloc u2_ca_realloc
#define free u2_ca_free
#endif
#ifndef BPT_EXPLICIT_CONFIGURATION
#define CHUNK_LENGTH 5
#define KEY_LENGTH 32
#define OFFSET_MASK 0x1f //((1 << chunk_length) - 1)
#define MAX_CHUNKS 7 //key_length / chunk_length + ((key_length % chunk_length == 0) ? 0 : 1)
#define LAST_CHUNK_LENGTH 2 //key_length - ((max_chunks - 1) * chunk_length)
#endif //!BPT_EXPLICIT_CONFIGURATION
typedef struct bpt_nonempty *bpt_nonempty_t;
typedef struct bpt_node *bpt_node_t;
typedef struct bpt_leaf *bpt_leaf_t;
struct bpt {
enum bpt_tag tag;
int refcount;
bool mutable;
bpt_key_t prefix;
};
struct bpt_leaf {
struct bpt bpt; // poor man's inheritance
void *value;
#ifdef BPT_ENABLE_DEALLOC_HOOKS
void (*dealloc_hook)(bpt_key_t, void *); // not actually used anywhere in client code
#endif
};
struct bpt_node {
struct bpt bpt; // poor man's inheritance
unsigned int branching_chunk;
bpt_key_bitmask_t bitmask;
bpt_t *children;
};
// Forward declarations.
void init_bpt_leaf(bpt_t leaf, bpt_key_t key, void *value);
bpt_t bpt_make_leaf(bpt_key_t key, void *value);
// Boilerplate definitions.
void bpt_retain0(bpt_t bpt, void *user_data) {
bpt_retain(bpt);
}
void bpt_seal0(bpt_t bpt, void *user_data) {
bpt_seal(bpt);
}
void bpt_release0(bpt_t bpt, void *user_data) {
bpt_release(bpt);
}
// Implementation.
void init_bpt_leaf(bpt_t a_leaf, bpt_key_t key, void *value) {
bpt_leaf_t leaf = (bpt_leaf_t)a_leaf;
leaf->bpt.tag = BPT_LEAF;
leaf->bpt.mutable = true;
leaf->bpt.prefix = key;
leaf->value = value;
#ifdef BPT_ENABLE_DEALLOC_HOOKS
leaf->dealloc_hook = NULL;
#endif
leaf->bpt.refcount = 1;
}
void init_bpt_node(bpt_node_t node, bpt_key_t prefix, unsigned int branching_chunk) {
node->bpt.tag = BPT_INNER_NODE;
node->bpt.mutable = true;
node->bpt.prefix = prefix;
node->branching_chunk = branching_chunk;
node->bitmask = 0;
node->children = NULL;
node->bpt.refcount = 1;
}
bpt_t bpt_make_leaf(bpt_key_t key, void *value) {
bpt_leaf_t leaf = malloc(sizeof *leaf);
init_bpt_leaf((bpt_t)leaf, key, value);
return (bpt_t)leaf;
}
bpt_node_t bpt_make_node(bpt_key_t prefix, unsigned int branching_chunk) {
bpt_node_t node = malloc(sizeof *node);
init_bpt_node(node, prefix, branching_chunk);
return node;
}
static inline unsigned int bpt_number_of_leading_zeros(bpt_key_t x);
static inline unsigned int bpt_number_of_trailing_zeros(bpt_key_t x);
static inline unsigned int bpt_popcount(bpt_key_bitmask_t key);
static unsigned int bpt_compute_child_index(bpt_key_bitmask_t bitmask, unsigned int child_number);
static inline uint_fast8_t bpt_offset_of_key(bpt_key_t key, unsigned int branching_chunk);
static bpt_key_t bpt_prefix_of_key(bpt_key_t key, unsigned int branching_chunk);
static inline unsigned int bpt_branching_chunk(bpt_t bpt);
static unsigned int bpt_find_diverging_chunk(bpt_key_t key1, bpt_key_t key2);
static void bpt_for_children(bpt_t bpt, void (*thunk)(bpt_t, void*), void *user_data);
static void bpt_for_children(bpt_t bpt, void (*thunk)(bpt_t, void*), void *user_data) {
if (bpt && bpt->tag == BPT_INNER_NODE) {
bpt_node_t b = (bpt_node_t)bpt;
bpt_t *iter = b->children;
bpt_t *children_end = b->children + bpt_popcount(b->bitmask);
while (iter < children_end) {
thunk(*iter, user_data);
iter++;
}
}
}
void *bpt_get(bpt_t bpt, bpt_key_t key) {
void **pointer = bpt_get_pointer(bpt, key);
if (pointer) {
return *pointer;
} else {
return NULL;
}
}
bpt_leaf_t bpt_get_leaf(bpt_t bpt, bpt_key_t key)
{
if (!bpt) {
return NULL;
} else if (bpt->tag == BPT_LEAF) {
bpt_leaf_t b = (bpt_leaf_t)bpt;
if (bpt->prefix == key) {
return b;
} else {
return NULL;
}
} else {
bpt_node_t b = (bpt_node_t)bpt;
int child_number = bpt_offset_of_key(key, b->branching_chunk);
if ((1 << child_number) & b->bitmask) {
int child_index = bpt_compute_child_index(b->bitmask, child_number);
return bpt_get_leaf(b->children[child_index], key);
} else {
return NULL;
}
}
}
void **bpt_get_pointer(bpt_t bpt, bpt_key_t key)
{
bpt_leaf_t leaf = bpt_get_leaf(bpt, key);
if (!leaf) {
return NULL;
} else {
return &leaf->value;
}
}
bool bpt_has_key(bpt_t bpt, bpt_key_t key) {
return (bpt_get_leaf(bpt, key) != NULL);
}
bpt_t bpt_assoc(bpt_t bpt, bpt_key_t key, void *value) {
if (!bpt) {
return (bpt_t)bpt_make_leaf(key, value);
} else {
bpt_key_t prefix = bpt->prefix;
if (bpt_prefix_of_key(key, bpt_branching_chunk(bpt)) != prefix) {
unsigned int diverging_chunk = bpt_find_diverging_chunk(key, prefix);
bpt_key_t my_number_in_parent = bpt_offset_of_key(prefix, diverging_chunk);
bpt_key_t their_number_in_parent = bpt_offset_of_key(key, diverging_chunk);
bpt_node_t new_node = bpt_make_node(bpt_prefix_of_key(prefix, diverging_chunk), diverging_chunk);
new_node->bitmask = (1 << my_number_in_parent) | (1 << their_number_in_parent);
new_node->children = malloc(sizeof (*new_node->children) * 2);
if (my_number_in_parent < their_number_in_parent) {
new_node->children[0] = bpt;
new_node->children[1] = bpt_make_leaf(key, value);
} else {
new_node->children[0] = bpt_make_leaf(key, value);
new_node->children[1] = bpt;
}
bpt_retain(bpt);
return (bpt_t)new_node;
} else {
if (bpt->tag == BPT_LEAF) {
bpt_leaf_t b = (bpt_leaf_t)bpt;
if (bpt->mutable) {
b->value = value;
bpt_retain(bpt);
return bpt;
} else {
return (bpt_t)bpt_make_leaf(key, value);
}
} else {
bpt_node_t b = (bpt_node_t)bpt;
uint_fast8_t child_number = bpt_offset_of_key(key, b->branching_chunk);
unsigned int child_index = bpt_compute_child_index(b->bitmask, child_number);
if ((1 << child_number) & b->bitmask) {
// We already have a child to pass the value to. Do that.
bpt_t child = b->children[child_index];
bpt_t new_child = bpt_assoc(child, key, value);
if (new_child == child) {
bpt_release(child);
bpt_retain(bpt);
return bpt;
} else {
if (bpt->mutable) {
bpt_release(child);
b->children[child_index] = new_child;
bpt_retain(bpt);
return bpt;
} else {
bpt_node_t new_node = malloc(sizeof *new_node);
*new_node = *b;
new_node->bpt.refcount = 1;
new_node->bpt.mutable = true;
unsigned int number_of_children = bpt_popcount(b->bitmask);
size_t size_of_child_array = sizeof (*new_node->children) * number_of_children;
new_node->children = malloc(size_of_child_array);
memcpy(new_node->children, b->children, size_of_child_array);
new_node->children[child_index] = new_child;
// Retain the children copied into the new node.
bpt_for_children((bpt_t)new_node, bpt_retain0, NULL);
bpt_release(new_child);
return (bpt_t)new_node;
}
}
} else {
// Create a new child.
unsigned int number_of_children = bpt_popcount(b->bitmask);
size_t new_size_of_child_array = sizeof (*b->children) * (number_of_children + 1);
if (bpt->mutable) {
b->children = realloc(b->children, new_size_of_child_array);
memmove(b->children + child_index + 1, b->children + child_index, sizeof (*b->children) * (number_of_children - child_index));
b->children[child_index] = bpt_make_leaf(key, value);
b->bitmask |= 1 << child_number;
bpt_retain(bpt);
return bpt;
} else {
bpt_t *new_children = malloc(new_size_of_child_array);
memcpy(new_children, b->children, sizeof (*b->children) * child_index);
memcpy(new_children + child_index + 1,
b->children + child_index,
sizeof (*b->children) * (number_of_children - child_index));
new_children[child_index] = bpt_make_leaf(key, value);
bpt_node_t new_node = bpt_make_node(b->bpt.prefix, b->branching_chunk);
new_node->children = new_children;
new_node->bitmask = b->bitmask | (1 << child_number);
// Retain the children copied into the new node.
bpt_for_children(bpt, bpt_retain0, NULL);
return (bpt_t)new_node;
}
}
}
}
}
}
bpt_t bpt_dissoc(bpt_t bpt, bpt_key_t key) {
if (!bpt || (bpt_prefix_of_key(key, bpt_branching_chunk(bpt)) != bpt->prefix)) {
bpt_retain(bpt);
return bpt;
} else if (bpt->tag == BPT_LEAF) {
// Key matches.
return NULL;
} else {
// Prefix matches.
bpt_node_t b = (bpt_node_t)bpt;
uint_fast8_t child_number = bpt_offset_of_key(key, b->branching_chunk);
if ((1 << child_number) & b->bitmask) {
unsigned int child_index = bpt_compute_child_index(b->bitmask, child_number);
bpt_t child = b->children[child_index];
bpt_t new_child = bpt_dissoc(child, key);
if (new_child == child) {
bpt_release(child);
bpt_retain(bpt);
return bpt;
} else {
unsigned int number_of_children = bpt_popcount(b->bitmask);
if (!new_child && number_of_children == 2) {
// When there is only a single child left, we replace ourselves
// with that child.
bpt_t remaining_child = b->children[1-child_index];
bpt_retain(remaining_child);
return remaining_child;
} else if (bpt->mutable) {
bpt_release(child);
if (!new_child) {
// We don't reallocate the array because it wouldn't really
// gain us anything (except maybe non-confusion of a
// conservative GC).
memmove(b->children + child_index, b->children + child_index + 1, sizeof(*b->children) * (number_of_children - child_index - 1));
b->bitmask &= ~(1 << child_number);
bpt_retain(bpt);
return bpt;
} else {
b->children[child_index] = new_child;
bpt_retain(bpt);
return bpt;
}
} else {
// If all else fails, allocate a new node.
bpt_t *new_children;
bpt_key_bitmask_t bitmask;
if (!new_child) {
new_children = malloc((sizeof *new_children) * (number_of_children - 1));
memcpy(new_children, b->children, sizeof (*b->children) * child_index);
memcpy(new_children + child_index,
b->children + child_index + 1,
sizeof (*b->children) * (number_of_children - child_index - 1));
bitmask = b->bitmask & ~(1 << child_number);
} else {
new_children = malloc((sizeof *new_children) * number_of_children);
memcpy(new_children, b->children, sizeof (*b->children) * number_of_children);
new_children[child_index] = new_child;
bitmask = b->bitmask;
}
bpt_node_t new_node = bpt_make_node(b->bpt.prefix, b->branching_chunk);
new_node->children = new_children;
new_node->bitmask = bitmask;
// Retain the children copied into the new node.
bpt_for_children((bpt_t)new_node, bpt_retain0, NULL);
bpt_release(new_child);
return (bpt_t)new_node;
}
}
} else {
bpt_retain(bpt);
return bpt;
}
}
}
void bpt_seal(bpt_t bpt) {
if (bpt) {
if (bpt->mutable) {
bpt->mutable = false;
if (bpt->tag == BPT_INNER_NODE) {
bpt_for_children(bpt, bpt_seal0, NULL);
}
}
}
}
/////////////// Helper functions ///////////////
static unsigned int bpt_compute_child_index(bpt_key_bitmask_t bitmask, unsigned int child_number) {
// Compute the sparse array index given a flat array index.
return bpt_popcount(bitmask & ((1 << child_number) - 1));
}
static inline uint_fast8_t bpt_offset_of_key(bpt_key_t key, unsigned int chunk_number) {
// Little-enidan:
//return (key >> (chunk_number * CHUNK_LENGTH)) & OFFSET_MASK;
// Big-endian:
int shift = 0;
if (chunk_number <= MAX_CHUNKS - 2) {
shift += LAST_CHUNK_LENGTH;
}
if (chunk_number <= MAX_CHUNKS - 3) {
shift += ((MAX_CHUNKS - 2 - chunk_number) * CHUNK_LENGTH);
}
return (key >> shift) & (chunk_number == MAX_CHUNKS - 1 ? ((1 << LAST_CHUNK_LENGTH) - 1) : OFFSET_MASK);
}
static bpt_key_t bpt_prefix_of_key(bpt_key_t key, unsigned int chunk_number) {
if (chunk_number == MAX_CHUNKS) {
return key;
} else {
// Little-endian:
//return key & ((1 << (chunk_number * CHUNK_LENGTH)) - 1)
// Big-endian:
return key & (((1 << (chunk_number * CHUNK_LENGTH)) - 1) << (KEY_LENGTH - (chunk_number * CHUNK_LENGTH)));
}
}
static inline unsigned int bpt_branching_chunk(bpt_t bpt) {
assert(bpt);
if (bpt->tag == BPT_LEAF) {
return MAX_CHUNKS;
} else {
return ((bpt_node_t)bpt)->branching_chunk;
}
}
static inline unsigned int bpt_popcount(bpt_key_bitmask_t x) {
return __builtin_popcount(x);
}
static inline unsigned int bpt_number_of_leading_zeros(bpt_key_t x) {
return __builtin_clz(x);
}
static inline unsigned int bpt_number_of_trailing_zeros(bpt_key_t x) {
return __builtin_ctz(x);
}
static unsigned int bpt_find_diverging_chunk(bpt_key_t a, bpt_key_t b) {
// Little-endian:
//return bpt_number_of_trailing_zeros(a ^ b) / CHUNK_LENGTH;
// Big-endian:
return bpt_number_of_leading_zeros(a ^ b) / CHUNK_LENGTH;
}
void bpt_retain(bpt_t bpt) {
if (bpt) {
__sync_fetch_and_add(&bpt->refcount, 1);
}
}
void bpt_release(bpt_t bpt) {
if (bpt) {
if (__sync_sub_and_fetch(&bpt->refcount, 1) == 0) {
bpt_dealloc(bpt);
}
}
}
void bpt_dealloc(bpt_t bpt) {
if (bpt) {
if (bpt->tag == BPT_LEAF) {
bpt_leaf_t b = (bpt_leaf_t)bpt;
#ifdef BPT_ENABLE_DEALLOC_HOOKS
if (b->dealloc_hook) {
b->dealloc_hook(b->bpt.prefix, b->value);
}
#endif
free(b);
} else {
bpt_node_t b = (bpt_node_t)bpt;
bpt_for_children(bpt, bpt_release0, NULL);
free(b->children);
free(b);
}
}
}
#ifdef BPT_ENABLE_DEALLOC_HOOKS
void bpt_leaf_set_dealloc_hook(bpt_leaf_t bpt, void (*hook)(bpt_key_t, void*)) {
if (bpt) {
bpt->dealloc_hook = hook;
}
}
void bpt_set_dealloc_hook(bpt_t bpt, bpt_key_t key, void (*hook)(bpt_key_t, void*)) {
bpt_leaf_set_dealloc_hook(bpt_get_leaf(bpt, key), hook);
}
#endif
/* Utilities */
struct bpt_for_mappings_closure_data {
void (*thunk)(bpt_key_t, void*, void*);
void *user_data;
};
static void bpt_for_mappings_iter(bpt_t bpt, void *closure_data_) {
struct bpt_for_mappings_closure_data *closure_data = closure_data_;
if (bpt->tag == BPT_LEAF) {
bpt_leaf_t leaf = (bpt_leaf_t)bpt;
closure_data->thunk(bpt->prefix, leaf->value, closure_data->user_data);
} else {
bpt_for_children(bpt, bpt_for_mappings_iter, closure_data);
}
}
void bpt_for_mappings(bpt_t bpt, void (*thunk)(bpt_key_t, void*, void*), void *user_data) {
struct bpt_for_mappings_closure_data closure_data =
{ .user_data = user_data, .thunk = thunk };
bpt_for_mappings_iter(bpt, &closure_data);
}

View File

@ -1,71 +0,0 @@
// -*- mode: c; coding: utf-8 -*- */
//
// Copyright 2010, 2011, Matthias Andreas Benkard.
//
//-----------------------------------------------------------------------------
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//-----------------------------------------------------------------------------
//
// An implementation of a bitmapped Patricia tree.
#ifndef __BITMAPPED_PATRICIA_TREE_H
#define __BITMAPPED_PATRICIA_TREE_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define BPT_ENABLE_DEALLOC_HOOKS 1
#ifdef BPT_EXPLICIT_CONFIGURATION
typedef BPT_KEY_T bpt_key_t;
typedef BPT_KEY_BITMASK_T bpt_key_bitmask_t;
#else
typedef int32_t bpt_key_t;
typedef int32_t bpt_key_bitmask_t;
#endif //!BPT_EXPLICIT_CONFIGURATION
enum bpt_tag {
BPT_LEAF,
BPT_INNER_NODE
};
struct bpt;
typedef struct bpt *bpt_t;
// Base functionality.
void *bpt_get(bpt_t bpt, bpt_key_t key);
bool bpt_has_key(bpt_t bpt, bpt_key_t key);
void **bpt_get_pointer(bpt_t bpt, bpt_key_t key);
bpt_t bpt_assoc(bpt_t bpt, bpt_key_t key, void *item);
bpt_t bpt_dissoc(bpt_t bpt, bpt_key_t key);
void bpt_retain(bpt_t bpt);
void bpt_release(bpt_t bpt);
void bpt_dealloc(bpt_t bpt);
void bpt_seal(bpt_t bpt);
// Utilities
void bpt_for_mappings(bpt_t bpt, void (*thunk)(bpt_key_t, void*, void*), void *user_data);
#ifdef BPT_ENABLE_DEALLOC_HOOKS
void bpt_set_dealloc_hook(bpt_t bpt, bpt_key_t key, void (*hook)(bpt_key_t key, void* value));
#endif
#ifdef __cplusplus
}
#endif
#endif