diff --git a/route.c b/route.c new file mode 100644 index 0000000..db368aa --- /dev/null +++ b/route.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include + +#include "treetrie.h" +#include "critbit.h" +#include "route.h" + +static inline tt_node_ptr_t rseq(tt_arena_t *a, tt_atom_t s, tt_node_ptr_t r) { + if (TT_EMPTY_P(r)) { + return TT_EMPTY; + } + assert(s != TT_WILD); + return tt_cons_branch(a, TT_EMPTY, RET_IF_NO_PTR(tt_dict_singleton(a, s, r))); +} + +static inline tt_node_ptr_t rwild(tt_arena_t *a, tt_node_ptr_t r) { + if (TT_EMPTY_P(r)) { + return TT_EMPTY; + } + return tt_cons_branch(a, r, TT_EMPTY_DICT); +} + +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; + } + return tt_cons_branch(a, wild, others); +} + +static inline tt_node_ptr_t rwildseq(tt_arena_t *a, tt_node_ptr_t r) { + if (TT_EMPTY_P(r)) { + return TT_EMPTY; + } + return tt_cons_tail(a, r); +} + +static inline tt_node_ptr_t runwildseq(tt_arena_t *a, tt_node_ptr_t r) { + if (tt_ptr_tag(r) == TT_TAG_TAIL) { + return TT_TAIL_TRIE(a,r); + } else { + return TT_EMPTY; + } +} + +static inline tt_node_ptr_t rlookup(tt_arena_t *a, + tt_node_ptr_t r, + 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); + if (!TT_NO_PTR_P(result)) { + return result; + } + result = TT_BRANCH_WILDCARD(a,r); + switch (key) { + case TT_BOS: return rwildseq(a, result); + case TT_EOS: return runwildseq(a, result); + default: return result; + } +} + +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 old_wild; + tt_node_ptr_t old_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 + + } +} diff --git a/route.h b/route.h new file mode 100644 index 0000000..6491319 --- /dev/null +++ b/route.h @@ -0,0 +1,23 @@ +#ifndef ROUTE_H_c2d88c54_f18d_4b71_9fce_5d43c0723360 +#define ROUTE_H_c2d88c54_f18d_4b71_9fce_5d43c0723360 + +/* Sticking to odd-numbered constants, since the plan is for most + bindings to use odd-numbered atoms for immediates and even-numbered + atoms for heap-allocated complex values. TODO: make this a proper + part of the interface? */ +#define TT_WILD ((tt_atom_t) -1) /* Wildcard */ +#define TT_BOS ((tt_atom_t) -3) /* Beginning of sequence */ +#define TT_EOS ((tt_atom_t) -5) /* End of sequence */ +#define TT_BOC ((tt_atom_t) -7) /* Beginning of capture */ +#define TT_EOC ((tt_atom_t) -9) /* End of capture */ + +// TODO move to the right place +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif