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

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"
9 #include "base/stringprintf.h" 11 #include "base/stringprintf.h"
10 #include "base/string_number_conversions.h" 12 #include "base/string_number_conversions.h"
11 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/autofill/autofill_country.h" 14 #include "chrome/browser/autofill/autofill_country.h"
13 #include "third_party/libphonenumber/cpp/src/phonenumberutil.h" 15 #include "third_party/libphonenumber/cpp/src/phonenumberutil.h"
14 16
15 namespace { 17 namespace {
16 18
(...skipping 14 matching lines...) Expand all
31 case autofill_i18n::NATIONAL: 33 case autofill_i18n::NATIONAL:
32 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL; 34 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
33 case autofill_i18n::RFC3966: 35 case autofill_i18n::RFC3966:
34 return i18n::phonenumbers::PhoneNumberUtil::RFC3966; 36 return i18n::phonenumbers::PhoneNumberUtil::RFC3966;
35 default: 37 default:
36 NOTREACHED(); 38 NOTREACHED();
37 } 39 }
38 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL; 40 return i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
39 } 41 }
40 42
41 } // namespace 43 bool ParsePhoneNumberInternal(const string16& value,
42 44 const std::string& locale,
43 namespace autofill_i18n { 45 string16* country_code,
44 46 string16* city_code,
45 string16 NormalizePhoneNumber(const string16& value, 47 string16* number,
46 std::string const& locale) { 48 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); 49 DCHECK(number);
74 DCHECK(city_code); 50 DCHECK(city_code);
75 DCHECK(country_code); 51 DCHECK(country_code);
52 DCHECK(i18n_number);
76 53
77 number->clear(); 54 number->clear();
78 city_code->clear(); 55 city_code->clear();
79 country_code->clear(); 56 country_code->clear();
80 57
81 std::string number_text(UTF16ToUTF8(value)); 58 std::string number_text(UTF16ToUTF8(value));
82 59
83 // Parse phone number based on the locale. 60 // Parse phone number based on the locale.
84 i18n::phonenumbers::PhoneNumber i18n_number;
85 i18n::phonenumbers::PhoneNumberUtil* phone_util = 61 i18n::phonenumbers::PhoneNumberUtil* phone_util =
86 i18n::phonenumbers::PhoneNumberUtil::GetInstance(); 62 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
87 DCHECK(phone_util); 63 DCHECK(phone_util);
88 64
89 if (phone_util->Parse(number_text, SanitizeLocaleCode(locale).c_str(), 65 if (phone_util->Parse(number_text, SanitizeLocaleCode(locale).c_str(),
90 &i18n_number) != 66 i18n_number) !=
91 i18n::phonenumbers::PhoneNumberUtil::NO_PARSING_ERROR) { 67 i18n::phonenumbers::PhoneNumberUtil::NO_PARSING_ERROR) {
92 return false; 68 return false;
93 } 69 }
94 70
95 i18n::phonenumbers::PhoneNumberUtil::ValidationResult validation = 71 i18n::phonenumbers::PhoneNumberUtil::ValidationResult validation =
96 phone_util->IsPossibleNumberWithReason(i18n_number); 72 phone_util->IsPossibleNumberWithReason(*i18n_number);
97 if (validation != i18n::phonenumbers::PhoneNumberUtil::IS_POSSIBLE) 73 if (validation != i18n::phonenumbers::PhoneNumberUtil::IS_POSSIBLE)
98 return false; 74 return false;
99 75
100 // This verifies that number has a valid area code (that in some cases could 76 // 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 77 // 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). 78 // number (in US 1234567 is not valid, because numbers do not start with 1).
103 if (!phone_util->IsValidNumber(i18n_number)) 79 if (!phone_util->IsValidNumber(*i18n_number))
104 return false; 80 return false;
105 81
106 std::string national_significant_number; 82 std::string national_significant_number;
107 phone_util->GetNationalSignificantNumber(i18n_number, 83 phone_util->GetNationalSignificantNumber(*i18n_number,
108 &national_significant_number); 84 &national_significant_number);
109 85
110 std::string area_code; 86 std::string area_code;
111 std::string subscriber_number; 87 std::string subscriber_number;
112 88
113 int area_length = phone_util->GetLengthOfGeographicalAreaCode(i18n_number); 89 int area_length = phone_util->GetLengthOfGeographicalAreaCode(*i18n_number);
114 int destination_length = 90 int destination_length =
115 phone_util->GetLengthOfNationalDestinationCode(i18n_number); 91 phone_util->GetLengthOfNationalDestinationCode(*i18n_number);
116 // Some phones have a destination code in lieu of area code: mobile operators 92 // 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 93 // in Europe, toll and toll-free numbers in USA, etc. From our point of view
118 // these two types of codes are the same. 94 // these two types of codes are the same.
119 if (destination_length > area_length) 95 if (destination_length > area_length)
120 area_length = destination_length; 96 area_length = destination_length;
121 if (area_length > 0) { 97 if (area_length > 0) {
122 area_code = national_significant_number.substr(0, area_length); 98 area_code = national_significant_number.substr(0, area_length);
123 subscriber_number = national_significant_number.substr(area_length); 99 subscriber_number = national_significant_number.substr(area_length);
124 } else { 100 } else {
125 subscriber_number = national_significant_number; 101 subscriber_number = national_significant_number;
126 } 102 }
127 *number = UTF8ToUTF16(subscriber_number); 103 *number = UTF8ToUTF16(subscriber_number);
128 *city_code = UTF8ToUTF16(area_code); 104 *city_code = UTF8ToUTF16(area_code);
129 *country_code = string16(); 105 *country_code = string16();
130 106
131 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&number_text); 107 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&number_text);
132 string16 normalized_number(UTF8ToUTF16(number_text)); 108 string16 normalized_number(UTF8ToUTF16(number_text));
133 // Check if parsed number has country code and it was not inferred from the 109 // Check if parsed number has country code and it was not inferred from the
134 // locale. 110 // locale.
135 if (i18n_number.has_country_code()) { 111 if (i18n_number->has_country_code()) {
136 *country_code = UTF8ToUTF16(base::StringPrintf("%d", 112 *country_code = UTF8ToUTF16(
137 i18n_number.country_code())); 113 base::StringPrintf("%d", i18n_number->country_code()));
138 if (normalized_number.length() <= national_significant_number.length() && 114 if (normalized_number.length() <= national_significant_number.length() &&
139 (normalized_number.length() < country_code->length() || 115 (normalized_number.length() < country_code->length() ||
140 normalized_number.compare(0, country_code->length(), *country_code))) { 116 normalized_number.compare(0, country_code->length(), *country_code))) {
141 country_code->clear(); 117 country_code->clear();
142 } 118 }
143 } 119 }
144 120
145 return true; 121 return true;
146 } 122 }
147 123
124 } // namespace
125
126 namespace autofill_i18n {
127
128 string16 NormalizePhoneNumber(const string16& value,
129 std::string const& locale) {
130 string16 number;
131 string16 city_code;
132 string16 country_code;
133 string16 result;
134 // Full number - parse it, split it and re-combine into canonical form.
135 if (!ParsePhoneNumber(value, locale, &country_code, &city_code, &number))
136 return string16(); // Parsing failed - do not store phone.
137 if (!autofill_i18n::ConstructPhoneNumber(
138 country_code, city_code, number,
139 locale,
140 (country_code.empty() ?
141 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
142 &result)) {
143 // Reconstruction failed - do not store phone.
144 return string16();
145 }
146 std::string result_utf8(UTF16ToUTF8(result));
147 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&result_utf8);
148 return UTF8ToUTF16(result_utf8);
149 }
150
151 bool ParsePhoneNumber(const string16& value,
152 const std::string& locale,
153 string16* country_code,
154 string16* city_code,
155 string16* number) {
156 i18n::phonenumbers::PhoneNumber i18n_number;
157 return ParsePhoneNumberInternal(value, locale, country_code, city_code,
158 number, &i18n_number);
159 }
160
148 bool ConstructPhoneNumber(const string16& country_code, 161 bool ConstructPhoneNumber(const string16& country_code,
149 const string16& city_code, 162 const string16& city_code,
150 const string16& number, 163 const string16& number,
151 const std::string& locale, 164 const std::string& locale,
152 FullPhoneFormat phone_format, 165 FullPhoneFormat phone_format,
153 string16* whole_number) { 166 string16* whole_number) {
154 DCHECK(whole_number); 167 DCHECK(whole_number);
155 168
156 whole_number->clear(); 169 whole_number->clear();
157 170
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 } 271 }
259 return PHONES_NOT_EQUAL; 272 return PHONES_NOT_EQUAL;
260 } 273 }
261 274
262 bool PhoneNumbersMatch(const string16& number_a, 275 bool PhoneNumbersMatch(const string16& number_a,
263 const string16& number_b, 276 const string16& number_b,
264 const std::string& country_code) { 277 const std::string& country_code) {
265 return ComparePhones(number_a, number_b, country_code) == PHONES_EQUAL; 278 return ComparePhones(number_a, number_b, country_code) == PHONES_EQUAL;
266 } 279 }
267 280
281 PhoneObject::PhoneObject(const string16& number, const std::string& locale)
282 : locale_(SanitizeLocaleCode(locale)),
283 i18n_number_(NULL) {
284 scoped_ptr<i18n::phonenumbers::PhoneNumber>
285 i18n_number(new i18n::phonenumbers::PhoneNumber);
286 if (ParsePhoneNumberInternal(number, locale_, &country_code_, &city_code_,
287 &number_, i18n_number.get())) {
288 i18n_number_ = i18n_number.release();
289 } else {
290 whole_number_ = number;
291 }
Ilya Sherman 2011/06/10 07:17:33 nit: The else stmt here makes the code a little bi
GeorgeY 2011/06/10 22:36:35 Commented. To move logic into GetWholeNumber() I w
292 }
293
294 PhoneObject::PhoneObject(const PhoneObject& other)
295 : i18n_number_(NULL) {
296 *this = other;
297 }
298
299 PhoneObject::PhoneObject()
300 : i18n_number_(NULL) {
301 }
302
303 PhoneObject::~PhoneObject() {
304 Clear();
305 }
306
307 string16 PhoneObject::GetCountryCode() const {
308 return country_code_;
309 }
310
311 string16 PhoneObject::GetCityCode() const {
312 return city_code_;
313 }
314
315 string16 PhoneObject::GetNumber() const {
316 return number_;
317 }
318
319 string16 PhoneObject::GetWholeNumber() const {
320 if (i18n_number_ && whole_number_.empty()) {
321 i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat format =
322 i18n::phonenumbers::PhoneNumberUtil::INTERNATIONAL;
323 if (country_code_.empty())
324 format = i18n::phonenumbers::PhoneNumberUtil::NATIONAL;
325
326 std::string formatted_number;
327 i18n::phonenumbers::PhoneNumberUtil* phone_util =
328 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
329 phone_util->Format(*i18n_number_, format, &formatted_number);
330 i18n::phonenumbers::PhoneNumberUtil::NormalizeDigitsOnly(&formatted_number);
331 whole_number_ = UTF8ToUTF16(formatted_number);
332 }
333 return whole_number_;
334 }
335
336 PhoneMatch PhoneObject::ComparePhones(const string16& phone) const {
337 const size_t kMaxCacheSize = 1024;
338 static std::map<string16, PhoneObject> cached_objects;
339 // Remove last element from cache to prevent unlimited grow.
340 if (cached_objects.size() > kMaxCacheSize) {
341 std::map<string16, PhoneObject>::iterator it = cached_objects.end();
342 --it;
343 cached_objects.erase(it);
344 }
345 string16 key(ASCIIToUTF16(locale_));
346 key.append(phone);
347 std::map<string16, PhoneObject>::const_iterator it = cached_objects.find(key);
348 if (it == cached_objects.end()) {
349 // Add it to the cache.
350 it = cached_objects.insert(
351 std::pair<string16, PhoneObject>(key,
352 PhoneObject(phone, locale_))).first;
353 DCHECK(it != cached_objects.end());
354 }
355 return ComparePhones(it->second);
356 }
357
358 PhoneMatch PhoneObject::ComparePhones(const PhoneObject& phone) const {
359 if (!i18n_number_ || !phone.i18n_number_) {
360 if (GetWholeNumber().empty())
361 return PHONES_NOT_EQUAL;
362 return (GetWholeNumber() == phone.GetWholeNumber()) ? PHONES_EQUAL :
363 PHONES_NOT_EQUAL;
364 }
365
366 i18n::phonenumbers::PhoneNumberUtil* phone_util =
367 i18n::phonenumbers::PhoneNumberUtil::GetInstance();
368 switch (phone_util->IsNumberMatch(*i18n_number_, *(phone.i18n_number_))) {
369 case i18n::phonenumbers::PhoneNumberUtil::INVALID_NUMBER:
370 case i18n::phonenumbers::PhoneNumberUtil::NO_MATCH:
371 return PHONES_NOT_EQUAL;
372 case i18n::phonenumbers::PhoneNumberUtil::SHORT_NSN_MATCH:
373 return PHONES_SUBMATCH;
374 case i18n::phonenumbers::PhoneNumberUtil::NSN_MATCH:
375 case i18n::phonenumbers::PhoneNumberUtil::EXACT_MATCH:
376 return PHONES_EQUAL;
377 default:
378 NOTREACHED();
379 }
380 return PHONES_NOT_EQUAL;
381 }
382
383 PhoneObject& PhoneObject::operator=(const PhoneObject& other) {
Ilya Sherman 2011/06/10 07:17:33 This is not currently a no-op when this == &other,
GeorgeY 2011/06/10 22:36:35 Sure, but most compilers are smart enough to auto
384 country_code_ = other.country_code_;
385 city_code_ = other.city_code_;
386 number_ = other.number_;
387 locale_ = other.locale_;
388 Clear();
389 if (other.i18n_number_)
390 i18n_number_ = new i18n::phonenumbers::PhoneNumber(*other.i18n_number_);
391 return *this;
392 }
393
394 void PhoneObject::Clear() {
395 if (i18n_number_)
396 delete i18n_number_;
Ilya Sherman 2011/06/10 07:17:33 How about making i18n_number_ be a scoped_ptr<> in
GeorgeY 2011/06/10 22:36:35 As I explained in the first review, there are some
397 i18n_number_ = NULL;
398 }
399
268 } // namespace autofill_i18n 400 } // namespace autofill_i18n
269 401
OLDNEW
« chrome/browser/autofill/phone_number_i18n.h ('K') | « chrome/browser/autofill/phone_number_i18n.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698