Home | History | Annotate | Download | only in src
      1 // Copyright (C) 2014 Google Inc.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 // http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "ruleset.h"
     16 
     17 #include <libaddressinput/address_field.h>
     18 #include <libaddressinput/util/scoped_ptr.h>
     19 
     20 #include <cassert>
     21 #include <cstddef>
     22 #include <map>
     23 #include <set>
     24 #include <string>
     25 #include <utility>
     26 
     27 #include "rule.h"
     28 #include "util/canonicalize_string.h"
     29 #include "util/stl_util.h"
     30 
     31 namespace i18n {
     32 namespace addressinput {
     33 
     34 Ruleset::Ruleset(AddressField field, scoped_ptr<Rule> rule)
     35     : tries_(),
     36       canonicalizer_(),
     37       parent_(NULL),
     38       field_(field),
     39       deepest_ruleset_level_(field),
     40       rule_(rule.Pass()),
     41       sub_regions_(),
     42       language_codes_() {
     43   assert(field_ >= COUNTRY);
     44   assert(field_ <= DEPENDENT_LOCALITY);
     45   assert(rule_ != NULL);
     46 }
     47 
     48 Ruleset::~Ruleset() {
     49   STLDeleteValues(&sub_regions_);
     50   STLDeleteValues(&language_codes_);
     51 
     52   // Delete the maps and trie objects owned by |tries_| field.
     53   for (LanguageCodeTries::const_iterator lang_it = tries_.begin();
     54        lang_it != tries_.end(); ++lang_it) {
     55     AddressFieldTries* address_field_tries = lang_it->second;
     56     assert(address_field_tries != NULL);
     57 
     58     for (AddressFieldTries::const_iterator address_field_it =
     59              address_field_tries->begin();
     60          address_field_it != address_field_tries->end();
     61          ++address_field_it) {
     62       IdentityFieldTries* identity_field_tries = address_field_it->second;
     63       assert(identity_field_tries != NULL);
     64 
     65       for (IdentityFieldTries::const_iterator identity_field_it =
     66                identity_field_tries->begin();
     67            identity_field_it != identity_field_tries->end();
     68            ++identity_field_it) {
     69         // The tries do not own the ruleset objects.
     70         Trie<const Ruleset*>* trie = identity_field_it->second;
     71         assert(trie != NULL);
     72         delete trie;
     73       }
     74       delete identity_field_tries;
     75     }
     76     delete address_field_tries;
     77   }
     78 }
     79 
     80 void Ruleset::AddSubRegionRuleset(const std::string& sub_region,
     81                                   scoped_ptr<Ruleset> ruleset) {
     82   assert(sub_regions_.find(sub_region) == sub_regions_.end());
     83   assert(ruleset != NULL);
     84   assert(ruleset->field() == static_cast<AddressField>(field() + 1));
     85 
     86   ruleset->parent_ = this;
     87   sub_regions_[sub_region] = ruleset.release();
     88 }
     89 
     90 void Ruleset::AddLanguageCodeRule(const std::string& language_code,
     91                                   scoped_ptr<Rule> rule) {
     92   assert(language_codes_.find(language_code) == language_codes_.end());
     93   assert(rule != NULL);
     94   language_codes_[language_code] = rule.release();
     95 }
     96 
     97 Ruleset* Ruleset::GetSubRegionRuleset(const std::string& sub_region) const {
     98   std::map<std::string, Ruleset*>::const_iterator it =
     99       sub_regions_.find(sub_region);
    100   return it != sub_regions_.end() ? it->second : NULL;
    101 }
    102 
    103 const Rule& Ruleset::GetLanguageCodeRule(
    104     const std::string& language_code) const {
    105   std::map<std::string, const Rule*>::const_iterator it =
    106       language_codes_.find(language_code);
    107   return it != language_codes_.end() ? *it->second : *rule_;
    108 }
    109 
    110 void Ruleset::BuildPrefixSearchIndex() {
    111   assert(field_ == COUNTRY);
    112   assert(tries_.empty());
    113 
    114   // Default language tries.
    115   tries_[""] = new AddressFieldTries;
    116 
    117   // Non-default language tries.
    118   for (std::vector<std::string>::const_iterator lang_it =
    119            rule_->GetLanguages().begin();
    120        lang_it != rule_->GetLanguages().end();
    121        ++lang_it) {
    122     if (*lang_it != rule_->GetLanguage() && !lang_it->empty()) {
    123       tries_[*lang_it] = new AddressFieldTries;
    124     }
    125   }
    126 
    127   for (LanguageCodeTries::const_iterator lang_it = tries_.begin();
    128        lang_it != tries_.end(); ++lang_it) {
    129     AddressFieldTries* address_field_tries = lang_it->second;
    130     address_field_tries->insert(
    131         std::make_pair(ADMIN_AREA, new IdentityFieldTries));
    132     address_field_tries->insert(
    133         std::make_pair(LOCALITY, new IdentityFieldTries));
    134     address_field_tries->insert(
    135         std::make_pair(DEPENDENT_LOCALITY, new IdentityFieldTries));
    136 
    137     for (AddressFieldTries::const_iterator address_field_it =
    138              address_field_tries->begin();
    139          address_field_it != address_field_tries->end();
    140          ++address_field_it) {
    141       IdentityFieldTries* identity_field_tries = address_field_it->second;
    142       identity_field_tries->insert(
    143           std::make_pair(Rule::KEY, new Trie<const Ruleset*>));
    144       identity_field_tries->insert(
    145           std::make_pair(Rule::NAME, new Trie<const Ruleset*>));
    146       identity_field_tries->insert(
    147           std::make_pair(Rule::LATIN_NAME, new Trie<const Ruleset*>));
    148     }
    149   }
    150 
    151   canonicalizer_ = StringCanonicalizer::Build();
    152   AddSubRegionRulesetsToTrie(*this);
    153 }
    154 
    155 void Ruleset::FindRulesetsByPrefix(const std::string& language_code,
    156                                    AddressField ruleset_level,
    157                                    Rule::IdentityField identity_field,
    158                                    const std::string& prefix,
    159                                    std::set<const Ruleset*>* result) const {
    160   assert(field_ == COUNTRY);
    161   assert(ruleset_level >= ADMIN_AREA);
    162   assert(ruleset_level <= DEPENDENT_LOCALITY);
    163   assert(result != NULL);
    164   assert(canonicalizer_ != NULL);
    165 
    166   LanguageCodeTries::const_iterator lang_it = tries_.find(language_code);
    167   AddressFieldTries* address_field_tries = lang_it != tries_.end()
    168       ? lang_it->second : tries_.find("")->second;
    169   assert(address_field_tries != NULL);
    170 
    171   AddressFieldTries::const_iterator address_field_it =
    172       address_field_tries->find(ruleset_level);
    173   assert(address_field_it != address_field_tries->end());
    174 
    175   IdentityFieldTries* identity_field_tries = address_field_it->second;
    176   assert(identity_field_tries != NULL);
    177 
    178   IdentityFieldTries::const_iterator identity_field_it =
    179       identity_field_tries->find(identity_field);
    180   assert(identity_field_it != identity_field_tries->end());
    181 
    182   Trie<const Ruleset*>* trie = identity_field_it->second;
    183   assert(trie != NULL);
    184 
    185   trie->FindDataForKeyPrefix(
    186       canonicalizer_->CanonicalizeString(prefix), result);
    187 }
    188 
    189 void Ruleset::AddSubRegionRulesetsToTrie(const Ruleset& parent_ruleset) {
    190   assert(field_ == COUNTRY);
    191   assert(canonicalizer_ != NULL);
    192 
    193   for (std::map<std::string, Ruleset*>::const_iterator sub_region_it =
    194            parent_ruleset.sub_regions_.begin();
    195        sub_region_it != parent_ruleset.sub_regions_.end();
    196        ++sub_region_it) {
    197     const Ruleset* ruleset = sub_region_it->second;
    198     assert(ruleset != NULL);
    199 
    200     if (deepest_ruleset_level_ < ruleset->field()) {
    201       deepest_ruleset_level_ = ruleset->field();
    202     }
    203 
    204     for (LanguageCodeTries::const_iterator lang_it = tries_.begin();
    205          lang_it != tries_.end(); ++lang_it) {
    206       const std::string& language_code = lang_it->first;
    207       const Rule& rule = ruleset->GetLanguageCodeRule(language_code);
    208 
    209       AddressFieldTries* address_field_tries = lang_it->second;
    210       assert(address_field_tries != NULL);
    211 
    212       AddressFieldTries::const_iterator address_field_it =
    213           address_field_tries->find(ruleset->field());
    214       assert(address_field_it != address_field_tries->end());
    215 
    216       IdentityFieldTries* identity_field_tries = address_field_it->second;
    217       assert(identity_field_tries != NULL);
    218 
    219       IdentityFieldTries::const_iterator identity_field_it =
    220           identity_field_tries->find(Rule::KEY);
    221       assert(identity_field_it != identity_field_tries->end());
    222 
    223       Trie<const Ruleset*>* key_trie = identity_field_it->second;
    224       assert(key_trie != NULL);
    225 
    226       identity_field_it = identity_field_tries->find(Rule::NAME);
    227       assert(identity_field_it != identity_field_tries->end());
    228 
    229       Trie<const Ruleset*>* name_trie = identity_field_it->second;
    230       assert(name_trie != NULL);
    231 
    232       identity_field_it = identity_field_tries->find(Rule::LATIN_NAME);
    233       assert(identity_field_it != identity_field_tries->end());
    234 
    235       Trie<const Ruleset*>* latin_name_trie = identity_field_it->second;
    236       assert(latin_name_trie != NULL);
    237 
    238       if (!rule.GetKey().empty()) {
    239         key_trie->AddDataForKey(
    240             canonicalizer_->CanonicalizeString(rule.GetKey()), ruleset);
    241       }
    242 
    243       if (!rule.GetName().empty()) {
    244         name_trie->AddDataForKey(
    245              canonicalizer_->CanonicalizeString(rule.GetName()), ruleset);
    246       }
    247 
    248       if (!rule.GetLatinName().empty()) {
    249         latin_name_trie->AddDataForKey(
    250             canonicalizer_->CanonicalizeString(rule.GetLatinName()), ruleset);
    251       }
    252     }
    253 
    254     AddSubRegionRulesetsToTrie(*ruleset);
    255   }
    256 }
    257 
    258 }  // namespace addressinput
    259 }  // namespace i18n
    260