diff --git a/dat.h b/dat.h index 19fe5bf..2b8c14f 100644 --- a/dat.h +++ b/dat.h @@ -74,7 +74,7 @@ struct Tnode int vlen; int child; int sibling; - char c; + Rune c; }; typedef struct Trie Trie; @@ -83,6 +83,9 @@ struct Trie Tnode *nodes; int n; int cap; + /* the last key put and its path, so a sorted file walks it once */ + Str last; + int path[Maxrunes]; }; enum diff --git a/dict.c b/dict.c index ebf74e9..65d387e 100644 --- a/dict.c +++ b/dict.c @@ -24,7 +24,7 @@ words(Tnode *nd, Str *out, int n, int max) return n; } -/* The entries at and below a node, in the dictionary's order. */ +/* The entries at and below a node, the shortest keys first. */ static int below(Trie *t, int ni, Str *out, int n, int max) { diff --git a/trie.c b/trie.c index ce94259..3eb7360 100644 --- a/trie.c +++ b/trie.c @@ -3,9 +3,9 @@ #include "fn.h" /* - * A byte trie over UTF-8 keys. Maps need prefix matches while composing; - * dictionaries need exact matches; both are small enough for one structure. - * Node 0 is the root. + * A trie over the runes of a key. Maps need prefix matches while + * composing; dictionaries need exact matches; both are small enough for + * one structure. Node 0 is the root. */ static int @@ -24,32 +24,37 @@ newnode(Trie *t) return i; } +/* The children of a node are kept in rune order, so both end early. */ static int -find(Trie *t, int ni, char c) +find(Trie *t, int ni, Rune c) { int pi; - for(pi = t->nodes[ni].child; pi >= 0; pi = t->nodes[pi].sibling) + for(pi = t->nodes[ni].child; pi >= 0; pi = t->nodes[pi].sibling){ if(t->nodes[pi].c == c) return pi; + if(t->nodes[pi].c > c) + break; + } return -1; } -/* Appends, so that a walk of the children keeps the file's order. */ static int -add(Trie *t, int ni, char c) +add(Trie *t, int ni, Rune c) { - int last, pi; + int next, pi, prev; - last = -1; - for(pi = t->nodes[ni].child; pi >= 0; pi = t->nodes[pi].sibling) - last = pi; + prev = -1; + for(next = t->nodes[ni].child; next >= 0 && t->nodes[next].c < c; + next = t->nodes[next].sibling) + prev = next; pi = newnode(t); t->nodes[pi].c = c; - if(last < 0) + t->nodes[pi].sibling = next; + if(prev < 0) t->nodes[ni].child = pi; else - t->nodes[last].sibling = pi; + t->nodes[prev].sibling = pi; return pi; } @@ -69,15 +74,26 @@ trienew(void) void trieput(Trie *t, char *key, int klen, char *val, int vlen) { - int ni, ci, i; + Str k; + int ci, i, ni, same; + if(!sinit(&k, key, klen)) + return; ni = 0; - for(i = 0; i < klen; i++){ - ci = find(t, ni, key[i]); + same = 1; + for(i = 0; i < k.n; i++){ + if(same && i < t->last.n && t->last.r[i] == k.r[i]){ + ni = t->path[i]; + continue; + } + same = 0; + ci = find(t, ni, k.r[i]); if(ci < 0) - ci = add(t, ni, key[i]); + ci = add(t, ni, k.r[i]); ni = ci; + t->path[i] = ni; } + t->last = k; free(t->nodes[ni].val); t->nodes[ni].val = emalloc(vlen + 1); memmove(t->nodes[ni].val, val, vlen); @@ -163,15 +179,13 @@ trieclose(Trie *t) int trienode(Trie *t, Str *key) { - char buf[Maxutf]; - int i, klen, ni; + int i, ni; if(t == nil) return -1; - klen = stoutf(key, buf, sizeof buf); ni = 0; - for(i = 0; i < klen && ni >= 0; i++) - ni = find(t, ni, buf[i]); + for(i = 0; i < key->n && ni >= 0; i++) + ni = find(t, ni, key->r[i]); return ni; }