combine, union. WIP because reference-counting is broken
This commit is contained in:
parent
039ec0e4bd
commit
b94668585f
98
critbit.c
98
critbit.c
|
@ -221,33 +221,101 @@ tt_node_ptr_t tt_dict_remove(tt_arena_t *a,
|
|||
}
|
||||
}
|
||||
|
||||
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))
|
||||
int tt_dict_foreach1(tt_arena_t *a,
|
||||
tt_node_ptr_t n,
|
||||
void *context,
|
||||
int (*f)(void *context, tt_atom_t key, tt_node_ptr_t trie))
|
||||
{
|
||||
switch (tt_ptr_tag(n)) {
|
||||
case TT_TAG_LEAF: {
|
||||
f(context, TT_LEAF_ATOM(a,n), TT_LEAF_TRIE(a,n));
|
||||
break;
|
||||
return f(context, TT_LEAF_ATOM(a,n), TT_LEAF_TRIE(a,n));
|
||||
}
|
||||
case TT_TAG_NODE: {
|
||||
tt_dict_foreach1(a, TT_NODE_ZERO(a,n), context, f);
|
||||
tt_dict_foreach1(a, TT_NODE_ONE(a,n), context, f);
|
||||
break;
|
||||
if (!tt_dict_foreach1(a, TT_NODE_ZERO(a,n), context, f)) return 0;
|
||||
return tt_dict_foreach1(a, TT_NODE_ONE(a,n), context, f);
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
int tt_dict_foreach(tt_arena_t *a,
|
||||
tt_node_ptr_t t,
|
||||
void *context,
|
||||
int (*f)(void *, tt_atom_t key, tt_node_ptr_t trie))
|
||||
{
|
||||
if (!TT_EMPTY_DICT_P(t)) {
|
||||
if (TT_EMPTY_DICT_P(t)) {
|
||||
return 1;
|
||||
} else {
|
||||
assert(tt_ptr_tag(t) == TT_TAG_DICT);
|
||||
tt_dict_foreach1(a, TT_DICT_ROOT(a,t), context, f);
|
||||
return tt_dict_foreach1(a, TT_DICT_ROOT(a,t), context, f);
|
||||
}
|
||||
}
|
||||
|
||||
tt_node_ptr_t tt_dictset_union(tt_arena_t *a, tt_node_ptr_t s1, tt_node_ptr_t s2) {
|
||||
tt_node_ptr_t result = TT_NO_PTR; /* grab'd */
|
||||
int f(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||
tt_node_ptr_t new_result = tt_grab(a, tt_dict_set(a, result, key, TT_EMPTY));
|
||||
tt_drop(a, result);
|
||||
result = new_result;
|
||||
return !TT_NO_PTR_P(result);
|
||||
}
|
||||
|
||||
if (tt_dict_size(a, s1) < tt_dict_size(a, s2)) {
|
||||
tt_node_ptr_t tmp = s2;
|
||||
s2 = s1;
|
||||
s1 = tmp;
|
||||
}
|
||||
/* Now s1 is larger, s2 is smaller. */
|
||||
result = tt_grab(a, s1);
|
||||
tt_dict_foreach(a, s2, NULL, f);
|
||||
return result;
|
||||
}
|
||||
|
||||
tt_node_ptr_t tt_dictset_intersection(tt_arena_t *a, tt_node_ptr_t s1, tt_node_ptr_t s2) {
|
||||
tt_node_ptr_t result = TT_NO_PTR; /* grab'd */
|
||||
int f(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||
if (!TT_NO_PTR_P(tt_dict_get(a, s1, key))) {
|
||||
tt_node_ptr_t new_result = tt_grab(a, tt_dict_set(a, result, key, TT_EMPTY));
|
||||
tt_drop(a, result);
|
||||
result = new_result;
|
||||
}
|
||||
return !TT_NO_PTR_P(result);
|
||||
}
|
||||
|
||||
if (tt_dict_size(a, s1) < tt_dict_size(a, s2)) {
|
||||
tt_node_ptr_t tmp = s2;
|
||||
s2 = s1;
|
||||
s1 = tmp;
|
||||
}
|
||||
/* Now s1 is larger, s2 is smaller. */
|
||||
result = TT_EMPTY_DICT;
|
||||
tt_dict_foreach(a, s2, NULL, f);
|
||||
return result;
|
||||
}
|
||||
|
||||
tt_node_ptr_t tt_dictset_difference(tt_arena_t *a, tt_node_ptr_t s1, tt_node_ptr_t s2) {
|
||||
tt_node_ptr_t result = TT_NO_PTR;
|
||||
if (tt_dict_size(a, s1) < tt_dict_size(a, s2)) {
|
||||
int f(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||
if (!TT_NO_PTR_P(tt_dict_get(a, s2, key))) {
|
||||
tt_node_ptr_t new_result = tt_grab(a, tt_dict_set(a, result, key, TT_EMPTY));
|
||||
tt_drop(a, result);
|
||||
result = new_result;
|
||||
}
|
||||
return !TT_NO_PTR_P(result);
|
||||
}
|
||||
result = TT_EMPTY_DICT;
|
||||
tt_dict_foreach(a, s1, NULL, f);
|
||||
} else {
|
||||
int f(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||
tt_node_ptr_t new_result = tt_grab(a, tt_dict_remove(a, result, key));
|
||||
tt_drop(a, result);
|
||||
result = new_result;
|
||||
return !TT_NO_PTR_P(result);
|
||||
}
|
||||
result = tt_grab(a, s1);
|
||||
tt_dict_foreach(a, s2, NULL, f);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
17
critbit.h
17
critbit.h
|
@ -27,10 +27,19 @@ 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));
|
||||
/* Returns 1 if it examined the whole dict; 0 if it was aborted early */
|
||||
extern int tt_dict_foreach(tt_arena_t *a,
|
||||
tt_node_ptr_t t,
|
||||
void *context,
|
||||
/* Return 1 to continue the loop; 0 to abort it. */
|
||||
int (*f)(void *, tt_atom_t key, tt_node_ptr_t trie));
|
||||
|
||||
/* Dictsets map to TT_EMPTY to indicate a *present* key (and
|
||||
implicitly to TT_NO_PTR to indicate an *absent* key). */
|
||||
/* THESE ALL RETURN grab'd RESULTS */
|
||||
extern tt_node_ptr_t tt_dictset_union(tt_arena_t *a, tt_node_ptr_t s1, tt_node_ptr_t s2);
|
||||
extern tt_node_ptr_t tt_dictset_intersection(tt_arena_t *a, tt_node_ptr_t s1, tt_node_ptr_t s2);
|
||||
extern tt_node_ptr_t tt_dictset_difference(tt_arena_t *a, tt_node_ptr_t s1, tt_node_ptr_t s2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
67
main.c
67
main.c
|
@ -6,6 +6,7 @@
|
|||
#include "fasthash.h"
|
||||
#include "treetrie.h"
|
||||
#include "critbit.h"
|
||||
#include "route.h"
|
||||
|
||||
static void atom_incref(void *atom_context, tt_arena_t *a, tt_atom_t atom) {
|
||||
/* printf("incref %u\n", atom); */
|
||||
|
@ -29,19 +30,19 @@ int main0(int argc, char *argv[]) {
|
|||
tt_drop(&a, prev);
|
||||
/* tt_arena_flush(&a); */
|
||||
/* printf("---------------------------------------- AFTER DROP of %d:\n", prev); */
|
||||
/* tt_dump_arena(&a); */
|
||||
/* tt_dump_arena(&a, 1); */
|
||||
prev = TT_EMPTY;
|
||||
/* printf("======================================== LOOP ITERATION %d\n", outer); */
|
||||
/* tt_dump_arena_summary(&a); */
|
||||
for (i = 0; i < 1000000; i++) {
|
||||
tt_node_ptr_t leaf = tt_cons_leaf(&a, TT_EMPTY, 1001);
|
||||
tt_node_ptr_t curr = tt_cons_node(&a, 0, leaf, prev);
|
||||
/* tt_dump_arena(&a); */
|
||||
/* tt_dump_arena(&a, 1); */
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
|
||||
/* tt_dump_arena(&a); */
|
||||
/* tt_dump_arena(&a, 1); */
|
||||
tt_grab(&a, prev);
|
||||
tt_drop(&a, prev);
|
||||
/* tt_arena_flush(&a); */
|
||||
|
@ -51,11 +52,12 @@ int main0(int argc, char *argv[]) {
|
|||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void dump_mapping(void *context, tt_atom_t key, tt_node_ptr_t trie) {
|
||||
static int 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));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int main1(int argc, char *argv[]) {
|
||||
tt_arena_t a;
|
||||
tt_node_ptr_t curr = TT_EMPTY_DICT;
|
||||
int i;
|
||||
|
@ -63,13 +65,13 @@ int main(int argc, char *argv[]) {
|
|||
setbuf(stdout, NULL);
|
||||
tt_arena_init(&a, NULL, atom_incref, atom_decref);
|
||||
|
||||
/* tt_dump_arena(&a); */
|
||||
/* tt_dump_arena(&a, 1); */
|
||||
for (i = 0; i < 1000000; i++) {
|
||||
tt_node_ptr_t next = tt_grab(&a, tt_dict_set(&a, curr, i, TT_EMPTY));
|
||||
tt_drop(&a, curr);
|
||||
curr = next;
|
||||
/* printf("\nAfter i=%d...\n", i); */
|
||||
/* tt_dump_arena(&a); */
|
||||
/* tt_dump_arena(&a, 1); */
|
||||
}
|
||||
|
||||
/* for (i = 0; i < 1000000; i++) { */
|
||||
|
@ -83,16 +85,63 @@ int main(int argc, char *argv[]) {
|
|||
tt_ptr_idx(curr),
|
||||
tt_ptr_tag(curr),
|
||||
TT_DICT_SIZE(&a, curr));
|
||||
/* tt_dump_arena(&a); */
|
||||
/* tt_dump_arena(&a, 1); */
|
||||
|
||||
/* 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_dump_arena(&a, 1); */
|
||||
tt_dump_arena_summary(&a);
|
||||
|
||||
tt_arena_done(&a);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
tt_arena_t a;
|
||||
tt_node_ptr_t a_set;
|
||||
tt_node_ptr_t b_set;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
tt_arena_init(&a, NULL, atom_incref, atom_decref);
|
||||
|
||||
a_set = tt_dict_singleton(&a, 'A', TT_EMPTY);
|
||||
b_set = tt_dict_singleton(&a, 'B', TT_EMPTY);
|
||||
|
||||
{
|
||||
tt_node_ptr_t A =
|
||||
tt_grab(&a,
|
||||
tt_prepend_path(&a, TT_BOS,
|
||||
tt_prepend_path(&a, 'A',
|
||||
tt_prepend_path(&a, TT_EOS,
|
||||
tt_begin_path(&a, a_set)))));
|
||||
printf("\nA node: %u/%u\n", tt_ptr_idx(A), tt_ptr_tag(A));
|
||||
tt_dump_arena(&a, 0);
|
||||
tt_node_ptr_t B =
|
||||
tt_grab(&a,
|
||||
tt_prepend_path(&a, TT_BOS,
|
||||
tt_prepend_path(&a, 'B',
|
||||
tt_prepend_path(&a, TT_EOS,
|
||||
tt_begin_path(&a, b_set)))));
|
||||
printf("\nB node: %u/%u\n", tt_ptr_idx(B), tt_ptr_tag(B));
|
||||
tt_dump_arena(&a, 0);
|
||||
tt_node_ptr_t C = tt_trie_union(&a, A, B);
|
||||
tt_drop(&a, A);
|
||||
tt_drop(&a, B);
|
||||
printf("\nC node: %u/%u\n", tt_ptr_idx(C), tt_ptr_tag(C));
|
||||
tt_dump_arena(&a, 0);
|
||||
putchar('\n');
|
||||
tt_dump_routingtable(&a, C, 0);
|
||||
tt_drop(&a, C);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
tt_arena_flush(&a);
|
||||
tt_dump_arena(&a, 0);
|
||||
/* tt_dump_arena_summary(&a); */
|
||||
|
||||
tt_arena_done(&a);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
350
route.c
350
route.c
|
@ -49,17 +49,17 @@ static inline tt_node_ptr_t runwildseq(tt_arena_t *a, tt_node_ptr_t r) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline tt_node_ptr_t rlookup(tt_arena_t *a,
|
||||
tt_node_ptr_t r,
|
||||
tt_atom_t key)
|
||||
static inline tt_node_ptr_t rlookup_dict(tt_arena_t *a,
|
||||
tt_node_ptr_t wild,
|
||||
tt_node_ptr_t others,
|
||||
tt_atom_t key)
|
||||
{
|
||||
tt_node_ptr_t result;
|
||||
assert(tt_ptr_tag(r) == TT_TAG_BRANCH);
|
||||
result = tt_dict_get(a, TT_BRANCH_OTHERS(a,r), key);
|
||||
result = tt_dict_get(a, others, key);
|
||||
if (!TT_NO_PTR_P(result)) {
|
||||
return result;
|
||||
}
|
||||
result = TT_BRANCH_WILDCARD(a,r);
|
||||
result = wild;
|
||||
switch (key) {
|
||||
case TT_BOS: return rwildseq(a, result);
|
||||
case TT_EOS: return runwildseq(a, result);
|
||||
|
@ -67,6 +67,47 @@ static inline tt_node_ptr_t rlookup(tt_arena_t *a,
|
|||
}
|
||||
}
|
||||
|
||||
static inline tt_node_ptr_t rlookup(tt_arena_t *a,
|
||||
tt_node_ptr_t r,
|
||||
tt_atom_t key)
|
||||
{
|
||||
assert(tt_ptr_tag(r) == TT_TAG_BRANCH);
|
||||
return rlookup_dict(a, TT_BRANCH_WILDCARD(a,r), TT_BRANCH_OTHERS(a,r), key);
|
||||
}
|
||||
|
||||
static inline tt_node_ptr_t rupdate_dict(tt_arena_t *a,
|
||||
tt_node_ptr_t old_wild, /* trie */
|
||||
tt_node_ptr_t old_others, /* dict */
|
||||
tt_atom_t key,
|
||||
tt_node_ptr_t k) /* trie */
|
||||
{
|
||||
assert(key != TT_WILD);
|
||||
assert(TT_EMPTY_DICT_P(old_others) || tt_ptr_tag(old_others) == TT_TAG_DICT);
|
||||
|
||||
#define OTHERS_SANS_KEY() (tt_dict_remove(a, old_others, key))
|
||||
#define OTHERS_WITH_KEY() (tt_dict_set(a, old_others, key, k))
|
||||
|
||||
switch (key) {
|
||||
case TT_BOS:
|
||||
if (tt_ptr_tag(k) == TT_TAG_TAIL) {
|
||||
return (TT_TAIL_TRIE(a,k) == old_wild) ? OTHERS_SANS_KEY() : OTHERS_WITH_KEY();
|
||||
} else {
|
||||
return TT_EMPTY_P(k) ? OTHERS_SANS_KEY() : OTHERS_WITH_KEY();
|
||||
}
|
||||
case TT_EOS:
|
||||
if (tt_ptr_tag(old_wild) == TT_TAG_TAIL) {
|
||||
return (TT_TAIL_TRIE(a,old_wild) == k) ? OTHERS_SANS_KEY() : OTHERS_WITH_KEY();
|
||||
} else {
|
||||
return TT_EMPTY_P(k) ? OTHERS_SANS_KEY() : OTHERS_WITH_KEY();
|
||||
}
|
||||
default:
|
||||
return (k == old_wild) ? OTHERS_SANS_KEY() : OTHERS_WITH_KEY();
|
||||
}
|
||||
|
||||
#undef OTHERS_SANS_KEY
|
||||
#undef OTHERS_WITH_KEY
|
||||
}
|
||||
|
||||
static inline tt_node_ptr_t rupdate(tt_arena_t *a,
|
||||
tt_node_ptr_t r0, /* branch */
|
||||
tt_atom_t key,
|
||||
|
@ -76,73 +117,248 @@ static inline tt_node_ptr_t rupdate(tt_arena_t *a,
|
|||
if (TT_EMPTY_P(r0)) {
|
||||
return rseq(a, key, k);
|
||||
} else {
|
||||
tt_node_ptr_t old_wild;
|
||||
tt_node_ptr_t old_others;
|
||||
tt_node_ptr_t new_others;
|
||||
assert(tt_ptr_tag(r0) == TT_TAG_BRANCH);
|
||||
old_wild = TT_BRANCH_WILDCARD(a,r0);
|
||||
old_others = TT_BRANCH_OTHERS(a,r0);
|
||||
|
||||
#define R0_SANS_KEY() (rbranch(a, old_wild, RET_IF_NO_PTR(tt_dict_remove(a, old_others, key))))
|
||||
#define R0_WITH_KEY() (rbranch(a, old_wild, RET_IF_NO_PTR(tt_dict_set(a, old_others, key, k))))
|
||||
|
||||
switch (key) {
|
||||
case TT_BOS:
|
||||
if (tt_ptr_tag(k) == TT_TAG_TAIL) {
|
||||
return (TT_TAIL_TRIE(a,k) == old_wild) ? R0_SANS_KEY() : R0_WITH_KEY();
|
||||
} else {
|
||||
return TT_EMPTY_P(k) ? R0_SANS_KEY() : R0_WITH_KEY();
|
||||
}
|
||||
case TT_EOS:
|
||||
if (tt_ptr_tag(old_wild) == TT_TAG_TAIL) {
|
||||
return (TT_TAIL_TRIE(a,old_wild) == k) ? R0_SANS_KEY() : R0_WITH_KEY();
|
||||
} else {
|
||||
return TT_EMPTY_P(k) ? R0_SANS_KEY() : R0_WITH_KEY();
|
||||
}
|
||||
default:
|
||||
return (k == old_wild) ? R0_SANS_KEY() : R0_WITH_KEY();
|
||||
}
|
||||
|
||||
#undef R0_SANS_KEY
|
||||
#undef R0_WITH_KEY
|
||||
|
||||
new_others = rupdate_dict(a, TT_BRANCH_WILDCARD(a,r0), TT_BRANCH_OTHERS(a,r0), key, k);
|
||||
return rbranch(a, TT_BRANCH_WILDCARD(a,r0), RET_IF_NO_PTR(new_others));
|
||||
}
|
||||
}
|
||||
|
||||
/* static tt_node_ptr_t combine(tt_arena_t *a, */
|
||||
/* tt_node_ptr_t r1, */
|
||||
/* tt_node_ptr_t r2, */
|
||||
/* int left_empty_keep, */
|
||||
/* int right_empty_keep, */
|
||||
/* int left_base_keep, */
|
||||
/* int right_base_keep, */
|
||||
/* void *f_context, */
|
||||
/* tt_node_ptr_t (*f)(void *f_context, tt_node_ptr_t r1, tt_node_ptr_t r2)) */
|
||||
/* { */
|
||||
/* tt_node_ptr_t g(tt_node_ptr_t r1, tt_node_ptr_t r2) { */
|
||||
/* tt_tag_t t1, t2; */
|
||||
static inline tt_node_ptr_t expand(tt_arena_t *a, tt_node_ptr_t tailnode) {
|
||||
tt_node_ptr_t others = RET_IF_NO_PTR(tt_dict_singleton(a, TT_EOS, TT_TAIL_TRIE(a,tailnode)));
|
||||
return rbranch(a, tailnode, others);
|
||||
}
|
||||
|
||||
/* if (TT_EMPTY_P(r1)) { */
|
||||
/* return left_empty_keep ? r2 : TT_EMPTY; */
|
||||
/* } */
|
||||
/* if (TT_EMPTY_P(r2)) { */
|
||||
/* return right_empty_keep ? r1 : TT_EMPTY; */
|
||||
/* } */
|
||||
/* N.B. Returns a tt_grab'd result. */
|
||||
tt_node_ptr_t tt_trie_combine(tt_arena_t *a,
|
||||
tt_node_ptr_t r1,
|
||||
tt_node_ptr_t r2,
|
||||
int left_empty_keep,
|
||||
int right_empty_keep,
|
||||
int left_base_keep,
|
||||
int right_base_keep,
|
||||
void *f_context,
|
||||
/* Should return a tt_grab'd result. */
|
||||
tt_node_ptr_t (*f)(void *f_context,
|
||||
tt_node_ptr_t r1,
|
||||
tt_node_ptr_t r2))
|
||||
{
|
||||
/* N.B. Returns a tt_grab'd result. */
|
||||
tt_node_ptr_t g(tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||
tt_tag_t t1, t2;
|
||||
|
||||
/* t1 = tt_ptr_tag(r1); */
|
||||
/* t2 = tt_ptr_tag(r2); */
|
||||
if (TT_EMPTY_P(r1)) {
|
||||
return left_empty_keep ? tt_grab(a, r2) : TT_EMPTY;
|
||||
}
|
||||
if (TT_EMPTY_P(r2)) {
|
||||
return right_empty_keep ? tt_grab(a, r1) : TT_EMPTY;
|
||||
}
|
||||
|
||||
/* if (t1 == TT_TAG_TAIL) { */
|
||||
/* if (t2 == TT_TAG_TAIL) { */
|
||||
/* return rwildseq(a, RET_IF_NO_PTR(g(TT_TAIL_TRIE(a,r1), TT_TAIL_TRIE(a,r2)))); */
|
||||
/* } else { */
|
||||
/* ....HERE */
|
||||
/* } */
|
||||
t1 = tt_ptr_tag(r1);
|
||||
t2 = tt_ptr_tag(r2);
|
||||
|
||||
/* switch (tt_ptr_tag(r1)) { */
|
||||
/* default: */
|
||||
/* abort(); */
|
||||
/* } */
|
||||
/* } */
|
||||
if (t1 == TT_TAG_BRANCH && t2 == TT_TAG_BRANCH) {
|
||||
tt_node_ptr_t w1 = TT_BRANCH_WILDCARD(a,r1);
|
||||
tt_node_ptr_t w2 = TT_BRANCH_WILDCARD(a,r2);
|
||||
tt_node_ptr_t dict1 = TT_BRANCH_OTHERS(a,r1);
|
||||
tt_node_ptr_t dict2 = TT_BRANCH_OTHERS(a,r2);
|
||||
tt_node_ptr_t result_wild = TT_NO_PTR; /* grab'd */
|
||||
tt_node_ptr_t result_others = TT_EMPTY_DICT; /* grab'd */
|
||||
tt_node_ptr_t result = TT_NO_PTR; /* grab'd */
|
||||
int ok = 1;
|
||||
|
||||
/* return g(r1, r2); */
|
||||
/* } */
|
||||
int examine_key(void *examine_key_context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||
tt_node_ptr_t trie1, trie2; /* Looked up in r1 and r2 */
|
||||
tt_node_ptr_t new_trie; /* Combination of trie1 and trie2 */
|
||||
tt_node_ptr_t new_result_others; /* Updated dictionary with key---new_trie association */
|
||||
trie1 = tt_grab(a, rlookup_dict(a, w1, dict1, key));
|
||||
if (TT_NO_PTR_P(trie1)) return 0;
|
||||
trie2 = tt_grab(a, rlookup_dict(a, w2, dict2, key));
|
||||
if (TT_NO_PTR_P(trie2)) {
|
||||
tt_drop(a, trie1);
|
||||
return 0;
|
||||
}
|
||||
new_trie = g(trie1, trie2); /* already grabbed */
|
||||
if (TT_NO_PTR_P(new_trie)) {
|
||||
tt_drop(a, trie1);
|
||||
tt_drop(a, trie2);
|
||||
return 0;
|
||||
}
|
||||
new_result_others = tt_grab(a, rupdate_dict(a, result_wild, result_others, key, new_trie));
|
||||
if (TT_NO_PTR_P(new_result_others)) {
|
||||
tt_drop(a, trie1);
|
||||
tt_drop(a, trie2);
|
||||
tt_drop(a, new_trie);
|
||||
return 0;
|
||||
}
|
||||
tt_drop(a, result_others);
|
||||
result_others = new_result_others;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!TT_EMPTY_P(w1) && !TT_EMPTY_P(w2)) {
|
||||
/* Two wildcards - worst case. Must loop over both dictionaries. */
|
||||
result_wild = g(w1, w2);
|
||||
ok = ok && tt_dict_foreach(a, dict1, NULL, examine_key);
|
||||
ok = ok && tt_dict_foreach(a, dict2, NULL, examine_key);
|
||||
} else if ((!TT_EMPTY_P(w1)) ||
|
||||
(TT_EMPTY_P(w2) &&
|
||||
(tt_dict_size(a, dict1) >= tt_dict_size(a, dict2)))) {
|
||||
/* Either a wildcard on the left, or no wildcard at all but the left is larger */
|
||||
result_wild = tt_grab(a, w1);
|
||||
result_others = left_base_keep ? tt_grab(a, dict1) : TT_EMPTY_DICT;
|
||||
ok = ok && tt_dict_foreach(a, dict2, NULL, examine_key);
|
||||
} else {
|
||||
/* Either a wildcard on the right, or no wildcard at all but the right is larger */
|
||||
result_wild = tt_grab(a, w2);
|
||||
result_others = right_base_keep ? tt_grab(a, dict2) : TT_EMPTY_DICT;
|
||||
ok = ok && tt_dict_foreach(a, dict1, NULL, examine_key);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
result = tt_grab(a, rbranch(a, result_wild, result_others));
|
||||
}
|
||||
|
||||
tt_drop(a, result_wild);
|
||||
tt_drop(a, result_others);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (t1 == TT_TAG_TAIL) {
|
||||
if (t2 == TT_TAG_TAIL) {
|
||||
tt_node_ptr_t combined = RET_IF_NO_PTR(g(TT_TAIL_TRIE(a,r1), TT_TAIL_TRIE(a,r2)));
|
||||
tt_node_ptr_t result = tt_grab(a, rwildseq(a, combined));
|
||||
tt_drop(a, combined);
|
||||
return result;
|
||||
} else {
|
||||
tt_node_ptr_t r2_expanded = tt_grab(a, RET_IF_NO_PTR(expand(a, r2)));
|
||||
tt_node_ptr_t result = g(r1, r2_expanded);
|
||||
tt_drop(a, r2_expanded);
|
||||
return result;
|
||||
}
|
||||
} else if (t2 == TT_TAG_TAIL) {
|
||||
tt_node_ptr_t r1_expanded = tt_grab(a, RET_IF_NO_PTR(expand(a, r1)));
|
||||
tt_node_ptr_t result = g(r1_expanded, r2);
|
||||
tt_drop(a, r1_expanded);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (t1 == TT_TAG_OK || t2 == TT_TAG_OK) {
|
||||
return f(f_context, r1, r2);
|
||||
}
|
||||
|
||||
/* There is no legitimate combination of tags that should let us get here. */
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* No need for tt_grab here - g has already done that for us */
|
||||
return g(r1, r2);
|
||||
}
|
||||
|
||||
tt_node_ptr_t tt_trie_union(tt_arena_t *a, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||
tt_node_ptr_t f_union(void *f_context, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||
tt_tag_t t1 = tt_ptr_tag(r1);
|
||||
tt_tag_t t2 = tt_ptr_tag(r2);
|
||||
if (t1 != TT_TAG_OK) {
|
||||
/* t2 must be ok. */
|
||||
return tt_grab(a, r2);
|
||||
} else if (t2 != TT_TAG_OK) {
|
||||
return tt_grab(a, r1);
|
||||
} else {
|
||||
tt_node_ptr_t s = RET_IF_NO_PTR(tt_dictset_union(a, TT_OK_DICT(a,r1), TT_OK_DICT(a,r2)));
|
||||
tt_node_ptr_t result = tt_cons_ok(a, s);
|
||||
tt_drop(a, s);
|
||||
return tt_grab(a, result);
|
||||
}
|
||||
}
|
||||
return tt_trie_combine(a, r1, r2, 1, 1, 1, 1, NULL, f_union);
|
||||
}
|
||||
|
||||
tt_node_ptr_t tt_begin_path(tt_arena_t *a, tt_node_ptr_t ok_dict) {
|
||||
return tt_cons_ok(a, ok_dict);
|
||||
}
|
||||
|
||||
tt_node_ptr_t tt_prepend_path(tt_arena_t *a, tt_atom_t tok, tt_node_ptr_t tail) {
|
||||
if (tok == TT_WILD) {
|
||||
return rwild(a, tail);
|
||||
} else {
|
||||
return rseq(a, tok, tail);
|
||||
}
|
||||
}
|
||||
|
||||
void print_indent(int spaces) {
|
||||
while (spaces--) {
|
||||
putchar(' ');
|
||||
}
|
||||
}
|
||||
|
||||
void tt_dump_routingtable(tt_arena_t *a, tt_node_ptr_t r, int initial_indent) {
|
||||
void walk(int indent, tt_node_ptr_t r) {
|
||||
switch (tt_ptr_tag(r)) {
|
||||
case TT_TAG_TAIL:
|
||||
printf(" ...>");
|
||||
walk(indent + 5, TT_TAIL_TRIE(a, r));
|
||||
break;
|
||||
case TT_TAG_OK: {
|
||||
int need_space = 0;
|
||||
int pkey(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||
if (need_space) {
|
||||
putchar(' ');
|
||||
} else {
|
||||
need_space = 1;
|
||||
}
|
||||
printf("%d", key);
|
||||
return 1;
|
||||
}
|
||||
fputs(" {", stdout);
|
||||
tt_dict_foreach(a, TT_OK_DICT(a, r), NULL, pkey);
|
||||
putchar('}');
|
||||
break;
|
||||
}
|
||||
case TT_TAG_BRANCH: {
|
||||
int need_sep = 0;
|
||||
int pedge(void *context, tt_atom_t key, tt_node_ptr_t node) {
|
||||
char keystr[256]; /* not very tight */
|
||||
if (need_sep) {
|
||||
putchar('\n');
|
||||
print_indent(indent);
|
||||
} else {
|
||||
need_sep = 1;
|
||||
}
|
||||
keystr[sizeof(keystr) - 1] = '\0';
|
||||
switch (key) {
|
||||
case TT_WILD: snprintf(keystr, sizeof(keystr) - 1, " ★"); break;
|
||||
case TT_BOS: snprintf(keystr, sizeof(keystr) - 1, " <"); break;
|
||||
case TT_EOS: snprintf(keystr, sizeof(keystr) - 1, " >"); break;
|
||||
case TT_BOC: snprintf(keystr, sizeof(keystr) - 1, " {"); break;
|
||||
case TT_EOC: snprintf(keystr, sizeof(keystr) - 1, " }"); break;
|
||||
default:
|
||||
snprintf(keystr, sizeof(keystr) - 1, " %d", key);
|
||||
}
|
||||
fputs(keystr, stdout);
|
||||
walk(indent + strlen(keystr), node);
|
||||
return 1;
|
||||
}
|
||||
if (!TT_EMPTY_P(TT_BRANCH_WILDCARD(a, r))) {
|
||||
pedge(NULL, TT_WILD, TT_BRANCH_WILDCARD(a, r));
|
||||
}
|
||||
tt_dict_foreach(a, TT_BRANCH_OTHERS(a, r), NULL, pedge);
|
||||
if (!need_sep) {
|
||||
printf(" ::: no edges!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TT_TAG_SPECIAL:
|
||||
if (TT_EMPTY_P(r)) {
|
||||
printf(" ::: nothing");
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
printf("?!?!?! %x", (unsigned int) r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
walk(initial_indent, r);
|
||||
putchar('\n');
|
||||
}
|
||||
|
|
23
route.h
23
route.h
|
@ -11,6 +11,29 @@
|
|||
#define TT_BOC ((tt_atom_t) -7) /* Beginning of capture */
|
||||
#define TT_EOC ((tt_atom_t) -9) /* End of capture */
|
||||
|
||||
/* N.B. Returns a tt_grab'd result. */
|
||||
extern tt_node_ptr_t tt_trie_combine(tt_arena_t *a,
|
||||
tt_node_ptr_t r1,
|
||||
tt_node_ptr_t r2,
|
||||
int left_empty_keep,
|
||||
int right_empty_keep,
|
||||
int left_base_keep,
|
||||
int right_base_keep,
|
||||
void *f_context,
|
||||
/* Should return a tt_grab'd result. */
|
||||
tt_node_ptr_t (*f)(void *f_context,
|
||||
tt_node_ptr_t r1,
|
||||
tt_node_ptr_t r2));
|
||||
|
||||
/* N.B. Returns a tt_grab'd result. */
|
||||
extern tt_node_ptr_t tt_trie_union(tt_arena_t *a, tt_node_ptr_t r1, tt_node_ptr_t r2);
|
||||
|
||||
/* These return ungrab'd */
|
||||
extern tt_node_ptr_t tt_begin_path(tt_arena_t *a, tt_node_ptr_t ok_dict);
|
||||
extern tt_node_ptr_t tt_prepend_path(tt_arena_t *a, tt_atom_t tok, tt_node_ptr_t tail);
|
||||
|
||||
extern void tt_dump_routingtable(tt_arena_t *a, tt_node_ptr_t r, int initial_indent);
|
||||
|
||||
// TODO move to the right place
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
27
treetrie.c
27
treetrie.c
|
@ -177,7 +177,7 @@ static int tt_grow(tt_arena_t *a) {
|
|||
unsigned int new_table_length = old_table_length << 1;
|
||||
|
||||
/* printf("PREGROW\n"); */
|
||||
/* tt_dump_arena(a); */
|
||||
/* tt_dump_arena(a, 1); */
|
||||
|
||||
{
|
||||
tt_hashtable_entry_t *new_table = calloc(new_table_length, sizeof(a->table[0]));
|
||||
|
@ -255,18 +255,23 @@ void tt_dump_arena_summary(tt_arena_t *a) {
|
|||
printf("free_count: %u\n", a->free_count);
|
||||
}
|
||||
|
||||
void tt_dump_arena(tt_arena_t *a) {
|
||||
void tt_dump_arena(tt_arena_t *a, int show_free_chain) {
|
||||
tt_dump_arena_summary(a);
|
||||
|
||||
printf("free_chain:");
|
||||
{
|
||||
if (show_free_chain) {
|
||||
int chain_counter = 0;
|
||||
tt_node_idx_t fp = a->free_chain.head;
|
||||
printf("free_chain:");
|
||||
while (fp != TT_NO_IDX) {
|
||||
if ((chain_counter % 10) == 0) {
|
||||
printf("\n ");
|
||||
}
|
||||
printf(" %d", fp);
|
||||
fp = a->headers[fp].next_free;
|
||||
chain_counter++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
{
|
||||
int i;
|
||||
|
@ -308,10 +313,10 @@ void tt_dump_arena(tt_arena_t *a) {
|
|||
tt_ptr_tag(a->nodes[n].b));
|
||||
break;
|
||||
case TT_TAG_LEAF:
|
||||
printf("leaf %u/%u %u\n",
|
||||
printf("leaf %u/%u %d\n",
|
||||
tt_ptr_idx(a->nodes[n].a),
|
||||
tt_ptr_tag(a->nodes[n].a),
|
||||
a->nodes[n].b);
|
||||
(int) a->nodes[n].b);
|
||||
break;
|
||||
case TT_TAG_NODE:
|
||||
printf("node index %d, %u/%u %u/%u\n",
|
||||
|
@ -427,7 +432,9 @@ static void recycle_node(tt_arena_t *a, tt_node_ptr_t p) {
|
|||
|
||||
inline tt_node_ptr_t tt_grab(tt_arena_t *a, tt_node_ptr_t p) {
|
||||
tt_node_idx_t i = tt_ptr_idx(p);
|
||||
if (tt_ptr_tag(p) != TT_TAG_SPECIAL && a->headers[i].inuse.refcount < TT_REFCOUNT_LIMIT) {
|
||||
tt_tag_t t = tt_ptr_tag(p);
|
||||
if (t != TT_TAG_INVALID && t != TT_TAG_SPECIAL
|
||||
&& a->headers[i].inuse.refcount < TT_REFCOUNT_LIMIT) {
|
||||
a->headers[i].inuse.refcount++;
|
||||
}
|
||||
return p;
|
||||
|
@ -435,7 +442,9 @@ inline tt_node_ptr_t tt_grab(tt_arena_t *a, tt_node_ptr_t p) {
|
|||
|
||||
inline void tt_drop(tt_arena_t *a, tt_node_ptr_t p) {
|
||||
tt_node_idx_t i = tt_ptr_idx(p);
|
||||
if (tt_ptr_tag(p) != TT_TAG_SPECIAL && a->headers[i].inuse.refcount < TT_REFCOUNT_LIMIT) {
|
||||
tt_tag_t t = tt_ptr_tag(p);
|
||||
if (t != TT_TAG_INVALID && t != TT_TAG_SPECIAL
|
||||
&& a->headers[i].inuse.refcount < TT_REFCOUNT_LIMIT) {
|
||||
/* printf("++++++++++++++++++++++++++++++ dropping %d\n", i); */
|
||||
if (--(a->headers[i].inuse.refcount) == 0) {
|
||||
recycle_node(a, p);
|
||||
|
|
|
@ -109,7 +109,7 @@ extern int tt_arena_init(tt_arena_t *a,
|
|||
extern void tt_arena_done(tt_arena_t *a);
|
||||
|
||||
extern void tt_dump_arena_summary(tt_arena_t *a);
|
||||
extern void tt_dump_arena(tt_arena_t *a);
|
||||
extern void tt_dump_arena(tt_arena_t *a, int show_free_chain);
|
||||
|
||||
extern void tt_arena_flush(tt_arena_t *a);
|
||||
|
||||
|
|
Loading…
Reference in New Issue