mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-28 11:40:11 +03:00
Incorporate HAMT into meme.c; delete old BPT.
This commit is contained in:
parent
66bd19ed0a
commit
af5352fc1a
2
Makefile
2
Makefile
@ -330,7 +330,7 @@ $(BIN)/vere: $(LIBCRE) $(VERE_OFILES) $(LIBUV) $(LIBRE2) $(LIBED25519) $(BPT_O)
|
||||
|
||||
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/dec.o \
|
||||
gen164/1/gth.o \
|
||||
|
385
f/meme.c
385
f/meme.c
@ -22,7 +22,6 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "f/meme.h"
|
||||
#include "f/pork.h"
|
||||
#include "../gen164/pit.h"
|
||||
|
||||
/** Jet dependencies. Minimize these.
|
||||
@ -3053,6 +3052,374 @@ u2_cr_tape(u2_noun a)
|
||||
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
|
||||
static c3_w*
|
||||
_test_walloc(c3_w siz_w)
|
||||
@ -3503,15 +3870,15 @@ _test_hash_bad(void)
|
||||
{
|
||||
_road_dump();
|
||||
{
|
||||
u2_ha_root* har_u = u2_ha_new();
|
||||
u2_ch_root* har_u = u2_ch_new();
|
||||
c3_w i_w;
|
||||
c3_w max_w = (1 << 20);
|
||||
|
||||
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++ ) {
|
||||
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 ) {
|
||||
printf("at %d, nothing\n", i_w);
|
||||
@ -3523,7 +3890,7 @@ _test_hash_bad(void)
|
||||
}
|
||||
u2_ca_lose(val);
|
||||
}
|
||||
u2_ha_free(har_u);
|
||||
u2_ch_free(har_u);
|
||||
}
|
||||
_road_dump();
|
||||
}
|
||||
@ -3533,15 +3900,15 @@ _test_hash(void)
|
||||
{
|
||||
_road_dump();
|
||||
{
|
||||
u2_ha_root* har_u = u2_ha_new();
|
||||
u2_ch_root* har_u = u2_ch_new();
|
||||
c3_w i_w;
|
||||
c3_w max_w = (1 << 20);
|
||||
|
||||
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++ ) {
|
||||
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 ( u2_none == val ) {
|
||||
@ -3551,7 +3918,7 @@ _test_hash(void)
|
||||
c3_assert(0);
|
||||
}
|
||||
}
|
||||
u2_ha_free(har_u);
|
||||
u2_ch_free(har_u);
|
||||
}
|
||||
_road_dump();
|
||||
}
|
||||
|
194
f/nash.c
194
f/nash.c
@ -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);
|
||||
}
|
@ -4,10 +4,9 @@
|
||||
*/
|
||||
#include "all.h"
|
||||
#include "../pit.h"
|
||||
#include "f/pork.h"
|
||||
|
||||
static u2_noun // produce
|
||||
_cue_in(u2_ha_root* har_u,
|
||||
_cue_in(u2_ch_root* har_u,
|
||||
u2_atom a, // retain
|
||||
u2_atom b) // retain
|
||||
{
|
||||
@ -20,7 +19,7 @@
|
||||
p = j2_mbc(Pt1, inc)(u2k(u2h(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(x);
|
||||
@ -42,13 +41,13 @@
|
||||
p = j2_mbc(Pt1, add)(2, y);
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
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));
|
||||
if ( u2_none == x ) {
|
||||
@ -66,12 +65,12 @@
|
||||
u2_noun // transfer
|
||||
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 y = u2k(u2h(u2t(x)));
|
||||
|
||||
u2_ha_free(har_u);
|
||||
u2_ch_free(har_u);
|
||||
|
||||
u2z(x);
|
||||
return y;
|
||||
|
@ -4,15 +4,14 @@
|
||||
*/
|
||||
#include "all.h"
|
||||
#include "../pit.h"
|
||||
#include "f/pork.h"
|
||||
|
||||
/* functions
|
||||
*/
|
||||
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
|
||||
_jam_in_pair(u2_ha_root* har_u,
|
||||
_jam_in_pair(u2_ch_root* har_u,
|
||||
u2_atom h_a, // retain
|
||||
u2_atom t_a, // retain
|
||||
u2_atom b, // retain
|
||||
@ -49,7 +48,7 @@
|
||||
}
|
||||
|
||||
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_noun l) // retain
|
||||
{
|
||||
@ -64,7 +63,7 @@
|
||||
}
|
||||
|
||||
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_noun l) // retain
|
||||
{
|
||||
@ -81,16 +80,16 @@
|
||||
}
|
||||
|
||||
static u2_noun // produce
|
||||
_jam_in(u2_ha_root* har_u,
|
||||
_jam_in(u2_ch_root* har_u,
|
||||
u2_noun a, // retain
|
||||
u2_atom b, // 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;
|
||||
|
||||
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) ) {
|
||||
x = _jam_in_flat(har_u, a, l);
|
||||
@ -112,7 +111,7 @@
|
||||
u2_noun // transfer
|
||||
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 q = j2_mbc(Pt2, flop)(u2h(u2t(x)));
|
||||
@ -120,7 +119,7 @@
|
||||
|
||||
u2z(x);
|
||||
u2z(q);
|
||||
u2_ha_free(har_u);
|
||||
u2_ch_free(har_u);
|
||||
return r;
|
||||
}
|
||||
u2_noun // transfer
|
||||
|
120
include/f/meme.h
120
include/f/meme.h
@ -6,7 +6,7 @@
|
||||
***
|
||||
*** u2_ca_: fundamental allocators.
|
||||
*** u2_cc_: constants.
|
||||
*** u2_ch_: memoization.
|
||||
*** u2_ch_: HAMT hash tables.
|
||||
*** u2_ci_: noun constructors
|
||||
*** u2_cj_: jets.
|
||||
*** u2_ck_: direct jet calls.
|
||||
@ -17,6 +17,7 @@
|
||||
*** u2_cs_: structures and definitions.
|
||||
*** u2_ct_: tracing.
|
||||
*** u2_cx_: read functions which do bail out.
|
||||
*** u2_cz_: memoization.
|
||||
***
|
||||
*** u2_cr_ and u2_cx_ functions use retain conventions; the caller
|
||||
*** retains ownership of passed-in nouns, the callee preserves
|
||||
@ -199,6 +200,75 @@
|
||||
? ( ((u2_cs_cell *)u2_co_to_ptr(som))->tel )\
|
||||
: 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.
|
||||
**
|
||||
** The box size is also stored at the end of the box in classic
|
||||
@ -1134,6 +1204,30 @@
|
||||
u2_noun
|
||||
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!)
|
||||
**/
|
||||
@ -1185,25 +1279,25 @@
|
||||
***
|
||||
*** 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_ch_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_ch_find_4(u2_mote, u2_noun, u2_noun, u2_noun, u2_noun);
|
||||
u2_weak u2_cz_find(u2_mote, u2_noun);
|
||||
u2_weak u2_cz_find_2(u2_mote, u2_noun, u2_noun);
|
||||
u2_weak u2_cz_find_3(u2_mote, 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_ch_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_ch_save_4
|
||||
u2_weak u2_cz_save(u2_mote, u2_noun, u2_noun);
|
||||
u2_weak u2_cz_save_2(u2_mote, 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_cz_save_4
|
||||
(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_ch_uniq(u2_noun som);
|
||||
u2_cz_uniq(u2_noun som);
|
||||
|
||||
|
||||
/* u2_ck: kernel and related functions
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue
Block a user