Skip to content

Commit 77438a9

Browse files
committed
fix(table_translator): null pointer exception when dict entries are filtered
1 parent d45240f commit 77438a9

7 files changed

+97
-56
lines changed

src/rime/dict/dictionary.cc

+35-22
Original file line numberDiff line numberDiff line change
@@ -68,37 +68,36 @@ void DictEntryIterator::Sort() {
6868
dictionary::compare_chunk_by_head_element);
6969
}
7070

71-
void DictEntryIterator::PrepareEntry() {
72-
if (exhausted() || !table_) {
73-
return;
74-
}
75-
const auto& chunk(chunks_[chunk_index_]);
76-
entry_ = New<DictEntry>();
77-
const auto& e(chunk.entries[chunk.cursor]);
78-
DLOG(INFO) << "creating temporary dict entry '"
79-
<< table_->GetEntryText(e) << "'.";
80-
entry_->code = chunk.code;
81-
entry_->text = table_->GetEntryText(e);
82-
const double kS = 1e8;
83-
entry_->weight = (e.weight + 1) / kS * chunk.credibility;
84-
if (!chunk.remaining_code.empty()) {
85-
entry_->comment = "~" + chunk.remaining_code;
86-
entry_->remaining_code_length = chunk.remaining_code.length();
71+
void DictEntryIterator::AddFilter(DictEntryFilter filter) {
72+
DictEntryFilterBinder::AddFilter(filter);
73+
// the introduced filter could invalidate the current or even all the
74+
// remaining entries
75+
while (!exhausted() && !filter_(Peek())) {
76+
FindNextEntry();
8777
}
8878
}
8979

9080
an<DictEntry> DictEntryIterator::Peek() {
91-
while (!entry_ && !exhausted()) {
92-
PrepareEntry();
93-
if (filter_ && !filter_(entry_)) {
94-
Next();
81+
if (!entry_ && !exhausted() && table_) {
82+
// get next entry from current chunk
83+
const auto& chunk(chunks_[chunk_index_]);
84+
const auto& e(chunk.entries[chunk.cursor]);
85+
DLOG(INFO) << "creating temporary dict entry '"
86+
<< table_->GetEntryText(e) << "'.";
87+
entry_ = New<DictEntry>();
88+
entry_->code = chunk.code;
89+
entry_->text = table_->GetEntryText(e);
90+
const double kS = 1e8;
91+
entry_->weight = (e.weight + 1) / kS * chunk.credibility;
92+
if (!chunk.remaining_code.empty()) {
93+
entry_->comment = "~" + chunk.remaining_code;
94+
entry_->remaining_code_length = chunk.remaining_code.length();
9595
}
9696
}
9797
return entry_;
9898
}
9999

100-
bool DictEntryIterator::Next() {
101-
entry_.reset();
100+
bool DictEntryIterator::FindNextEntry() {
102101
if (exhausted()) {
103102
return false;
104103
}
@@ -113,6 +112,20 @@ bool DictEntryIterator::Next() {
113112
return !exhausted();
114113
}
115114

115+
bool DictEntryIterator::Next() {
116+
entry_.reset();
117+
if (!FindNextEntry()) {
118+
return false;
119+
}
120+
while (filter_ && !filter_(Peek())) {
121+
if (!FindNextEntry()) {
122+
return false;
123+
}
124+
}
125+
return true;
126+
}
127+
128+
// Note: does not apply filters
116129
bool DictEntryIterator::Skip(size_t num_entries) {
117130
while (num_entries > 0) {
118131
if (exhausted()) return false;

src/rime/dict/dictionary.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,15 @@ class DictEntryIterator : public DictEntryFilterBinder {
4747

4848
void AddChunk(dictionary::Chunk&& chunk, Table* table);
4949
void Sort();
50+
void AddFilter(DictEntryFilter filter) override;
5051
RIME_API an<DictEntry> Peek();
5152
RIME_API bool Next();
5253
bool Skip(size_t num_entries);
53-
bool exhausted() const { return chunk_index_ == chunks_.size(); }
54+
bool exhausted() const { return chunk_index_ >= chunks_.size(); }
5455
size_t entry_count() const { return entry_count_; }
5556

5657
protected:
57-
void PrepareEntry();
58+
bool FindNextEntry();
5859

5960
private:
6061
vector<dictionary::Chunk> chunks_;

src/rime/dict/user_dictionary.cc

+28-11
Original file line numberDiff line numberDiff line change
@@ -96,23 +96,40 @@ bool UserDictEntryIterator::Release(DictEntryList* receiver) {
9696
return true;
9797
}
9898

99+
void UserDictEntryIterator::AddFilter(DictEntryFilter filter) {
100+
DictEntryFilterBinder::AddFilter(filter);
101+
// the introduced filter could invalidate the current or even all the
102+
// remaining entries
103+
while (!exhausted() && !filter_(Peek())) {
104+
FindNextEntry();
105+
}
106+
}
107+
99108
an<DictEntry> UserDictEntryIterator::Peek() {
100-
an<DictEntry> result;
101-
while (!result && !exhausted()) {
102-
result = (*entries_)[index_];
103-
if (filter_ && !filter_(result)) {
104-
++index_;
105-
result.reset();
106-
}
109+
if (exhausted()) {
110+
return nullptr;
107111
}
108-
return result;
112+
return (*entries_)[index_];
109113
}
110114

111-
bool UserDictEntryIterator::Next() {
112-
if (exhausted())
115+
bool UserDictEntryIterator::FindNextEntry() {
116+
if (exhausted()) {
113117
return false;
118+
}
114119
++index_;
115-
return exhausted();
120+
return !exhausted();
121+
}
122+
123+
bool UserDictEntryIterator::Next() {
124+
if (!FindNextEntry()) {
125+
return false;
126+
}
127+
while (filter_ && !filter_(Peek())) {
128+
if (!FindNextEntry()) {
129+
return false;
130+
}
131+
}
132+
return true;
116133
}
117134

118135
// UserDictionary members

src/rime/dict/user_dictionary.h

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class UserDictEntryIterator : public DictEntryFilterBinder {
2626
void SortRange(size_t start, size_t count);
2727
bool Release(DictEntryList* receiver);
2828

29+
void AddFilter(DictEntryFilter filter) override;
2930
an<DictEntry> Peek();
3031
bool Next();
3132
bool exhausted() const {
@@ -36,6 +37,8 @@ class UserDictEntryIterator : public DictEntryFilterBinder {
3637
}
3738

3839
protected:
40+
bool FindNextEntry();
41+
3942
an<DictEntryList> entries_;
4043
size_t index_ = 0;
4144
};

src/rime/dict/vocabulary.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ using DictEntryFilter = function<bool (an<DictEntry> entry)>;
5353

5454
class DictEntryFilterBinder {
5555
public:
56-
void AddFilter(DictEntryFilter filter);
56+
virtual ~DictEntryFilterBinder() = default;
57+
virtual void AddFilter(DictEntryFilter filter);
5758

5859
protected:
5960
DictEntryFilter filter_;

src/rime/gear/table_translator.cc

+25-19
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ an<Candidate> TableTranslation::Peek() {
6767
if (exhausted())
6868
return nullptr;
6969
bool is_user_phrase = PreferUserPhrase();
70-
auto e = PreferedEntry(is_user_phrase);
70+
auto e = PreferredEntry(is_user_phrase);
7171
string comment(is_constructed(e.get()) ? kUnitySymbol : e->comment);
7272
if (options_) {
7373
options_->comment_formatter().Apply(&comment);
@@ -559,12 +559,14 @@ TableTranslator::MakeSentence(const string& input, size_t start,
559559
if (filter_by_charset) {
560560
uter.AddFilter(CharsetFilter::FilterDictEntry);
561561
}
562-
entries[consumed_length] = uter.Peek();
563-
if (start_pos == 0 && !uter.exhausted()) {
564-
// also provide words for manual composition
565-
uter.Release(&user_phrase_collector[consumed_length]);
566-
DLOG(INFO) << "user phrase[" << consumed_length << "]: "
567-
<< user_phrase_collector[consumed_length].size();
562+
if (!uter.exhausted()) {
563+
entries[consumed_length] = uter.Peek();
564+
if (start_pos == 0) {
565+
// also provide words for manual composition
566+
uter.Release(&user_phrase_collector[consumed_length]);
567+
DLOG(INFO) << "user phrase[" << consumed_length << "]: "
568+
<< user_phrase_collector[consumed_length].size();
569+
}
568570
}
569571
if (resume_key > active_key &&
570572
!boost::starts_with(resume_key, active_key))
@@ -586,12 +588,14 @@ TableTranslator::MakeSentence(const string& input, size_t start,
586588
if (filter_by_charset) {
587589
uter.AddFilter(CharsetFilter::FilterDictEntry);
588590
}
589-
entries[consumed_length] = uter.Peek();
590-
if (start_pos == 0 && !uter.exhausted()) {
591-
// also provide words for manual composition
592-
uter.Release(&user_phrase_collector[consumed_length]);
593-
DLOG(INFO) << "unity phrase[" << consumed_length << "]: "
594-
<< user_phrase_collector[consumed_length].size();
591+
if (!uter.exhausted()) {
592+
entries[consumed_length] = uter.Peek();
593+
if (start_pos == 0) {
594+
// also provide words for manual composition
595+
uter.Release(&user_phrase_collector[consumed_length]);
596+
DLOG(INFO) << "unity phrase[" << consumed_length << "]: "
597+
<< user_phrase_collector[consumed_length].size();
598+
}
595599
}
596600
if (resume_key > active_key &&
597601
!boost::starts_with(resume_key, active_key))
@@ -615,12 +619,14 @@ TableTranslator::MakeSentence(const string& input, size_t start,
615619
if (filter_by_charset) {
616620
iter.AddFilter(CharsetFilter::FilterDictEntry);
617621
}
618-
entries[consumed_length] = iter.Peek();
619-
if (start_pos == 0 && !iter.exhausted()) {
620-
// also provide words for manual composition
621-
collector[consumed_length] = std::move(iter);
622-
DLOG(INFO) << "table[" << consumed_length << "]: "
623-
<< collector[consumed_length].entry_count();
622+
if (!iter.exhausted()) {
623+
entries[consumed_length] = iter.Peek();
624+
if (start_pos == 0) {
625+
// also provide words for manual composition
626+
collector[consumed_length] = std::move(iter);
627+
DLOG(INFO) << "table[" << consumed_length << "]: "
628+
<< collector[consumed_length].entry_count();
629+
}
624630
}
625631
}
626632
}

src/rime/gear/table_translator.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class TableTranslation : public Translation {
6969
bool CheckEmpty();
7070
bool PreferUserPhrase();
7171

72-
an<DictEntry> PreferedEntry(bool prefer_user_phrase) {
72+
an<DictEntry> PreferredEntry(bool prefer_user_phrase) {
7373
return prefer_user_phrase ? uter_.Peek() : iter_.Peek();
7474
}
7575

0 commit comments

Comments
 (0)