diff --git a/main.c b/main.c index d078f5e..ffec8d8 100644 --- a/main.c +++ b/main.c @@ -99,6 +99,21 @@ int main1(int argc, char *argv[]) { return EXIT_SUCCESS; } +static tt_node_ptr_t make_path(tt_arena_t *a, tt_node_ptr_t ok_dict, int n, tt_atom_t const *atoms) +{ + int i; + tt_node_ptr_t result = tt_begin_path(a, ok_dict); + for (i = n - 1; i >= 0; i--) { + result = tt_prepend_path(a, atoms[i], result); + } + return result; +} + +#define MAKE_PATH(a, ok_dict, elts...) ({ \ + tt_atom_t __atoms[] = elts; \ + make_path(a, ok_dict, sizeof(__atoms)/sizeof(tt_atom_t), __atoms); \ + }) + int main(int argc, char *argv[]) { tt_arena_t a; tt_node_ptr_t a_set; @@ -112,21 +127,11 @@ int main(int argc, char *argv[]) { printf("\n============================================================ 1\n"); { - 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))))); + tt_node_ptr_t A = tt_grab(&a, MAKE_PATH(&a, a_set, {TT_BOS, 'A', TT_EOS})); printf("\nA node: %u/%u\n", tt_ptr_idx(A), tt_ptr_tag(A)); tt_arena_flush(&a); tt_dump_arena_dot("A", A, &a); - 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))))); + tt_node_ptr_t B = tt_grab(&a, MAKE_PATH(&a, b_set, {TT_BOS, 'B', TT_EOS})); printf("\nB node: %u/%u\n", tt_ptr_idx(B), tt_ptr_tag(B)); tt_dump_arena_dot("B", B, &a); tt_node_ptr_t C = tt_trie_union(&a, A, B); @@ -147,21 +152,11 @@ int main(int argc, char *argv[]) { printf("\n============================================================ 2\n"); { - 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))))); + tt_node_ptr_t A = tt_grab(&a, MAKE_PATH(&a, a_set, {TT_BOS, 'A', TT_EOS})); printf("\nA node: %u/%u\n", tt_ptr_idx(A), tt_ptr_tag(A)); tt_arena_flush(&a); tt_dump_arena_dot("A", A, &a); - tt_node_ptr_t B = - tt_grab(&a, - tt_prepend_path(&a, TT_BOS, - tt_prepend_path(&a, TT_WILD, - tt_prepend_path(&a, TT_EOS, - tt_begin_path(&a, b_set))))); + tt_node_ptr_t B = tt_grab(&a, MAKE_PATH(&a, b_set, {TT_BOS, TT_WILD, TT_EOS})); printf("\nB node: %u/%u\n", tt_ptr_idx(B), tt_ptr_tag(B)); tt_dump_arena_dot("B", B, &a); tt_node_ptr_t C = tt_trie_union(&a, A, B); @@ -179,16 +174,11 @@ int main(int argc, char *argv[]) { printf("\n============================================================ 3\n"); { - 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))))); + tt_node_ptr_t A = tt_grab(&a, MAKE_PATH(&a, a_set, {TT_BOS, 'A', TT_EOS})); printf("\nA node: %u/%u\n", tt_ptr_idx(A), tt_ptr_tag(A)); tt_arena_flush(&a); tt_dump_arena_dot("A", A, &a); - tt_node_ptr_t B = tt_grab(&a, tt_prepend_path(&a, TT_WILD, tt_begin_path(&a, b_set))); + tt_node_ptr_t B = tt_grab(&a, MAKE_PATH(&a, b_set, {TT_WILD})); printf("\nB node: %u/%u\n", tt_ptr_idx(B), tt_ptr_tag(B)); tt_dump_arena_dot("B", B, &a); tt_node_ptr_t C = tt_trie_union(&a, A, B); @@ -206,17 +196,11 @@ int main(int argc, char *argv[]) { printf("\n============================================================ 4\n"); { - 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, - /* NB b_set below */ - tt_begin_path(&a, b_set))))); + tt_node_ptr_t A = tt_grab(&a, MAKE_PATH(&a, b_set /* !!! */, {TT_BOS, 'A', TT_EOS})); printf("\nA node: %u/%u\n", tt_ptr_idx(A), tt_ptr_tag(A)); tt_arena_flush(&a); tt_dump_arena_dot("A", A, &a); - tt_node_ptr_t B = tt_grab(&a, tt_prepend_path(&a, TT_WILD, tt_begin_path(&a, b_set))); + tt_node_ptr_t B = tt_grab(&a, MAKE_PATH(&a, b_set, {TT_WILD})); printf("\nB node: %u/%u\n", tt_ptr_idx(B), tt_ptr_tag(B)); tt_dump_arena_dot("B", B, &a); tt_node_ptr_t C = tt_trie_union(&a, A, B); @@ -232,6 +216,86 @@ int main(int argc, char *argv[]) { tt_drop(&a, C); } + printf("\n============================================================ 5\n"); + { + tt_node_ptr_t A = tt_grab(&a, MAKE_PATH(&a, a_set, {TT_BOS, 'A', 'B', TT_EOS})); + printf("\nA node: %u/%u\n", tt_ptr_idx(A), tt_ptr_tag(A)); + tt_arena_flush(&a); + tt_dump_arena_dot("A", A, &a); + tt_node_ptr_t B = tt_grab(&a, MAKE_PATH(&a, b_set, {TT_BOS, TT_WILD, TT_EOS})); + printf("\nB node: %u/%u\n", tt_ptr_idx(B), tt_ptr_tag(B)); + tt_dump_arena_dot("B", B, &a); + tt_node_ptr_t C = tt_trie_union(&a, A, B); + tt_arena_flush(&a); + tt_dump_arena_dot("Cpredrop", C, &a); + tt_drop(&a, A); + tt_drop(&a, B); + printf("\nC node: %u/%u\n", tt_ptr_idx(C), tt_ptr_tag(C)); + tt_arena_flush(&a); + tt_dump_arena_dot("Cpostdrop", C, &a); + putchar('\n'); + tt_dump_routingtable(&a, C, 0); + tt_drop(&a, C); + } + + printf("\n============================================================ 6\n"); + { + tt_node_ptr_t A = tt_grab(&a, MAKE_PATH(&a, a_set, {TT_BOS, 'A', 'B', TT_EOS})); + printf("\nA node: %u/%u\n", tt_ptr_idx(A), tt_ptr_tag(A)); + tt_arena_flush(&a); + tt_dump_arena_dot("A", A, &a); + tt_node_ptr_t B = tt_grab(&a, MAKE_PATH(&a, b_set, {TT_BOS, TT_WILD, TT_WILD, TT_EOS})); + printf("\nB node: %u/%u\n", tt_ptr_idx(B), tt_ptr_tag(B)); + tt_dump_arena_dot("B", B, &a); + tt_node_ptr_t C = tt_trie_union(&a, A, B); + tt_arena_flush(&a); + tt_dump_arena_dot("Cpredrop", C, &a); + tt_drop(&a, A); + tt_drop(&a, B); + printf("\nC node: %u/%u\n", tt_ptr_idx(C), tt_ptr_tag(C)); + tt_arena_flush(&a); + tt_dump_arena_dot("Cpostdrop", C, &a); + putchar('\n'); + tt_dump_routingtable(&a, C, 0); + tt_drop(&a, C); + } + + printf("\n============================================================ 7\n"); + { + tt_node_ptr_t A = tt_grab(&a, MAKE_PATH(&a, a_set, {TT_BOS, 'A', TT_WILD, TT_EOS})); + printf("\nA node: %u/%u\n", tt_ptr_idx(A), tt_ptr_tag(A)); + tt_arena_flush(&a); + tt_dump_arena_dot("A", A, &a); + tt_node_ptr_t B = tt_grab(&a, MAKE_PATH(&a, b_set, {TT_BOS, TT_WILD, 'B', TT_EOS})); + printf("\nB node: %u/%u\n", tt_ptr_idx(B), tt_ptr_tag(B)); + tt_dump_arena_dot("B", B, &a); + tt_node_ptr_t C = tt_trie_union(&a, A, B); + tt_arena_flush(&a); + tt_dump_arena_dot("Cpredrop", C, &a); + tt_drop(&a, A); + tt_drop(&a, B); + printf("\nC node: %u/%u\n", tt_ptr_idx(C), tt_ptr_tag(C)); + tt_arena_flush(&a); + tt_dump_arena_dot("Cpostdrop", C, &a); + putchar('\n'); + tt_dump_routingtable(&a, C, 0); + + tt_node_ptr_t D = tt_trie_union(&a, C, C); + tt_drop(&a, C); + tt_arena_flush(&a); + tt_dump_arena_dot("D", D, &a); + tt_dump_routingtable(&a, D, 0); + + tt_node_ptr_t E = tt_grab(&a, MAKE_PATH(&a, b_set, {TT_WILD})); + tt_node_ptr_t F = tt_trie_union(&a, D, E); + tt_drop(&a, D); + tt_drop(&a, E); + tt_arena_flush(&a); + tt_dump_arena_dot("F", F, &a); + tt_dump_routingtable(&a, F, 0); + tt_drop(&a, F); + } + tt_arena_flush(&a); tt_dump_arena_dot("afterAll", TT_NO_PTR, &a); /* expect a_set and b_set here */ diff --git a/route.c b/route.c index 437a63f..c804476 100644 --- a/route.c +++ b/route.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -28,8 +29,12 @@ static inline tt_node_ptr_t rbranch(tt_arena_t *a, tt_node_ptr_t wild, /* trie */ tt_node_ptr_t others) /* dict */ { - if (TT_EMPTY_P(wild) && TT_EMPTY_DICT_P(others)) { - return TT_EMPTY; + if (TT_EMPTY_DICT_P(others)) { + if (TT_EMPTY_P(wild)) { + return TT_EMPTY; + } else if (tt_ptr_tag(wild) == TT_TAG_TAIL) { + return wild; + } } return tt_cons_branch(a, wild, others); } @@ -83,6 +88,14 @@ static inline tt_node_ptr_t rupdate_dict(tt_arena_t *a, { assert(key != TT_WILD); assert(TT_EMPTY_DICT_P(old_others) || tt_ptr_tag(old_others) == TT_TAG_DICT); + /* printf("rupdate_dict key %d k %u/%u old_wild %u/%u old_others %u/%u\n", */ + /* key, */ + /* tt_ptr_idx(k), */ + /* tt_ptr_tag(k), */ + /* tt_ptr_idx(old_wild), */ + /* tt_ptr_tag(old_wild), */ + /* tt_ptr_idx(old_others), */ + /* tt_ptr_tag(old_others)); */ #define OTHERS_SANS_KEY() (tt_dict_remove(a, old_others, key)) #define OTHERS_WITH_KEY() (tt_dict_set(a, old_others, key, k)) @@ -108,27 +121,45 @@ static inline tt_node_ptr_t rupdate_dict(tt_arena_t *a, #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, - tt_node_ptr_t k) /* trie */ -{ - assert(key != TT_WILD); - if (TT_EMPTY_P(r0)) { - return rseq(a, key, k); - } else { - tt_node_ptr_t new_others; - assert(tt_ptr_tag(r0) == TT_TAG_BRANCH); - 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 inline tt_node_ptr_t rupdate(tt_arena_t *a, */ +/* tt_node_ptr_t r0, /\* branch *\/ */ +/* tt_atom_t key, */ +/* tt_node_ptr_t k) /\* trie *\/ */ +/* { */ +/* assert(key != TT_WILD); */ +/* if (TT_EMPTY_P(r0)) { */ +/* return rseq(a, key, k); */ +/* } else { */ +/* tt_node_ptr_t new_others; */ +/* assert(tt_ptr_tag(r0) == TT_TAG_BRANCH); */ +/* 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 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); } +static inline tt_node_ptr_t collapse(tt_arena_t *a, tt_node_ptr_t n) { + if (tt_ptr_tag(n) == TT_TAG_BRANCH) { + tt_node_ptr_t w = TT_BRANCH_WILDCARD(a,n); + tt_node_ptr_t o = TT_BRANCH_OTHERS(a,n); + if (tt_ptr_tag(w) == TT_TAG_TAIL && + tt_ptr_tag(o) == TT_TAG_DICT && + TT_DICT_SIZE(a,o) == 1) { + tt_node_ptr_t root = TT_DICT_ROOT(a,o); + assert(tt_ptr_tag(root) == TT_TAG_LEAF); + if (TT_LEAF_ATOM(a,root) == TT_EOS && + TT_LEAF_TRIE(a,root) == TT_TAIL_TRIE(a,w)) { + return w; + } + } + } + return n; +} + /* N.B. Returns a tt_grab'd result. */ tt_node_ptr_t tt_trie_combine(tt_arena_t *a, tt_node_ptr_t r1, @@ -187,12 +218,22 @@ tt_node_ptr_t tt_trie_combine(tt_arena_t *a, if (TT_NO_PTR_P(new_result_others)) return 0; tt_drop(a, result_others); result_others = new_result_others; + /* printf("after update key %d, result_others %u/%u\n", */ + /* key, */ + /* tt_ptr_idx(result_others), */ + /* tt_ptr_tag(result_others)); */ return 1; } + /* printf("{{{ combining %u/%u with %u/%u\n", */ + /* tt_ptr_idx(r1), */ + /* tt_ptr_tag(r1), */ + /* tt_ptr_idx(r2), */ + /* tt_ptr_tag(r2)); */ if (!TT_EMPTY_P(w1) && !TT_EMPTY_P(w2)) { /* Two wildcards - worst case. Must loop over both dictionaries. */ result_wild = g(w1, w2); + ok = !TT_NO_PTR_P(result_wild); 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)) || @@ -211,7 +252,15 @@ tt_node_ptr_t tt_trie_combine(tt_arena_t *a, if (ok) { result = tt_grab(a, rbranch(a, result_wild, result_others)); + if (!TT_NO_PTR_P(result)) { + tt_node_ptr_t collapsed = tt_grab(a, collapse(a, result)); + tt_drop(a, result); + result = collapsed; + } } + /* printf("}}} result %u/%u\n", */ + /* tt_ptr_idx(result), */ + /* tt_ptr_tag(result)); */ tt_drop(a, result_wild); tt_drop(a, result_others); @@ -286,6 +335,18 @@ void print_indent(int spaces) { } } +static size_t gross_approximate_utf8_strlen(char const *c) { + size_t count = 0; + while (*c) { + unsigned char b = *c; + if (b < 0x80 || b >= 0xc0) { + count++; + } + c++; + } + return count; +} + 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)) { @@ -330,7 +391,7 @@ void tt_dump_routingtable(tt_arena_t *a, tt_node_ptr_t r, int initial_indent) { snprintf(keystr, sizeof(keystr) - 1, " %d", key); } fputs(keystr, stdout); - walk(indent + strlen(keystr), node); + walk(indent + gross_approximate_utf8_strlen(keystr), node); return 1; } if (!TT_EMPTY_P(TT_BRANCH_WILDCARD(a, r))) {