diff --git a/critbit.c b/critbit.c index e5ce991..c0e6d66 100644 --- a/critbit.c +++ b/critbit.c @@ -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); } } diff --git a/critbit.h b/critbit.h index 2dd6d0e..9387546 100644 --- a/critbit.h +++ b/critbit.h @@ -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 } diff --git a/main.c b/main.c index e4f718d..f011355 100644 --- a/main.c +++ b/main.c @@ -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; +} diff --git a/treetrie.c b/treetrie.c index 650c1c5..d545a37 100644 --- a/treetrie.c +++ b/treetrie.c @@ -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++) {