Cleaned up indentation & comments

This commit is contained in:
Ben Merritt 2017-02-18 17:11:41 +00:00
parent dcb98bede6
commit 8b94ed59e6
7 changed files with 426 additions and 417 deletions

View File

@ -6,7 +6,7 @@
#include "phonenumbers/phonenumberutil.h"
extern "C" {
#include "postgres.h"
#include "postgres.h"
}
#include "short_phone_number.h"
@ -14,24 +14,24 @@ extern "C" {
using namespace i18n::phonenumbers;
static const char* parseErrorMessage(PhoneNumberUtil::ErrorType error) {
using PNU = i18n::phonenumbers::PhoneNumberUtil;
switch(error) {
case PNU::NO_PARSING_ERROR:
return "Parsed successfully";
case PNU::INVALID_COUNTRY_CODE_ERROR:
return "Invalid country code";
case PNU::NOT_A_NUMBER:
return "String does not appear to contain a phone number";
case PNU::TOO_SHORT_AFTER_IDD:
return "Too short after IDD";
case PNU::TOO_SHORT_NSN:
return "National number is too short";
case PNU::TOO_LONG_NSN:
return "National number is too long";
default:
//We have some generic parsing error.
return "Unable to parse number";
}
using PNU = i18n::phonenumbers::PhoneNumberUtil;
switch(error) {
case PNU::NO_PARSING_ERROR:
return "Parsed successfully";
case PNU::INVALID_COUNTRY_CODE_ERROR:
return "Invalid country code";
case PNU::NOT_A_NUMBER:
return "String does not appear to contain a phone number";
case PNU::TOO_SHORT_AFTER_IDD:
return "Too short after IDD";
case PNU::TOO_SHORT_NSN:
return "National number is too short";
case PNU::TOO_LONG_NSN:
return "National number is too long";
default:
//We have some generic parsing error.
return "Unable to parse number";
}
}
/*
@ -39,9 +39,9 @@ static const char* parseErrorMessage(PhoneNumberUtil::ErrorType error) {
*/
void reportOutOfMemory() {
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("Out of memory")));
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("Out of memory")));
}
/*
@ -51,42 +51,42 @@ void reportOutOfMemory() {
* depending on the type of the exception
*/
void reportException(const std::exception& exception) {
{
const std::bad_alloc* bad_alloc = dynamic_cast<const std::bad_alloc*>(&exception);
if(bad_alloc != nullptr) {
reportOutOfMemory();
return;
}
const PhoneNumberTooLongException* too_long =
dynamic_cast<const PhoneNumberTooLongException*>(&exception);
if(too_long != nullptr) {
std::string phone_number = too_long->number_string();
phone_number += '\0';
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("phone number '%s' is too long", phone_number.data()),
errdetail("%s", exception.what())));
return;
}
}
{
const std::bad_alloc* bad_alloc = dynamic_cast<const std::bad_alloc*>(&exception);
if(bad_alloc != nullptr) {
reportOutOfMemory();
return;
}
const PhoneNumberTooLongException* too_long =
dynamic_cast<const PhoneNumberTooLongException*>(&exception);
if(too_long != nullptr) {
std::string phone_number = too_long->number_string();
phone_number += '\0';
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("phone number '%s' is too long", phone_number.data()),
errdetail("%s", exception.what())));
return;
}
}
//If we don't have a special way to handle this exception, report
//a generic error.
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
errmsg("C++ exception: %s", typeid(exception).name()),
errdetail("%s", exception.what())));
//If we don't have a special way to handle this exception, report
//a generic error.
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
errmsg("C++ exception: %s", typeid(exception).name()),
errdetail("%s", exception.what())));
}
void reportParseError(const char* phone_number, PhoneNumberUtil::ErrorType err) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("unable to parse '%s' as a phone number", phone_number),
errdetail("%s", parseErrorMessage(err))));
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("unable to parse '%s' as a phone number", phone_number),
errdetail("%s", parseErrorMessage(err))));
}
void logInfo(const char* msg) {
ereport(INFO,
(errcode(ERRCODE_SUCCESSFUL_COMPLETION),
errmsg("%s", msg)));
ereport(INFO,
(errcode(ERRCODE_SUCCESSFUL_COMPLETION),
errmsg("%s", msg)));
}

