diff --git a/src/common_code/common_code.cc b/src/common_code/common_code.cc index 9408f27..c3c9d81 100644 --- a/src/common_code/common_code.cc +++ b/src/common_code/common_code.cc @@ -8,22 +8,89 @@ inline uint8_t last_zero_num(uint32_t bin) { // get last zero number return __builtin_popcount(bin >> 1); } -std::string CommonCode::to_string(uint64_t common_code, bool shorten) { - if (!CommonCode::check(common_code)) { - throw std::invalid_argument("invalid common code"); +//std::string CommonCode::to_string_(uint64_t common_code, bool shorten) { +// if (!CommonCode::check(common_code)) { +// throw std::invalid_argument("invalid common code"); +// } +// char result[10]; // max length 9-bits +// sprintf(result, "%09lX", common_code); +// if (shorten) { // remove `0` after common code +// if (common_code == 0x000000000) { +// return "0"; // special case +// } +// result[9 - last_zero_num(common_code) / 4] = '\0'; // truncate string +// } +// return result; +//} + +//uint64_t CommonCode::from_string_(const std::string &common_code) { +// if (common_code.length() > 9 || common_code.length() == 0) { +// throw std::invalid_argument("common code format error"); +// } +// uint64_t result = 0; +// for (auto const &bit : common_code) { +// result <<= 4; +// if (bit >= '0' && bit <= '9') { // 0 ~ 9 +// result |= (bit - 48); +// } else if (bit >= 'A' && bit <= 'Z') { // A ~ Z +// result |= (bit - 55); +// } else if (bit >= 'a' && bit <= 'z') { // a ~ z +// result |= (bit - 87); +// } else { +// throw std::invalid_argument("common code format error"); +// } +// } +// // TODO: should we ensure that common code is valid? +// return result << (9 - common_code.length()) * 4; // low-bits fill with zero +//} + +bool CommonCode::check(uint64_t common_code) { // check whether common code is valid + uint32_t head = common_code >> 32; + if (head >= 16 || (head & 0b11) == 0b11) { // check 2x2 block address + return false; // invalid common code + } + + uint32_t fill_num = 0, space_num = 0; + auto range = Common::range_reverse((uint32_t)common_code); // get common code range + for (int i = 0; i < 32; i += 2) { // traverse range + switch ((range >> i) & 0b11) { + case 0b00: // space block + ++space_num; + case 0b11: // 1x1 block + ++fill_num; + break; + case 0b01: // 1x2 block + case 0b10: // 2x1 block + fill_num += 2; + } + if (fill_num >= 16) { // all block filled + break; + } + } + if (space_num < 2) { + return false; // at least 2 space } + return Common::check_case(head, range); // check by head and range +} + +std::string CommonCode::to_string(bool shorten) const { + char result[10]; // max length 9-bits - sprintf(result, "%09lX", common_code); + sprintf(result, "%09lX", code); if (shorten) { // remove `0` after common code - if (common_code == 0x000000000) { + if (code == 0x000000000) { return "0"; // special case } - result[9 - last_zero_num(common_code) / 4] = '\0'; // truncate string + result[9 - last_zero_num(code) / 4] = '\0'; // truncate string } return result; + +// return CommonCode::to_string_(code, shorten); + } -uint64_t CommonCode::from_string(const std::string &common_code) { +CommonCode CommonCode::from_string(const std::string &common_code) { + if (common_code.length() > 9 || common_code.length() == 0) { throw std::invalid_argument("common code format error"); } @@ -40,35 +107,27 @@ uint64_t CommonCode::from_string(const std::string &common_code) { throw std::invalid_argument("common code format error"); } } + + return CommonCode(result << (9 - common_code.length()) * 4); // low-bits fill with zero + // TODO: should we ensure that common code is valid? - return result << (9 - common_code.length()) * 4; // low-bits fill with zero +// return result << (9 - common_code.length()) * 4; // low-bits fill with zero + + +// return CommonCode(CommonCode::from_string_(common_code)); + } -bool CommonCode::check(uint64_t common_code) { // check whether common code is valid - uint32_t head = common_code >> 32; - if (head >= 16 || (head & 0b11) == 0b11) { // check 2x2 block address - return false; // invalid common code - } +CommonCode::CommonCode(uint64_t common_code) { - uint32_t fill_num = 0, space_num = 0; - auto range = Common::range_reverse((uint32_t)common_code); // get common code range - for (int i = 0; i < 32; i += 2) { // traverse range - switch ((range >> i) & 0b11) { - case 0b00: // space block - ++space_num; - case 0b11: // 1x1 block - ++fill_num; - break; - case 0b01: // 1x2 block - case 0b10: // 2x1 block - fill_num += 2; - } - if (fill_num >= 16) { // all block filled - break; - } - } - if (space_num < 2) { - return false; // at least 2 space + if (!CommonCode::check(common_code)) { + throw std::invalid_argument("invalid common code"); } - return Common::check_case(head, range); // check by head and range + + code = common_code; + +} + +uint64_t CommonCode::unwrap() const { + return code; } diff --git a/src/common_code/common_code.h b/src/common_code/common_code.h index 614886a..8148c93 100644 --- a/src/common_code/common_code.h +++ b/src/common_code/common_code.h @@ -5,7 +5,24 @@ class CommonCode { public: + + explicit CommonCode(uint64_t common_code); + + uint64_t unwrap() const; + + std::string to_string(bool shorten = false) const; + + static CommonCode from_string(const std::string &common_code); + + +private: + + uint64_t code; + static bool check(uint64_t common_code); - static uint64_t from_string(const std::string &common_code); - static std::string to_string(uint64_t common_code, bool shorten = false); + +// static uint64_t from_string(const std::string &common_code); +// static std::string to_string(uint64_t common_code, bool shorten = false); + + }; diff --git a/src/main.cc b/src/main.cc index b6c7339..98b159e 100644 --- a/src/main.cc +++ b/src/main.cc @@ -45,13 +45,20 @@ int main() { // std::cout << AllCases::get_basic_ranges() << std::endl; - std::cout << CommonCode::check(0x123456789) << std::endl; - std::cout << CommonCode::check(0x4FEA13400) << std::endl; +// std::cout << CommonCode::check(0x123456789) << std::endl; +// std::cout << CommonCode::check(0x4FEA13400) << std::endl; +// +// // TODO: should we return a CommonCode object like String::new(...) in rust? +// printf("%09lX\n", CommonCode::from_string("1A9bF0c0")); +// std::cout << CommonCode::to_string(0x1A9BF0C00) << std::endl; +// std::cout << CommonCode::to_string(0x1A9BF0C00, true) << std::endl; + + auto c = CommonCode::from_string("1A9bF0c0"); + std::cout << c.to_string(true) << std::endl; + std::cout << c.to_string() << std::endl; + printf("%09lX\n", c.unwrap()); - // TODO: should we return a CommonCode object like String::new(...) in rust? - printf("%09lX\n", CommonCode::from_string("1A9bF0c0")); - std::cout << CommonCode::to_string(0x1A9BF0C00) << std::endl; - std::cout << CommonCode::to_string(0x1A9BF0C00, true) << std::endl; + std::cout << CommonCode(0x1A9BF0C00).to_string() << std::endl; return 0; }