From 5080bf839e24a30049ad06e65bf0de1865df313e Mon Sep 17 00:00:00 2001 From: BLM Date: Wed, 22 Jul 2015 14:23:40 -0500 Subject: [PATCH] Moved away from bitfields to increase portability --- mask.h | 12 ++++++++++++ short_phone_number.cpp | 17 +++++++++-------- short_phone_number.h | 42 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 mask.h diff --git a/mask.h b/mask.h new file mode 100644 index 0000000..b1fa189 --- /dev/null +++ b/mask.h @@ -0,0 +1,12 @@ +template constexpr T mask(size_t bits, size_t offset = 0) { + return (((T)1 << bits) - 1) << offset; +} + +template constexpr T getMasked(T data, size_t bits, size_t offset) { + return (data >> offset) & mask(bits); +} + +//TODO: support typeof(data) != typeof(value)? +template constexpr T setMasked(T data, T value, size_t bits, size_t offset) { + return (data & ~mask(bits, offset)) | ((value & mask(bits)) << offset); +} diff --git a/short_phone_number.cpp b/short_phone_number.cpp index 979f0f2..49a133c 100644 --- a/short_phone_number.cpp +++ b/short_phone_number.cpp @@ -13,30 +13,31 @@ ShortPhoneNumber::ShortPhoneNumber(i18n::phonenumbers::PhoneNumber number) { if(country_code > MAX_COUNTRY_CODE) { throw PhoneNumberTooLongException(number, "Country code is too long"); } - _country_code = country_code; + 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"); } - _national_number = national_number; + 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"); } - _leading_zeros = leading_zeros; + this->leading_zeros(leading_zeros); } else { - _leading_zeros = 0; + this->leading_zeros(0); } } ShortPhoneNumber::operator PhoneNumber() const { PhoneNumber number; - number.set_country_code(_country_code); - number.set_national_number(_national_number); - number.set_italian_leading_zero(_leading_zeros > 0); - number.set_number_of_leading_zeros(_leading_zeros); + 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; } diff --git a/short_phone_number.h b/short_phone_number.h index c4c27cb..2390fe3 100644 --- a/short_phone_number.h +++ b/short_phone_number.h @@ -2,6 +2,8 @@ #include "phonenumbers/phonenumberutil.h" +#include "mask.h" + class PhoneNumberTooLongException : public std::runtime_error { public: PhoneNumberTooLongException(const i18n::phonenumbers::PhoneNumber& number, const char* msg); @@ -20,14 +22,48 @@ class ShortPhoneNumber { MAX_NATIONAL_NUMBER = 999999999999999, MAX_LEADING_ZEROS = 15, }; + + enum : size_t { + COUNTRY_CODE_BITS = 10, + NATIONAL_NUMBER_BITS = 50, + LEADING_ZEROS_BITS = 4, + }; + + enum : size_t { + COUNTRY_CODE_OFFSET = 0, + NATIONAL_NUMBER_OFFSET = COUNTRY_CODE_OFFSET + COUNTRY_CODE_BITS, + LEADING_ZEROS_OFFSET = NATIONAL_NUMBER_OFFSET + NATIONAL_NUMBER_BITS, + }; ShortPhoneNumber(i18n::phonenumbers::PhoneNumber number); operator i18n::phonenumbers::PhoneNumber() const; + google::protobuf::uint32 country_code() const { + return getMasked(_data, COUNTRY_CODE_BITS, COUNTRY_CODE_OFFSET); + } + + void country_code(google::protobuf::uint32 value) { + _data = setMasked(_data, (google::protobuf::uint64)value, COUNTRY_CODE_BITS, COUNTRY_CODE_OFFSET); + } + + google::protobuf::uint64 national_number() const { + return getMasked(_data, NATIONAL_NUMBER_BITS, NATIONAL_NUMBER_OFFSET); + } + + 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::uint32 _country_code : 10; - google::protobuf::uint64 _national_number : 50; - google::protobuf::uint32 _leading_zeros : 4; + google::protobuf::uint64 _data; };