| @ -0,0 +1,100 @@ | |||
| // Copyright (C) 2012 The Libphonenumber Authors | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| // | |||
| // Author: Patrick Mezard | |||
| #include "phonenumbers/geocoding/area_code_map.h" | |||
| #include <cstddef> | |||
| #include <iterator> | |||
| #include <set> | |||
| #include "phonenumbers/geocoding/area_code_map_storage_strategy.h" | |||
| #include "phonenumbers/geocoding/default_map_storage.h" | |||
| #include "phonenumbers/phonenumber.pb.h" | |||
| #include "phonenumbers/phonenumberutil.h" | |||
| #include "phonenumbers/stringutil.h" | |||
| namespace i18n { | |||
| namespace phonenumbers { | |||
| AreaCodeMap::AreaCodeMap() | |||
| : phone_util_(*PhoneNumberUtil::GetInstance()) { | |||
| } | |||
| AreaCodeMap::~AreaCodeMap() { | |||
| } | |||
| AreaCodeMapStorageStrategy* AreaCodeMap::CreateDefaultMapStorage() const { | |||
| return new DefaultMapStorage(); | |||
| } | |||
| void AreaCodeMap::ReadAreaCodeMap(const map<int, string>& area_codes) { | |||
| AreaCodeMapStorageStrategy* storage = CreateDefaultMapStorage(); | |||
| storage->ReadFromMap(area_codes); | |||
| storage_.reset(storage); | |||
| } | |||
| const string* AreaCodeMap::Lookup(const PhoneNumber& number) const { | |||
| const int entries = storage_->GetNumOfEntries(); | |||
| if (!entries) { | |||
| return NULL; | |||
| } | |||
| string national_number; | |||
| phone_util_.GetNationalSignificantNumber(number, &national_number); | |||
| int64 phone_prefix; | |||
| safe_strto64(SimpleItoa(number.country_code()) + national_number, | |||
| &phone_prefix); | |||
| const set<int>& lengths = storage_->GetPossibleLengths(); | |||
| int current_index = entries - 1; | |||
| for (set<int>::const_reverse_iterator lengths_it = lengths.rbegin(); | |||
| lengths_it != lengths.rend(); ++lengths_it) { | |||
| const int possible_length = *lengths_it; | |||
| string phone_prefix_str = SimpleItoa(phone_prefix); | |||
| if (static_cast<int>(phone_prefix_str.length()) > possible_length) { | |||
| safe_strto64(phone_prefix_str.substr(0, possible_length), &phone_prefix); | |||
| } | |||
| current_index = BinarySearch(0, current_index, phone_prefix); | |||
| if (current_index < 0) { | |||
| return NULL; | |||
| } | |||
| const int current_prefix = storage_->GetPrefix(current_index); | |||
| if (phone_prefix == current_prefix) { | |||
| return &storage_->GetDescription(current_index); | |||
| } | |||
| } | |||
| return NULL; | |||
| } | |||
| int AreaCodeMap::BinarySearch(int start, int end, int64 value) const { | |||
| int current = 0; | |||
| while (start <= end) { | |||
| current = (start + end) / 2; | |||
| int current_value = storage_->GetPrefix(current); | |||
| if (current_value == value) { | |||
| return current; | |||
| } else if (current_value > value) { | |||
| --current; | |||
| end = current; | |||
| } else { | |||
| start = current + 1; | |||
| } | |||
| } | |||
| return current; | |||
| } | |||
| } // namespace phonenumbers | |||
| } // namespace i18n | |||
| @ -0,0 +1,76 @@ | |||
| // Copyright (C) 2012 The Libphonenumber Authors | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| // | |||
| // Author: Patrick Mezard | |||
| #ifndef I18N_PHONENUMBERS_AREA_CODE_MAP_H_ | |||
| #define I18N_PHONENUMBERS_AREA_CODE_MAP_H_ | |||
| #include <map> | |||
| #include <string> | |||
| #include "base/basictypes.h" | |||
| #include "base/memory/scoped_ptr.h" | |||
| namespace i18n { | |||
| namespace phonenumbers { | |||
| using std::map; | |||
| using std::string; | |||
| class AreaCodeMapStorageStrategy; | |||
| class PhoneNumber; | |||
| class PhoneNumberUtil; | |||
| // A utility that maps phone number prefixes to a string describing the | |||
| // geographical area the prefix covers. | |||
| class AreaCodeMap { | |||
| public: | |||
| AreaCodeMap(); | |||
| ~AreaCodeMap(); | |||
| // Returns the description of the geographical area the number corresponds | |||
| // to. This method distinguishes the case of an invalid prefix and a prefix | |||
| // for which the name is not available in the current language. If the | |||
| // description is not available in the current language an empty string is | |||
| // returned. If no description was found for the provided number, null is | |||
| // returned. | |||
| const string* Lookup(const PhoneNumber& number) const; | |||
| // Creates an AreaCodeMap initialized with area_codes. Note that the | |||
| // underlying implementation of this method is expensive thus should | |||
| // not be called by time-critical applications. | |||
| // | |||
| // area_codes maps phone number prefixes to geographical area description. | |||
| void ReadAreaCodeMap(const map<int, string>& area_codes); | |||
| private: | |||
| AreaCodeMapStorageStrategy* CreateDefaultMapStorage() const; | |||
| // Does a binary search for value in the provided array from start to end | |||
| // (inclusive). Returns the position if {@code value} is found; otherwise, | |||
| // returns the position which has the largest value that is less than value. | |||
| // This means if value is the smallest, -1 will be returned. | |||
| int BinarySearch(int start, int end, int64 value) const; | |||
| const PhoneNumberUtil& phone_util_; | |||
| scoped_ptr<const AreaCodeMapStorageStrategy> storage_; | |||
| DISALLOW_COPY_AND_ASSIGN(AreaCodeMap); | |||
| }; | |||
| } // namespace phonenumbers | |||
| } // namespace i18n | |||
| #endif /* I18N_PHONENUMBERS_AREA_CODE_MAP_H_ */ | |||
| @ -0,0 +1,62 @@ | |||
| // Copyright (C) 2012 The Libphonenumber Authors | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| // | |||
| // Author: Patrick Mezard | |||
| // | |||
| // Interface for phone numbers area prefixes storage classes. | |||
| #ifndef I18N_PHONENUMBERS_AREA_CODE_MAP_STRATEGY_H_ | |||
| #define I18N_PHONENUMBERS_AREA_CODE_MAP_STRATEGY_H_ | |||
| #include <map> | |||
| #include <set> | |||
| #include <string> | |||
| namespace i18n { | |||
| namespace phonenumbers { | |||
| using std::map; | |||
| using std::set; | |||
| using std::string; | |||
| // Abstracts the way area code data is stored into memory. It is used by | |||
| // AreaCodeMap to support the most space-efficient storage strategy according | |||
| // to the provided data. | |||
| class AreaCodeMapStorageStrategy { | |||
| public: | |||
| virtual ~AreaCodeMapStorageStrategy() {} | |||
| // Returns the phone number prefix located at the provided index. | |||
| virtual int GetPrefix(int index) const = 0; | |||
| // Gets the description corresponding to the phone number prefix located | |||
| // at the provided index. If the description is not available in the current | |||
| // language an empty string is returned. | |||
| virtual const string& GetDescription(int index) const = 0; | |||
| // Sets the internal state of the underlying storage implementation from the | |||
| // provided area_codes that maps phone number prefixes to description strings. | |||
| virtual void ReadFromMap(const map<int, string>& area_codes) = 0; | |||
| // Returns the number of entries contained in the area code map. | |||
| virtual int GetNumOfEntries() const = 0; | |||
| // Returns the set containing the possible lengths of prefixes. | |||
| virtual const set<int>& GetPossibleLengths() const = 0; | |||
| }; | |||
| } // namespace phonenumbers | |||
| } // namespace i18n | |||
| #endif // I18N_PHONENUMBERS_AREA_CODE_MAP_STRATEGY_H_ | |||
| @ -0,0 +1,71 @@ | |||
| // Copyright (C) 2012 The Libphonenumber Authors | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| // | |||
| // Author: Patrick Mezard | |||
| #include "phonenumbers/geocoding/default_map_storage.h" | |||
| #include <math.h> | |||
| #include <utility> | |||
| #include "base/logging.h" | |||
| namespace i18n { | |||
| namespace phonenumbers { | |||
| using std::map; | |||
| using std::set; | |||
| using std::string; | |||
| DefaultMapStorage::DefaultMapStorage() { | |||
| } | |||
| DefaultMapStorage::~DefaultMapStorage() { | |||
| } | |||
| int DefaultMapStorage::GetPrefix(int index) const { | |||
| DCHECK_GE(index, 0); | |||
| DCHECK_LT(index, static_cast<int>(prefixes_.size())); | |||
| return prefixes_[index]; | |||
| } | |||
| const string& DefaultMapStorage::GetDescription(int index) const { | |||
| DCHECK_GE(index, 0); | |||
| DCHECK_LT(index, static_cast<int>(descriptions_.size())); | |||
| return descriptions_[index]; | |||
| } | |||
| void DefaultMapStorage::ReadFromMap(const map<int, string>& area_codes) { | |||
| prefixes_.resize(area_codes.size()); | |||
| descriptions_.resize(area_codes.size()); | |||
| possible_lengths_.clear(); | |||
| int index = 0; | |||
| for (map<int, string>::const_iterator it = area_codes.begin(); | |||
| it != area_codes.end(); ++it, ++index) { | |||
| prefixes_[index] = it->first; | |||
| descriptions_[index] = it->second; | |||
| possible_lengths_.insert(static_cast<int>(log10(it->first)) + 1); | |||
| } | |||
| } | |||
| int DefaultMapStorage::GetNumOfEntries() const { | |||
| return prefixes_.size(); | |||
| } | |||
| const set<int>& DefaultMapStorage::GetPossibleLengths() const { | |||
| return possible_lengths_; | |||
| } | |||
| } // namespace phonenumbers | |||
| } // namespace i18n | |||
| @ -0,0 +1,67 @@ | |||
| // Copyright (C) 2012 The Libphonenumber Authors | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| // | |||
| // Author: Patrick Mezard | |||
| // | |||
| // Default class for storing area codes. | |||
| #ifndef I18N_PHONENUMBERS_DEFAULT_MAP_STORAGE_H_ | |||
| #define I18N_PHONENUMBERS_DEFAULT_MAP_STORAGE_H_ | |||
| #include <map> | |||
| #include <set> | |||
| #include <string> | |||
| #include <vector> | |||
| #include "base/basictypes.h" | |||
| #include "phonenumbers/geocoding/area_code_map_storage_strategy.h" | |||
| namespace i18n { | |||
| namespace phonenumbers { | |||
| using std::map; | |||
| using std::set; | |||
| using std::string; | |||
| using std::vector; | |||
| // Default area code map storage strategy that is used for data not | |||
| // containing description duplications. It is mainly intended to avoid | |||
| // the overhead of the string table management when it is actually | |||
| // unnecessary (i.e no string duplication). | |||
| class DefaultMapStorage : public AreaCodeMapStorageStrategy { | |||
| public: | |||
| DefaultMapStorage(); | |||
| virtual ~DefaultMapStorage(); | |||
| virtual int GetPrefix(int index) const; | |||
| virtual const string& GetDescription(int index) const; | |||
| virtual void ReadFromMap(const map<int, string>& area_codes); | |||
| virtual int GetNumOfEntries() const; | |||
| virtual const set<int>& GetPossibleLengths() const; | |||
| private: | |||
| // Sorted sequence of phone number prefixes. | |||
| vector<int> prefixes_; | |||
| // Sequence of prefix descriptions, in the same order than prefixes_. | |||
| vector<string> descriptions_; | |||
| // Sequence of unique possible lengths in ascending order. | |||
| set<int> possible_lengths_; | |||
| DISALLOW_COPY_AND_ASSIGN(DefaultMapStorage); | |||
| }; | |||
| } // namespace phonenumbers | |||
| } // namespace i18n | |||
| #endif /* I18N_PHONENUMBERS_DEFAULT_MAP_STORAGE_H_ */ | |||
| @ -0,0 +1,146 @@ | |||
| // Copyright (C) 2012 The Libphonenumber Authors | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| // | |||
| // Author: Patrick Mezard | |||
| // | |||
| // Basic test cases for MappingFileProvider. | |||
| #include "phonenumbers/geocoding/area_code_map.h" | |||
| #include <cstddef> | |||
| #include <vector> | |||
| #include <gtest/gtest.h> // NOLINT(build/include_order) | |||
| #include "phonenumbers/phonenumber.pb.h" | |||
| namespace i18n { | |||
| namespace phonenumbers { | |||
| using std::map; | |||
| using std::string; | |||
| using std::vector; | |||
| namespace { | |||
| void MakeCodeMap(const map<int, string>& m, scoped_ptr<AreaCodeMap>* code_map) { | |||
| scoped_ptr<AreaCodeMap> cm(new AreaCodeMap()); | |||
| cm->ReadAreaCodeMap(m); | |||
| code_map->swap(cm); | |||
| } | |||
| void MakeCodeMapUS(scoped_ptr<AreaCodeMap>* code_map) { | |||
| map<int, string> m; | |||
| m[1212] = "New York"; | |||
| m[1480] = "Arizona"; | |||
| m[1650] = "California"; | |||
| m[1907] = "Alaska"; | |||
| m[1201664] = "Westwood, NJ"; | |||
| m[1480893] = "Phoenix, AZ"; | |||
| m[1501372] = "Little Rock, AR"; | |||
| m[1626308] = "Alhambra, CA"; | |||
| m[1650345] = "San Mateo, CA"; | |||
| m[1867993] = "Dawson, YT"; | |||
| m[1972480] = "Richardson, TX"; | |||
| MakeCodeMap(m, code_map); | |||
| } | |||
| void MakeCodeMapIT(scoped_ptr<AreaCodeMap>* code_map) { | |||
| map<int, string> m; | |||
| m[3902] = "Milan"; | |||
| m[3906] = "Rome"; | |||
| m[39010] = "Genoa"; | |||
| m[390131] = "Alessandria"; | |||
| m[390321] = "Novara"; | |||
| m[390975] = "Potenza"; | |||
| MakeCodeMap(m, code_map); | |||
| } | |||
| PhoneNumber MakePhoneNumber(int32 country_code, uint64 national_number) { | |||
| PhoneNumber number; | |||
| number.set_country_code(country_code); | |||
| number.set_national_number(national_number); | |||
| return number; | |||
| } | |||
| } // namespace | |||
| class AreaCodeMapTest : public testing::Test { | |||
| protected: | |||
| virtual void SetUp() { | |||
| MakeCodeMapUS(&map_US_); | |||
| MakeCodeMapIT(&map_IT_); | |||
| } | |||
| scoped_ptr<AreaCodeMap> map_US_; | |||
| scoped_ptr<AreaCodeMap> map_IT_; | |||
| }; | |||
| TEST_F(AreaCodeMapTest, TestLookupInvalidNumberUS) { | |||
| EXPECT_EQ("New York", *map_US_->Lookup(MakePhoneNumber(1, 2121234567L))); | |||
| } | |||
| TEST_F(AreaCodeMapTest, TestLookupNumberNJ) { | |||
| EXPECT_EQ("Westwood, NJ", *map_US_->Lookup(MakePhoneNumber(1, 2016641234L))); | |||
| } | |||
| TEST_F(AreaCodeMapTest, TestLookupNumberNY) { | |||
| EXPECT_EQ("New York", *map_US_->Lookup(MakePhoneNumber(1, 2126641234L))); | |||
| } | |||
| TEST_F(AreaCodeMapTest, TestLookupNumberCA1) { | |||
| EXPECT_EQ("San Mateo, CA", *map_US_->Lookup(MakePhoneNumber(1, 6503451234L))); | |||
| } | |||
| TEST_F(AreaCodeMapTest, TestLookupNumberCA2) { | |||
| EXPECT_EQ("California", *map_US_->Lookup(MakePhoneNumber(1, 6502531234L))); | |||
| } | |||
| TEST_F(AreaCodeMapTest, TestLookupNumberTX) { | |||
| EXPECT_EQ("Richardson, TX", | |||
| *map_US_->Lookup(MakePhoneNumber(1, 9724801234L))); | |||
| } | |||
| TEST_F(AreaCodeMapTest, TestLookupNumberNotFoundTX) { | |||
| EXPECT_EQ(NULL, map_US_->Lookup(MakePhoneNumber(1, 9724811234L))); | |||
| } | |||
| TEST_F(AreaCodeMapTest, TestLookupNumberCH) { | |||
| EXPECT_EQ(NULL, map_US_->Lookup(MakePhoneNumber(41, 446681300L))); | |||
| } | |||
| TEST_F(AreaCodeMapTest, TestLookupNumberIT) { | |||
| PhoneNumber number = MakePhoneNumber(39, 212345678L); | |||
| number.set_italian_leading_zero(true); | |||
| EXPECT_EQ("Milan", *map_IT_->Lookup(number)); | |||
| number.set_national_number(612345678L); | |||
| EXPECT_EQ("Rome", *map_IT_->Lookup(number)); | |||
| number.set_national_number(3211234L); | |||
| EXPECT_EQ("Novara", *map_IT_->Lookup(number)); | |||
| // A mobile number | |||
| number.set_national_number(321123456L); | |||
| number.set_italian_leading_zero(false); | |||
| EXPECT_EQ(NULL, map_IT_->Lookup(number)); | |||
| // An invalid number (too short) | |||
| number.set_national_number(321123L); | |||
| number.set_italian_leading_zero(true); | |||
| EXPECT_EQ("Novara", *map_IT_->Lookup(number)); | |||
| } | |||
| } // namespace phonenumbers | |||
| } // namespace i18n | |||