dict: lookups take a trie; a prefix search is its own function; no self-key rule
dictlookup took a Lang for two reasons that were not its business: to know whether to walk below the key (the emoji dictionary) and to drop a candidate equal to the key except there. No dictionary lists its key among its candidates — the rule was left from a first version that put the reading first itself — so it goes, and the walk is dictprefix(), called by the emoji search alone.
This commit is contained in:
46
dict.c
46
dict.c
@@ -1,13 +1,9 @@
|
|||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fn.h"
|
#include "fn.h"
|
||||||
|
|
||||||
/*
|
/* Appends the space-separated words of a node's entry to out[], up to max. */
|
||||||
* Appends the space-separated words of a node's entry to out[], up to
|
|
||||||
* max: its candidates, minus the key itself, except in the emoji
|
|
||||||
* dictionary, where a query may name its own answer.
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
words(Lang *l, Str *key, Tnode *nd, Str *out, int n, int max)
|
words(Tnode *nd, Str *out, int n, int max)
|
||||||
{
|
{
|
||||||
char *p, *e, *sp;
|
char *p, *e, *sp;
|
||||||
Str tmp;
|
Str tmp;
|
||||||
@@ -22,8 +18,7 @@ words(Lang *l, Str *key, Tnode *nd, Str *out, int n, int max)
|
|||||||
sp = p;
|
sp = p;
|
||||||
while(p < e && *p != ' ')
|
while(p < e && *p != ' ')
|
||||||
p++;
|
p++;
|
||||||
if(sinit(&tmp, sp, p - sp) && tmp.n > 0 &&
|
if(sinit(&tmp, sp, p - sp) && tmp.n > 0)
|
||||||
(l->lang == LangEMOJI || scmp(&tmp, key) != 0))
|
|
||||||
out[n++] = tmp;
|
out[n++] = tmp;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
@@ -31,33 +26,40 @@ words(Lang *l, Str *key, Tnode *nd, Str *out, int n, int max)
|
|||||||
|
|
||||||
/* The entries at and below a node, in the dictionary's order. */
|
/* The entries at and below a node, in the dictionary's order. */
|
||||||
static int
|
static int
|
||||||
below(Lang *l, Str *key, int ni, Str *out, int n, int max)
|
below(Trie *t, int ni, Str *out, int n, int max)
|
||||||
{
|
{
|
||||||
Tnode *nd;
|
Tnode *nd;
|
||||||
int ci;
|
int ci;
|
||||||
|
|
||||||
nd = &l->dict->nodes[ni];
|
nd = &t->nodes[ni];
|
||||||
n = words(l, key, nd, out, n, max);
|
n = words(nd, out, n, max);
|
||||||
for(ci = nd->child; ci >= 0 && n < max; ci = l->dict->nodes[ci].sibling)
|
for(ci = nd->child; ci >= 0 && n < max; ci = t->nodes[ci].sibling)
|
||||||
n = below(l, key, ci, out, n, max);
|
n = below(t, ci, out, n, max);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Fills out[] with up to max candidates for key: the words of its entry. */
|
||||||
* Fills out[] with up to max candidates for key. The emoji dictionary is
|
|
||||||
* searched by prefix, the key's own entry first; the others exactly.
|
|
||||||
*/
|
|
||||||
int
|
int
|
||||||
dictlookup(Lang *l, Str *key, Str *out, int max)
|
dictlookup(Trie *t, Str *key, Str *out, int max)
|
||||||
{
|
{
|
||||||
int ni;
|
int ni;
|
||||||
|
|
||||||
ni = key->n == 0 ? -1 : trienode(l->dict, key);
|
ni = key->n == 0 ? -1 : trienode(t, key);
|
||||||
if(ni < 0)
|
if(ni < 0)
|
||||||
return 0;
|
return 0;
|
||||||
if(l->lang == LangEMOJI)
|
return words(&t->nodes[ni], out, 0, max);
|
||||||
return below(l, key, ni, out, 0, max);
|
}
|
||||||
return words(l, key, &l->dict->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*
|
static Trie*
|
||||||
|
|||||||
3
fn.h
3
fn.h
@@ -21,7 +21,8 @@ int trielookup(Trie*, Str*, char**, int*);
|
|||||||
Lang* getlang(int);
|
Lang* getlang(int);
|
||||||
void langinit(char*);
|
void langinit(char*);
|
||||||
|
|
||||||
int dictlookup(Lang*, Str*, Str*, int);
|
int dictlookup(Trie*, Str*, Str*, int);
|
||||||
|
int dictprefix(Trie*, Str*, Str*, int);
|
||||||
|
|
||||||
void drawthread(void*);
|
void drawthread(void*);
|
||||||
void popuparea(Area*, int, Area*, int, int, Area*);
|
void popuparea(Area*, int, Area*, int, int, Area*);
|
||||||
|
|||||||
12
strans.c
12
strans.c
@@ -289,7 +289,7 @@ dictqokuri(Str *reading)
|
|||||||
key = *reading;
|
key = *reading;
|
||||||
key.n = i;
|
key.n = i;
|
||||||
sputr(&key, c);
|
sputr(&key, c);
|
||||||
n = dictlookup(im.l, &key, kouho, Maxkouho);
|
n = dictlookup(im.l->dict, &key, kouho, Maxkouho);
|
||||||
sclear(&okuri);
|
sclear(&okuri);
|
||||||
for(j = i - (reading->r[i-1] == L'っ'); j < reading->n; j++)
|
for(j = i - (reading->r[i-1] == L'っ'); j < reading->n; j++)
|
||||||
sputr(&okuri, reading->r[j]);
|
sputr(&okuri, reading->r[j]);
|
||||||
@@ -310,7 +310,7 @@ dictqjp(void)
|
|||||||
if(!isjp(&im) || !jpreading(im.l->map, &im.pre, &im.raw, &reading) ||
|
if(!isjp(&im) || !jpreading(im.l->map, &im.pre, &im.raw, &reading) ||
|
||||||
reading.n == 0)
|
reading.n == 0)
|
||||||
return;
|
return;
|
||||||
im.nkouho = dictlookup(im.l, &reading, im.kouho, Maxkouho);
|
im.nkouho = dictlookup(im.l->dict, &reading, im.kouho, Maxkouho);
|
||||||
dictqokuri(&reading);
|
dictqokuri(&reading);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,13 +572,13 @@ emojiquery(void)
|
|||||||
transstr(im.l, nil, &search.raw, &local);
|
transstr(im.l, nil, &search.raw, &local);
|
||||||
foldascii(&local);
|
foldascii(&local);
|
||||||
clearkouho();
|
clearkouho();
|
||||||
n = dictlookup(getlang(LangEMOJI), &raw, kouho, Maxkouho);
|
n = dictprefix(getlang(LangEMOJI)->dict, &raw, kouho, Maxkouho);
|
||||||
rawhit = n != 0;
|
rawhit = n != 0;
|
||||||
for(i = 0; i < n; i++)
|
for(i = 0; i < n; i++)
|
||||||
addkouho(&kouho[i]);
|
addkouho(&kouho[i]);
|
||||||
localhit = 0;
|
localhit = 0;
|
||||||
if(scmp(&raw, &local) != 0){
|
if(scmp(&raw, &local) != 0){
|
||||||
n = dictlookup(getlang(LangEMOJI), &local, kouho, Maxkouho);
|
n = dictprefix(getlang(LangEMOJI)->dict, &local, kouho, Maxkouho);
|
||||||
localhit = n != 0;
|
localhit = n != 0;
|
||||||
for(i = 0; i < n; i++)
|
for(i = 0; i < n; i++)
|
||||||
addkouho(&kouho[i]);
|
addkouho(&kouho[i]);
|
||||||
@@ -593,8 +593,8 @@ hanjaquery(void)
|
|||||||
{
|
{
|
||||||
transstr(im.l, &search.seed, &search.raw, &search.text);
|
transstr(im.l, &search.seed, &search.raw, &search.text);
|
||||||
clearkouho();
|
clearkouho();
|
||||||
im.nkouho = dictlookup(getlang(LangHANJA), &search.text, im.kouho,
|
im.nkouho = dictlookup(getlang(LangHANJA)->dict, &search.text,
|
||||||
Maxkouho);
|
im.kouho, Maxkouho);
|
||||||
selectfirst();
|
selectfirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ dictionary_candidates(struct ct *t)
|
|||||||
lang = getlang(LangJP);
|
lang = getlang(LangJP);
|
||||||
saved = lang->dict;
|
saved = lang->dict;
|
||||||
lang->dict = trienew();
|
lang->dict = trienew();
|
||||||
trieput(lang->dict, "かな", strlen("かな"), " 候補1 かな 候補2 ",
|
trieput(lang->dict, "かな", strlen("かな"), " 候補1 候補2 ",
|
||||||
strlen(" 候補1 かな 候補2 "));
|
strlen(" 候補1 候補2 "));
|
||||||
key = mkstr("かな");
|
key = mkstr("かな");
|
||||||
n = dictlookup(lang, &key, kouho, Maxkouho);
|
n = dictlookup(lang->dict, &key, kouho, Maxkouho);
|
||||||
if(CT_EQ_INT(t, 2, n)){
|
if(CT_EQ_INT(t, 2, n)){
|
||||||
checkstr(t, "candidate 1", "候補1", &kouho[0]);
|
checkstr(t, "candidate 1", "候補1", &kouho[0]);
|
||||||
checkstr(t, "candidate 2", "候補2", &kouho[1]);
|
checkstr(t, "candidate 2", "候補2", &kouho[1]);
|
||||||
@@ -34,13 +34,13 @@ dictionary_candidates(struct ct *t)
|
|||||||
*p = '\0';
|
*p = '\0';
|
||||||
trieput(lang->dict, "key", 3, many, strlen(many));
|
trieput(lang->dict, "key", 3, many, strlen(many));
|
||||||
key = mkstr("key");
|
key = mkstr("key");
|
||||||
n = dictlookup(lang, &key, kouho, Maxkouho);
|
n = dictlookup(lang->dict, &key, kouho, Maxkouho);
|
||||||
if(CT_EQ_INT(t, Maxkouho, n)){
|
if(CT_EQ_INT(t, Maxkouho, n)){
|
||||||
checkstr(t, "first capped candidate", "c00", &kouho[0]);
|
checkstr(t, "first capped candidate", "c00", &kouho[0]);
|
||||||
snprint(item, sizeof item, "c%02d", Maxkouho-1);
|
snprint(item, sizeof item, "c%02d", Maxkouho-1);
|
||||||
checkstr(t, "last capped candidate", item, &kouho[Maxkouho-1]);
|
checkstr(t, "last capped candidate", item, &kouho[Maxkouho-1]);
|
||||||
}
|
}
|
||||||
CT_EQ_INT(t, 3, dictlookup(lang, &key, kouho, 3));
|
CT_EQ_INT(t, 3, dictlookup(lang->dict, &key, kouho, 3));
|
||||||
trieclose(lang->dict);
|
trieclose(lang->dict);
|
||||||
lang->dict = saved;
|
lang->dict = saved;
|
||||||
}
|
}
|
||||||
@@ -56,28 +56,33 @@ dictionary_misses(struct ct *t)
|
|||||||
saved = lang->dict;
|
saved = lang->dict;
|
||||||
lang->dict = trienew();
|
lang->dict = trienew();
|
||||||
key = mkstr("");
|
key = mkstr("");
|
||||||
CT_EQ_INT(t, 0, dictlookup(lang, &key, kouho, Maxkouho));
|
CT_EQ_INT(t, 0, dictlookup(lang->dict, &key, kouho, Maxkouho));
|
||||||
key = mkstr("missing");
|
key = mkstr("missing");
|
||||||
CT_EQ_INT(t, 0, dictlookup(lang, &key, kouho, Maxkouho));
|
CT_EQ_INT(t, 0, dictlookup(lang->dict, &key, kouho, Maxkouho));
|
||||||
CT_EQ_INT(t, 0, dictlookup(getlang(LangKO), &key, kouho, Maxkouho));
|
CT_EQ_INT(t, 0, dictlookup(getlang(LangKO)->dict, &key, kouho, Maxkouho));
|
||||||
trieclose(lang->dict);
|
trieclose(lang->dict);
|
||||||
lang->dict = saved;
|
lang->dict = saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dictionary_emoji_identity(struct ct *t)
|
dictionary_prefix(struct ct *t)
|
||||||
{
|
{
|
||||||
Str kouho[Maxkouho], key;
|
Str kouho[Maxkouho], key;
|
||||||
Trie *saved;
|
Trie *dict;
|
||||||
Lang *lang;
|
|
||||||
|
|
||||||
lang = getlang(LangEMOJI);
|
dict = trienew();
|
||||||
saved = lang->dict;
|
trieput(dict, "smile", 5, "A B", 3);
|
||||||
lang->dict = trienew();
|
trieput(dict, "smiley", 6, "B C", 3);
|
||||||
trieput(lang->dict, "é", strlen("é"), "é", strlen("é"));
|
trieput(dict, "sad", 3, "D", 1);
|
||||||
key = mkstr("é");
|
key = mkstr("smile");
|
||||||
if(CT_EQ_INT(t, 1, dictlookup(lang, &key, kouho, Maxkouho)))
|
if(CT_EQ_INT(t, 4, dictprefix(dict, &key, kouho, Maxkouho))){
|
||||||
checkstr(t, "emoji identity candidate", "é", &kouho[0]);
|
checkstr(t, "own entry first", "A", &kouho[0]);
|
||||||
trieclose(lang->dict);
|
checkstr(t, "entry below", "C", &kouho[3]);
|
||||||
lang->dict = saved;
|
}
|
||||||
|
key = mkstr("s");
|
||||||
|
CT_EQ_INT(t, 5, dictprefix(dict, &key, kouho, Maxkouho));
|
||||||
|
CT_EQ_INT(t, 2, dictprefix(dict, &key, kouho, 2));
|
||||||
|
key = mkstr("x");
|
||||||
|
CT_EQ_INT(t, 0, dictprefix(dict, &key, kouho, Maxkouho));
|
||||||
|
trieclose(dict);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ void engine_randomized_stress(struct ct*);
|
|||||||
void engine_full_boundary_passthrough(struct ct*);
|
void engine_full_boundary_passthrough(struct ct*);
|
||||||
void dictionary_candidates(struct ct*);
|
void dictionary_candidates(struct ct*);
|
||||||
void dictionary_misses(struct ct*);
|
void dictionary_misses(struct ct*);
|
||||||
void dictionary_emoji_identity(struct ct*);
|
void dictionary_prefix(struct ct*);
|
||||||
void ipc_masks_modifiers(struct ct*);
|
void ipc_masks_modifiers(struct ct*);
|
||||||
void ipc_control_and_caret_frames(struct ct*);
|
void ipc_control_and_caret_frames(struct ct*);
|
||||||
void ipc_runtime_path(struct ct*);
|
void ipc_runtime_path(struct ct*);
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ static const struct ct_test tests[] = {
|
|||||||
{ "engine/full-boundary-passthrough", engine_full_boundary_passthrough },
|
{ "engine/full-boundary-passthrough", engine_full_boundary_passthrough },
|
||||||
{ "dict/candidates", dictionary_candidates },
|
{ "dict/candidates", dictionary_candidates },
|
||||||
{ "dict/misses", dictionary_misses },
|
{ "dict/misses", dictionary_misses },
|
||||||
{ "dict/emoji-identity", dictionary_emoji_identity },
|
{ "dict/prefix", dictionary_prefix },
|
||||||
{ "ipc/masks-modifiers", ipc_masks_modifiers },
|
{ "ipc/masks-modifiers", ipc_masks_modifiers },
|
||||||
{ "ipc/control-caret-frames", ipc_control_and_caret_frames },
|
{ "ipc/control-caret-frames", ipc_control_and_caret_frames },
|
||||||
{ "ipc/runtime-path", ipc_runtime_path },
|
{ "ipc/runtime-path", ipc_runtime_path },
|
||||||
|
|||||||
Reference in New Issue
Block a user