More critbit

This commit is contained in:
Tony Garnock-Jones 2015-06-30 16:10:10 -04:00
parent ce496ceade
commit 4fda08adc0
4 changed files with 157 additions and 35 deletions

120
critbit.c
View File

@ -16,6 +16,9 @@
#define TT_DICT_SIZE(a,p) TT_LEAF_ATOM(a,p)
#define tt_cons_dict(a,root,size) tt_cons_leaf(a,root,size)
#define RET_IF_NO_PTR(v) \
({ tt_node_ptr_t ___w = (v); if (___w == TT_NO_PTR) return TT_NO_PTR; ___w; })
int tt_dict_size(tt_arena_t *a, tt_node_ptr_t t) {
if (t == TT_EMPTY) {
return 0;
@ -29,7 +32,7 @@ static inline int bit_ref(tt_atom_t key, unsigned int bit) {
return key & (1 << bit);
}
tt_node_ptr_t tt_dict_lookup(tt_arena_t *a, tt_node_ptr_t t, tt_atom_t key) {
tt_node_ptr_t tt_dict_get(tt_arena_t *a, tt_node_ptr_t t, tt_atom_t key) {
if (t == TT_EMPTY) {
return TT_NO_PTR;
}
@ -52,9 +55,9 @@ static tt_node_ptr_t splice_key(tt_arena_t *a,
tt_node_ptr_t sib)
{
if (bit_ref(key, index)) {
return tt_cons_node(a, index, sib, tt_cons_leaf(a, trie, key));
return tt_cons_node(a, index, sib, RET_IF_NO_PTR(tt_cons_leaf(a, trie, key)));
} else {
return tt_cons_node(a, index, tt_cons_leaf(a, trie, key), sib);
return tt_cons_node(a, index, RET_IF_NO_PTR(tt_cons_leaf(a, trie, key)), sib);
}
}
@ -78,7 +81,7 @@ static int set_walk(tt_arena_t *a,
}
} else {
int leading_zeros = __builtin_clz(differences);
int first_differing_bit = (8 * sizeof(differences)) - leading_zeros;
int first_differing_bit = (8 * sizeof(differences)) - leading_zeros - 1;
return first_differing_bit;
}
}
@ -90,17 +93,19 @@ static int set_walk(tt_arena_t *a,
if (first_differing_bit == -1) {
if (*result == one) {
*result = n;
} else if (*result == TT_NO_PTR) {
/* Do nothing. */
} else {
*result = tt_cons_node(a, index, TT_NODE_ZERO(a, n), *result);
}
return -1;
} else if (first_differing_bit < index) {
} else if (first_differing_bit > index) {
return first_differing_bit;
} else {
*result = tt_cons_node(a,
index,
TT_NODE_ZERO(a, n),
splice_key(a, key, trie, first_differing_bit, one));
*result = splice_key(a, key, trie, first_differing_bit, one);
if (*result != TT_NO_PTR) {
*result = tt_cons_node(a, index, TT_NODE_ZERO(a, n), *result);
}
return -1;
}
} else {
@ -109,17 +114,19 @@ static int set_walk(tt_arena_t *a,
if (first_differing_bit == -1) {
if (*result == zero) {
*result = n;
} else if (*result == TT_NO_PTR) {
/* Do nothing. */
} else {
*result = tt_cons_node(a, index, *result, TT_NODE_ONE(a, n));
}
return -1;
} else if (first_differing_bit < index) {
} else if (first_differing_bit > index) {
return first_differing_bit;
} else {
*result = tt_cons_node(a,
index,
splice_key(a, key, trie, first_differing_bit, zero),
TT_NODE_ONE(a, n));
*result = splice_key(a, key, trie, first_differing_bit, zero);
if (*result != TT_NO_PTR) {
*result = tt_cons_node(a, index, *result, TT_NODE_ONE(a, n));
}
return -1;
}
}
@ -135,7 +142,7 @@ tt_node_ptr_t tt_dict_set(tt_arena_t *a,
tt_node_ptr_t trie)
{
if (t == TT_EMPTY) {
return tt_cons_dict(a, tt_cons_leaf(a, trie, key), 1);
return tt_cons_dict(a, RET_IF_NO_PTR(tt_cons_leaf(a, trie, key)), 1);
}
assert(tt_ptr_tag(t) == TT_TAG_DICT);
@ -146,11 +153,76 @@ tt_node_ptr_t tt_dict_set(tt_arena_t *a,
if (first_differing_bit != -1) {
result = splice_key(a, key, trie, first_differing_bit, TT_DICT_ROOT(a,t));
}
return tt_cons_dict(a, result, TT_DICT_SIZE(a,t) + 1);
if (result == TT_NO_PTR) {
return TT_NO_PTR;
} else {
return tt_cons_dict(a, result, TT_DICT_SIZE(a,t) + 1);
}
}
}
void tt_foreach1(tt_arena_t *a,
tt_node_ptr_t tt_dict_remove1(tt_arena_t *a,
tt_node_ptr_t n,
tt_atom_t key,
int *removed_count)
{
switch (tt_ptr_tag(n)) {
case TT_TAG_LEAF: {
if (TT_LEAF_ATOM(a,n) == key) {
*removed_count = 1;
return TT_EMPTY;
} else {
return n;
}
}
case TT_TAG_NODE: {
int index = TT_NODE_INDEX(a,n);
if (bit_ref(key, index)) {
tt_node_ptr_t n1 =
RET_IF_NO_PTR(tt_dict_remove1(a, TT_NODE_ONE(a,n), key, removed_count));
if (n1 == TT_EMPTY) {
return TT_NODE_ZERO(a,n);
} else {
return tt_cons_node(a, index, TT_NODE_ZERO(a,n), n1);
}
} else {
tt_node_ptr_t n1 =
RET_IF_NO_PTR(tt_dict_remove1(a, TT_NODE_ZERO(a,n), key, removed_count));
if (n1 == TT_EMPTY) {
return TT_NODE_ONE(a,n);
} else {
return tt_cons_node(a, index, n1, TT_NODE_ONE(a,n));
}
}
}
default:
assert(0);
}
}
tt_node_ptr_t tt_dict_remove(tt_arena_t *a,
tt_node_ptr_t t,
tt_atom_t key)
{
if (t == TT_EMPTY) {
return TT_EMPTY;
}
assert(tt_ptr_tag(t) == TT_TAG_DICT);
{
int removed_count = 0;
tt_node_ptr_t n =
RET_IF_NO_PTR(tt_dict_remove1(a, TT_DICT_ROOT(a,t), key, &removed_count));
if (n == TT_EMPTY) {
return TT_EMPTY;
} else {
return tt_cons_dict(a, n, TT_DICT_SIZE(a,t) - removed_count);
}
}
}
void tt_dict_foreach1(tt_arena_t *a,
tt_node_ptr_t n,
void *context,
void (*f)(void *context, tt_atom_t key, tt_node_ptr_t trie))
@ -161,8 +233,8 @@ void tt_foreach1(tt_arena_t *a,
break;
}
case TT_TAG_NODE: {
tt_foreach1(a, TT_NODE_ZERO(a,n), context, f);
tt_foreach1(a, TT_NODE_ONE(a,n), context, f);
tt_dict_foreach1(a, TT_NODE_ZERO(a,n), context, f);
tt_dict_foreach1(a, TT_NODE_ONE(a,n), context, f);
break;
}
default:
@ -170,13 +242,13 @@ void tt_foreach1(tt_arena_t *a,
}
}
void tt_foreach(tt_arena_t *a,
tt_node_ptr_t t,
void *context,
void (*f)(void *, tt_atom_t key, tt_node_ptr_t trie))
void tt_dict_foreach(tt_arena_t *a,
tt_node_ptr_t t,
void *context,
void (*f)(void *, tt_atom_t key, tt_node_ptr_t trie))
{
if (t != TT_EMPTY) {
assert(tt_ptr_tag(t) == TT_TAG_DICT);
tt_foreach1(a, TT_DICT_ROOT(a,t), context, f);
tt_dict_foreach1(a, TT_DICT_ROOT(a,t), context, f);
}
}

View File

@ -5,10 +5,12 @@
extern "C" {
#endif
#define TT_EMPTY_DICT TT_EMPTY
extern int tt_dict_size(tt_arena_t *a, tt_node_ptr_t t);
/* Returns TT_NO_PTR when key not present. Does not manipulate references. */
extern tt_node_ptr_t tt_dict_lookup(tt_arena_t *a, tt_node_ptr_t t, tt_atom_t key);
extern tt_node_ptr_t tt_dict_get(tt_arena_t *a, tt_node_ptr_t t, tt_atom_t key);
/* Returns TT_NO_PTR when allocation failed. Otherwise, yields a dict.
Grabs `trie` if required. */
@ -17,10 +19,14 @@ extern tt_node_ptr_t tt_dict_set(tt_arena_t *a,
tt_atom_t key,
tt_node_ptr_t trie);
extern void tt_foreach(tt_arena_t *a,
tt_node_ptr_t t,
void *context,
void (*f)(void *, tt_atom_t key, tt_node_ptr_t trie));
extern tt_node_ptr_t tt_dict_remove(tt_arena_t *a,
tt_node_ptr_t t,
tt_atom_t key);
extern void tt_dict_foreach(tt_arena_t *a,
tt_node_ptr_t t,
void *context,
void (*f)(void *, tt_atom_t key, tt_node_ptr_t trie));
#ifdef __cplusplus
}

39
main.c
View File

@ -5,8 +5,9 @@
#include "fasthash.h"
#include "treetrie.h"
#include "critbit.h"
int main(int argc, char *argv[]) {
int main0(int argc, char *argv[]) {
tt_arena_t a;
int i, outer;
tt_node_ptr_t prev = TT_EMPTY;
@ -41,3 +42,39 @@ int main(int argc, char *argv[]) {
tt_arena_done(&a);
return EXIT_SUCCESS;
}
static void dump_mapping(void *context, tt_atom_t key, tt_node_ptr_t trie) {
printf(" -- %u --> %u/%u\n", key, tt_ptr_idx(trie), tt_ptr_tag(trie));
}
int main(int argc, char *argv[]) {
tt_arena_t a;
tt_node_ptr_t curr = TT_EMPTY;
int i;
setbuf(stdout, NULL);
tt_arena_init(&a);
tt_dump_arena(&a);
for (i = 0; i < 10; i++) {
tt_node_ptr_t next = tt_dict_set(&a, curr, i, TT_OK);
tt_drop(&a, curr);
curr = tt_grab(&a, next);
printf("\nAfter i=%d...\n", i);
tt_dump_arena(&a);
}
/* tt_arena_flush(&a); */
printf("\nFinal tree node index is %u/%u\n", tt_ptr_idx(curr), tt_ptr_tag(curr));
tt_dump_arena(&a);
tt_dict_foreach(&a, curr, NULL, dump_mapping);
tt_drop(&a, curr);
curr = TT_NO_PTR;
/* tt_arena_flush(&a); */
tt_dump_arena(&a);
tt_arena_done(&a);
return EXIT_SUCCESS;
}

View File

@ -49,12 +49,11 @@ static inline tt_hash_t hash(uint32_t tag,
/* x = (x << 8) ^ b; */
/* return x - (x >> 32); */
uint64_t x = tag;
x ^= index * 11;
uint64_t x = index * 11;
x *= 11;
x ^= a;
x *= 11;
x ^= b;
x ^= b * tag;
return x - (x >> 32);
}
@ -80,6 +79,14 @@ static void chain_append(tt_arena_t *a, tt_free_chain_t *chain, tt_node_idx_t i)
chain->tail = i;
}
static void chain_prepend(tt_arena_t *a, tt_free_chain_t *chain, tt_node_idx_t i) {
a->headers[i].next_free = chain->head;
if (chain->tail == TT_NO_IDX) {
chain->tail = i;
}
chain->head = i;
}
/* Does not modify chain2. */
static void chain_splice(tt_arena_t *a, tt_free_chain_t *chain1, tt_free_chain_t *chain2) {
if (chain2->head == TT_NO_IDX) {
@ -105,7 +112,7 @@ static tt_node_idx_t chain_pop(tt_arena_t *a, tt_free_chain_t *chain) {
int tt_arena_init(tt_arena_t *a) {
a->max_probe = 0;
a->table_length = 16411; /* 16384; */
a->table_length = 16; // 16411; /* 16384; */
a->table = calloc(a->table_length, sizeof(a->table[0]));
a->headers = calloc(a->table_length, sizeof(a->headers[0]));
a->nodes = calloc(a->table_length, sizeof(a->nodes[0]));
@ -352,7 +359,7 @@ static void recycle_node(tt_arena_t *a, tt_node_ptr_t p) {
if (tt_ptr_tag(p) == TT_TAG_LEAF) {
a->nodes[ni].b = TT_NO_PTR;
}
chain_append(a, &a->free_chain, ni);
chain_prepend(a, &a->free_chain, ni);
a->free_count++;
for (i = 0; i < a->max_probe+1; i++) {