41 | 41 |
#include "base/mutex.h"
|
42 | 42 |
#include "base/singleton.h"
|
43 | 43 |
#include "base/stl_util.h"
|
|
44 |
#include "base/string_piece.h"
|
44 | 45 |
#include "base/thread.h"
|
45 | 46 |
#include "base/util.h"
|
46 | 47 |
#include "dictionary/dictionary_token.h"
|
|
57 | 58 |
namespace {
|
58 | 59 |
|
59 | 60 |
struct OrderByKey {
|
60 | |
bool operator()(const UserPOS::Token *lhs,
|
61 | |
const UserPOS::Token *rhs) const {
|
62 | |
return lhs->key < rhs->key;
|
|
61 |
bool operator()(const UserPOS::Token *token, StringPiece key) const {
|
|
62 |
return token->key < key;
|
|
63 |
}
|
|
64 |
|
|
65 |
bool operator()(StringPiece key, const UserPOS::Token *token) const {
|
|
66 |
return key < token->key;
|
63 | 67 |
}
|
64 | 68 |
};
|
65 | 69 |
|
|
70 |
struct OrderByKeyPrefix {
|
|
71 |
bool operator()(const UserPOS::Token *token, StringPiece prefix) const {
|
|
72 |
return StringPiece(token->key, 0, prefix.size()) < prefix;
|
|
73 |
}
|
|
74 |
|
|
75 |
bool operator()(StringPiece prefix, const UserPOS::Token *token) const {
|
|
76 |
return prefix < StringPiece(token->key, 0, prefix.size());
|
|
77 |
}
|
|
78 |
};
|
|
79 |
|
66 | 80 |
struct OrderByKeyThenById {
|
67 | |
bool operator()(const UserPOS::Token *lhs,
|
68 | |
const UserPOS::Token *rhs) const {
|
|
81 |
bool operator()(const UserPOS::Token *lhs, const UserPOS::Token *rhs) const {
|
69 | 82 |
const int comp = lhs->key.compare(rhs->key);
|
70 | 83 |
return comp == 0 ? (lhs->id < rhs->id) : (comp < 0);
|
71 | 84 |
}
|
|
109 | 122 |
|
110 | 123 |
class UserDictionary::TokensIndex : public vector<UserPOS::Token *> {
|
111 | 124 |
public:
|
112 | |
explicit TokensIndex(const UserPOSInterface *user_pos,
|
113 | |
SuppressionDictionary *suppression_dictionary)
|
|
125 |
TokensIndex(const UserPOSInterface *user_pos,
|
|
126 |
SuppressionDictionary *suppression_dictionary)
|
114 | 127 |
: user_pos_(user_pos),
|
115 | 128 |
suppression_dictionary_(suppression_dictionary) {}
|
|
129 |
|
116 | 130 |
~TokensIndex() {
|
117 | 131 |
Clear();
|
118 | 132 |
}
|
|
211 | 225 |
DCHECK(dic_);
|
212 | 226 |
}
|
213 | 227 |
|
214 | |
virtual ~UserDictionaryReloader() {
|
|
228 |
~UserDictionaryReloader() override {
|
215 | 229 |
Join();
|
216 | 230 |
}
|
217 | 231 |
|
|
248 | 262 |
Start("UserDictionaryReloader");
|
249 | 263 |
}
|
250 | 264 |
|
251 | |
virtual void Run() {
|
|
265 |
void Run() override {
|
252 | 266 |
std::unique_ptr<UserDictionaryStorage> storage(new UserDictionaryStorage(
|
253 | 267 |
Singleton<UserDictionaryFileManager>::get()->GetFileName()));
|
254 | 268 |
|
|
341 | 355 |
}
|
342 | 356 |
|
343 | 357 |
// Find the starting point of iteration over dictionary contents.
|
344 | |
UserPOS::Token key_token;
|
345 | |
key.CopyToString(&key_token.key);
|
346 | |
vector<UserPOS::Token *>::const_iterator it = std::lower_bound(
|
347 | |
tokens_->begin(), tokens_->end(), &key_token, OrderByKey());
|
348 | |
|
349 | 358 |
Token token;
|
350 | |
for (; it != tokens_->end(); ++it) {
|
351 | |
if (!Util::StartsWith((*it)->key, key)) {
|
352 | |
break;
|
353 | |
}
|
354 | |
switch (callback->OnKey((*it)->key)) {
|
|
359 |
for (auto range = std::equal_range(tokens_->begin(), tokens_->end(), key,
|
|
360 |
OrderByKeyPrefix());
|
|
361 |
range.first != range.second; ++range.first) {
|
|
362 |
const UserPOS::Token &user_pos_token = **range.first;
|
|
363 |
switch (callback->OnKey(user_pos_token.key)) {
|
355 | 364 |
case Callback::TRAVERSE_DONE:
|
356 | 365 |
return;
|
357 | 366 |
case Callback::TRAVERSE_NEXT_KEY:
|
|
360 | 369 |
default:
|
361 | 370 |
break;
|
362 | 371 |
}
|
363 | |
FillTokenFromUserPOSToken(**it, &token);
|
|
372 |
FillTokenFromUserPOSToken(user_pos_token, &token);
|
364 | 373 |
// Override POS IDs for suggest only words.
|
365 | |
if (pos_matcher_.IsSuggestOnlyWord((*it)->id)) {
|
|
374 |
if (pos_matcher_.IsSuggestOnlyWord(user_pos_token.id)) {
|
366 | 375 |
token.lid = token.rid = pos_matcher_.GetUnknownId();
|
367 | 376 |
}
|
368 | |
if (callback->OnToken((*it)->key, (*it)->key, token) ==
|
|
377 |
if (callback->OnToken(user_pos_token.key, user_pos_token.key, token) ==
|
369 | 378 |
Callback::TRAVERSE_DONE) {
|
370 | 379 |
return;
|
371 | 380 |
}
|
|
391 | 400 |
}
|
392 | 401 |
|
393 | 402 |
// Find the starting point for iteration over dictionary contents.
|
394 | |
UserPOS::Token key_token;
|
395 | |
key_token.key.assign(key.data(), Util::OneCharLen(key.data()));
|
396 | |
vector<UserPOS::Token *>::const_iterator it = std::lower_bound(
|
397 | |
tokens_->begin(), tokens_->end(), &key_token, OrderByKey());
|
398 | |
|
|
403 |
const StringPiece first_char(key, 0, Util::OneCharLen(key.data()));
|
399 | 404 |
Token token;
|
400 | |
for (; it != tokens_->end(); ++it) {
|
401 | |
if ((*it)->key > key) {
|
|
405 |
for (auto it = std::lower_bound(tokens_->begin(), tokens_->end(), first_char,
|
|
406 |
OrderByKey());
|
|
407 |
it != tokens_->end(); ++it) {
|
|
408 |
const UserPOS::Token &user_pos_token = **it;
|
|
409 |
if (user_pos_token.key > key) {
|
402 | 410 |
break;
|
403 | 411 |
}
|
404 | |
if (pos_matcher_.IsSuggestOnlyWord((*it)->id)) {
|
|
412 |
if (pos_matcher_.IsSuggestOnlyWord(user_pos_token.id)) {
|
405 | 413 |
continue;
|
406 | 414 |
}
|
407 | |
if (!Util::StartsWith(key, (*it)->key)) {
|
|
415 |
if (!Util::StartsWith(key, user_pos_token.key)) {
|
408 | 416 |
continue;
|
409 | 417 |
}
|
410 | |
switch (callback->OnKey((*it)->key)) {
|
|
418 |
switch (callback->OnKey(user_pos_token.key)) {
|
411 | 419 |
case Callback::TRAVERSE_DONE:
|
412 | 420 |
return;
|
413 | 421 |
case Callback::TRAVERSE_NEXT_KEY:
|
|
418 | 426 |
default:
|
419 | 427 |
break;
|
420 | 428 |
}
|
421 | |
FillTokenFromUserPOSToken(**it, &token);
|
422 | |
switch (callback->OnToken((*it)->key, (*it)->key, token)) {
|
|
429 |
FillTokenFromUserPOSToken(user_pos_token, &token);
|
|
430 |
switch (callback->OnToken(user_pos_token.key, user_pos_token.key, token)) {
|
423 | 431 |
case Callback::TRAVERSE_DONE:
|
424 | 432 |
return;
|
425 | 433 |
case Callback::TRAVERSE_CULL:
|
|
440 | 448 |
conversion_request.config().incognito_mode()) {
|
441 | 449 |
return;
|
442 | 450 |
}
|
443 | |
UserPOS::Token key_token;
|
444 | |
key.CopyToString(&key_token.key);
|
445 | |
typedef vector<UserPOS::Token *>::const_iterator TokenIterator;
|
446 | |
pair<TokenIterator, TokenIterator> range = std::equal_range(
|
447 | |
tokens_->begin(), tokens_->end(), &key_token, OrderByKey());
|
|
451 |
auto range = std::equal_range(tokens_->begin(), tokens_->end(), key,
|
|
452 |
OrderByKey());
|
448 | 453 |
if (range.first == range.second) {
|
449 | 454 |
return;
|
450 | 455 |
}
|
|
483 | 488 |
return false;
|
484 | 489 |
}
|
485 | 490 |
|
486 | |
UserPOS::Token key_token;
|
487 | |
key.CopyToString(&key_token.key);
|
488 | |
typedef vector<UserPOS::Token *>::const_iterator TokenIterator;
|
489 | |
pair<TokenIterator, TokenIterator> range = std::equal_range(
|
490 | |
tokens_->begin(), tokens_->end(), &key_token, OrderByKey());
|
491 | |
|
492 | 491 |
// Set the comment that was found first.
|
493 | |
for (; range.first != range.second; ++range.first) {
|
494 | |
const UserPOS::Token *token = *range.first;
|
495 | |
if (token->value == value && !token->comment.empty()) {
|
496 | |
comment->assign(token->comment);
|
|
492 |
for (auto range = std::equal_range(tokens_->begin(), tokens_->end(), key,
|
|
493 |
OrderByKey());
|
|
494 |
range.first != range.second; ++range.first) {
|
|
495 |
const UserPOS::Token &token = **range.first;
|
|
496 |
if (token.value == value && !token.comment.empty()) {
|
|
497 |
comment->assign(token.comment);
|
497 | 498 |
return true;
|
498 | 499 |
}
|
499 | 500 |
}
|