6
mask.h
View File

@ -1,14 +1,14 @@
#include <algorithm>
template<typename T> constexpr T mask(size_t bits, size_t offset = 0) {
return (((T)1 << bits) - 1) << offset;
return (((T)1 << bits) - 1) << offset;
}
template<typename T> constexpr T getMasked(T data, size_t bits, size_t offset) {
return (data >> offset) & mask<T>(bits);
return (data >> offset) & mask<T>(bits);
}
//TODO: support typeof(data) != typeof(value)?
template<typename T> constexpr T setMasked(T data, T value, size_t bits, size_t offset) {
return (data & ~mask<T>(bits, offset)) | ((value & mask<T>(bits)) << offset);
return (data & ~mask<T>(bits, offset)) | ((value & mask<T>(bits)) << offset);
}

View File

@ -4,9 +4,9 @@
#include "phonenumbers/phonenumberutil.h"
extern "C" {
#include "postgres.h"
#include "libpq/pqformat.h"
#include "fmgr.h"
#include "postgres.h"
#include "libpq/pqformat.h"
#include "fmgr.h"
}
#include "error_handling.h"
@ -16,6 +16,9 @@ using namespace i18n::phonenumbers;
static const PhoneNumberUtil* const phoneUtil = PhoneNumberUtil::GetInstance();
/**
* Clips a value to the given (inclusive) range
*/
template <typename T>
T clip(const T& n, const T& lower, const T& upper) {
return std::max(lower, std::min(n, upper));
@ -25,36 +28,39 @@ T clip(const T& n, const T& lower, const T& upper) {
* Utility functions
*/
/**
* Converts a text object to a C-style string
*/
static char* textToCString(const text* text) {
size_t len = VARSIZE(text) - VARHDRSZ;
char* str = (char*)palloc(len + 1);
memcpy(str, VARDATA(text), len);
str[len] = '\0';
return str;
size_t len = VARSIZE(text) - VARHDRSZ;
char* str = (char*)palloc(len + 1);
memcpy(str, VARDATA(text), len);
str[len] = '\0';
return str;
}
//Internal function used by phone_number_in and parse_phone_number
//TODO: take a std::string to minimize copying?
ShortPhoneNumber* parsePhoneNumber(const char* number_str, const char* country) {
PhoneNumber number;
ShortPhoneNumber* short_number;
PhoneNumber number;
ShortPhoneNumber* short_number;
short_number = (ShortPhoneNumber*)palloc0(sizeof(ShortPhoneNumber));
if(short_number == nullptr) {
throw std::bad_alloc();
}
short_number = (ShortPhoneNumber*)palloc0(sizeof(ShortPhoneNumber));
if(short_number == nullptr) {
throw std::bad_alloc();
}
PhoneNumberUtil::ErrorType error;
error = phoneUtil->Parse(number_str, country, &number);
if(error == PhoneNumberUtil::NO_PARSING_ERROR) {
//Initialize short_number using placement new.
new(short_number) ShortPhoneNumber(number);
return short_number;
} else {
reportParseError(number_str, error);
return nullptr;
}
//TODO: check number validity.
PhoneNumberUtil::ErrorType error;
error = phoneUtil->Parse(number_str, country, &number);
if(error == PhoneNumberUtil::NO_PARSING_ERROR) {
//Initialize short_number using placement new.
new(short_number) ShortPhoneNumber(number);
return short_number;
} else {
reportParseError(number_str, error);
return nullptr;
}
//TODO: check number validity.
}
//TODO: check null args (PG_ARGISNULL) and make non-strict?
@ -64,232 +70,232 @@ ShortPhoneNumber* parsePhoneNumber(const char* number_str, const char* country)
*/
extern "C" {
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_in);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_in);
PGDLLEXPORT Datum
phone_number_in(PG_FUNCTION_ARGS) {
try {
const char *number_str = PG_GETARG_CSTRING(0);
PGDLLEXPORT Datum
phone_number_in(PG_FUNCTION_ARGS) {
try {
const char *number_str = PG_GETARG_CSTRING(0);
//TODO: use international format instead.
ShortPhoneNumber* number = parsePhoneNumber(number_str, "US");
if(number) {
PG_RETURN_POINTER(number);
} else {
PG_RETURN_NULL();
}
} catch(std::exception& e) {
reportException(e);
}
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(parse_phone_number);
//TODO: use international format instead.
ShortPhoneNumber* number = parsePhoneNumber(number_str, "US");
if(number) {
PG_RETURN_POINTER(number);
} else {
PG_RETURN_NULL();
}
} catch(std::exception& e) {
reportException(e);
}
}
PGDLLEXPORT Datum
parse_phone_number(PG_FUNCTION_ARGS) {
try {
const text* number_text = PG_GETARG_TEXT_P(0);
const text* country_text = PG_GETARG_TEXT_P(1);
PGDLLEXPORT PG_FUNCTION_INFO_V1(parse_phone_number);
char* number_str = textToCString(number_text);
char* country = textToCString(country_text);
PGDLLEXPORT Datum
parse_phone_number(PG_FUNCTION_ARGS) {
try {
const text* number_text = PG_GETARG_TEXT_P(0);
const text* country_text = PG_GETARG_TEXT_P(1);
ShortPhoneNumber* number = parsePhoneNumber(number_str, country);
//TODO: prevent leaks.
pfree(number_str);
pfree(country);
if(number) {
PG_RETURN_POINTER(number);
} else {
PG_RETURN_NULL();
}
} catch(std::exception& e) {
reportException(e);
}
}
char* number_str = textToCString(number_text);
char* country = textToCString(country_text);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_out);
ShortPhoneNumber* number = parsePhoneNumber(number_str, country);
//TODO: prevent leaks.
pfree(number_str);
pfree(country);
if(number) {
PG_RETURN_POINTER(number);
} else {
PG_RETURN_NULL();
}
} catch(std::exception& e) {
reportException(e);
}
}
PGDLLEXPORT Datum
phone_number_out(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* short_number = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
PhoneNumber number = *short_number;
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_out);
std::string formatted;
phoneUtil->Format(number, PhoneNumberUtil::INTERNATIONAL, &formatted);
PGDLLEXPORT Datum
phone_number_out(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* short_number = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
PhoneNumber number = *short_number;
//Copy the formatted number to a C-style string.
//We must use the PostgreSQL allocator, not new/malloc.
size_t len = formatted.length();
char* result = (char*)palloc(len + 1);
if(result == nullptr) {
throw std::bad_alloc();
}
memcpy(result, formatted.data(), len);
result[len] = '\0';
std::string formatted;
phoneUtil->Format(number, PhoneNumberUtil::INTERNATIONAL, &formatted);
PG_RETURN_CSTRING(result);
} catch (const std::exception& e) {
reportException(e);
}
//Copy the formatted number to a C-style string.
//We must use the PostgreSQL allocator, not new/malloc.
size_t len = formatted.length();
char* result = (char*)palloc(len + 1);
if(result == nullptr) {
throw std::bad_alloc();
}
memcpy(result, formatted.data(), len);
result[len] = '\0';
PG_RETURN_NULL();
}
PG_RETURN_CSTRING(result);
} catch (const std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_recv);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_recv(PG_FUNCTION_ARGS) {
try {
StringInfo buf = (StringInfo)PG_GETARG_POINTER(0);
ShortPhoneNumber* number;
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_recv);
number = (ShortPhoneNumber*)palloc(sizeof(ShortPhoneNumber));
//TODO: make portable (fix endianness issues, etc.).
pq_copymsgbytes(buf, (char*)number, sizeof(ShortPhoneNumber));
PG_RETURN_POINTER(number);
} catch (const std::exception& e) {
reportException(e);
}
PGDLLEXPORT Datum
phone_number_recv(PG_FUNCTION_ARGS) {
try {
StringInfo buf = (StringInfo)PG_GETARG_POINTER(0);
ShortPhoneNumber* number;
PG_RETURN_NULL();
}
number = (ShortPhoneNumber*)palloc(sizeof(ShortPhoneNumber));
//TODO: make portable (fix endianness issues, etc.).
pq_copymsgbytes(buf, (char*)number, sizeof(ShortPhoneNumber));
PG_RETURN_POINTER(number);
} catch (const std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_send);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_send(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber *number = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
StringInfoData buf;
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_send);
pq_begintypsend(&buf);
pq_sendbytes(&buf, (const char*)number, sizeof(ShortPhoneNumber));
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
} catch (const std::exception& e) {
reportException(e);
}
PGDLLEXPORT Datum
phone_number_send(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber *number = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
StringInfoData buf;
PG_RETURN_NULL();
}
pq_begintypsend(&buf);
pq_sendbytes(&buf, (const char*)number, sizeof(ShortPhoneNumber));
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
} catch (const std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_equal);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_equal);
PG_RETURN_BOOL(*number1 == *number2);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT Datum
phone_number_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_NULL();
}
PG_RETURN_BOOL(*number1 == *number2);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_not_equal);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_not_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_not_equal);
PG_RETURN_BOOL(*number1 != *number2);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT Datum
phone_number_not_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_NULL();
}
PG_RETURN_BOOL(*number1 != *number2);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_less);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_less(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_less);
PG_RETURN_BOOL(number1->compare_fast(*number2) < 0);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT Datum
phone_number_less(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_NULL();
}
PG_RETURN_BOOL(number1->compare_fast(*number2) < 0);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_less_or_equal);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_less_or_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_less_or_equal);
PG_RETURN_BOOL(number1->compare_fast(*number2) <= 0);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT Datum
phone_number_less_or_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_NULL();
}
PG_RETURN_BOOL(number1->compare_fast(*number2) <= 0);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_greater);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_greater(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_greater);
PG_RETURN_BOOL(number1->compare_fast(*number2) > 0);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT Datum
phone_number_greater(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_NULL();
}
PG_RETURN_BOOL(number1->compare_fast(*number2) > 0);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_greater_or_equal);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_greater_or_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_greater_or_equal);
PG_RETURN_BOOL(number1->compare_fast(*number2) >= 0);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT Datum
phone_number_greater_or_equal(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_NULL();
}
PG_RETURN_BOOL(number1->compare_fast(*number2) >= 0);
} catch(std::exception& e) {
reportException(e);
}
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_cmp);
PG_RETURN_NULL();
}
PGDLLEXPORT Datum
phone_number_cmp(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PGDLLEXPORT PG_FUNCTION_INFO_V1(phone_number_cmp);
int64 compared = number1->compare_fast(*number2);
PGDLLEXPORT Datum
phone_number_cmp(PG_FUNCTION_ARGS) {
try {
const ShortPhoneNumber* number1 = (ShortPhoneNumber*)PG_GETARG_POINTER(0);
const ShortPhoneNumber* number2 = (ShortPhoneNumber*)PG_GETARG_POINTER(1);
PG_RETURN_INT32(clip<int64>(compared, -1, 1));
} catch(std::exception& e) {
reportException(e);
}
int64 compared = number1->compare_fast(*number2);
PG_RETURN_NULL();
}
PG_RETURN_INT32(clip<int64>(compared, -1, 1));
} catch(std::exception& e) {
reportException(e);
}
PG_RETURN_NULL();
}
}

