diff --git a/src/klotski_core/short_code/convert.cc b/src/klotski_core/short_code/convert.cc index 83be7f3..1fac5ad 100644 --- a/src/klotski_core/short_code/convert.cc +++ b/src/klotski_core/short_code/convert.cc @@ -12,26 +12,26 @@ using klotski::CommonCode; CommonCode ShortCode::to_common_code() const noexcept { if (ShortCode::mode() == ShortCode::NORMAL) { - return CommonCode::unsafe_create(tiny_decode(code)); // normal mode + return CommonCode::unsafe_create(tiny_decode(code_)); // normal mode } - return CommonCode::unsafe_create(fast_decode(code)); // fast mode + return CommonCode::unsafe_create(fast_decode(code_)); // fast mode } /// ------------------------- ShortCode to CommonCode ------------------------- ShortCode::ShortCode(CommonCode &&common_code) noexcept { if (ShortCode::mode() == ShortCode::NORMAL) { - code = tiny_encode(common_code.unwrap()); // normal mode + code_ = tiny_encode(common_code.unwrap()); // normal mode } else { - code = fast_encode(common_code.unwrap()); // fast mode + code_ = fast_encode(common_code.unwrap()); // fast mode } } ShortCode::ShortCode(const CommonCode &common_code) noexcept { if (ShortCode::mode() == ShortCode::NORMAL) { - code = tiny_encode(common_code.unwrap()); // normal mode + code_ = tiny_encode(common_code.unwrap()); // normal mode } else { - code = fast_encode(common_code.unwrap()); // fast mode + code_ = fast_encode(common_code.unwrap()); // fast mode } } diff --git a/src/klotski_core/short_code/serialize.cc b/src/klotski_core/short_code/serialize.cc index 07f977e..e502f15 100644 --- a/src/klotski_core/short_code/serialize.cc +++ b/src/klotski_core/short_code/serialize.cc @@ -7,17 +7,17 @@ using klotski::ShortCodeException; /// --------------------------- ShortCode to String --------------------------- std::string ShortCode::to_string() const noexcept { // encode as 5-bits string - return string_encode(code); + return string_encode(code_); } /// --------------------------- String to ShortCode --------------------------- ShortCode::ShortCode(std::string &&short_code) { - code = string_decode(short_code); + code_ = string_decode(short_code); } ShortCode::ShortCode(const std::string &short_code) { - code = string_decode(short_code); + code_ = string_decode(short_code); } ShortCode ShortCode::from_string(std::string &&short_code) { diff --git a/src/klotski_core/short_code/serialize_chars.h b/src/klotski_core/short_code/serialize_chars.h index 570fa37..e352a13 100644 --- a/src/klotski_core/short_code/serialize_chars.h +++ b/src/klotski_core/short_code/serialize_chars.h @@ -1,22 +1,39 @@ #pragma once +/// ShortCode Convert Table +/// ------------------------------------------------- +/// | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | +/// | `1` | `2` | `3` | `4` | `5` | `6` | `7` | `8` | +/// |-----------------------------------------------| +/// | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | +/// | `9` | `A` | `B` | `C` | `D` | `E` | `F` | `G` | +/// |-----------------------------------------------| +/// | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | +/// | `H` | `J` | `K` | `M` | `N` | `P` | `Q` | `R` | +/// |-----------------------------------------------| +/// | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | +/// | `S` | `T` | `U` | `V` | `W` | `X` | `Y` | `Z` | +/// ------------------------------------------------- + #include namespace klotski { - const int8_t SHORT_CODE_TABLE[32] = { - '1', '2', '3', '4', '5', '6', '7', '8', '9', // skip `0` - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // skip `I` - 'J', 'K', // skip `L` - 'M', 'N', // skip `O` - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - }; - /// `1`(49) ~ `Z`(90) - const int8_t SHORT_CODE_TABLE_REV[42] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, // `1`(49) ~ `9`(57) - -1, -1, -1, -1, -1, -1, -1, // `:`(58) ~ `@`(64) - 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, // `A`(65) ~ `J`(74) - 18, -1, 19, 20, -1, 21, 22, 23, 24, 25, // `K`(75) ~ `T`(84) - 26, 27, 28, 29, 30, 31, // `U`(85) ~ `Z`(90) - }; +const int8_t SHORT_CODE_TABLE[32] = { + '1', '2', '3', '4', '5', '6', '7', '8', '9', // skip `0` + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // skip `I` + 'J', 'K', // skip `L` + 'M', 'N', // skip `O` + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', +}; + +/// `1`(49) ~ `Z`(90) +const int8_t SHORT_CODE_TABLE_REV[42] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, // `1`(49) ~ `9`(57) + -1, -1, -1, -1, -1, -1, -1, // `:`(58) ~ `@`(64) + 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, // `A`(65) ~ `J`(74) + 18, -1, 19, 20, -1, 21, 22, 23, 24, 25, // `K`(75) ~ `T`(84) + 26, 27, 28, 29, 30, 31, // `U`(85) ~ `Z`(90) +}; + } diff --git a/src/klotski_core/short_code/short_code.cc b/src/klotski_core/short_code/short_code.cc index c93d85c..99df07a 100644 --- a/src/klotski_core/short_code/short_code.cc +++ b/src/klotski_core/short_code/short_code.cc @@ -1,63 +1,35 @@ #include "all_cases.h" #include "short_code.h" -using klotski::ShortCode; - -bool ShortCode::fast_mode_available = false; -bool ShortCode::normal_mode_available = false; - -namespace std { - template<> - struct hash { - std::size_t operator()(const klotski::ShortCode &c) const { - return std::hash()(c.unwrap()); - } - }; - - template<> - struct equal_to { - bool operator()(const klotski::ShortCode &c1, const klotski::ShortCode &c2) const { - return c1.unwrap() == c2.unwrap(); - } - }; -} - namespace klotski { - bool ShortCode::operator==(const ShortCode &short_code) const noexcept { - return this->code == short_code.code; - } - bool ShortCode::operator!=(const ShortCode &short_code) const noexcept { - return this->code != short_code.code; - } +bool ShortCode::fast_mode_available_ = false; +bool ShortCode::normal_mode_available_ = false; - std::ostream& operator<<(std::ostream &out, const ShortCode &self) { - out << self.to_string() << "(" << self.code << ")"; // short code info - return out; - } +bool ShortCode::valid() const noexcept { + return ShortCode::check(code_); } -namespace klotski { - bool ShortCode::valid() const noexcept { - return ShortCode::check(code); - } +ShortCode ShortCode::create(uint32_t short_code) { + return ShortCode(short_code); +} - ShortCode ShortCode::create(uint32_t short_code) { - return ShortCode(short_code); - } +ShortCode ShortCode::unsafe_create(uint32_t short_code) noexcept { // create without check + auto tmp = ShortCode(); // init directly + tmp.code_ = short_code; + return tmp; +} - ShortCode ShortCode::unsafe_create(uint32_t short_code) noexcept { // create without check - auto tmp = ShortCode(); // init directly - tmp.code = short_code; - return tmp; +ShortCode::ShortCode(uint32_t short_code) { + if (!ShortCode::check(short_code)) { // check input short code + throw klotski::ShortCodeException("short code invalid"); } + code_ = short_code; +} - ShortCode::ShortCode(uint32_t short_code) { - if (!ShortCode::check(short_code)) { // check input short code - throw klotski::ShortCodeException("short code invalid"); - } - code = short_code; - } +std::ostream& operator<<(std::ostream &out, const ShortCode &self) { + out << self.to_string() << "(" << self.code_ << ")"; // short code info + return out; } bool ShortCode::check(uint32_t short_code) noexcept { @@ -65,25 +37,27 @@ bool ShortCode::check(uint32_t short_code) noexcept { } ShortCode::Mode ShortCode::mode() { // ensure speed up enabled and return current mode - if (fast_mode_available) { + if (fast_mode_available_) { return ShortCode::FAST; // fast mode already enabled } - if (normal_mode_available) { + if (normal_mode_available_) { return ShortCode::NORMAL; // normal mode already enabled } speed_up(ShortCode::Mode::NORMAL); // uninitialized -> enable normal mode - return ShortCode::Mode::NORMAL; // normal mode enabled + return ShortCode::Mode::NORMAL; } void ShortCode::speed_up(ShortCode::Mode mode) { - if (fast_mode_available) { + if (fast_mode_available_) { return; // fast mode already available } if (mode == ShortCode::FAST) { // build fast mode data AllCases::build(); // blocking function - fast_mode_available = true; - } else if (!normal_mode_available) { // build normal mode data + fast_mode_available_ = true; + } else if (!normal_mode_available_) { // build normal mode data BasicRanges::build(); // blocking function - normal_mode_available = true; + normal_mode_available_ = true; } } + +} // namespace klotski diff --git a/src/klotski_core/short_code/short_code.h b/src/klotski_core/short_code/short_code.h index 72c2eae..a8cdba4 100644 --- a/src/klotski_core/short_code/short_code.h +++ b/src/klotski_core/short_code/short_code.h @@ -2,7 +2,7 @@ /// ShortCode is a high-compression encoding scheme based on CommonCode. Since there /// are a total of 29334498 valid klotski layouts, arrange their CommonCodes from -/// small to large (36-bits positive integers), and use the index as the ShortCode. +/// small to large (36-bit positive integers), and use the index as the ShortCode. /// Therefore, the valid value of ShortCode is [0, 29334498), stored in `uint32_t`. /// The goal of high compression ratio is to facilitate verbal sharing, so it is @@ -11,21 +11,21 @@ /// and 26 characters, forming a private base32 scheme. /// Coincidentally, log(32, 29334498) is approximately equal to `4.96`, so using -/// 5-bits base32 can make good use of space, so any valid klotski layout can be -/// represented by a 5-bits length code. As in CommonCode, the characters here are +/// 5-bit base32 can make good use of space, so any valid klotski layout can be +/// represented by a 5-bit length code. As in CommonCode, the characters here are /// case insensitive, but uppercase is still recommended. -/// ShortCode Convert Table +/// ShortCode Convert Table /// ------------------------------------------------- /// | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | /// | `1` | `2` | `3` | `4` | `5` | `6` | `7` | `8` | -/// ------------------------------------------------- +/// |-----------------------------------------------| /// | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | /// | `9` | `A` | `B` | `C` | `D` | `E` | `F` | `G` | -/// ------------------------------------------------- +/// |-----------------------------------------------| /// | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | /// | `H` | `J` | `K` | `M` | `N` | `P` | `Q` | `R` | -/// ------------------------------------------------- +/// |-----------------------------------------------| /// | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | /// | `S` | `T` | `U` | `V` | `W` | `X` | `Y` | `Z` | /// ------------------------------------------------- @@ -51,85 +51,93 @@ #include #include #include -#include #include +#include #include "all_cases.h" #include "common_code.h" namespace klotski { - class CommonCode; // import for convert interface - - const uint32_t SHORT_CODE_LIMIT = klotski::ALL_CASES_SIZE_SUM; - - class ShortCodeException : public std::runtime_error { - public: - ShortCodeException() : std::runtime_error("invalid short code") {} - explicit ShortCodeException(const std::string &msg) : std::runtime_error(msg) {} - ~ShortCodeException() noexcept override = default; - }; - - class ShortCode { - public: - enum Mode {NORMAL, FAST}; - - private: - uint32_t code; - ShortCode() = default; // unsafe initialize - - static Mode mode(); - static bool fast_mode_available; - static bool normal_mode_available; - - static inline uint64_t fast_decode(uint32_t short_code) noexcept; // short code -> common code - static inline uint32_t fast_encode(uint64_t common_code) noexcept; // common code -> short code - static inline uint64_t tiny_decode(uint32_t short_code) noexcept; // short code -> common code - static inline uint32_t tiny_encode(uint64_t common_code) noexcept; // common code -> short code - - static inline std::string string_encode(uint32_t short_code) noexcept; // short code -> string - static inline uint32_t string_decode(const std::string &short_code); // string -> short code - - public: - /// ShortCode validity check - bool valid() const noexcept; - static bool check(uint32_t short_code) noexcept; - - /// ShortCode convert mode - static void speed_up(Mode mode); - - /// Operators of ShortCode - bool operator==(const ShortCode &short_code) const noexcept; - bool operator!=(const ShortCode &short_code) const noexcept; - constexpr explicit operator uint32_t() const noexcept { return code; } - friend std::ostream& operator<<(std::ostream &out, const ShortCode &self); - - /// Export functions - std::string to_string() const noexcept; - CommonCode to_common_code() const noexcept; - constexpr uint32_t unwrap() const noexcept { return code; } - - /// ShortCode constructors - explicit ShortCode(uint32_t short_code); - explicit ShortCode(std::string &&short_code); - explicit ShortCode(CommonCode &&common_code) noexcept; - explicit ShortCode(const std::string &short_code); - explicit ShortCode(const CommonCode &common_code) noexcept; - - /// Static initialization - static ShortCode create(uint32_t short_code); - static ShortCode unsafe_create(uint32_t short_code) noexcept; - - static ShortCode from_string(std::string &&short_code); - static ShortCode from_string(const std::string &short_code); - - static ShortCode from_common_code(uint64_t common_code); - static ShortCode from_common_code(CommonCode &&common_code) noexcept; - static ShortCode from_common_code(std::string &&common_code); - static ShortCode from_common_code(const CommonCode &common_code) noexcept; - static ShortCode from_common_code(const std::string &common_code); - }; - - inline bool operator==(uint32_t s1, const ShortCode &s2) noexcept { return s1 == s2.unwrap(); } - inline bool operator!=(uint32_t s1, const ShortCode &s2) noexcept { return s1 != s2.unwrap(); } - inline bool operator==(const ShortCode &s1, uint32_t s2) noexcept { return s1.unwrap() == s2; } - inline bool operator!=(const ShortCode &s1, uint32_t s2) noexcept { return s1.unwrap() != s2; } -} + +class CommonCode; + +const uint32_t SHORT_CODE_LIMIT = klotski::ALL_CASES_SIZE_SUM; + +class ShortCodeException : public std::runtime_error { +public: + ShortCodeException() : std::runtime_error("invalid short code") {} + explicit ShortCodeException(const std::string &msg) : std::runtime_error(msg) {} + ~ShortCodeException() noexcept override = default; +}; + +/// For ShortCode, you must choose at least one mode (NORMAL or FAST) to convert, and +/// they all need a certain amount of time to warm up. `NORMAL` warms up quickly, and +/// `FAST` is slower, but the conversion speed of `FAST` is much faster than `NORMAL`. +/// When only converting a small amount of codes, please choose NORMAL mode. Otherwise +/// FAST mode should be used. + +class ShortCode { +public: + enum Mode {NORMAL, FAST}; + +private: + uint32_t code_; + ShortCode() = default; // unsafe initialize + + static Mode mode(); + static bool fast_mode_available_; + static bool normal_mode_available_; + + static inline uint64_t fast_decode(uint32_t short_code) noexcept; // short code -> common code + static inline uint32_t fast_encode(uint64_t common_code) noexcept; // common code -> short code + static inline uint64_t tiny_decode(uint32_t short_code) noexcept; // short code -> common code + static inline uint32_t tiny_encode(uint64_t common_code) noexcept; // common code -> short code + + static inline uint32_t string_decode(const std::string &short_code); + static inline std::string string_encode(uint32_t short_code) noexcept; + +public: + /// Validity check + bool valid() const noexcept; + static bool check(uint32_t short_code) noexcept; + + /// ShortCode convert mode + static void speed_up(Mode mode); // {} -> {NORMAL} -> {FAST} + + /// Operators of ShortCode + constexpr explicit operator uint32_t() const noexcept { return code_; } + friend std::ostream& operator<<(std::ostream &out, const ShortCode &self); + + /// Export functions + std::string to_string() const noexcept; + CommonCode to_common_code() const noexcept; + constexpr uint32_t unwrap() const noexcept { return code_; } + + /// ShortCode constructors + explicit ShortCode(uint32_t short_code); + explicit ShortCode(std::string &&short_code); + explicit ShortCode(CommonCode &&common_code) noexcept; + explicit ShortCode(const std::string &short_code); + explicit ShortCode(const CommonCode &common_code) noexcept; + + /// Static initialization + static ShortCode create(uint32_t short_code); + static ShortCode unsafe_create(uint32_t short_code) noexcept; + + static ShortCode from_string(std::string &&short_code); + static ShortCode from_string(const std::string &short_code); + + static ShortCode from_common_code(uint64_t common_code); + static ShortCode from_common_code(CommonCode &&common_code) noexcept; + static ShortCode from_common_code(std::string &&common_code); + static ShortCode from_common_code(const CommonCode &common_code) noexcept; + static ShortCode from_common_code(const std::string &common_code); +}; + +inline bool operator==(uint32_t s1, const ShortCode &s2) noexcept { return s1 == s2.unwrap(); } +inline bool operator!=(uint32_t s1, const ShortCode &s2) noexcept { return s1 != s2.unwrap(); } +inline bool operator==(const ShortCode &s1, uint32_t s2) noexcept { return s1.unwrap() == s2; } +inline bool operator!=(const ShortCode &s1, uint32_t s2) noexcept { return s1.unwrap() != s2; } +inline bool operator==(const ShortCode &s1, const ShortCode &s2) noexcept { return s1.unwrap() == s2.unwrap(); } +inline bool operator!=(const ShortCode &s1, const ShortCode &s2) noexcept { return s1.unwrap() != s2.unwrap(); } + +} // namespace klotski