• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Ruleset(AddressField field,scoped_ptr<Rule> rule)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 
~Ruleset()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 
AddSubRegionRuleset(const std::string & sub_region,scoped_ptr<Ruleset> ruleset)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 
AddLanguageCodeRule(const std::string & language_code,scoped_ptr<Rule> rule)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 
GetSubRegionRuleset(const std::string & sub_region) const97 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 
GetLanguageCodeRule(const std::string & language_code) const103 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 
BuildPrefixSearchIndex()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 
FindRulesetsByPrefix(const std::string & language_code,AddressField ruleset_level,Rule::IdentityField identity_field,const std::string & prefix,std::set<const Ruleset * > * result) const155 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 
AddSubRegionRulesetsToTrie(const Ruleset & parent_ruleset)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