View File

@ -34,7 +34,7 @@ CREATE TYPE phone_number (
--Cast definitions
CREATE CAST (phone_number AS text)
WITH INOUT;
WITH INOUT;
--Operator definitions
@ -42,16 +42,18 @@ CREATE FUNCTION phone_number_equal(phone_number, phone_number) RETURNS bool
LANGUAGE c IMMUTABLE STRICT
AS 'pg_libphonenumber', 'phone_number_equal';
-- TODO: make these operators strict.
CREATE OPERATOR = (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_equal,
commutator = =,
negator = <>,
restrict = eqsel,
join = eqjoinsel,
hashes = true,
merges = true
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_equal,
commutator = =,
negator = <>,
restrict = eqsel,
join = eqjoinsel,
hashes = true,
merges = true
);
CREATE FUNCTION phone_number_not_equal(phone_number, phone_number) RETURNS bool
@ -59,13 +61,13 @@ CREATE FUNCTION phone_number_not_equal(phone_number, phone_number) RETURNS bool
AS 'pg_libphonenumber', 'phone_number_not_equal';
CREATE OPERATOR <> (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_not_equal,
commutator = <>,
negator = =,
restrict = neqsel,
join = neqjoinsel
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_not_equal,
commutator = <>,
negator = =,
restrict = neqsel,
join = neqjoinsel
);
CREATE FUNCTION phone_number_less(phone_number, phone_number) RETURNS bool
@ -73,13 +75,13 @@ CREATE FUNCTION phone_number_less(phone_number, phone_number) RETURNS bool
AS 'pg_libphonenumber', 'phone_number_less';
CREATE OPERATOR < (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_less,
commutator = >,
negator = >=,
restrict = scalarltsel,
join = scalarltjoinsel
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_less,
commutator = >,
negator = >=,
restrict = scalarltsel,
join = scalarltjoinsel
);
CREATE FUNCTION phone_number_less_or_equal(phone_number, phone_number) RETURNS bool
@ -87,13 +89,13 @@ CREATE FUNCTION phone_number_less_or_equal(phone_number, phone_number) RETURNS b
AS 'pg_libphonenumber', 'phone_number_less_or_equal';
CREATE OPERATOR <= (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_less_or_equal,
commutator = >=,
negator = >,
restrict = scalarltsel,
join = scalarltjoinsel
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_less_or_equal,
commutator = >=,
negator = >,
restrict = scalarltsel,
join = scalarltjoinsel
);
CREATE FUNCTION phone_number_greater(phone_number, phone_number) RETURNS bool
@ -101,13 +103,13 @@ CREATE FUNCTION phone_number_greater(phone_number, phone_number) RETURNS bool
AS 'pg_libphonenumber', 'phone_number_greater';
CREATE OPERATOR > (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_greater,
commutator = >,
negator = <=,
restrict = scalargtsel,
join = scalargtjoinsel
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_greater,
commutator = >,
negator = <=,
restrict = scalargtsel,
join = scalargtjoinsel
);
CREATE FUNCTION phone_number_greater_or_equal(phone_number, phone_number) RETURNS bool
@ -115,13 +117,13 @@ CREATE FUNCTION phone_number_greater_or_equal(phone_number, phone_number) RETURN
AS 'pg_libphonenumber', 'phone_number_greater_or_equal';
CREATE OPERATOR >= (
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_greater_or_equal,
commutator = >=,
negator = <,
restrict = scalargtsel,
join = scalargtjoinsel
leftarg = phone_number,
rightarg = phone_number,
procedure = phone_number_greater_or_equal,
commutator = >=,
negator = <,
restrict = scalargtsel,
join = scalargtjoinsel
);
CREATE FUNCTION phone_number_cmp(phone_number, phone_number) RETURNS integer
@ -129,13 +131,13 @@ CREATE FUNCTION phone_number_cmp(phone_number, phone_number) RETURNS integer
AS 'pg_libphonenumber', 'phone_number_cmp';
CREATE OPERATOR CLASS phone_number_ops
DEFAULT FOR TYPE phone_number USING btree AS
OPERATOR 1 <,
OPERATOR 2 <=,
OPERATOR 3 =,
OPERATOR 4 >=,
OPERATOR 5 >,
FUNCTION 1 phone_number_cmp(phone_number, phone_number);
DEFAULT FOR TYPE phone_number USING btree AS
OPERATOR 1 <,
OPERATOR 2 <=,
OPERATOR 3 =,
OPERATOR 4 >=,
OPERATOR 5 >,
FUNCTION 1 phone_number_cmp(phone_number, phone_number);
--General functions

View File

@ -6,45 +6,44 @@ using namespace i18n::phonenumbers;
const PhoneNumberUtil* const PhoneNumberTooLongException::phoneUtil = PhoneNumberUtil::GetInstance();
PhoneNumberTooLongException::PhoneNumberTooLongException(const PhoneNumber& number, const char* msg) :
_number(number), std::runtime_error(msg) {};
_number(number), std::runtime_error(msg) {};
std::string PhoneNumberTooLongException::number_string() const {
std::string formatted;
phoneUtil->Format(number(), PhoneNumberUtil::INTERNATIONAL, &formatted);
return formatted;
std::string formatted;
phoneUtil->Format(number(), PhoneNumberUtil::INTERNATIONAL, &formatted);
return formatted;
}
ShortPhoneNumber::ShortPhoneNumber(i18n::phonenumbers::PhoneNumber number) {
uint32 country_code = number.country_code();
if(country_code > MAX_COUNTRY_CODE) {
throw PhoneNumberTooLongException(number, "Country code is too long");
}
this->country_code(country_code);
uint32 country_code = number.country_code();
if(country_code > MAX_COUNTRY_CODE) {
throw PhoneNumberTooLongException(number, "Country code is too long");
}
this->country_code(country_code);
uint64 national_number = number.national_number();
if(national_number > MAX_NATIONAL_NUMBER) {
throw PhoneNumberTooLongException(number, "National number is too long");
}
this->national_number(national_number);
uint64 national_number = number.national_number();
if(national_number > MAX_NATIONAL_NUMBER) {
throw PhoneNumberTooLongException(number, "National number is too long");
}
this->national_number(national_number);
if(number.has_number_of_leading_zeros()) {
uint32 leading_zeros = number.number_of_leading_zeros();
if(leading_zeros > MAX_LEADING_ZEROS) {
throw PhoneNumberTooLongException(number, "Too many leading zeros");
}
this->leading_zeros(leading_zeros);
} else {
this->leading_zeros(0);
}
if(number.has_number_of_leading_zeros()) {
uint32 leading_zeros = number.number_of_leading_zeros();
if(leading_zeros > MAX_LEADING_ZEROS) {
throw PhoneNumberTooLongException(number, "Too many leading zeros");
}
this->leading_zeros(leading_zeros);
} else {
this->leading_zeros(0);
}
}
ShortPhoneNumber::operator PhoneNumber() const {
PhoneNumber number;
number.set_country_code(country_code());
number.set_national_number(national_number());
int32 leading_zeros = this->leading_zeros();
number.set_italian_leading_zero(leading_zeros > 0);
number.set_number_of_leading_zeros(leading_zeros);
return number;
PhoneNumber number;
number.set_country_code(country_code());
number.set_national_number(national_number());
int32 leading_zeros = this->leading_zeros();
number.set_italian_leading_zero(leading_zeros > 0);
number.set_number_of_leading_zeros(leading_zeros);
return number;
}

View File

@ -6,94 +6,96 @@
#include "mask.h"
class PhoneNumberTooLongException : public std::runtime_error {
public:
PhoneNumberTooLongException(const i18n::phonenumbers::PhoneNumber& number, const char* msg);
public:
PhoneNumberTooLongException(const i18n::phonenumbers::PhoneNumber& number, const char* msg);
i18n::phonenumbers::PhoneNumber number() const {
return _number;
}
i18n::phonenumbers::PhoneNumber number() const {
return _number;
}
//TODO: just get the number string from which the PhoneNumber was parsed? (if it exists...)
std::string number_string() const;
private:
i18n::phonenumbers::PhoneNumber _number;
//TODO: just get the number string from which the PhoneNumber was parsed? (if it exists...)
std::string number_string() const;
private:
i18n::phonenumbers::PhoneNumber _number;
static const i18n::phonenumbers::PhoneNumberUtil* const phoneUtil;
static const i18n::phonenumbers::PhoneNumberUtil* const phoneUtil;
};
/**
* Stores a phone number (packed into a 64-bit integer)
*/
class ShortPhoneNumber {
public:
enum : size_t {
MAX_COUNTRY_CODE = 999,
MAX_LEADING_ZEROS = 15,
//15 digits
MAX_NATIONAL_NUMBER = 999999999999999,
};
enum : size_t {
COUNTRY_CODE_BITS = 10,
LEADING_ZEROS_BITS = 4,
NATIONAL_NUMBER_BITS = 50,
};
enum : size_t {
COUNTRY_CODE_OFFSET = 0,
LEADING_ZEROS_OFFSET = COUNTRY_CODE_OFFSET + COUNTRY_CODE_BITS,
NATIONAL_NUMBER_OFFSET = LEADING_ZEROS_OFFSET + LEADING_ZEROS_BITS,
};
public:
enum : size_t {
MAX_COUNTRY_CODE = 999,
MAX_LEADING_ZEROS = 15,
//15 digits
MAX_NATIONAL_NUMBER = 999999999999999,
};
ShortPhoneNumber(i18n::phonenumbers::PhoneNumber number);
enum : size_t {
COUNTRY_CODE_BITS = 10,
LEADING_ZEROS_BITS = 4,
NATIONAL_NUMBER_BITS = 50,
};
bool operator == (const ShortPhoneNumber other) const {
return this->_data == other._data;
}
bool operator != (const ShortPhoneNumber other) const {
return !(*this == other);
}
enum : size_t {
COUNTRY_CODE_OFFSET = 0,
LEADING_ZEROS_OFFSET = COUNTRY_CODE_OFFSET + COUNTRY_CODE_BITS,
NATIONAL_NUMBER_OFFSET = LEADING_ZEROS_OFFSET + LEADING_ZEROS_BITS,
};
operator i18n::phonenumbers::PhoneNumber() const;
ShortPhoneNumber(i18n::phonenumbers::PhoneNumber number);
/*
* Compares to another PhoneNumber using a fast collation heuristic
*
* May not produce intuitive results for numbers with the same
* country code but different lengths
*
* Returns:
* - <0 (if a < b)
* - 0 (if a == b)
* - >0 (if a > b)
*/
google::protobuf::int64 compare_fast(ShortPhoneNumber other) const {
return other._data - this->_data;
}
bool operator == (const ShortPhoneNumber other) const {
return this->_data == other._data;
}
google::protobuf::uint32 country_code() const {
return getMasked(_data, COUNTRY_CODE_BITS, COUNTRY_CODE_OFFSET);
}
bool operator != (const ShortPhoneNumber other) const {
return !(*this == other);
}
void country_code(google::protobuf::uint32 value) {
_data = setMasked(_data, (google::protobuf::uint64)value, COUNTRY_CODE_BITS, COUNTRY_CODE_OFFSET);
}
operator i18n::phonenumbers::PhoneNumber() const;
google::protobuf::uint64 national_number() const {
return getMasked(_data, NATIONAL_NUMBER_BITS, NATIONAL_NUMBER_OFFSET);
}
/*
* Compares to another PhoneNumber using a fast collation heuristic
*
* May not produce intuitive results for numbers with the same
* country code but different lengths
*
* Returns:
* - <0 (if a < b)
* - 0 (if a == b)
* - >0 (if a > b)
*/
google::protobuf::int64 compare_fast(ShortPhoneNumber other) const {
return other._data - this->_data;
}
void national_number(google::protobuf::uint64 value) {
_data = setMasked(_data, value, NATIONAL_NUMBER_BITS, NATIONAL_NUMBER_OFFSET);
}
google::protobuf::uint32 country_code() const {
return getMasked(_data, COUNTRY_CODE_BITS, COUNTRY_CODE_OFFSET);
}
google::protobuf::uint64 leading_zeros() const {
return getMasked(_data, LEADING_ZEROS_BITS, LEADING_ZEROS_OFFSET);
}
void country_code(google::protobuf::uint32 value) {
_data = setMasked(_data, (google::protobuf::uint64)value, COUNTRY_CODE_BITS, COUNTRY_CODE_OFFSET);
}
void leading_zeros(google::protobuf::uint64 value) {
_data = setMasked(_data, value, LEADING_ZEROS_BITS, LEADING_ZEROS_OFFSET);
}
google::protobuf::uint64 national_number() const {
return getMasked(_data, NATIONAL_NUMBER_BITS, NATIONAL_NUMBER_OFFSET);
}
private:
google::protobuf::uint64 _data;
void national_number(google::protobuf::uint64 value) {
_data = setMasked(_data, value, NATIONAL_NUMBER_BITS, NATIONAL_NUMBER_OFFSET);
}
google::protobuf::uint64 leading_zeros() const {
return getMasked(_data, LEADING_ZEROS_BITS, LEADING_ZEROS_OFFSET);
}
void leading_zeros(google::protobuf::uint64 value) {
_data = setMasked(_data, value, LEADING_ZEROS_BITS, LEADING_ZEROS_OFFSET);
}
private:
google::protobuf::uint64 _data;
};

View File

@ -3,6 +3,6 @@
#include "../short_phone_number.h"
int main(int argc, const char** argv) {
std::cout << sizeof(ShortPhoneNumber) << std::endl;
return 0;
std::cout << sizeof(ShortPhoneNumber) << std::endl;
return 0;
}