Browse Source

CPP: use new geocoding data in AreaCodeMap.

pull/567/head
Patrick Mézard 14 years ago
committed by Mihaela Rosca
parent
commit
2699d37d34
6 changed files with 155 additions and 166 deletions
  1. +12
    -18
      cpp/src/phonenumbers/geocoding/area_code_map.cc
  2. +5
    -6
      cpp/src/phonenumbers/geocoding/area_code_map.h
  3. +0
    -62
      cpp/src/phonenumbers/geocoding/area_code_map_storage_strategy.h
  4. +18
    -24
      cpp/src/phonenumbers/geocoding/default_map_storage.cc
  5. +28
    -19
      cpp/src/phonenumbers/geocoding/default_map_storage.h
  6. +92
    -37
      cpp/test/phonenumbers/geocoding/area_code_map_test.cc

+ 12
- 18
cpp/src/phonenumbers/geocoding/area_code_map.cc View File

@ -17,10 +17,7 @@
#include "phonenumbers/geocoding/area_code_map.h" #include "phonenumbers/geocoding/area_code_map.h"
#include <cstddef> #include <cstddef>
#include <iterator>
#include <set>
#include "phonenumbers/geocoding/area_code_map_storage_strategy.h"
#include "phonenumbers/geocoding/default_map_storage.h" #include "phonenumbers/geocoding/default_map_storage.h"
#include "phonenumbers/phonenumber.pb.h" #include "phonenumbers/phonenumber.pb.h"
#include "phonenumbers/phonenumberutil.h" #include "phonenumbers/phonenumberutil.h"
@ -36,17 +33,13 @@ AreaCodeMap::AreaCodeMap()
AreaCodeMap::~AreaCodeMap() { 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);
void AreaCodeMap::ReadAreaCodeMap(const PrefixDescriptions* descriptions) {
DefaultMapStorage* storage = new DefaultMapStorage();
storage->ReadFromMap(descriptions);
storage_.reset(storage); storage_.reset(storage);
} }
const string* AreaCodeMap::Lookup(const PhoneNumber& number) const {
const char* AreaCodeMap::Lookup(const PhoneNumber& number) const {
const int entries = storage_->GetNumOfEntries(); const int entries = storage_->GetNumOfEntries();
if (!entries) { if (!entries) {
return NULL; return NULL;
@ -58,11 +51,12 @@ const string* AreaCodeMap::Lookup(const PhoneNumber& number) const {
safe_strto64(SimpleItoa(number.country_code()) + national_number, safe_strto64(SimpleItoa(number.country_code()) + national_number,
&phone_prefix); &phone_prefix);
const set<int>& lengths = storage_->GetPossibleLengths();
const int* const lengths = storage_->GetPossibleLengths();
const int lengths_size = storage_->GetPossibleLengthsSize();
int current_index = entries - 1; 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;
for (int lengths_index = lengths_size - 1; lengths_index >= 0;
--lengths_index) {
const int possible_length = lengths[lengths_index];
string phone_prefix_str = SimpleItoa(phone_prefix); string phone_prefix_str = SimpleItoa(phone_prefix);
if (static_cast<int>(phone_prefix_str.length()) > possible_length) { if (static_cast<int>(phone_prefix_str.length()) > possible_length) {
safe_strto64(phone_prefix_str.substr(0, possible_length), &phone_prefix); safe_strto64(phone_prefix_str.substr(0, possible_length), &phone_prefix);
@ -71,9 +65,9 @@ const string* AreaCodeMap::Lookup(const PhoneNumber& number) const {
if (current_index < 0) { if (current_index < 0) {
return NULL; return NULL;
} }
const int current_prefix = storage_->GetPrefix(current_index);
const int32 current_prefix = storage_->GetPrefix(current_index);
if (phone_prefix == current_prefix) { if (phone_prefix == current_prefix) {
return &storage_->GetDescription(current_index);
return storage_->GetDescription(current_index);
} }
} }
return NULL; return NULL;
@ -83,7 +77,7 @@ int AreaCodeMap::BinarySearch(int start, int end, int64 value) const {
int current = 0; int current = 0;
while (start <= end) { while (start <= end) {
current = (start + end) / 2; current = (start + end) / 2;
int current_value = storage_->GetPrefix(current);
int32 current_value = storage_->GetPrefix(current);
if (current_value == value) { if (current_value == value) {
return current; return current;
} else if (current_value > value) { } else if (current_value > value) {


+ 5
- 6
cpp/src/phonenumbers/geocoding/area_code_map.h View File

@ -29,9 +29,10 @@ namespace phonenumbers {
using std::map; using std::map;
using std::string; using std::string;
class AreaCodeMapStorageStrategy;
class DefaultMapStorage;
class PhoneNumber; class PhoneNumber;
class PhoneNumberUtil; class PhoneNumberUtil;
struct PrefixDescriptions;
// A utility that maps phone number prefixes to a string describing the // A utility that maps phone number prefixes to a string describing the
// geographical area the prefix covers. // geographical area the prefix covers.
@ -46,18 +47,16 @@ class AreaCodeMap {
// description is not available in the current language an empty string is // 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. If no description was found for the provided number, null is
// returned. // returned.
const string* Lookup(const PhoneNumber& number) const;
const char* Lookup(const PhoneNumber& number) const;
// Creates an AreaCodeMap initialized with area_codes. Note that the // Creates an AreaCodeMap initialized with area_codes. Note that the
// underlying implementation of this method is expensive thus should // underlying implementation of this method is expensive thus should
// not be called by time-critical applications. // not be called by time-critical applications.
// //
// area_codes maps phone number prefixes to geographical area description. // area_codes maps phone number prefixes to geographical area description.
void ReadAreaCodeMap(const map<int, string>& area_codes);
void ReadAreaCodeMap(const PrefixDescriptions* descriptions);
private: private:
AreaCodeMapStorageStrategy* CreateDefaultMapStorage() const;
// Does a binary search for value in the provided array from start to end // Does a binary search for value in the provided array from start to end
// (inclusive). Returns the position if {@code value} is found; otherwise, // (inclusive). Returns the position if {@code value} is found; otherwise,
// returns the position which has the largest value that is less than value. // returns the position which has the largest value that is less than value.
@ -65,7 +64,7 @@ class AreaCodeMap {
int BinarySearch(int start, int end, int64 value) const; int BinarySearch(int start, int end, int64 value) const;
const PhoneNumberUtil& phone_util_; const PhoneNumberUtil& phone_util_;
scoped_ptr<const AreaCodeMapStorageStrategy> storage_;
scoped_ptr<const DefaultMapStorage> storage_;
DISALLOW_COPY_AND_ASSIGN(AreaCodeMap); DISALLOW_COPY_AND_ASSIGN(AreaCodeMap);
}; };


+ 0
- 62
cpp/src/phonenumbers/geocoding/area_code_map_storage_strategy.h View File

@ -1,62 +0,0 @@
// 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_

+ 18
- 24
cpp/src/phonenumbers/geocoding/default_map_storage.cc View File

@ -16,56 +16,50 @@
#include "phonenumbers/geocoding/default_map_storage.h" #include "phonenumbers/geocoding/default_map_storage.h"
#include <math.h>
#include <utility>
#include "base/basictypes.h"
#include "base/logging.h" #include "base/logging.h"
#include "phonenumbers/geocoding/geocoding_data.h"
namespace i18n { namespace i18n {
namespace phonenumbers { namespace phonenumbers {
using std::map;
using std::set;
using std::string;
DefaultMapStorage::DefaultMapStorage() { DefaultMapStorage::DefaultMapStorage() {
} }
DefaultMapStorage::~DefaultMapStorage() { DefaultMapStorage::~DefaultMapStorage() {
} }
int DefaultMapStorage::GetPrefix(int index) const {
int32 DefaultMapStorage::GetPrefix(int index) const {
DCHECK_GE(index, 0); DCHECK_GE(index, 0);
DCHECK_LT(index, static_cast<int>(prefixes_.size()));
DCHECK_LT(index, prefixes_size_);
return prefixes_[index]; return prefixes_[index];
} }
const string& DefaultMapStorage::GetDescription(int index) const {
const char* DefaultMapStorage::GetDescription(int index) const {
DCHECK_GE(index, 0); DCHECK_GE(index, 0);
DCHECK_LT(index, static_cast<int>(descriptions_.size()));
DCHECK_LT(index, prefixes_size_);
return descriptions_[index]; 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);
}
void DefaultMapStorage::ReadFromMap(const PrefixDescriptions* descriptions) {
prefixes_ = descriptions->prefixes;
prefixes_size_ = descriptions->prefixes_size;
descriptions_ = descriptions->descriptions;
possible_lengths_ = descriptions->possible_lengths;
possible_lengths_size_ = descriptions->possible_lengths_size;
} }
int DefaultMapStorage::GetNumOfEntries() const { int DefaultMapStorage::GetNumOfEntries() const {
return prefixes_.size();
return prefixes_size_;
} }
const set<int>& DefaultMapStorage::GetPossibleLengths() const {
const int* DefaultMapStorage::GetPossibleLengths() const {
return possible_lengths_; return possible_lengths_;
} }
int DefaultMapStorage::GetPossibleLengthsSize() const {
return possible_lengths_size_;
}
} // namespace phonenumbers } // namespace phonenumbers
} // namespace i18n } // namespace i18n

+ 28
- 19
cpp/src/phonenumbers/geocoding/default_map_storage.h View File

@ -19,44 +19,53 @@
#ifndef I18N_PHONENUMBERS_DEFAULT_MAP_STORAGE_H_ #ifndef I18N_PHONENUMBERS_DEFAULT_MAP_STORAGE_H_
#define 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 "base/basictypes.h"
#include "phonenumbers/geocoding/area_code_map_storage_strategy.h"
namespace i18n { namespace i18n {
namespace phonenumbers { namespace phonenumbers {
using std::map;
using std::set;
using std::string;
using std::vector;
struct PrefixDescriptions;
// Default area code map storage strategy that is used for data not // Default area code map storage strategy that is used for data not
// containing description duplications. It is mainly intended to avoid // containing description duplications. It is mainly intended to avoid
// the overhead of the string table management when it is actually // the overhead of the string table management when it is actually
// unnecessary (i.e no string duplication). // unnecessary (i.e no string duplication).
class DefaultMapStorage : public AreaCodeMapStorageStrategy {
class DefaultMapStorage {
public: public:
DefaultMapStorage(); DefaultMapStorage();
virtual ~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;
// Returns the phone number prefix located at the provided index.
int32 GetPrefix(int index) const;
// 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.
const char* GetDescription(int index) const;
// Sets the internal state of the underlying storage implementation from the
// provided area_codes that maps phone number prefixes to description strings.
void ReadFromMap(const PrefixDescriptions* descriptions);
// Returns the number of entries contained in the area code map.
int GetNumOfEntries() const;
// Returns an array containing the possible lengths of prefixes sorted in
// ascending order.
const int* GetPossibleLengths() const;
// Returns the number of elements in GetPossibleLengths() array.
int GetPossibleLengthsSize() const;
private: private:
// Sorted sequence of phone number prefixes. // Sorted sequence of phone number prefixes.
vector<int> prefixes_;
const int32* prefixes_;
int prefixes_size_;
// Sequence of prefix descriptions, in the same order than prefixes_. // Sequence of prefix descriptions, in the same order than prefixes_.
vector<string> descriptions_;
const char** descriptions_;
// Sequence of unique possible lengths in ascending order. // Sequence of unique possible lengths in ascending order.
set<int> possible_lengths_;
const int32* possible_lengths_;
int possible_lengths_size_;
DISALLOW_COPY_AND_ASSIGN(DefaultMapStorage); DISALLOW_COPY_AND_ASSIGN(DefaultMapStorage);
}; };


+ 92
- 37
cpp/test/phonenumbers/geocoding/area_code_map_test.cc View File

@ -23,6 +23,7 @@
#include <gtest/gtest.h> // NOLINT(build/include_order) #include <gtest/gtest.h> // NOLINT(build/include_order)
#include "phonenumbers/geocoding/geocoding_data.h"
#include "phonenumbers/phonenumber.pb.h" #include "phonenumbers/phonenumber.pb.h"
namespace i18n { namespace i18n {
@ -34,37 +35,89 @@ using std::vector;
namespace { namespace {
void MakeCodeMap(const map<int, string>& m, scoped_ptr<AreaCodeMap>* code_map) {
void MakeCodeMap(const PrefixDescriptions* descriptions,
scoped_ptr<AreaCodeMap>* code_map) {
scoped_ptr<AreaCodeMap> cm(new AreaCodeMap()); scoped_ptr<AreaCodeMap> cm(new AreaCodeMap());
cm->ReadAreaCodeMap(m);
cm->ReadAreaCodeMap(descriptions);
code_map->swap(cm); code_map->swap(cm);
} }
const int32 prefix_1_us_prefixes[] = {
1212,
1480,
1650,
1907,
1201664,
1480893,
1501372,
1626308,
1650345,
1867993,
1972480,
};
const char* prefix_1_us_descriptions[] = {
"New York",
"Arizona",
"California",
"Alaska",
"Westwood, NJ",
"Phoenix, AZ",
"Little Rock, AR",
"Alhambra, CA",
"San Mateo, CA",
"Dawson, YT",
"Richardson, TX",
};
const int32 prefix_1_us_lengths[] = {
4, 7,
};
const PrefixDescriptions prefix_1_us = {
prefix_1_us_prefixes,
sizeof(prefix_1_us_prefixes) / sizeof(*prefix_1_us_prefixes),
prefix_1_us_descriptions,
prefix_1_us_lengths,
sizeof(prefix_1_us_lengths) / sizeof(*prefix_1_us_lengths),
};
const int32 prefix_39_it_prefixes[] = {
3902,
3906,
39010,
390131,
390321,
390975,
};
const char* prefix_39_it_descriptions[] = {
"Milan",
"Rome",
"Genoa",
"Alessandria",
"Novara",
"Potenza",
};
const int32 prefix_39_it_lengths[] = {
4, 5, 6,
};
const PrefixDescriptions prefix_39_it = {
prefix_39_it_prefixes,
sizeof(prefix_39_it_prefixes) / sizeof(*prefix_39_it_prefixes),
prefix_39_it_descriptions,
prefix_39_it_lengths,
sizeof(prefix_39_it_lengths) / sizeof(*prefix_1_us_lengths),
};
void MakeCodeMapUS(scoped_ptr<AreaCodeMap>* code_map) { 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);
MakeCodeMap(&prefix_1_us, code_map);
} }
void MakeCodeMapIT(scoped_ptr<AreaCodeMap>* 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);
MakeCodeMap(&prefix_39_it, code_map);
} }
PhoneNumber MakePhoneNumber(int32 country_code, uint64 national_number) { PhoneNumber MakePhoneNumber(int32 country_code, uint64 national_number) {
@ -88,58 +141,60 @@ class AreaCodeMapTest : public testing::Test {
}; };
TEST_F(AreaCodeMapTest, TestLookupInvalidNumberUS) { TEST_F(AreaCodeMapTest, TestLookupInvalidNumberUS) {
EXPECT_EQ("New York", *map_US_->Lookup(MakePhoneNumber(1, 2121234567L)));
EXPECT_STREQ("New York", map_US_->Lookup(MakePhoneNumber(1, 2121234567L)));
} }
TEST_F(AreaCodeMapTest, TestLookupNumberNJ) { TEST_F(AreaCodeMapTest, TestLookupNumberNJ) {
EXPECT_EQ("Westwood, NJ", *map_US_->Lookup(MakePhoneNumber(1, 2016641234L)));
EXPECT_STREQ("Westwood, NJ",
map_US_->Lookup(MakePhoneNumber(1, 2016641234L)));
} }
TEST_F(AreaCodeMapTest, TestLookupNumberNY) { TEST_F(AreaCodeMapTest, TestLookupNumberNY) {
EXPECT_EQ("New York", *map_US_->Lookup(MakePhoneNumber(1, 2126641234L)));
EXPECT_STREQ("New York", map_US_->Lookup(MakePhoneNumber(1, 2126641234L)));
} }
TEST_F(AreaCodeMapTest, TestLookupNumberCA1) { TEST_F(AreaCodeMapTest, TestLookupNumberCA1) {
EXPECT_EQ("San Mateo, CA", *map_US_->Lookup(MakePhoneNumber(1, 6503451234L)));
EXPECT_STREQ("San Mateo, CA",
map_US_->Lookup(MakePhoneNumber(1, 6503451234L)));
} }
TEST_F(AreaCodeMapTest, TestLookupNumberCA2) { TEST_F(AreaCodeMapTest, TestLookupNumberCA2) {
EXPECT_EQ("California", *map_US_->Lookup(MakePhoneNumber(1, 6502531234L)));
EXPECT_STREQ("California", map_US_->Lookup(MakePhoneNumber(1, 6502531234L)));
} }
TEST_F(AreaCodeMapTest, TestLookupNumberTX) { TEST_F(AreaCodeMapTest, TestLookupNumberTX) {
EXPECT_EQ("Richardson, TX",
*map_US_->Lookup(MakePhoneNumber(1, 9724801234L)));
EXPECT_STREQ("Richardson, TX",
map_US_->Lookup(MakePhoneNumber(1, 9724801234L)));
} }
TEST_F(AreaCodeMapTest, TestLookupNumberNotFoundTX) { TEST_F(AreaCodeMapTest, TestLookupNumberNotFoundTX) {
EXPECT_EQ(NULL, map_US_->Lookup(MakePhoneNumber(1, 9724811234L)));
EXPECT_STREQ(NULL, map_US_->Lookup(MakePhoneNumber(1, 9724811234L)));
} }
TEST_F(AreaCodeMapTest, TestLookupNumberCH) { TEST_F(AreaCodeMapTest, TestLookupNumberCH) {
EXPECT_EQ(NULL, map_US_->Lookup(MakePhoneNumber(41, 446681300L)));
EXPECT_STREQ(NULL, map_US_->Lookup(MakePhoneNumber(41, 446681300L)));
} }
TEST_F(AreaCodeMapTest, TestLookupNumberIT) { TEST_F(AreaCodeMapTest, TestLookupNumberIT) {
PhoneNumber number = MakePhoneNumber(39, 212345678L); PhoneNumber number = MakePhoneNumber(39, 212345678L);
number.set_italian_leading_zero(true); number.set_italian_leading_zero(true);
EXPECT_EQ("Milan", *map_IT_->Lookup(number));
EXPECT_STREQ("Milan", map_IT_->Lookup(number));
number.set_national_number(612345678L); number.set_national_number(612345678L);
EXPECT_EQ("Rome", *map_IT_->Lookup(number));
EXPECT_STREQ("Rome", map_IT_->Lookup(number));
number.set_national_number(3211234L); number.set_national_number(3211234L);
EXPECT_EQ("Novara", *map_IT_->Lookup(number));
EXPECT_STREQ("Novara", map_IT_->Lookup(number));
// A mobile number // A mobile number
number.set_national_number(321123456L); number.set_national_number(321123456L);
number.set_italian_leading_zero(false); number.set_italian_leading_zero(false);
EXPECT_EQ(NULL, map_IT_->Lookup(number));
EXPECT_STREQ(NULL, map_IT_->Lookup(number));
// An invalid number (too short) // An invalid number (too short)
number.set_national_number(321123L); number.set_national_number(321123L);
number.set_italian_leading_zero(true); number.set_italian_leading_zero(true);
EXPECT_EQ("Novara", *map_IT_->Lookup(number));
EXPECT_STREQ("Novara", map_IT_->Lookup(number));
} }
} // namespace phonenumbers } // namespace phonenumbers


Loading…
Cancel
Save