#include "config.h" #include #include #include #include #include #include #include #include #include #include #define NWORDS 1000 #define LETTERS "abcdefghijklmnopqrstuvwxyz" #define NLETTERS (sizeof(LETTERS) - 1) char **wordarray; char **wordarrayb; /* Word array sorted by length */ int nwords; struct trie_node { int start, end; const char *prefix; bool isword; struct trie_node *next[NLETTERS]; struct aga_node agan; }; /* Sorts by length first, then alphabetically */ static int lensort(const void *xv, const void *yv) { char *x = *((char **)xv); char *y = *((char **)yv); int xn = strlen(x); int yn = strlen(y); if (xn < yn) return -1; else if (xn > yn) return 1; else /* We need this because qsort is not stable */ return strcmp(x, y); } static void setup_words(void) { char *wordfile; /* read in the words */ wordfile = grab_file(NULL, "test/api-lazytrie-words.txt"); ok1(wordfile); wordarray = tal_strsplit(NULL, take(wordfile), "\n", STR_NO_EMPTY); ok1(wordarray); nwords = tal_count(wordarray) - 1; diag("lazytrie: %d words loaded", nwords); ok1(nwords == NWORDS); wordarrayb = tal_arr(NULL, char *, nwords); memcpy(wordarrayb, wordarray, tal_count(wordarrayb) * sizeof(char *)); qsort(wordarrayb, nwords, sizeof(char *), lensort); } struct lazytrie { struct trie_node root; struct aga_graph g; }; static void init_trie_node(struct trie_node *n, int start, int end, const char *prefix) { int i; n->start = start; n->end = end; n->prefix = prefix; n->isword = (strcmp(n->prefix, wordarray[n->start]) == 0); for (i = 0; i < NLETTERS; i++) n->next[i] = NULL; aga_node_init(&n->agan); } static ptrint_t *lazytrie_first_edge(const struct aga_graph *g, const struct aga_node *n) { return int2ptr(1); } static ptrint_t *lazytrie_next_edge(const struct aga_graph *g, const struct aga_node *n, ptrint_t *e) { int index = ptr2int(e); assert((index >= 1) && (index <= NLETTERS)); if (index == NLETTERS) return NULL; else return int2ptr(index + 1); } static int lazytrie_edge_info(const struct aga_graph *g, const struct aga_node *n, ptrint_t *e, struct aga_edge_info *ei) { struct trie_node *tn = container_of(n, struct trie_node, agan); struct trie_node *next; int index = ptr2int(e); assert((index >= 1) && (index <= NLETTERS)); next = tn->next[index - 1]; if (!next) { int depth = strlen(tn->prefix); int start, end; start = tn->start; while (start < tn->end) { if (wordarray[start][depth] >= LETTERS[index - 1]) break; start++; } end = start; while (end < tn->end) { if (wordarray[end][depth] > LETTERS[index - 1]) break; end++; } if (end > start) { char plus[2] = { LETTERS[index - 1], '\0' }; next = tal(tn, struct trie_node); init_trie_node(next, start, end, tal_strcat(next, tn->prefix, plus)); } } if (next) ei->to = &next->agan; return 0; } static struct lazytrie *setup_trie(void) { struct lazytrie *lt; lt = tal(NULL, struct lazytrie); init_trie_node(<->root, 0, nwords, ""); aga_init_graph(<->g, lazytrie_first_edge, lazytrie_next_edge, lazytrie_edge_info); return lt; } int main(void) { struct lazytrie *lt; struct aga_node *an; int xn; plan_tests(3 + NWORDS*2); setup_words(); lt = setup_trie(); aga_dfs_start(<->g); xn = 0; aga_dfs(an, <->g, <->root.agan) { struct trie_node *n = container_of(an, struct trie_node, agan); diag("Visited \"%s\"\n", n->prefix); if (n->isword) { ok1(strcmp(n->prefix, wordarray[xn]) == 0); xn++; } } aga_finish(<->g); tal_free(lt); lt = setup_trie(); aga_bfs_start(<->g); xn = 0; aga_bfs(an, <->g, <->root.agan) { struct trie_node *n = container_of(an, struct trie_node, agan); diag("Visited \"%s\"\n", n->prefix); if (n->isword) { ok1(strcmp(n->prefix, wordarrayb[xn]) == 0); xn++; } } /* This exits depending on whether all tests passed */ return exit_status(); }