16
16
#include < rime/ticket.h>
17
17
#include < rime/algo/dynamics.h>
18
18
#include < rime/algo/syllabifier.h>
19
+ #include < rime/algo/strings.h>
19
20
#include < rime/dict/db.h>
20
21
#include < rime/dict/table.h>
21
22
#include < rime/dict/user_dictionary.h>
23
+ #include < rime/dict/vocabulary.h>
22
24
23
25
namespace rime {
24
26
25
27
struct DfsState {
26
28
size_t depth_limit;
29
+ size_t predict_word_from_depth;
27
30
TickCount present_tick;
28
31
Code code;
29
32
vector<double > credibility;
@@ -32,13 +35,15 @@ struct DfsState {
32
35
string key;
33
36
string value;
34
37
38
+ size_t depth () const { return code.size (); }
39
+
35
40
bool IsExactMatch (const string& prefix) {
36
41
return boost::starts_with (key, prefix + ' \t ' );
37
42
}
38
43
bool IsPrefixMatch (const string& prefix) {
39
44
return boost::starts_with (key, prefix);
40
45
}
41
- void RecruitEntry (size_t pos);
46
+ void RecruitEntry (size_t pos, map<string, SyllableId>* syllabary = nullptr );
42
47
bool NextEntry () {
43
48
if (!accessor->GetNextRecord (&key, &value)) {
44
49
key.clear ();
@@ -63,11 +68,30 @@ struct DfsState {
63
68
}
64
69
};
65
70
66
- void DfsState::RecruitEntry (size_t pos) {
71
+ void DfsState::RecruitEntry (size_t pos, map<string, SyllableId>* syllabary) {
72
+ string full_code;
67
73
auto e = UserDictionary::CreateDictEntry (key, value, present_tick,
68
- credibility.back ());
74
+ credibility.back (),
75
+ syllabary ? &full_code : nullptr );
69
76
if (e) {
70
- e->code = code;
77
+ if (syllabary) {
78
+ vector<string> syllables =
79
+ strings::split (full_code, " " , strings::SplitBehavior::SkipToken);
80
+ Code numeric_code;
81
+ for (auto s = syllables.begin (); s != syllables.end (); ++s) {
82
+ auto found = syllabary->find (*s);
83
+ if (found == syllabary->end ()) {
84
+ LOG (ERROR) << " failed to recruit dict entry '" << e->text
85
+ << " ', unrecognized syllable: " << *s;
86
+ return ;
87
+ }
88
+ numeric_code.push_back (found->second );
89
+ }
90
+ e->code = numeric_code;
91
+ e->matching_code_size = code.size ();
92
+ } else {
93
+ e->code = code;
94
+ }
71
95
DLOG (INFO) << " add entry at pos " << pos;
72
96
query_result[pos].push_back (e);
73
97
}
@@ -230,10 +254,36 @@ void UserDictionary::DfsLookup(const SyllableGraph& syll_graph,
230
254
if (!state->NextEntry ()) // reached the end of db
231
255
break ;
232
256
}
233
- // the caller can limit the number of syllables to look up
234
- if ((!state->depth_limit || state->code .size () < state->depth_limit ) &&
235
- state->IsPrefixMatch (prefix)) { // 'b |e ' vs. 'b e f \tBefore'
236
- DfsLookup (syll_graph, end_pos, prefix, state);
257
+ auto next_index = syll_graph.indices .find (end_pos);
258
+ if (next_index == syll_graph.indices .end ()) {
259
+ // reached the end of input, predict word if requested
260
+ if (state->predict_word_from_depth != 0 &&
261
+ state->depth () >= state->predict_word_from_depth ) {
262
+ while (state->IsPrefixMatch (prefix)) {
263
+ DLOG (INFO) << " prefix match found for '" << prefix << " '." ;
264
+ if (syllabary_.empty ()) {
265
+ Syllabary syllabary;
266
+ if (!table_->GetSyllabary (&syllabary)) {
267
+ LOG (ERROR) << " failed to get syllabary for user dict: "
268
+ << name ();
269
+ break ;
270
+ }
271
+ SyllableId syllable_id = 0 ;
272
+ for (auto s = syllabary.begin (); s != syllabary.end (); ++s) {
273
+ syllabary_[*s] = syllable_id++;
274
+ }
275
+ }
276
+ state->RecruitEntry (end_pos, &syllabary_);
277
+ if (!state->NextEntry ()) // reached the end of db
278
+ break ;
279
+ }
280
+ }
281
+ } else {
282
+ // the caller can limit the number of syllables to look up
283
+ if ((!state->depth_limit || state->depth () < state->depth_limit ) &&
284
+ state->IsPrefixMatch (prefix)) { // 'b |e ' vs. 'b e f \tBefore'
285
+ DfsLookup (syll_graph, end_pos, prefix, state);
286
+ }
237
287
}
238
288
}
239
289
if (!state->IsPrefixMatch (current_prefix)) // 'b |' vs. 'g o \tGo'
@@ -254,12 +304,14 @@ an<UserDictEntryCollector> UserDictionary::Lookup(
254
304
const SyllableGraph& syll_graph,
255
305
size_t start_pos,
256
306
size_t depth_limit,
307
+ size_t predict_word_from_depth,
257
308
double initial_credibility) {
258
309
if (!table_ || !prism_ || !loaded () ||
259
310
start_pos >= syll_graph.interpreted_length )
260
311
return nullptr ;
261
312
DfsState state;
262
313
state.depth_limit = depth_limit;
314
+ state.predict_word_from_depth = predict_word_from_depth;
263
315
FetchTickCount ();
264
316
state.present_tick = tick_ + 1 ;
265
317
state.credibility .push_back (initial_credibility);
0 commit comments