Remove uses of GCC nested function extension
This commit is contained in:
parent
9c215008c7
commit
4afeb7f515
116
critbit.c
116
critbit.c
|
@ -258,14 +258,23 @@ int tt_dict_foreach(tt_arena_t *a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tt_dictset_union_context {
|
||||||
|
tt_arena_t *a;
|
||||||
|
tt_node_ptr_t result;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tt_dictset_union_f(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||||
|
struct tt_dictset_union_context *c = (struct tt_dictset_union_context *) context;
|
||||||
|
tt_node_ptr_t new_result = tt_grab(c->a, tt_dict_set(c->a, c->result, key, TT_EMPTY));
|
||||||
|
tt_drop(c->a, c->result);
|
||||||
|
c->result = new_result;
|
||||||
|
return !TT_NO_PTR_P(c->result);
|
||||||
|
}
|
||||||
|
|
||||||
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 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 */
|
struct tt_dictset_union_context context;
|
||||||
int f(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
context.a = a;
|
||||||
tt_node_ptr_t new_result = tt_grab(a, tt_dict_set(a, result, key, TT_EMPTY));
|
context.result = TT_NO_PTR; /* grab'd */
|
||||||
tt_drop(a, result);
|
|
||||||
result = new_result;
|
|
||||||
return !TT_NO_PTR_P(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tt_dict_size(a, s1) < tt_dict_size(a, s2)) {
|
if (tt_dict_size(a, s1) < tt_dict_size(a, s2)) {
|
||||||
tt_node_ptr_t tmp = s2;
|
tt_node_ptr_t tmp = s2;
|
||||||
|
@ -273,55 +282,76 @@ tt_node_ptr_t tt_dictset_union(tt_arena_t *a, tt_node_ptr_t s1, tt_node_ptr_t s2
|
||||||
s1 = tmp;
|
s1 = tmp;
|
||||||
}
|
}
|
||||||
/* Now s1 is larger, s2 is smaller. */
|
/* Now s1 is larger, s2 is smaller. */
|
||||||
result = tt_grab(a, s1);
|
context.result = tt_grab(a, s1);
|
||||||
tt_dict_foreach(a, s2, NULL, f);
|
tt_dict_foreach(a, s2, &context, tt_dictset_union_f);
|
||||||
return result;
|
return context.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tt_dictset_intersection_context {
|
||||||
|
tt_arena_t *a;
|
||||||
|
tt_node_ptr_t s1;
|
||||||
|
tt_node_ptr_t result;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tt_dictset_intersection_f(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||||
|
struct tt_dictset_intersection_context *c = (struct tt_dictset_intersection_context *) context;
|
||||||
|
if (!TT_NO_PTR_P(tt_dict_get(c->a, c->s1, key))) {
|
||||||
|
tt_node_ptr_t new_result = tt_grab(c->a, tt_dict_set(c->a, c->result, key, TT_EMPTY));
|
||||||
|
tt_drop(c->a, c->result);
|
||||||
|
c->result = new_result;
|
||||||
|
}
|
||||||
|
return !TT_NO_PTR_P(c->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 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 */
|
struct tt_dictset_intersection_context context;
|
||||||
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)) {
|
if (tt_dict_size(a, s1) < tt_dict_size(a, s2)) {
|
||||||
tt_node_ptr_t tmp = s2;
|
tt_node_ptr_t tmp = s2;
|
||||||
s2 = s1;
|
s2 = s1;
|
||||||
s1 = tmp;
|
s1 = tmp;
|
||||||
}
|
}
|
||||||
/* Now s1 is larger, s2 is smaller. */
|
/* Now s1 is larger, s2 is smaller. */
|
||||||
result = TT_EMPTY_DICT;
|
context.a = a;
|
||||||
tt_dict_foreach(a, s2, NULL, f);
|
context.s1 = s1;
|
||||||
return result;
|
context.result = TT_EMPTY_DICT; /* grab'd */
|
||||||
|
tt_dict_foreach(a, s2, &context, tt_dictset_intersection_f);
|
||||||
|
return context.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tt_dictset_difference_context {
|
||||||
|
tt_arena_t *a;
|
||||||
|
tt_node_ptr_t s2;
|
||||||
|
tt_node_ptr_t result;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tt_dictset_difference_f1(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||||
|
struct tt_dictset_difference_context *c = (struct tt_dictset_difference_context *) context;
|
||||||
|
if (!TT_NO_PTR_P(tt_dict_get(c->a, c->s2, key))) {
|
||||||
|
tt_node_ptr_t new_result = tt_grab(c->a, tt_dict_set(c->a, c->result, key, TT_EMPTY));
|
||||||
|
tt_drop(c->a, c->result);
|
||||||
|
c->result = new_result;
|
||||||
|
}
|
||||||
|
return !TT_NO_PTR_P(c->result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tt_dictset_difference_f2(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||||
|
struct tt_dictset_difference_context *c = (struct tt_dictset_difference_context *) context;
|
||||||
|
tt_node_ptr_t new_result = tt_grab(c->a, tt_dict_remove(c->a, c->result, key));
|
||||||
|
tt_drop(c->a, c->result);
|
||||||
|
c->result = new_result;
|
||||||
|
return !TT_NO_PTR_P(c->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 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;
|
struct tt_dictset_difference_context context;
|
||||||
|
context.a = a;
|
||||||
|
context.s2 = s2;
|
||||||
if (tt_dict_size(a, s1) < tt_dict_size(a, s2)) {
|
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) {
|
context.result = TT_EMPTY_DICT;
|
||||||
if (!TT_NO_PTR_P(tt_dict_get(a, s2, key))) {
|
tt_dict_foreach(a, s1, &context, tt_dictset_difference_f1);
|
||||||
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 {
|
} else {
|
||||||
int f(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
context.result = tt_grab(a, s1);
|
||||||
tt_node_ptr_t new_result = tt_grab(a, tt_dict_remove(a, result, key));
|
tt_dict_foreach(a, s2, &context, tt_dictset_difference_f2);
|
||||||
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;
|
return context.result;
|
||||||
}
|
}
|
||||||
|
|
626
route.c
626
route.c
|
@ -160,6 +160,179 @@ static inline tt_node_ptr_t collapse(tt_arena_t *a, tt_node_ptr_t n) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tt_trie_combine_context {
|
||||||
|
tt_arena_t *a;
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tt_trie_combine_examine_key_context {
|
||||||
|
struct tt_trie_combine_context *c;
|
||||||
|
tt_arena_t *a; /* the same as from tt_trie_combine_context */
|
||||||
|
tt_node_ptr_t w1;
|
||||||
|
tt_node_ptr_t w2;
|
||||||
|
tt_node_ptr_t dict1;
|
||||||
|
tt_node_ptr_t dict2;
|
||||||
|
tt_node_ptr_t result_wild; /* grab'd */
|
||||||
|
tt_node_ptr_t result_others; /* grab'd */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Forward declaration (mutual recursion) */
|
||||||
|
static tt_node_ptr_t tt_trie_combine_g(struct tt_trie_combine_context *c,
|
||||||
|
tt_node_ptr_t r1,
|
||||||
|
tt_node_ptr_t r2);
|
||||||
|
|
||||||
|
static int tt_trie_combine_examine_key(void *examine_key_context,
|
||||||
|
tt_atom_t key,
|
||||||
|
tt_node_ptr_t ignored_trie)
|
||||||
|
{
|
||||||
|
struct tt_trie_combine_examine_key_context *c =
|
||||||
|
(struct tt_trie_combine_examine_key_context *) examine_key_context;
|
||||||
|
tt_arena_t *a = c->a;
|
||||||
|
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, c->w1, c->dict1, key));
|
||||||
|
if (TT_NO_PTR_P(trie1)) return 0;
|
||||||
|
trie2 = tt_grab(a, rlookup_dict(a, c->w2, c->dict2, key));
|
||||||
|
if (TT_NO_PTR_P(trie2)) {
|
||||||
|
tt_drop(a, trie1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* printf("descending into key %d, trie1 %u/%u trie2 %u/%u\n", */
|
||||||
|
/* key, */
|
||||||
|
/* tt_ptr_idx(trie1), */
|
||||||
|
/* tt_ptr_tag(trie1), */
|
||||||
|
/* tt_ptr_idx(trie2), */
|
||||||
|
/* tt_ptr_tag(trie2)); */
|
||||||
|
new_trie = tt_trie_combine_g(c->c, trie1, trie2); /* already grabbed */
|
||||||
|
tt_drop(a, trie1);
|
||||||
|
tt_drop(a, trie2);
|
||||||
|
if (TT_NO_PTR_P(new_trie)) return 0;
|
||||||
|
new_result_others = tt_grab(a, rupdate_dict(a, c->result_wild, c->result_others, key, new_trie));
|
||||||
|
tt_drop(a, new_trie);
|
||||||
|
if (TT_NO_PTR_P(new_result_others)) return 0;
|
||||||
|
tt_drop(a, c->result_others);
|
||||||
|
c->result_others = new_result_others;
|
||||||
|
/* printf("after update key %d, result_others %u/%u\n", */
|
||||||
|
/* key, */
|
||||||
|
/* tt_ptr_idx(c->result_others), */
|
||||||
|
/* tt_ptr_tag(c->result_others)); */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* N.B. Returns a tt_grab'd result. */
|
||||||
|
static tt_node_ptr_t tt_trie_combine_g(struct tt_trie_combine_context *c,
|
||||||
|
tt_node_ptr_t r1,
|
||||||
|
tt_node_ptr_t r2)
|
||||||
|
{
|
||||||
|
tt_arena_t *a = c->a;
|
||||||
|
tt_tag_t t1, t2;
|
||||||
|
|
||||||
|
if (TT_EMPTY_P(r1)) {
|
||||||
|
return c->left_empty_keep ? tt_grab(a, r2) : TT_EMPTY;
|
||||||
|
}
|
||||||
|
if (TT_EMPTY_P(r2)) {
|
||||||
|
return c->right_empty_keep ? tt_grab(a, r1) : TT_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
t1 = tt_ptr_tag(r1);
|
||||||
|
t2 = tt_ptr_tag(r2);
|
||||||
|
|
||||||
|
if (t1 == TT_TAG_BRANCH && t2 == TT_TAG_BRANCH) {
|
||||||
|
tt_node_ptr_t result = TT_NO_PTR; /* grab'd */
|
||||||
|
struct tt_trie_combine_examine_key_context ekc;
|
||||||
|
int ok = 1;
|
||||||
|
|
||||||
|
ekc.c = c;
|
||||||
|
ekc.a = a;
|
||||||
|
ekc.w1 = TT_BRANCH_WILDCARD(a,r1);
|
||||||
|
ekc.w2 = TT_BRANCH_WILDCARD(a,r2);
|
||||||
|
ekc.dict1 = TT_BRANCH_OTHERS(a,r1);
|
||||||
|
ekc.dict2 = TT_BRANCH_OTHERS(a,r2);
|
||||||
|
ekc.result_wild = TT_EMPTY; /* grab'd */
|
||||||
|
ekc.result_others = TT_EMPTY_DICT; /* grab'd */
|
||||||
|
|
||||||
|
/* 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(ekc.w1) && !TT_EMPTY_P(ekc.w2)) {
|
||||||
|
/* Two wildcards - worst case. Must loop over both dictionaries. */
|
||||||
|
ekc.result_wild = tt_trie_combine_g(c, ekc.w1, ekc.w2);
|
||||||
|
ok = !TT_NO_PTR_P(ekc.result_wild);
|
||||||
|
ok = ok && tt_dict_foreach(a, ekc.dict1, &ekc, tt_trie_combine_examine_key);
|
||||||
|
ok = ok && tt_dict_foreach(a, ekc.dict2, &ekc, tt_trie_combine_examine_key);
|
||||||
|
} else if ((!TT_EMPTY_P(ekc.w1)) ||
|
||||||
|
(TT_EMPTY_P(ekc.w2) &&
|
||||||
|
(tt_dict_size(a, ekc.dict1) >= tt_dict_size(a, ekc.dict2)))) {
|
||||||
|
/* Either a wildcard on the left, or no wildcard at all but the left is larger */
|
||||||
|
if (c->left_base_keep) {
|
||||||
|
ekc.result_wild = tt_grab(a, ekc.w1);
|
||||||
|
ekc.result_others = tt_grab(a, ekc.dict1);
|
||||||
|
}
|
||||||
|
ok = ok && tt_dict_foreach(a, ekc.dict2, &ekc, tt_trie_combine_examine_key);
|
||||||
|
} else {
|
||||||
|
/* Either a wildcard on the right, or no wildcard at all but the right is larger */
|
||||||
|
if (c->right_base_keep) {
|
||||||
|
ekc.result_wild = tt_grab(a, ekc.w2);
|
||||||
|
ekc.result_others = tt_grab(a, ekc.dict2);
|
||||||
|
}
|
||||||
|
ok = ok && tt_dict_foreach(a, ekc.dict1, &ekc, tt_trie_combine_examine_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
result = tt_grab(a, rbranch(a, ekc.result_wild, ekc.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, ekc.result_wild);
|
||||||
|
tt_drop(a, ekc.result_others);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t1 == TT_TAG_TAIL) {
|
||||||
|
if (t2 == TT_TAG_TAIL) {
|
||||||
|
tt_node_ptr_t combined =
|
||||||
|
RET_IF_NO_PTR(tt_trie_combine_g(c, 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 r1_expanded = tt_grab(a, RET_IF_NO_PTR(expand(a, r1)));
|
||||||
|
tt_node_ptr_t result = tt_trie_combine_g(c, r1_expanded, r2);
|
||||||
|
tt_drop(a, r1_expanded);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else if (t2 == TT_TAG_TAIL) {
|
||||||
|
tt_node_ptr_t r2_expanded = tt_grab(a, RET_IF_NO_PTR(expand(a, r2)));
|
||||||
|
tt_node_ptr_t result = tt_trie_combine_g(c, r1, r2_expanded);
|
||||||
|
tt_drop(a, r2_expanded);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t1 == TT_TAG_OK || t2 == TT_TAG_OK) {
|
||||||
|
return c->f(c->f_context, r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no legitimate combination of tags that should let us get here. */
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
/* N.B. Returns a tt_grab'd result. */
|
/* N.B. Returns a tt_grab'd result. */
|
||||||
tt_node_ptr_t tt_trie_combine(tt_arena_t *a,
|
tt_node_ptr_t tt_trie_combine(tt_arena_t *a,
|
||||||
tt_node_ptr_t r1,
|
tt_node_ptr_t r1,
|
||||||
|
@ -174,174 +347,64 @@ tt_node_ptr_t tt_trie_combine(tt_arena_t *a,
|
||||||
tt_node_ptr_t r1,
|
tt_node_ptr_t r1,
|
||||||
tt_node_ptr_t r2))
|
tt_node_ptr_t r2))
|
||||||
{
|
{
|
||||||
/* N.B. Returns a tt_grab'd result. */
|
struct tt_trie_combine_context context;
|
||||||
tt_node_ptr_t g(tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
context.a = a;
|
||||||
tt_tag_t t1, t2;
|
context.left_empty_keep = left_empty_keep;
|
||||||
|
context.right_empty_keep = right_empty_keep;
|
||||||
|
context.left_base_keep = left_base_keep;
|
||||||
|
context.right_base_keep = right_base_keep;
|
||||||
|
context.f_context = f_context;
|
||||||
|
context.f = f;
|
||||||
|
/* No need for tt_grab here - tt_trie_combine_g has already done that for us */
|
||||||
|
return tt_trie_combine_g(&context, r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
if (TT_EMPTY_P(r1)) {
|
static tt_node_ptr_t f_union_map(void *f_context, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||||
return left_empty_keep ? tt_grab(a, r2) : TT_EMPTY;
|
tt_arena_t *a = (tt_arena_t *) f_context;
|
||||||
}
|
tt_tag_t t1 = tt_ptr_tag(r1);
|
||||||
if (TT_EMPTY_P(r2)) {
|
tt_tag_t t2 = tt_ptr_tag(r2);
|
||||||
return right_empty_keep ? tt_grab(a, r1) : TT_EMPTY;
|
if (t1 != TT_TAG_OK) {
|
||||||
}
|
/* t2 must be ok. */
|
||||||
|
return tt_grab(a, r2);
|
||||||
t1 = tt_ptr_tag(r1);
|
} else if (t2 != TT_TAG_OK) {
|
||||||
t2 = tt_ptr_tag(r2);
|
return tt_grab(a, r1);
|
||||||
|
} else {
|
||||||
if (t1 == TT_TAG_BRANCH && t2 == TT_TAG_BRANCH) {
|
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 w1 = TT_BRANCH_WILDCARD(a,r1);
|
tt_node_ptr_t result = tt_cons_ok(a, s);
|
||||||
tt_node_ptr_t w2 = TT_BRANCH_WILDCARD(a,r2);
|
tt_drop(a, s);
|
||||||
tt_node_ptr_t dict1 = TT_BRANCH_OTHERS(a,r1);
|
return tt_grab(a, result);
|
||||||
tt_node_ptr_t dict2 = TT_BRANCH_OTHERS(a,r2);
|
|
||||||
tt_node_ptr_t result_wild = TT_EMPTY; /* 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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
/* printf("descending into key %d, trie1 %u/%u trie2 %u/%u\n", */
|
|
||||||
/* key, */
|
|
||||||
/* tt_ptr_idx(trie1), */
|
|
||||||
/* tt_ptr_tag(trie1), */
|
|
||||||
/* tt_ptr_idx(trie2), */
|
|
||||||
/* tt_ptr_tag(trie2)); */
|
|
||||||
new_trie = g(trie1, trie2); /* already grabbed */
|
|
||||||
tt_drop(a, trie1);
|
|
||||||
tt_drop(a, trie2);
|
|
||||||
if (TT_NO_PTR_P(new_trie)) return 0;
|
|
||||||
new_result_others = tt_grab(a, rupdate_dict(a, result_wild, result_others, key, new_trie));
|
|
||||||
tt_drop(a, new_trie);
|
|
||||||
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)) ||
|
|
||||||
(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 */
|
|
||||||
if (left_base_keep) {
|
|
||||||
result_wild = tt_grab(a, w1);
|
|
||||||
result_others = tt_grab(a, dict1);
|
|
||||||
}
|
|
||||||
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 */
|
|
||||||
if (right_base_keep) {
|
|
||||||
result_wild = tt_grab(a, w2);
|
|
||||||
result_others = tt_grab(a, dict2);
|
|
||||||
}
|
|
||||||
ok = ok && tt_dict_foreach(a, dict1, NULL, examine_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
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 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;
|
|
||||||
}
|
|
||||||
} else if (t2 == TT_TAG_TAIL) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_map(tt_arena_t *a, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
tt_node_ptr_t tt_trie_union_map(tt_arena_t *a, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||||
tt_node_ptr_t f_union_map(void *f_context, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
return tt_trie_combine(a, r1, r2, 1, 1, 1, 1, a, f_union_map);
|
||||||
tt_tag_t t1 = tt_ptr_tag(r1);
|
}
|
||||||
tt_tag_t t2 = tt_ptr_tag(r2);
|
|
||||||
if (t1 != TT_TAG_OK) {
|
struct f_union_set_context {
|
||||||
/* t2 must be ok. */
|
tt_arena_t *a;
|
||||||
return tt_grab(a, r2);
|
tt_node_ptr_t emptyset;
|
||||||
} else if (t2 != TT_TAG_OK) {
|
};
|
||||||
return tt_grab(a, r1);
|
|
||||||
} else {
|
static tt_node_ptr_t f_union_set(void *f_context, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||||
tt_node_ptr_t s = RET_IF_NO_PTR(tt_dictset_union(a, TT_OK_DICT(a,r1), TT_OK_DICT(a,r2)));
|
struct f_union_set_context *c = (struct f_union_set_context *) f_context;
|
||||||
tt_node_ptr_t result = tt_cons_ok(a, s);
|
return tt_grab(c->a, c->emptyset);
|
||||||
tt_drop(a, s);
|
|
||||||
return tt_grab(a, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tt_trie_combine(a, r1, r2, 1, 1, 1, 1, NULL, f_union_map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tt_node_ptr_t tt_trie_union_set(tt_arena_t *a, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
tt_node_ptr_t tt_trie_union_set(tt_arena_t *a, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||||
tt_node_ptr_t emptyset = tt_grab(a, RET_IF_NO_PTR(tt_cons_ok(a, TT_EMPTY_DICT)));
|
struct f_union_set_context context;
|
||||||
tt_node_ptr_t result;
|
tt_node_ptr_t result;
|
||||||
tt_node_ptr_t f_union_map(void *f_context, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
context.a = a;
|
||||||
return tt_grab(a, emptyset);
|
context.emptyset = tt_grab(a, RET_IF_NO_PTR(tt_cons_ok(a, TT_EMPTY_DICT)));
|
||||||
}
|
result = tt_trie_combine(a, r1, r2, 1, 1, 1, 1, &context, f_union_set);
|
||||||
result = tt_trie_combine(a, r1, r2, 1, 1, 1, 1, NULL, f_union_map);
|
tt_drop(a, context.emptyset);
|
||||||
tt_drop(a, emptyset);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static tt_node_ptr_t f_subtract_set(void *f_context, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||||
|
return TT_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
tt_node_ptr_t tt_trie_subtract_set(tt_arena_t *a, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
tt_node_ptr_t tt_trie_subtract_set(tt_arena_t *a, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
||||||
tt_node_ptr_t f_subtract_set(void *f_context, tt_node_ptr_t r1, tt_node_ptr_t r2) {
|
|
||||||
return TT_EMPTY;
|
|
||||||
}
|
|
||||||
return tt_trie_combine(a, r1, r2, 0, 1, 1, 0, NULL, f_subtract_set);
|
return tt_trie_combine(a, r1, r2, 0, 1, 1, 0, NULL, f_subtract_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,59 +428,74 @@ tt_node_ptr_t tt_trie_step(tt_arena_t *a, tt_node_ptr_t r, tt_atom_t key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tt_trie_relabel_visit_edge_context {
|
||||||
|
tt_arena_t *a;
|
||||||
|
void *f_context;
|
||||||
|
tt_node_ptr_t (*f)(void *f_context, tt_node_ptr_t oldlabel);
|
||||||
|
tt_node_ptr_t wild;
|
||||||
|
tt_node_ptr_t others;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tt_trie_relabel_visit_edge(void *context, tt_atom_t key, tt_node_ptr_t trie) {
|
||||||
|
struct tt_trie_relabel_visit_edge_context *c =
|
||||||
|
(struct tt_trie_relabel_visit_edge_context *) context;
|
||||||
|
tt_arena_t *a = c->a;
|
||||||
|
tt_node_ptr_t new_trie = tt_grab(a, tt_trie_relabel(a, trie, c->f_context, c->f));
|
||||||
|
tt_node_ptr_t new_others;
|
||||||
|
if (TT_NO_PTR_P(new_trie)) return 0;
|
||||||
|
new_others = tt_grab(a, rupdate_dict(a, c->wild, c->others, key, new_trie));
|
||||||
|
tt_drop(a, new_trie);
|
||||||
|
if (TT_NO_PTR_P(new_others)) return 0;
|
||||||
|
tt_drop(a, c->others);
|
||||||
|
c->others = new_others;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
tt_node_ptr_t tt_trie_relabel(tt_arena_t *a,
|
tt_node_ptr_t tt_trie_relabel(tt_arena_t *a,
|
||||||
tt_node_ptr_t r,
|
tt_node_ptr_t r,
|
||||||
void *f_context,
|
void *f_context,
|
||||||
tt_node_ptr_t (*f)(void *f_context,
|
tt_node_ptr_t (*f)(void *f_context,
|
||||||
tt_node_ptr_t oldlabel))
|
tt_node_ptr_t oldlabel))
|
||||||
{
|
{
|
||||||
tt_node_ptr_t walk(tt_node_ptr_t r) {
|
if (TT_EMPTY_P(r)) {
|
||||||
if (TT_EMPTY_P(r)) {
|
return r;
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (tt_ptr_tag(r)) {
|
|
||||||
case TT_TAG_OK:
|
|
||||||
return tt_cons_ok(a, RET_IF_NO_PTR(f(f_context, TT_OK_DICT(a, r))));
|
|
||||||
|
|
||||||
case TT_TAG_TAIL:
|
|
||||||
return tt_cons_tail(a, RET_IF_NO_PTR(walk(TT_TAIL_TRIE(a, r))));
|
|
||||||
|
|
||||||
case TT_TAG_BRANCH: {
|
|
||||||
tt_node_ptr_t wild = tt_grab(a, RET_IF_NO_PTR(walk(TT_BRANCH_WILDCARD(a, r))));
|
|
||||||
tt_node_ptr_t others = TT_EMPTY_DICT; /* grab'd */
|
|
||||||
tt_node_ptr_t result = TT_NO_PTR;
|
|
||||||
int visit_edge(void *context, tt_atom_t key, tt_node_ptr_t trie) {
|
|
||||||
tt_node_ptr_t new_trie = tt_grab(a, walk(trie));
|
|
||||||
tt_node_ptr_t new_others;
|
|
||||||
if (TT_NO_PTR_P(new_trie)) return 0;
|
|
||||||
new_others = tt_grab(a, rupdate_dict(a, wild, others, key, new_trie));
|
|
||||||
tt_drop(a, new_trie);
|
|
||||||
if (TT_NO_PTR_P(new_others)) return 0;
|
|
||||||
tt_drop(a, others);
|
|
||||||
others = new_others;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (tt_dict_foreach(a, TT_BRANCH_OTHERS(a, r), NULL, visit_edge)) {
|
|
||||||
result = rbranch(a, wild, others);
|
|
||||||
}
|
|
||||||
tt_drop(a, wild);
|
|
||||||
tt_drop(a, others);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return walk(r);
|
|
||||||
|
switch (tt_ptr_tag(r)) {
|
||||||
|
case TT_TAG_OK:
|
||||||
|
return tt_cons_ok(a, RET_IF_NO_PTR(f(f_context, TT_OK_DICT(a, r))));
|
||||||
|
|
||||||
|
case TT_TAG_TAIL:
|
||||||
|
return tt_cons_tail(a, RET_IF_NO_PTR(tt_trie_relabel(a, TT_TAIL_TRIE(a, r), f_context, f)));
|
||||||
|
|
||||||
|
case TT_TAG_BRANCH: {
|
||||||
|
struct tt_trie_relabel_visit_edge_context context;
|
||||||
|
context.a = a;
|
||||||
|
context.f_context = f_context;
|
||||||
|
context.f = f;
|
||||||
|
context.wild =
|
||||||
|
tt_grab(a, RET_IF_NO_PTR(tt_trie_relabel(a, TT_BRANCH_WILDCARD(a, r), f_context, f)));
|
||||||
|
context.others = TT_EMPTY_DICT; /* grab'd */
|
||||||
|
tt_node_ptr_t result = TT_NO_PTR;
|
||||||
|
if (tt_dict_foreach(a, TT_BRANCH_OTHERS(a, r), &context, tt_trie_relabel_visit_edge)) {
|
||||||
|
result = rbranch(a, context.wild, context.others);
|
||||||
|
}
|
||||||
|
tt_drop(a, context.wild);
|
||||||
|
tt_drop(a, context.others);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static tt_node_ptr_t relabel_to_const(void *context, tt_node_ptr_t oldlabel) {
|
||||||
|
return *((tt_node_ptr_t *) context);
|
||||||
}
|
}
|
||||||
|
|
||||||
tt_node_ptr_t tt_trie_relabel_const(tt_arena_t *a, tt_node_ptr_t r, tt_node_ptr_t newlabel) {
|
tt_node_ptr_t tt_trie_relabel_const(tt_arena_t *a, tt_node_ptr_t r, tt_node_ptr_t newlabel) {
|
||||||
tt_node_ptr_t relabel_to_const(void *context, tt_node_ptr_t oldlabel) {
|
return tt_trie_relabel(a, r, &newlabel, relabel_to_const);
|
||||||
return newlabel;
|
|
||||||
}
|
|
||||||
return tt_trie_relabel(a, r, NULL, relabel_to_const);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tt_node_ptr_t tt_begin_path(tt_arena_t *a, tt_node_ptr_t ok_dict) {
|
tt_node_ptr_t tt_begin_path(tt_arena_t *a, tt_node_ptr_t ok_dict) {
|
||||||
|
@ -450,73 +528,91 @@ static size_t gross_approximate_utf8_strlen(char const *c) {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tt_dump_routingtable(tt_arena_t *a, tt_node_ptr_t r, int initial_indent) {
|
static int tt_dump_routingtable_pkey(void *context, tt_atom_t key, tt_node_ptr_t ignored_trie) {
|
||||||
void walk(int indent, tt_node_ptr_t r) {
|
int *need_space = (int *) context;
|
||||||
switch (tt_ptr_tag(r)) {
|
if (*need_space) {
|
||||||
case TT_TAG_TAIL:
|
putchar(' ');
|
||||||
printf(" ...>");
|
} else {
|
||||||
walk(indent + 5, TT_TAIL_TRIE(a, r));
|
*need_space = 1;
|
||||||
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 + gross_approximate_utf8_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);
|
printf("%d", key);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forward declaration (mutual recursion) */
|
||||||
|
static void tt_dump_routingtable_walk(tt_arena_t *a, tt_node_ptr_t r, int indent);
|
||||||
|
|
||||||
|
struct tt_dump_routingtable_pedge_context {
|
||||||
|
tt_arena_t *a;
|
||||||
|
int indent;
|
||||||
|
int need_sep;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tt_dump_routingtable_pedge(void *context, tt_atom_t key, tt_node_ptr_t node) {
|
||||||
|
struct tt_dump_routingtable_pedge_context *c =
|
||||||
|
(struct tt_dump_routingtable_pedge_context *) context;
|
||||||
|
char keystr[256]; /* not very tight */
|
||||||
|
if (c->need_sep) {
|
||||||
|
putchar('\n');
|
||||||
|
print_indent(c->indent);
|
||||||
|
} else {
|
||||||
|
c->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);
|
||||||
|
tt_dump_routingtable_walk(c->a, node, c->indent + gross_approximate_utf8_strlen(keystr));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tt_dump_routingtable_walk(tt_arena_t *a, tt_node_ptr_t r, int indent) {
|
||||||
|
switch (tt_ptr_tag(r)) {
|
||||||
|
case TT_TAG_TAIL:
|
||||||
|
printf(" ...>");
|
||||||
|
tt_dump_routingtable_walk(a, TT_TAIL_TRIE(a, r), indent + 5);
|
||||||
|
break;
|
||||||
|
case TT_TAG_OK: {
|
||||||
|
int need_space = 0;
|
||||||
|
fputs(" {", stdout);
|
||||||
|
tt_dict_foreach(a, TT_OK_DICT(a, r), &need_space, tt_dump_routingtable_pkey);
|
||||||
|
putchar('}');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TT_TAG_BRANCH: {
|
||||||
|
struct tt_dump_routingtable_pedge_context context;
|
||||||
|
context.a = a;
|
||||||
|
context.indent = indent;
|
||||||
|
context.need_sep = 0;
|
||||||
|
if (!TT_EMPTY_P(TT_BRANCH_WILDCARD(a, r))) {
|
||||||
|
tt_dump_routingtable_pedge(&context, TT_WILD, TT_BRANCH_WILDCARD(a, r));
|
||||||
|
}
|
||||||
|
tt_dict_foreach(a, TT_BRANCH_OTHERS(a, r), &context, tt_dump_routingtable_pedge);
|
||||||
|
if (!context.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tt_dump_routingtable(tt_arena_t *a, tt_node_ptr_t r, int initial_indent) {
|
||||||
|
tt_dump_routingtable_walk(a, r, initial_indent);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue