Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(605)

Side by Side Diff: chrome/browser/autofill/phone_number_i18n.cc

Issue 7044102: Another performance improvement for phone library - at least +25% to previous cl (982ms for 100 i... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/autofill/phone_number_i18n.h" 5 #include "chrome/browser/autofill/phone_number_i18n.h"
6 6
7 #include <map>
8
7 #include "base/basictypes.h" 9 #include "base/basictypes.h"
8 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/singleton.h"
9 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
10 #include "base/string_number_conversions.h" 13 #include "base/string_number_conversions.h"
11 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/autofill/autofill_country.h" 15 #include "chrome/browser/autofill/autofill_country.h"
13 #include "third_party/libphonenumber/cpp/src/phonenumberutil.h" 16 #include "third_party/libphonenumber/cpp/src/phonenumberutil.h"
14 17
15 namespace { 18 namespace {
16 19
17 std::string SanitizeLocaleCode(const std::string& locale_code) { 20 std::string SanitizeLocaleCode(const std::string& locale_code) {
18 if (locale_code.length() == 2) 21 if (locale_code.length() == 2)
(...skipping 12 matching lines...) Expand all
31 case autofill_i18n::NATIONAL: 34 case autofill_i18n::NATIONAL:
32 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL; 35 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
33 case autofill_i18n::RFC3966: 36 case autofill_i18n::RFC3966:
34 return i18n::phonenumbers::PhoneNumberUtil::RFC3966; 37 return i18n::phonenumbers::PhoneNumberUtil::RFC3966;
35 default: 38 default:
36 NOTREACHED(); 39 NOTREACHED();
37 } 40 }
38 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL; 41 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
39 } 42 }
40 43
41 } // namespace 44 bool ParsePhoneNumberInternal(const string16& value,
42 45 const std::string& locale,
43 namespace autofill_i18n { 46 string16* country_code,
44 47 string16* city_code,
45 string16 NormalizePhoneNumber(const string16& value, 48 string16* number,
46 std::string const& locale) { 49 i18n::phonenumbers::PhoneNumber* i18n_number) {
47 string16 number;
48 string16 city_code;
49 string16 country_code;
50 string16 result;
51 // Full number - parse it, split it and re-combine into canonical form.
52 if (!ParsePhoneNumber(value, locale, &country_code, &city_code, &number))
53 return string16(); // Parsing failed - do not store phone.
54 if (!autofill_i18n::ConstructPhoneNumber(
55 country_code, city_code, number,
56 locale,
57 (country_code.empty() ?
58 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
59 &result)) {
60 // Reconstruction failed - do not store phone.
61 return string16();
62 }
63 std::string result_utf8(UTF16ToUTF8(result));
64 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&result_utf8);
65 return UTF8ToUTF16(result_utf8);
66 }
67
68 bool ParsePhoneNumber(const string16& value,
69 const std::string& locale,
70 string16* country_code,
71 string16* city_code,
72 string16* number) {
73 DCHECK(number); 50 DCHECK(number);
74 DCHECK(city_code); 51 DCHECK(city_code);
75 DCHECK(country_code); 52 DCHECK(country_code);
53 DCHECK(i18n_number);
76 54
77 number->clear(); 55 number->clear();
78 city_code->clear(); 56 city_code->clear();
79 country_code->clear(); 57 country_code->clear();
80 58
81 std::string number_text(UTF16ToUTF8(value)); 59 std::string number_text(UTF16ToUTF8(value));
82 60
83 // Parse phone number based on the locale. 61 // Parse phone number based on the locale.
84 i18n::phonenumbers::PhoneNumber i18n_number;
85 i18n::phonenumbers::PhoneNumberUtil* phone_util = 62 i18n::phonenumbers::PhoneNumberUtil* phone_util =
86 i18n::phonenumbers::PhoneNumberUtil::GetInstance(); 63 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
87 DCHECK(phone_util); 64 DCHECK(phone_util);
88 65
89 if (phone_util->Parse(number_text, SanitizeLocaleCode(locale).c_str(), 66 if (phone_util->Parse(number_text, SanitizeLocaleCode(locale).c_str(),
90 &i18n_number) != 67 i18n_number) !=
91 i18n::phonenumbers::PhoneNumberUtil::NO_PARSING_ERROR) { 68 i18n::phonenumbers::PhoneNumberUtil::NO_PARSING_ERROR) {
92 return false; 69 return false;
93 } 70 }
94 71
95 i18n::phonenumbers::PhoneNumberUtil::ValidationResult validation = 72 i18n::phonenumbers::PhoneNumberUtil::ValidationResult validation =
96 phone_util->IsPossibleNumberWithReason(i18n_number); 73 phone_util->IsPossibleNumberWithReason(*i18n_number);
97 if (validation != i18n::phonenumbers::PhoneNumberUtil::IS_POSSIBLE) 74 if (validation != i18n::phonenumbers::PhoneNumberUtil::IS_POSSIBLE)
98 return false; 75 return false;
99 76
100 // This verifies that number has a valid area code (that in some cases could 77 // This verifies that number has a valid area code (that in some cases could
101 // be empty) for parsed country code. Also verifies that this is a valid 78 // be empty) for parsed country code. Also verifies that this is a valid
102 // number (in US 1234567 is not valid, because numbers do not start with 1). 79 // number (in US 1234567 is not valid, because numbers do not start with 1).
103 if (!phone_util->IsValidNumber(i18n_number)) 80 if (!phone_util->IsValidNumber(*i18n_number))
104 return false; 81 return false;
105 82
106 std::string national_significant_number; 83 std::string national_significant_number;
107 phone_util->GetNationalSignificantNumber(i18n_number, 84 phone_util->GetNationalSignificantNumber(*i18n_number,
108 &national_significant_number); 85 &national_significant_number);
109 86
110 std::string area_code; 87 std::string area_code;
111 std::string subscriber_number; 88 std::string subscriber_number;
112 89
113 int area_length = phone_util->GetLengthOfGeographicalAreaCode(i18n_number); 90 int area_length = phone_util->GetLengthOfGeographicalAreaCode(*i18n_number);
114 int destination_length = 91 int destination_length =
115 phone_util->GetLengthOfNationalDestinationCode(i18n_number); 92 phone_util->GetLengthOfNationalDestinationCode(*i18n_number);
116 // Some phones have a destination code in lieu of area code: mobile operators 93 // Some phones have a destination code in lieu of area code: mobile operators
117 // in Europe, toll and toll-free numbers in USA, etc. From our point of view 94 // in Europe, toll and toll-free numbers in USA, etc. From our point of view
118 // these two types of codes are the same. 95 // these two types of codes are the same.
119 if (destination_length > area_length) 96 if (destination_length > area_length)
120 area_length = destination_length; 97 area_length = destination_length;
121 if (area_length > 0) { 98 if (area_length > 0) {
122 area_code = national_significant_number.substr(0, area_length); 99 area_code = national_significant_number.substr(0, area_length);
123 subscriber_number = national_significant_number.substr(area_length); 100 subscriber_number = national_significant_number.substr(area_length);
124 } else { 101 } else {
125 subscriber_number = national_significant_number; 102 subscriber_number = national_significant_number;
126 } 103 }
127 *number = UTF8ToUTF16(subscriber_number); 104 *number = UTF8ToUTF16(subscriber_number);
128 *city_code = UTF8ToUTF16(area_code); 105 *city_code = UTF8ToUTF16(area_code);
129 *country_code = string16(); 106 *country_code = string16();
130 107
131 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&number_text); 108 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&number_text);
132 string16 normalized_number(UTF8ToUTF16(number_text)); 109 string16 normalized_number(UTF8ToUTF16(number_text));
133 // Check if parsed number has country code and it was not inferred from the 110 // Check if parsed number has country code and it was not inferred from the
134 // locale. 111 // locale.
135 if (i18n_number.has_country_code()) { 112 if (i18n_number->has_country_code()) {
136 *country_code = UTF8ToUTF16(base::StringPrintf("%d", 113 *country_code = UTF8ToUTF16(
137 i18n_number.country_code())); 114 base::StringPrintf("%d", i18n_number->country_code()));
138 if (normalized_number.length() <= national_significant_number.length() && 115 if (normalized_number.length() <= national_significant_number.length() &&
139 (normalized_number.length() < country_code->length() || 116 (normalized_number.length() < country_code->length() ||
140 normalized_number.compare(0, country_code->length(), *country_code))) { 117 normalized_number.compare(0, country_code->length(), *country_code))) {
141 country_code->clear(); 118 country_code->clear();
142 } 119 }
143 } 120 }
144 121
145 return true; 122 return true;
146 } 123 }
147 124
125 class PhoneCache {
126 public:
127 static PhoneCache* GetInstance();
128
129 // Fills cached number and returns true if found, returns false otherwise.
130 bool GetFromCache(const string16& key, autofill_i18n::PhoneObject* out);
131 void CachePhone(const string16& key, const autofill_i18n::PhoneObject& n);
Ilya Sherman 2011/06/18 00:47:14 Why not combine these two methods together, so tha
GeorgeY 2011/06/20 22:59:11 Specifically, I did it so cache will be completely
132
133 private:
134 std::map<string16, autofill_i18n::PhoneObject> cached_numbers_;
135 static const size_t kMaxCacheSize;
136 };
137
138 const size_t PhoneCache::kMaxCacheSize = 1024;
139
140 PhoneCache* PhoneCache::GetInstance() {
141 return Singleton<PhoneCache>::get();
142 }
143
144 bool PhoneCache::GetFromCache(const string16& key,
145 autofill_i18n::PhoneObject* out) {
146 DCHECK(out);
147 std::map<string16, autofill_i18n::PhoneObject>::iterator it =
148 cached_numbers_.find(key);
149 if (it != cached_numbers_.end())
150 *out = it->second;
151 return (it != cached_numbers_.end());
152 }
153
154 void PhoneCache::CachePhone(const string16& key,
155 const autofill_i18n::PhoneObject& n) {
156 // Remove last elements from cache to prevent unlimited grow.
157 if (cached_numbers_.size() > kMaxCacheSize) {
158 std::map<string16, autofill_i18n::PhoneObject>::iterator it =
159 cached_numbers_.end();
160 // Phone works as a hash value here, so the last removed could've been added
161 // at any time.
162 --it;
163 cached_numbers_.erase(it);
164 }
165 cached_numbers_[key] = n;
166 }
167
168 } // namespace
169
170 namespace autofill_i18n {
171
172 string16 NormalizePhoneNumber(const string16& value,
173 std::string const& locale) {
174 string16 number;
175 string16 city_code;
176 string16 country_code;
177 string16 result;
178 // Full number - parse it, split it and re-combine into canonical form.
179 if (!ParsePhoneNumber(value, locale, &country_code, &city_code, &number))
180 return string16(); // Parsing failed - do not store phone.
181 if (!autofill_i18n::ConstructPhoneNumber(
182 country_code, city_code, number,
183 locale,
184 (country_code.empty() ?
185 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
186 &result)) {
187 // Reconstruction failed - do not store phone.
188 return string16();
189 }
190 std::string result_utf8(UTF16ToUTF8(result));
191 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&result_utf8);
192 return UTF8ToUTF16(result_utf8);
193 }
194
195 bool ParsePhoneNumber(const string16& value,
196 const std::string& locale,
197 string16* country_code,
198 string16* city_code,
199 string16* number) {
200 i18n::phonenumbers::PhoneNumber i18n_number;
201 return ParsePhoneNumberInternal(value, locale, country_code, city_code,
202 number, &i18n_number);
203 }
204
148 bool ConstructPhoneNumber(const string16& country_code, 205 bool ConstructPhoneNumber(const string16& country_code,
149 const string16& city_code, 206 const string16& city_code,
150 const string16& number, 207 const string16& number,
151 const std::string& locale, 208 const std::string& locale,
152 FullPhoneFormat phone_format, 209 FullPhoneFormat phone_format,
153 string16* whole_number) { 210 string16* whole_number) {
154 DCHECK(whole_number); 211 DCHECK(whole_number);
155 212
156 whole_number->clear(); 213 whole_number->clear();
157 214
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 } 315 }
259 return PHONES_NOT_EQUAL; 316 return PHONES_NOT_EQUAL;
260 } 317 }
261 318
262 bool PhoneNumbersMatch(const string16& number_a, 319 bool PhoneNumbersMatch(const string16& number_a,
263 const string16& number_b, 320 const string16& number_b,
264 const std::string& country_code) { 321 const std::string& country_code) {
265 return ComparePhones(number_a, number_b, country_code) == PHONES_EQUAL; 322 return ComparePhones(number_a, number_b, country_code) == PHONES_EQUAL;
266 } 323 }
267 324
325 PhoneObject::PhoneObject(const string16& number, const std::string& locale)
326 : locale_(SanitizeLocaleCode(locale)),
327 i18n_number_(NULL) {
328 scoped_ptr<i18n::phonenumbers::PhoneNumber>
329 i18n_number(new i18n::phonenumbers::PhoneNumber);
330 if (ParsePhoneNumberInternal(number, locale_, &country_code_, &city_code_,
331 &number_, i18n_number.get())) {
332 // Phone successfully parsed - set |i18n_number_| object, |whole_number_|
333 // will be set on the first call to GetWholeNumber().
334 i18n_number_.reset(i18n_number.release());
335 } else {
336 // Parsing failed. Store passed phone "as is" into |whole_number_|.
337 whole_number_ = number;
338 }
339 }
340
341 PhoneObject::PhoneObject(const PhoneObject& other)
342 : i18n_number_(NULL) {
343 *this = other;
344 }
345
346 PhoneObject::PhoneObject()
347 : i18n_number_(NULL) {
348 }
349
350 PhoneObject::~PhoneObject() {
351 }
352
353 string16 PhoneObject::GetCountryCode() const {
354 return country_code_;
355 }
356
357 string16 PhoneObject::GetCityCode() const {
358 return city_code_;
359 }
360
361 string16 PhoneObject::GetNumber() const {
362 return number_;
363 }
364
365 string16 PhoneObject::GetWholeNumber() const {
366 if (i18n_number_.get() && whole_number_.empty()) {
367 i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat format =
368 i18n::phonenumbers::PhoneNumberUtil::INTERNATIONAL;
369 if (country_code_.empty())
370 format = i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
371
372 std::string formatted_number;
373 i18n::phonenumbers::PhoneNumberUtil* phone_util =
374 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
375 phone_util->Format(*i18n_number_, format, &formatted_number);
376 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&formatted_number);
377 whole_number_ = UTF8ToUTF16(formatted_number);
378 }
379 return whole_number_;
380 }
381
382 PhoneMatch PhoneObject::ComparePhones(const string16& phone) const {
383 string16 key(ASCIIToUTF16(locale_));
384 key.append(phone);
385 PhoneObject second;
386 if (!PhoneCache::GetInstance()->GetFromCache(key, &second)) {
387 second = PhoneObject(phone, locale_);
388 PhoneCache::GetInstance()->CachePhone(key, second);
389 }
390 return ComparePhones(second);
391 }
392
393 PhoneMatch PhoneObject::ComparePhones(const PhoneObject& phone) const {
394 if (!i18n_number_.get() || !phone.i18n_number_.get()) {
395 if (GetWholeNumber().empty())
396 return PHONES_NOT_EQUAL;
397 return (GetWholeNumber() == phone.GetWholeNumber()) ? PHONES_EQUAL :
398 PHONES_NOT_EQUAL;
399 }
400
401 i18n::phonenumbers::PhoneNumberUtil* phone_util =
402 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
403 switch (phone_util->IsNumberMatch(*i18n_number_, *(phone.i18n_number_))) {
404 case i18n::phonenumbers::PhoneNumberUtil::INVALID_NUMBER:
405 case i18n::phonenumbers::PhoneNumberUtil::NO_MATCH:
406 return PHONES_NOT_EQUAL;
407 case i18n::phonenumbers::PhoneNumberUtil::SHORT_NSN_MATCH:
408 return PHONES_SUBMATCH;
409 case i18n::phonenumbers::PhoneNumberUtil::NSN_MATCH:
410 case i18n::phonenumbers::PhoneNumberUtil::EXACT_MATCH:
411 return PHONES_EQUAL;
412 default:
413 NOTREACHED();
414 }
415 return PHONES_NOT_EQUAL;
416 }
417
418 PhoneObject& PhoneObject::operator=(const PhoneObject& other) {
419 if (this == &other)
420 return *this;
421 country_code_ = other.country_code_;
422 city_code_ = other.city_code_;
423 number_ = other.number_;
424 locale_ = other.locale_;
425 if (other.i18n_number_.get()) {
426 i18n_number_.reset(new i18n::phonenumbers::PhoneNumber(
427 *other.i18n_number_));
428 }
429 return *this;
430 }
431
268 } // namespace autofill_i18n 432 } // namespace autofill_i18n
269 433
OLDNEW
« no previous file with comments | « chrome/browser/autofill/phone_number_i18n.h ('k') | third_party/libphonenumber/cpp/src/base/singleton.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698