data: one trie for maps and dictionaries, one loader

The hash map served a single exact-match lookup that the trie already
answers, at the price of a second container, a second file loader with
its own drift, and a Str-to-UTF-8 conversion on every chain probe. The
files are small (kanji.dict is 7.5k lines), so the trie holds both.
trieopen validates keys and each space-separated value word against Str
and reports path:line; trielookup takes the Str every caller holds and
treats a nil trie as an unloaded map; trienew/trieput exist for tests.
The overflow guards on growth, Trie.root (always 0) and the per-language
init loop written twice are gone.
This commit is contained in:
2026-08-16 15:56:32 +09:00
parent eb0f88f764
commit c7718ece52
15 changed files with 206 additions and 609 deletions

View File

@@ -3,21 +3,20 @@
void
dictionary_candidates(struct ct *t)
{
static char malformed[] = { 'o', 'k', ' ', (char)0x80 };
char many[512], item[8];
char *p;
Dictreq req;
Dictres res;
Hmap *saved;
Trie *saved;
Lang *lang;
Str key;
int i;
lang = getlang(LangJP);
saved = lang->dict;
lang->dict = hmapalloc(1);
lang->dict = trienew();
key = mkstr("かな");
hmapset(&lang->dict, &key, " 候補1 かな 候補2 ",
trieput(lang->dict, "かな", strlen("かな"), " 候補1 かな 候補2 ",
strlen(" 候補1 かな 候補2 "));
memset(&req, 0, sizeof req);
req.key = key;
@@ -42,7 +41,7 @@ dictionary_candidates(struct ct *t)
p += strlen(item);
}
*p = '\0';
hmapset(&lang->dict, &key, many, strlen(many));
trieput(lang->dict, "key", 3, many, strlen(many));
req.key = key;
req.pre = mkstr("preedit-two");
req.seq = 29;
@@ -54,13 +53,8 @@ dictionary_candidates(struct ct *t)
CT_EQ_INT(t, 0, scmp(&req.pre, &res.key));
checkstr(t, "first capped candidate", "c00", &res.kouho[0]);
checkstr(t, "last capped candidate", "c31", &res.kouho[31]);
key = mkstr("malformed");
hmapset(&lang->dict, &key, malformed, sizeof malformed);
req.key = key;
dictlookup(&req, &res);
CT_EQ_INT(t, 0, res.nkouho);
cleanup:
hmapfree(lang->dict);
trieclose(lang->dict);
lang->dict = saved;
}
@@ -77,13 +71,13 @@ dictionary_misses_clear_result(struct ct *t)
};
Dictreq req;
Dictres res;
Hmap *saved;
Trie *saved;
Lang *lang;
int i;
lang = getlang(LangJP);
saved = lang->dict;
lang->dict = hmapalloc(1);
lang->dict = trienew();
for(i = 0; i < nelem(cases); i++){
memset(&res, 0xa5, sizeof res);
req.key = mkstr(cases[i].key);
@@ -98,7 +92,7 @@ dictionary_misses_clear_result(struct ct *t)
CT_EQ_UINT(t, 0xf00d0000U + i, res.seq);
checkstr(t, cases[i].name, cases[i].pre, &res.key);
}
hmapfree(lang->dict);
trieclose(lang->dict);
lang->dict = saved;
}
@@ -107,15 +101,15 @@ dictionary_emoji_identity(struct ct *t)
{
Dictreq req;
Dictres res;
Hmap *saved;
Trie *saved;
Lang *lang;
Str key;
lang = getlang(LangEMOJI);
saved = lang->dict;
lang->dict = hmapalloc(2);
lang->dict = trienew();
key = mkstr("é");
hmapset(&lang->dict, &key, "é", strlen("é"));
trieput(lang->dict, "é", strlen("é"), "é", strlen("é"));
memset(&req, 0, sizeof req);
req.key = key;
req.pre = key;
@@ -124,6 +118,6 @@ dictionary_emoji_identity(struct ct *t)
dictlookup(&req, &res);
if(CT_EQ_INT(t, 1, res.nkouho))
checkstr(t, "emoji identity candidate", "é", &res.kouho[0]);
hmapfree(lang->dict);
trieclose(lang->dict);
lang->dict = saved;
}