18 #define LIBAVL_PAVL 11
19 #define LIBAVL_PBST 12
21 #define LIBAVL_RTAVL 14
22 #define LIBAVL_RTBST 15
23 #define LIBAVL_RTRB 16
24 #define LIBAVL_TAVL 17
25 #define LIBAVL_TBST 18
28 #define POSIX_HSEARCH 21
29 #define POSIX_TSEARCH 22
36 # error "`TREE' not defined or bungled constant setting"
37 #elif TREE == XYLA_AVL
38 # include <xyla/avl.h>
40 # define WANT_HEIGHT 1
41 # define TREE__NAME(name) XYLA_AVL_##name
42 # define tree__name(name) xyla_avl_##name
47 # define WANT_HEIGHT 1
48 # define TREE__NAME(name) XYLA_RB_##name
49 # define tree__name(name) xyla_rb_##name
51 #elif TREE == XYLA_SPLAY
52 # include <xyla/splay.h>
55 # define TREE__NAME(name) XYLA_SPLAY_##name
56 # define tree__name(name) xyla_splay_##name
58 #elif TREE == XYLA_TREAP
59 # include <xyla/treap.h>
62 # define TREE__NAME(name) XYLA_TREAP_##name
63 # define tree__name(name) xyla_treap_##name
65 #elif TREE == QPTRIE_QP
71 #elif TREE == QPTRIE_FN
77 #elif TREE == SGT_TREE234
79 #elif TREE == LIBAVL_AVL
82 # define tree__name(name) avl_##name
83 #elif TREE == LIBAVL_BST
86 # define tree__name(name) bst_##name
87 #elif TREE == LIBAVL_RB
90 # define tree__name(name) rb_##name
91 #elif TREE == LIBAVL_PAVL
94 # define tree__name(name) pavl_##name
95 #elif TREE == LIBAVL_PBST
98 # define tree__name(name) pbst_##name
99 #elif TREE == LIBAVL_PRB
101 # define USE_LIBAVL 1
102 # define tree__name(name) prb_##name
103 #elif TREE == LIBAVL_RTAVL
105 # define USE_LIBAVL 1
106 # define tree__name(name) rtavl_##name
107 #elif TREE == LIBAVL_RTBST
109 # define USE_LIBAVL 1
110 # define tree__name(name) rtbst_##name
111 #elif TREE == LIBAVL_RTRB
113 # define USE_LIBAVL 1
114 # define tree__name(name) rtrb_##name
115 #elif TREE == LIBAVL_TAVL
117 # define USE_LIBAVL 1
118 # define tree__name(name) tavl_##name
119 #elif TREE == LIBAVL_BST
121 # define USE_LIBAVL 1
122 # define tree__name(name) tbst_##name
123 #elif TREE == LIBAVL_TRB
125 # define USE_LIBAVL 1
126 # define tree__name(name) trb_##name
127 #elif TREE == MLIB_SYM
129 # include <mLib/sym.h>
130 # include <mLib/unihash.h>
131 #elif TREE == POSIX_HSEARCH
134 # ifndef HSEARCH_INITSZ
135 # define HSEARCH_INITSZ 1024
137 #elif TREE == POSIX_TSEARCH
140 # error "unknown `TREE' value"
144 # define NODE tree__name(node)
145 # define PATH tree__name(path)
146 # define ITER tree__name(iter)
147 # define TREE_NODEPFX TREE__NAME(NODEPFX)
148 # define TREE_NODEUSFX TREE__NAME(NODEUSFX)
149 # define TREE_CHECK tree__name(check)
150 # define TREE_LOOKUP tree__name(lookup)
151 # define TREE_PROBE tree__name(probe)
152 # define TREE_INITITER tree__name(inititer)
153 # define TREE_NEXT tree__name(next)
154 # define TREE_INSERT tree__name(insert)
163 # define TABLE tree__name(table)
164 # define TRAVERSER tree__name(traverser)
165 # define TREE_CREATE tree__name(create)
166 # define TREE_DESTROY tree__name(destroy)
167 # define TREE_PROBE tree__name(probe)
168 # define TREE_FIND tree__name(find)
169 # define TREE_T_INIT tree__name(t_init)
170 # define TREE_T_NEXT tree__name(t_next)
175 # error "`QPTRIE_ITER' not defined or bungled constant setting"
176 # elif QPTRIE_ITER == QPITER_FANF
177 # elif QPTRIE_ITER == QPITER_MDW
178 # elif QPTRIE_ITER == QPITER_LIST
180 # error "unknown `QPTRIE_ITER' value"
197 #elif TREE == MLIB_SYM
199 # define WORDPTR(node) (SYM_NAME(node))
200 # define WORDLEN(node) (SYM_LEN(node))
206 # define CHLEN(node) ((node)->chlen)
208 #elif USE_LIBAVL || TREE == POSIX_TSEARCH
212 struct { const char *p; unsigned short n; short chlen; } pack;
214 # define WORDPTR(node) ((const char *)((node) + 1))
215 # define WORDLEN(node) ((node)->u.w.n)
216 # define CHLEN(node) ((node)->u.pack.chlen)
221 # define WORDPTR(node) ((const char *)((node) + 1))
222 # define WORDLEN(node) ((node)->wlen)
225 # define CHLEN(node) ((node)->chlen)
229 #if TREE == MLIB_SYM || \
230 (USE_QPTRIE && QPTRIE_ITER == QPITER_LIST) || \
231 TREE == POSIX_HSEARCH || TREE == POSIX_TSEARCH
235 struct node *down, *right, *up;
240 static void bail(const char *msg, ...)
245 va_start(ap, msg); vfprintf(stderr, msg, ap); va_end(ap);
247 if (pos >= 0) fprintf(stderr, " (input pos = %ld)", pos);
252 #if USE_XYLA || TREE == SGT_TREE234 || USE_LIBAVL || TREE == POSIX_TSEARCH
254 static int compare_words(const char *a, size_t alen,
255 const char *b, size_t blen)
259 ord = memcmp(a, b, alen <= blen ? alen : blen);
260 if (!ord) ord = alen < blen ? -1 : alen > blen ? +1 : 0;
268 union nodeu { struct node node; TREE_NODEUSFX; };
270 static int word_nav(struct xyla_bt_nodecls *cls,
271 const struct xyla_bt_node *nn, void *arg)
273 const struct word *k = arg;
274 const struct node *node = (struct node *)nn;
276 return (compare_words(k->p, k->n, WORDPTR(node), WORDLEN(node)));
280 struct xyla_bt_node *root = 0; \
281 union nodeu *nodeu; \
285 # define INIT do ; while (0)
287 # if TREE == XYLA_TREAP
288 # define EXTRA_NODE_SETUP do { node->trp.wt = rand(); } while (0)
290 # ifndef EXTRA_NODE_SETUP
291 # define EXTRA_NODE_SETUP do ; while (0)
293 # define INSERT do { \
294 if (TREE_PROBE(0, &root, word_nav, &word, &path)) { \
295 fprintf(stderr, ";; duplicate `%s'\n", buf); \
296 free(node); node = 0; \
299 nodeu = (union nodeu *)node; \
300 TREE_INSERT(0, &path, &nodeu->T); \
305 for (TREE_INITITER(root, &it); node = TREE_NEXT(&it), node; )
307 # if TREE == XYLA_SPLAY
308 # define FOCUS do { xyla_splay_splay(0, &path); } while (0)
310 # define FOCUS do ; while (0)
313 # define LOOKUP TREE_LOOKUP(0, &root, word_nav, &word)
316 while (node = xyla_bt_severfirst(&root), node) free(node); \
320 # define CHECK do ; while (0)
323 static const void *node_key(struct xyla_bt_nodecls *cls,
324 const struct xyla_bt_node *nn)
327 static int node_nav(struct xyla_bt_nodecls *cls,
328 const struct xyla_bt_node *nn, void *k)
330 const struct node *na = k, *nb = (const struct node *)nn;
332 return (compare_words(WORDPTR(na), WORDLEN(na), WORDPTR(nb), WORDLEN(nb)));
335 static void word_ident(struct xyla_bt_nodecls *cls,
336 const struct xyla_bt_node *nn, FILE *fp)
338 struct node *node = (struct node *)nn;
340 fprintf(fp, "`%s'", WORDPTR(node));
343 static const struct xyla_bt_chkops word_ops = {
344 { sizeof(word_ops), 0 },
345 { node_nav, node_key },
346 { xyla_bt_chkorder, sizeof(struct xyla_bt_ordinfo), word_ident }
348 struct xyla_bt_nodecls word_cls = { &word_ops.node };
350 # define CHECK do { \
351 if (TREE_CHECK(&word_cls, &root, stderr, 0 HARG(-1), 0)) \
352 bail("check failed"); \
358 # if QPTRIE_ITER == QPITER_FANF
359 # define my_Tnextl Tnextl
363 # define INSERT_LIST do ; while (0)
364 # elif QPTRIE_ITER == QPITER_MDW
368 # define INSERT_LIST do ; while (0)
370 # if TREE == QPTRIE_QP
372 static bool my_Tnextl(Tbl *tbl, const char **k_inout, size_t *sz_inout,
375 const char *k = *k_inout;
376 size_t sz = *sz_inout;
387 while (isbranch(t)) {
388 __builtin_prefetch(t->branch.twigs);
389 b = twigbit(t, k, sz);
390 TWIGOFFMAX(off, max, t, b);
391 if (!hastwig(t, b)) return (false);
393 if (off + 1 < max) resume = t + 1;
395 /* if (strcmp(k, t->leaf.key) != 0) return (false); */
396 t = resume; if (!t) return (false);
399 while (isbranch(t)) t = twig(t, 0);
400 *k_inout = k = t->leaf.key; *sz_inout = strlen(k); *val_out = t->leaf.val;
404 # elif TREE == QPTRIE_FN
406 static bool my_Tnextl(Tbl *t, const char **k_inout, size_t *sz_inout,
409 const char *k = *k_inout;
410 size_t sz = *sz_inout;
420 while (isbranch(t)) {
421 __builtin_prefetch(t->ptr);
422 i = t->index; b = twigbit(i, k, sz);
423 TWIGOFFMAX(off, max, i, b);
424 if (!hastwig(i, b)) return (false);
425 t = Tbranch_twigs(t) + off;
426 if (off + 1 < max) resume = t + 1;
428 /* if (strcmp(k, Tleaf_key(t)) != 0) return (false); */
429 t = resume; if (!t) return (false);
431 while (isbranch(t)) t = Tbranch_twigs(t);
432 *k_inout = k = Tleaf_key(t); *sz_inout = strlen(k);
433 *val_out = Tleaf_val(t);
438 # error "no mdw `Tnextl' for this QP trie variant"
440 # elif QPTRIE_ITER == QPITER_LIST
442 struct node *all = 0, **all_tail = &all
443 # define INSERT_LIST do { \
444 node->next = 0; *all_tail = node; all_tail = &node->next; \
452 # define INIT do ; while (0)
454 # define INSERT do { \
455 tbl = Tsetl(tbl, WORDPTR(node), WORDLEN(node), node); \
459 # if QPTRIE_ITER == QPITER_LIST
461 for (next = all; node = next, node; next = next->next)
464 for (cur.p = 0, cur.n = 0; \
465 my_Tnextl(tbl, &cur.p, &cur.n, &v) ? node = v, 1 : 0; )
468 # define FOCUS do ; while (0)
470 # define GETPREFIX do { \
471 word.n = WORDLEN(node) - 1; assert(word.n < WORDMAX); \
472 memcpy(buf, WORDPTR(node), word.n); buf[word.n] = 0; \
475 # define LOOKUP Tgetl(tbl, buf, word.n)
477 # if QPTRIE_ITER == QPITER_LIST
479 for (node = all; node; node = next) { \
480 tbl = Tsetl(tbl, WORDPTR(node), WORDLEN(node), 0); \
481 next = node->next; free(node); \
488 cur.p = 0; cur.n = 0; my_Tnextl(tbl, &cur.p, &cur.n, &v); \
489 tbl = Tsetl(tbl, cur.p, cur.n, 0); free(v); \
494 # define CHECK do ; while (0)
496 #elif TREE == SGT_TREE234
498 static int node_cmp(void *a, void *b)
500 const struct node *na = a, *nb = b;
502 return (compare_words(WORDPTR(na), WORDLEN(na),
503 WORDPTR(nb), WORDLEN(nb)));
506 static int word_cmp(void *k, void *n)
508 const struct word *word = k;
509 const struct node *node = n;
511 return (compare_words(word->p, word->n, WORDPTR(node), WORDLEN(node)));
518 # define INIT do { root = newtree234(node_cmp); } while (0)
520 # define INSERT do { \
521 if (add234(root, node) != node) { \
522 fprintf(stderr, ";; duplicate `%s'\n", buf); \
523 free(node); node = 0; \
527 # define ITERATE for (i = 0; node = index234(root, i), node; i++)
529 # define FOCUS do ; while (0)
531 # define LOOKUP find234(root, &word, word_cmp)
534 while (node = delpos234(root, 0), node) free(node); \
538 # define CHECK do ; while (0)
542 static int node_cmp(const void *a, const void *b, void *arg)
544 const struct word *wa = a, *wb = b;
546 return (compare_words(wa->p, wa->n, wb->p, wb->n));
549 static void free_node(void *n, void *arg) { free(n); }
553 struct TRAVERSER it; \
557 tab = TREE_CREATE(node_cmp, 0, 0); \
558 if (!tab) bail("out of memory"); \
561 # define PREPNODE do { \
562 node = malloc(sizeof(*node) + word.n + 1); \
563 if (!node) bail("out of memory"); \
564 memcpy(node + 1, buf, word.n + 1); \
565 node->u.w.p = (const char *)(node + 1); node->u.w.n = word.n; \
568 # define INSERT do { \
569 p = TREE_PROBE(tab, node); if (!p) bail("out of memory"); \
571 fprintf(stderr, ";; duplicate `%s'\n", buf); \
572 free(node); node = 0; \
577 for (TREE_T_INIT(&it, tab); node = TREE_T_NEXT(&it), node; )
579 # define FOCUS do ; while (0)
581 # define LOOKUP TREE_FIND(tab, &word)
583 # define FREE do { TREE_DESTROY(tab, free_node); } while (0)
585 # define CHECK do ; while (0)
587 #elif TREE == MLIB_SYM
591 struct node *all = 0, **all_tail = &all; \
595 unihash_setkey(&unihash_global, getpid()); \
599 # define PREPNODE do ; while (0)
601 # define INSERT do { \
602 node = sym_find(&tab, buf, word.n, sizeof(*node), &foundp); \
604 node->next = 0; *all_tail = node; all_tail = &node->next; \
606 fprintf(stderr, ";; duplicate `%s'\n", buf); \
607 free(node); node = 0; \
611 # define ITERATE for (next = all; node = next, node; next = next->next)
613 # define FOCUS do ; while (0)
615 # define LOOKUP sym_find(&tab, word.p, word.n, 0, 0)
617 # define FREE do { sym_destroy(&tab); } while (0)
619 # define CHECK do ; while (0)
621 #elif TREE == POSIX_HSEARCH
625 size_t hmax = HSEARCH_INITSZ, hcap = 3*(hmax/4), hused = 0; \
626 struct node *all = 0, **all_tail = &all \
629 if (!hcreate(hmax)) \
630 bail("hcreate (initial) failed: %s", strerror(errno)); \
633 # define INSERT do { \
634 if (hused >= hcap) { \
636 hmax *= 2; hcap *= 2; \
637 if (!hcreate(hmax)) \
638 bail("hcreate (grow) failed: %s", strerror(errno)); \
639 for (next = all; next; next = next->next) { \
640 ee.key = (/*unconst*/ char *)WORDPTR(next); ee.data = next; \
641 if (!hsearch(ee, ENTER)) \
642 bail("hsearch (grow) failed: table full"); \
645 ee.key = (char *)(node + 1); ee.data = 0; \
646 e = hsearch(ee, ENTER); \
648 bail("hsearch (insert) failed: table full"); \
649 else if (!e->data) { \
651 node->next = 0; *all_tail = node; all_tail = &node->next; \
654 fprintf(stderr, ";; duplicate `%s'\n", buf); \
655 free(node); node = 0; \
659 # define ITERATE for (next = all; node = next, node; next = next->next)
661 # define FOCUS do ; while (0)
663 # define GETPREFIX do { \
664 word.n = WORDLEN(node) - 1; assert(word.n < WORDMAX); \
665 memcpy(buf, WORDPTR(node), word.n); buf[word.n] = 0; \
669 (ee.key = (/*unconst*/ char *)word.p, \
670 e = hsearch(ee, FIND), e ? e->data : 0)
674 while (node) { next = node->next; free(node); node = next; } \
678 # define CHECK do ; while (0)
680 #elif TREE == POSIX_TSEARCH
682 typedef struct { struct node *node; } TNODE;
684 static int word_cmp(const void *x, const void *y)
686 const struct word *nx = x, *ny = y;
688 return (compare_words(nx->p, nx->n, ny->p, ny->n));
693 struct node *all = 0, **all_tail = &all; \
696 # define INIT do ; while (0)
698 # define PREPNODE do { \
699 node = malloc(sizeof(*node) + word.n + 1); \
700 if (!node) bail("out of memory"); \
701 memcpy(node + 1, buf, word.n + 1); \
702 node->u.w.p = (const char *)(node + 1); node->u.w.n = word.n; \
705 # define INSERT do { \
706 tn = tsearch(node, &root, word_cmp); \
707 if (tn->node == node) { \
708 node->next = 0; *all_tail = node; all_tail = &node->next; \
710 fprintf(stderr, ";; duplicate `%s'\n", buf); \
711 free(node); node = 0; \
715 # define ITERATE for (next = all; node = next, node; next = next->next)
717 # define FOCUS do ; while (0)
719 # define LOOKUP (tn = tfind(&word, &root, word_cmp), tn ? tn->node : 0)
722 # define FREE do tdestroy(root, free); while (0)
725 for (next = all; node = next, node; next = next->next) \
726 { tdelete(node, &root, word_cmp); free(node); } \
730 # define CHECK do ; while (0)
735 # define PREPNODE do { \
736 node = malloc(sizeof(*node) + word.n + 1); \
737 if (!node) bail("out of memory"); \
738 memcpy(node + 1, buf, word.n + 1); node->wlen = word.n; \
743 # define GETPREFIX do { \
744 word.p = WORDPTR(node); word.n = WORDLEN(node) - 1; \
749 static void print_chain(struct node *node)
752 fputs(WORDPTR(node), stdout);
753 if (node->down) { putchar(' '); print_chain(node->down); }
757 fputs(WORDPTR(node), stdout);
758 if (node->down) { putchar(' '); print_chain(node->down); }
759 node = node->right; if (!node) break;
760 fputs(" | ", stdout);
769 struct node *node, *parent, *winners, **winners_tail, *next;
772 int ch, max, nlen, plen;
777 if (!fgets(buf, WORDMAX, stdin)) break;
778 word.n = strlen(buf); assert(word.n);
779 if (buf[word.n - 1] == '\n') buf[--word.n] = 0;
780 else if (word.n == WORDMAX - 1) bail("word too long");
781 else if (ch = getchar(), ch != EOF) bail("short read, found `%c'", ch);
784 if (node) { node->up = node->down = node->right = 0; CHLEN(node) = 1; }
789 max = 0; winners_tail = &winners;
793 /* fprintf(stderr, ";; ponder `%.*s'\n", WORDLEN(node), WORDPTR(node)); */
794 if (WORDLEN(node) <= 1)
798 /* fprintf(stderr, ";; search `%.*s'\n", word.n, word.p); */
799 parent = LOOKUP; if (!parent) continue;
801 node->up = parent; nlen = CHLEN(node);
806 { max = nlen; *winners_tail = 0; winners_tail = &winners; }
807 *winners_tail = node; winners_tail = &node->right;
811 plen = CHLEN(parent); nlen++;
814 else if (plen == nlen) {
815 node->right = parent->down; parent->down = node;
818 parent->down = node; node->right = 0;
819 CHLEN(parent) = nlen;
820 node = parent; parent = node->up;
825 for (*winners_tail = 0, node = winners; node; node = next) {
826 next = node->right; node->right = 0;
827 print_chain(node); putchar('\n');