// Copyright 2010-2020, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dictionary/dictionary_impl.h"
#include <string>
#include <utility>
#include "base/logging.h"
#include "base/util.h"
#include "dictionary/dictionary_interface.h"
#include "dictionary/dictionary_token.h"
#include "dictionary/pos_matcher.h"
#include "dictionary/suppression_dictionary.h"
#include "protocol/commands.pb.h"
#include "absl/strings/string_view.h"
namespace mozc {
namespace dictionary {
DictionaryImpl::DictionaryImpl(
std::unique_ptr<const DictionaryInterface> system_dictionary,
std::unique_ptr<const DictionaryInterface> value_dictionary,
DictionaryInterface *user_dictionary,
const SuppressionDictionary *suppression_dictionary,
const POSMatcher *pos_matcher)
: pos_matcher_(pos_matcher),
system_dictionary_(std::move(system_dictionary)),
value_dictionary_(std::move(value_dictionary)),
user_dictionary_(user_dictionary),
suppression_dictionary_(suppression_dictionary) {
CHECK(pos_matcher_);
CHECK(system_dictionary_.get());
CHECK(value_dictionary_.get());
CHECK(user_dictionary_);
CHECK(suppression_dictionary_);
dics_.push_back(system_dictionary_.get());
dics_.push_back(value_dictionary_.get());
dics_.push_back(user_dictionary_);
}
DictionaryImpl::~DictionaryImpl() { dics_.clear(); }
bool DictionaryImpl::HasKey(absl::string_view key) const {
for (size_t i = 0; i < dics_.size(); ++i) {
if (dics_[i]->HasKey(key)) {
return true;
}
}
return false;
}
bool DictionaryImpl::HasValue(absl::string_view value) const {
for (size_t i = 0; i < dics_.size(); ++i) {
if (dics_[i]->HasValue(value)) {
return true;
}
}
return false;
}
namespace {
class CallbackWithFilter : public DictionaryInterface::Callback {
public:
CallbackWithFilter(const bool use_spelling_correction,
const bool use_zip_code_conversion,
const bool use_t13n_conversion,
const POSMatcher *pos_matcher,
const SuppressionDictionary *suppression_dictionary,
DictionaryInterface::Callback *callback)
: use_spelling_correction_(use_spelling_correction),
use_zip_code_conversion_(use_zip_code_conversion),
use_t13n_conversion_(use_t13n_conversion),
pos_matcher_(pos_matcher),
suppression_dictionary_(suppression_dictionary),
callback_(callback) {}
ResultType OnKey(absl::string_view key) override {
return callback_->OnKey(key);
}
ResultType OnActualKey(absl::string_view key, absl::string_view actual_key,
bool is_expanded) override {
return callback_->OnActualKey(key, actual_key, is_expanded);
}
ResultType OnToken(absl::string_view key, absl::string_view actual_key,
const Token &token) override {
if (!(token.attributes & Token::USER_DICTIONARY)) {
if (!use_spelling_correction_ &&
(token.attributes & Token::SPELLING_CORRECTION)) {
return TRAVERSE_CONTINUE;
}
if (!use_zip_code_conversion_ && pos_matcher_->IsZipcode(token.lid)) {
return TRAVERSE_CONTINUE;
}
if (!use_t13n_conversion_ &&
Util::IsEnglishTransliteration(token.value)) {
return TRAVERSE_CONTINUE;
}
}
if (suppression_dictionary_->SuppressEntry(token.key, token.value)) {
return TRAVERSE_CONTINUE;
}
return callback_->OnToken(key, actual_key, token);
}
private:
const bool use_spelling_correction_;
const bool use_zip_code_conversion_;
const bool use_t13n_conversion_;
const POSMatcher *pos_matcher_;
const SuppressionDictionary *suppression_dictionary_;
DictionaryInterface::Callback *callback_;
};
} // namespace
void DictionaryImpl::LookupPredictive(
absl::string_view key, const ConversionRequest &conversion_request,
Callback *callback) const {
CallbackWithFilter callback_with_filter(
conversion_request.config().use_spelling_correction(),
conversion_request.config().use_zip_code_conversion(),
conversion_request.config().use_t13n_conversion(), pos_matcher_,
suppression_dictionary_, callback);
for (size_t i = 0; i < dics_.size(); ++i) {
dics_[i]->LookupPredictive(key, conversion_request, &callback_with_filter);
}
}
void DictionaryImpl::LookupPrefix(absl::string_view key,
const ConversionRequest &conversion_request,
Callback *callback) const {
CallbackWithFilter callback_with_filter(
conversion_request.config().use_spelling_correction(),
conversion_request.config().use_zip_code_conversion(),
conversion_request.config().use_t13n_conversion(), pos_matcher_,
suppression_dictionary_, callback);
for (size_t i = 0; i < dics_.size(); ++i) {
dics_[i]->LookupPrefix(key, conversion_request, &callback_with_filter);
}
}
void DictionaryImpl::LookupExact(absl::string_view key,
const ConversionRequest &conversion_request,
Callback *callback) const {
CallbackWithFilter callback_with_filter(
conversion_request.config().use_spelling_correction(),
conversion_request.config().use_zip_code_conversion(),
conversion_request.config().use_t13n_conversion(), pos_matcher_,
suppression_dictionary_, callback);
for (size_t i = 0; i < dics_.size(); ++i) {
dics_[i]->LookupExact(key, conversion_request, &callback_with_filter);
}
}
void DictionaryImpl::LookupReverse(absl::string_view str,
const ConversionRequest &conversion_request,
Callback *callback) const {
CallbackWithFilter callback_with_filter(
conversion_request.config().use_spelling_correction(),
conversion_request.config().use_zip_code_conversion(),
conversion_request.config().use_t13n_conversion(), pos_matcher_,
suppression_dictionary_, callback);
for (size_t i = 0; i < dics_.size(); ++i) {
dics_[i]->LookupReverse(str, conversion_request, &callback_with_filter);
}
}
bool DictionaryImpl::LookupComment(absl::string_view key,
absl::string_view value,
const ConversionRequest &conversion_request,
std::string *comment) const {
// TODO(komatsu): UserDictionary should be treated as the highest priority.
// In the current implementation, UserDictionary is the last node of dics_,
// but the only dictionary which may return true.
for (size_t i = 0; i < dics_.size(); ++i) {
if (dics_[i]->LookupComment(key, value, conversion_request, comment)) {
return true;
}
}
return false;
}
bool DictionaryImpl::Reload() { return user_dictionary_->Reload(); }
void DictionaryImpl::PopulateReverseLookupCache(absl::string_view str) const {
for (size_t i = 0; i < dics_.size(); ++i) {
dics_[i]->PopulateReverseLookupCache(str);
}
}
void DictionaryImpl::ClearReverseLookupCache() const {
for (size_t i = 0; i < dics_.size(); ++i) {
dics_[i]->ClearReverseLookupCache();
}
}
} // namespace dictionary
} // namespace mozc