• 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 #ifndef I18N_ADDRESSINPUT_RULESET_H_
16 #define I18N_ADDRESSINPUT_RULESET_H_
17 
18 #include <libaddressinput/address_field.h>
19 #include <libaddressinput/util/basictypes.h>
20 #include <libaddressinput/util/scoped_ptr.h>
21 
22 #include <map>
23 #include <set>
24 #include <string>
25 
26 #include "rule.h"
27 #include "util/canonicalize_string.h"
28 #include "util/trie.h"
29 
30 namespace i18n {
31 namespace addressinput {
32 
33 // A recursive data structure that stores a set of rules for a region. Can store
34 // the rules for a country, its administrative areas, localities, and dependent
35 // localities, in addition to the language-specific rules.
36 //
37 // Example for Canada and some of its provinces:
38 //                   CA-->fr
39 //                   |
40 // -------------------------------------
41 // |        |        |        |        |
42 // v        v        v        v        v
43 // AB-->fr  BC-->fr  MB-->fr  NB-->fr  NL-->fr
44 //
45 // The rules in Canada are in English by default. Each rule also has a French
46 // language version.
47 class Ruleset {
48  public:
49   // Builds a ruleset for |field| with a region-wide |rule| in the default
50   // language of the country. The |field| should be between COUNTRY and
51   // DEPENDENT_LOCALITY (inclusively). The |rule| should not be NULL.
52   Ruleset(AddressField field, scoped_ptr<Rule> rule);
53 
54   ~Ruleset();
55 
56   // Returns the parent ruleset. This is NULL until this ruleset has been passed
57   // into a AddSubRegionRuleset() method. Consequently, this is always NULL for
58   // a country-level ruleset.
parent()59   Ruleset* parent() const { return parent_; }
60 
61   // Returns the field type for this ruleset.
field()62   AddressField field() const { return field_; }
63 
64   // Returns the region-wide rule for this ruleset in the default language of
65   // the country.
rule()66   const Rule& rule() const { return *rule_; }
67 
68   // Adds the |ruleset| for |sub_region| and sets this to be its parent. A
69   // |sub_region| should be added at most once. The |ruleset| should not be
70   // NULL.
71   //
72   // The field of the |ruleset| parameter must be exactly one smaller than the
73   // field of this ruleset. For example, a COUNTRY ruleset can contain
74   // ADMIN_AREA rulesets, but should not contain COUNTRY or LOCALITY rulesets.
75   void AddSubRegionRuleset(const std::string& sub_region,
76                            scoped_ptr<Ruleset> ruleset);
77 
78   // Adds a language-specific |rule| for |language_code| for this region. A
79   // |language_code| should be added at most once. The |rule| should not be
80   // NULL.
81   void AddLanguageCodeRule(const std::string& language_code,
82                            scoped_ptr<Rule> rule);
83 
84   // Returns the set of rules for |sub_region|. The result is NULL if there's no
85   // such |sub_region|. The caller does not own the result.
86   Ruleset* GetSubRegionRuleset(const std::string& sub_region) const;
87 
88   // If there's a language-specific rule for |language_code|, then returns this
89   // rule. Otherwise returns the rule in the default language of the country.
90   const Rule& GetLanguageCodeRule(const std::string& language_code) const;
91 
92   // Returns a mapping of sub-region keys to rulesets. The caller does now own
93   // the result. The values are not NULL.
GetSubRegionRulesets()94   const std::map<std::string, Ruleset*>& GetSubRegionRulesets() const {
95     return sub_regions_;
96   }
97 
98   // Enables using FindRulesetsByPrefix() method. Should be called only once and
99   // on a COUNTRY level ruleset.
100   void BuildPrefixSearchIndex();
101 
102   // Returns true if BuildPrefixSearchIndex() has been called.
prefix_search_index_ready()103   bool prefix_search_index_ready() const { return !tries_.empty(); }
104 
105   // Returns the deepest possible ruleset level for this country. Must be called
106   // on a COUNTRY level ruleset. Must be called after BuildPrefixSearchIndex()
107   // has been called.
deepest_ruleset_level()108   AddressField deepest_ruleset_level() const { return deepest_ruleset_level_; }
109 
110   // Finds all rulesets at |ruleset_level| where the rule for |language_code|
111   // has the |identity_field| that starts with |prefix|. Ignores diacritics and
112   // capitalization differences between the rule data and |prefix|.
113   //
114   // If there're no rules for |language_code| (or |language_code| is an empty
115   // string), then the default language code is used.
116   //
117   // Should be called only on a COUNTRY level ruleset. Should be called only
118   // after BuildPrefixSearchIndex() has been called.
119   //
120   // The |field| parameter should be only ADMIN_AREA, LOCALITY, or
121   // DEPENDENT_LOCALITY. The result parameter should not be NULL.
122   void FindRulesetsByPrefix(const std::string& language_code,
123                             AddressField ruleset_level,
124                             Rule::IdentityField identity_field,
125                             const std::string& prefix,
126                             std::set<const Ruleset*>* result) const;
127 
128  private:
129   // The type that maps rule identity field to tries of rulesets.
130   typedef std::map<Rule::IdentityField, Trie<const Ruleset*>*>
131       IdentityFieldTries;
132 
133   // The type that maps address field to IdentityFieldTries.
134   typedef std::map<AddressField, IdentityFieldTries*> AddressFieldTries;
135 
136   // The type that maps language code to AddressFieldTries.
137   typedef std::map<std::string, AddressFieldTries*> LanguageCodeTries;
138 
139   // Adds all children of |parent_ruleset| into |tries_| of this ruleset. Should
140   // be called only on a COUNTRY level ruleset.
141   void AddSubRegionRulesetsToTrie(const Ruleset& parent_ruleset);
142 
143   // The tries to lookup rulesets by a prefix of key, name, or latin-name in a
144   // rule. Has data only in a COUNTRY level ruleset. Owns the map and trie
145   // objects. Does not own the ruleset objects.
146   LanguageCodeTries tries_;
147 
148   // Canonicalizes region keys, names, and latin names when building a trie.
149   scoped_ptr<StringCanonicalizer> canonicalizer_;
150 
151   // The parent ruleset of this object. The parent ruleset owns this object.
152   Ruleset* parent_;
153 
154   // The field of this ruleset.
155   const AddressField field_;
156 
157   // The deepest possible ruleset level for this country. Set in
158   // BuildPrefixSearchIndex() method and, therefore, meaningful only on a
159   // COUNTRY level ruleset.
160   AddressField deepest_ruleset_level_;
161 
162   // The region-wide rule in the default language of the country.
163   const scoped_ptr<const Rule> rule_;
164 
165   // Owned rulesets for sub-regions.
166   std::map<std::string, Ruleset*> sub_regions_;
167 
168   // Owned language-specific rules for the region.
169   std::map<std::string, const Rule*> language_codes_;
170 
171   DISALLOW_COPY_AND_ASSIGN(Ruleset);
172 };
173 
174 }  // namespace addressinput
175 }  // namespace i18n
176 
177 #endif  // I18N_ADDRESSINPUT_RULESET_H_
178