The trie walked a key byte by byte, so a Hangul syllable cost three nodes and every lookup first spelled its key back into UTF-8. It walks runes now: a third of the nodes for Korean data, and no buffer in the lookup. Children are kept in rune order, so both the search and the insert stop early, and a trie remembers the path of the last key put, which a file sorted by key — hanja.dict is one — walks straight down.
91 lines
1.7 KiB
C
91 lines
1.7 KiB
C
#include "dat.h"
|
|
#include "fn.h"
|
|
|
|
/* Appends the space-separated words of a node's entry to out[], up to max. */
|
|
static int
|
|
words(Tnode *nd, Str *out, int n, int max)
|
|
{
|
|
char *p, *e, *sp;
|
|
Str tmp;
|
|
|
|
if(nd->val == nil)
|
|
return n;
|
|
p = nd->val;
|
|
e = p + nd->vlen;
|
|
while(n < max && p < e){
|
|
while(p < e && *p == ' ')
|
|
p++;
|
|
sp = p;
|
|
while(p < e && *p != ' ')
|
|
p++;
|
|
if(sinit(&tmp, sp, p - sp) && tmp.n > 0)
|
|
out[n++] = tmp;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/* The entries at and below a node, the shortest keys first. */
|
|
static int
|
|
below(Trie *t, int ni, Str *out, int n, int max)
|
|
{
|
|
Tnode *nd;
|
|
int ci;
|
|
|
|
nd = &t->nodes[ni];
|
|
n = words(nd, out, n, max);
|
|
for(ci = nd->child; ci >= 0 && n < max; ci = t->nodes[ci].sibling)
|
|
n = below(t, ci, out, n, max);
|
|
return n;
|
|
}
|
|
|
|
/* Fills out[] with up to max candidates for key: the words of its entry. */
|
|
int
|
|
dictlookup(Trie *t, Str *key, Str *out, int max)
|
|
{
|
|
int ni;
|
|
|
|
ni = key->n == 0 ? -1 : trienode(t, key);
|
|
if(ni < 0)
|
|
return 0;
|
|
return words(&t->nodes[ni], out, 0, max);
|
|
}
|
|
|
|
/* As dictlookup, for every entry key is a prefix of, key's own first. */
|
|
int
|
|
dictprefix(Trie *t, Str *key, Str *out, int max)
|
|
{
|
|
int ni;
|
|
|
|
ni = key->n == 0 ? -1 : trienode(t, key);
|
|
if(ni < 0)
|
|
return 0;
|
|
return below(t, ni, out, 0, max);
|
|
}
|
|
|
|
static Trie*
|
|
langopen(char *dir, char *name, char *ext)
|
|
{
|
|
char *path;
|
|
Trie *t;
|
|
|
|
path = smprint("%s/%s.%s", dir, name, ext);
|
|
if(path == nil)
|
|
die("out of memory");
|
|
t = trieopen(path);
|
|
free(path);
|
|
return t;
|
|
}
|
|
|
|
void
|
|
langinit(char *dir)
|
|
{
|
|
Lang *l;
|
|
|
|
for(l = langs; l < langs + nlang; l++){
|
|
if(l->mapname != nil)
|
|
l->map = langopen(dir, l->mapname, "map");
|
|
if(l->dictname != nil)
|
|
l->dict = langopen(dir, l->dictname, "dict");
|
|
}
|
|
}
|