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