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_DICT_SIZE(a,p) TT_LEAF_ATOM(a,p)
#define tt_cons_dict(a,root,size) tt_cons_leaf(a,root,size) #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) { int tt_dict_size(tt_arena_t *a, tt_node_ptr_t t) {
if (t == TT_EMPTY) { if (t == TT_EMPTY) {
return 0; return 0;
@ -29,7 +32,7 @@ static inline int bit_ref(tt_atom_t key, unsigned int bit) {
return key & (1 << 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) { if (t == TT_EMPTY) {
return TT_NO_PTR; return TT_NO_PTR;
} }
@ -52,9 +55,9 @@ static tt_node_ptr_t splice_key(tt_arena_t *a,
tt_node_ptr_t sib) tt_node_ptr_t sib)
{ {
if (bit_ref(key, index)) { 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 { } 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 { } else {
int leading_zeros = __builtin_clz(differences); 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; return first_differing_bit;
} }
} }
@ -90,17 +93,19 @@ static int set_walk(tt_arena_t *a,
if (first_differing_bit == -1) { if (first_differing_bit == -1) {
if (*result == one) { if (*result == one) {
*result = n; *result = n;
} else if (*result == TT_NO_PTR) {
/* Do nothing. */
} else { } else {
*result = tt_cons_node(a, index, TT_NODE_ZERO(a, n), *result); *result = tt_cons_node(a, index, TT_NODE_ZERO(a, n), *result);
} }
return -1; return -1;
} else if (first_differing_bit < index) { } else if (first_differing_bit > index) {
return first_differing_bit; return first_differing_bit;
} else { } else {
*result = tt_cons_node(a, *result = splice_key(a, key, trie, first_differing_bit, one);
index, if (*result != TT_NO_PTR) {
TT_NODE_ZERO(a, n), *result = tt_cons_node(a, index, TT_NODE_ZERO(a, n), *result);
splice_key(a, key, trie, first_differing_bit, one)); }
return -1; return -1;
} }
} else { } else {
@ -109,17 +114,19 @@ static int set_walk(tt_arena_t *a,
if (first_differing_bit == -1) { if (first_differing_bit == -1) {
if (*result == zero) { if (*result == zero) {
*result = n; *result = n;
} else if (*result == TT_NO_PTR) {
/* Do nothing. */
} else { } else {
*result = tt_cons_node(a, index, *result, TT_NODE_ONE(a, n)); *result = tt_cons_node(a, index, *result, TT_NODE_ONE(a, n));
} }
return -1; return -1;
} else if (first_differing_bit < index) { } else if (first_differing_bit > index) {
return first_differing_bit; return first_differing_bit;
} else { } else {
*result = tt_cons_node(a, *result = splice_key(a, key, trie, first_differing_bit, zero);
index, if (*result != TT_NO_PTR) {
splice_key(a, key, trie, first_differing_bit, zero), *result = tt_cons_node(a, index, *result, TT_NODE_ONE(a, n));
TT_NODE_ONE(a, n)); }
return -1; return -1;
} }
} }
@ -135,7 +142,7 @@ tt_node_ptr_t tt_dict_set(tt_arena_t *a,
tt_node_ptr_t trie) tt_node_ptr_t trie)
{ {
if (t == TT_EMPTY) { 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); 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) { if (first_differing_bit != -1) {
result = splice_key(a, key, trie, first_differing_bit, TT_DICT_ROOT(a,t)); 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, tt_node_ptr_t n,
void *context, void *context,
void (*f)(void *context, tt_atom_t key, tt_node_ptr_t trie)) 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; break;
} }
case TT_TAG_NODE: { case TT_TAG_NODE: {
tt_foreach1(a, TT_NODE_ZERO(a,n), context, f); tt_dict_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_ONE(a,n), context, f);
break; break;
} }
default: default:
@ -170,13 +242,13 @@ void tt_foreach1(tt_arena_t *a,
} }
} }
void tt_foreach(tt_arena_t *a, void tt_dict_foreach(tt_arena_t *a,
tt_node_ptr_t t, tt_node_ptr_t t,
void *context, void *context,
void (*f)(void *, tt_atom_t key, tt_node_ptr_t trie)) void (*f)(void *, tt_atom_t key, tt_node_ptr_t trie))
{ {
if (t != TT_EMPTY) { if (t != TT_EMPTY) {
assert(tt_ptr_tag(t) == TT_TAG_DICT); 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" { extern "C" {
#endif #endif
#define TT_EMPTY_DICT TT_EMPTY
extern int tt_dict_size(tt_arena_t *a, tt_node_ptr_t t); 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. */ /* 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. /* Returns TT_NO_PTR when allocation failed. Otherwise, yields a dict.
Grabs `trie` if required. */ 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_atom_t key,
tt_node_ptr_t trie); tt_node_ptr_t trie);
extern void tt_foreach(tt_arena_t *a, extern tt_node_ptr_t tt_dict_remove(tt_arena_t *a,
tt_node_ptr_t t, tt_node_ptr_t t,
void *context, tt_atom_t key);
void (*f)(void *, tt_atom_t key, tt_node_ptr_t trie));
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 #ifdef __cplusplus
} }

39
main.c
View File

@ -5,8 +5,9 @@
#include "fasthash.h" #include "fasthash.h"
#include "treetrie.h" #include "treetrie.h"
#include "critbit.h"
int main(int argc, char *argv[]) { int main0(int argc, char *argv[]) {
tt_arena_t a; tt_arena_t a;
int i, outer; int i, outer;
tt_node_ptr_t prev = TT_EMPTY; tt_node_ptr_t prev = TT_EMPTY;
@ -41,3 +42,39 @@ int main(int argc, char *argv[]) {
tt_arena_done(&a); tt_arena_done(&a);
return EXIT_SUCCESS; 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; */ /* x = (x << 8) ^ b; */
/* return x - (x >> 32); */ /* return x - (x >> 32); */
uint64_t x = tag; uint64_t x = index * 11;
x ^= index * 11;
x *= 11; x *= 11;
x ^= a; x ^= a;
x *= 11; x *= 11;
x ^= b; x ^= b * tag;
return x - (x >> 32); 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; 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. */ /* Does not modify chain2. */
static void chain_splice(tt_arena_t *a, tt_free_chain_t *chain1, tt_free_chain_t *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) { 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) { int tt_arena_init(tt_arena_t *a) {
a->max_probe = 0; 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->table = calloc(a->table_length, sizeof(a->table[0]));
a->headers = calloc(a->table_length, sizeof(a->headers[0])); a->headers = calloc(a->table_length, sizeof(a->headers[0]));
a->nodes = calloc(a->table_length, sizeof(a->nodes[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) { if (tt_ptr_tag(p) == TT_TAG_LEAF) {
a->nodes[ni].b = TT_NO_PTR; a->nodes[ni].b = TT_NO_PTR;
} }
chain_append(a, &a->free_chain, ni); chain_prepend(a, &a->free_chain, ni);
a->free_count++; a->free_count++;
for (i = 0; i < a->max_probe+1; i++) { for (i = 0; i < a->max_probe+1; i++) {