From 24961cc32c397cb781a18ac7a9a43818eed2fda1 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 4 May 2024 14:58:04 +0800 Subject: [PATCH] refactor: project structure of short code --- src/core/CMakeLists.txt | 6 +- src/core/short_code/inline_impl.h | 56 -------- src/core/short_code/{ => internal}/convert.cc | 22 +--- .../short_code/{ => internal}/offset/basic.h | 12 +- .../{ => internal}/offset/range_prefix.h | 10 +- .../offset/range_prefix/offset_0x0.inc | 0 .../offset/range_prefix/offset_0x1.inc | 0 .../offset/range_prefix/offset_0x2.inc | 0 .../offset/range_prefix/offset_0x4.inc | 0 .../offset/range_prefix/offset_0x5.inc | 0 .../offset/range_prefix/offset_0x6.inc | 0 .../offset/range_prefix/offset_0x8.inc | 0 .../offset/range_prefix/offset_0x9.inc | 0 .../offset/range_prefix/offset_0xA.inc | 0 .../offset/range_prefix/offset_0xC.inc | 0 .../offset/range_prefix/offset_0xD.inc | 0 .../offset/range_prefix/offset_0xE.inc | 0 .../short_code/{ => internal}/serialize.cc | 26 ++-- .../{ => internal}/serialize_chars.h | 11 +- src/core/short_code/internal/short_code.inl | 120 +++++++++++++++++ src/core/short_code/short_code.cc | 24 ---- src/core/short_code/short_code.h | 121 +++++++++++++----- src/core/short_code/sundry.cc | 71 ---------- 23 files changed, 242 insertions(+), 237 deletions(-) delete mode 100644 src/core/short_code/inline_impl.h rename src/core/short_code/{ => internal}/convert.cc (87%) rename src/core/short_code/{ => internal}/offset/basic.h (99%) rename src/core/short_code/{ => internal}/offset/range_prefix.h (85%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0x0.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0x1.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0x2.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0x4.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0x5.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0x6.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0x8.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0x9.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0xA.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0xC.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0xD.inc (100%) rename src/core/short_code/{ => internal}/offset/range_prefix/offset_0xE.inc (100%) rename src/core/short_code/{ => internal}/serialize.cc (54%) rename src/core/short_code/{ => internal}/serialize_chars.h (88%) create mode 100644 src/core/short_code/internal/short_code.inl delete mode 100644 src/core/short_code/short_code.cc delete mode 100644 src/core/short_code/sundry.cc diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c24ee9e..e81a413 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -16,10 +16,8 @@ set(KLOTSKI_CORE_SRC raw_code/internal/sundry.cc raw_code/internal/mirror.cc - short_code/convert.cc - short_code/serialize.cc - short_code/short_code.cc - short_code/sundry.cc + short_code/internal/convert.cc + short_code/internal/serialize.cc ) add_library(klotski_core STATIC ${KLOTSKI_CORE_SRC}) diff --git a/src/core/short_code/inline_impl.h b/src/core/short_code/inline_impl.h deleted file mode 100644 index 8eda2d7..0000000 --- a/src/core/short_code/inline_impl.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -namespace klotski { -namespace codec { - -/// Get the original 32-bit code. -inline uint32_t ShortCode::unwrap() const noexcept { - return code_; -} - -/// Implicit conversion to 32-bit code. -inline ShortCode::operator uint32_t() const noexcept { - return code_; -} - -/// Equality comparison between ShortCode and numbers. -inline bool operator==(ShortCode s1, uint32_t s2) noexcept { - return s1.unwrap() == s2; -} - -/// ShortCode equal comparison implement. -inline bool operator==(ShortCode s1, ShortCode s2) noexcept { - return s1.unwrap() == s2.unwrap(); -} - -/// ShortCode less than comparison implement. -inline bool operator<(ShortCode s1, ShortCode s2) noexcept { - return s1.unwrap() < s2.unwrap(); -} - -/// ShortCode greater than comparison implement. -inline bool operator>(ShortCode s1, ShortCode s2) noexcept { - return s1.unwrap() > s2.unwrap(); -} - -/// ShortCode create without any check. -inline ShortCode ShortCode::unsafe_create(uint32_t short_code) noexcept { - return *reinterpret_cast(&short_code); // init directly -} - -/// ShortCode create with valid check. -inline std::optional ShortCode::create(uint32_t short_code) noexcept { - if (!ShortCode::check(short_code)) { - return std::nullopt; // invalid short code - } - return ShortCode::unsafe_create(short_code); -} - -/// Output string encoding of ShortCode. -inline std::ostream& operator<<(std::ostream &out, ShortCode self) { - out << ShortCode::string_encode(self.code_); - return out; -} - -} // namespace codec -} // namespace klotski diff --git a/src/core/short_code/convert.cc b/src/core/short_code/internal/convert.cc similarity index 87% rename from src/core/short_code/convert.cc rename to src/core/short_code/internal/convert.cc index b057672..2da6328 100644 --- a/src/core/short_code/convert.cc +++ b/src/core/short_code/internal/convert.cc @@ -1,18 +1,17 @@ #include -#include "short_code.h" + #include "offset/basic.h" #include "offset/range_prefix.h" +#include "short_code/short_code.h" using klotski::cases::AllCases; +using klotski::codec::ShortCode; using klotski::cases::BasicRanges; using klotski::codec::offset::ALL_CASES_OFFSET; using klotski::codec::offset::BASIC_RANGES_OFFSET; using klotski::codec::offset::RANGE_PREFIX_OFFSET; -namespace klotski { -namespace codec { - /// FIXME: temporarily used to implement tidy conversion static uint32_t check_range(uint32_t head, uint32_t range) noexcept { /// M_1x1 | M_1x2 | M_2x1 | M_2x2 @@ -52,23 +51,20 @@ static uint32_t check_range(uint32_t head, uint32_t range) noexcept { return 0; // pass check } -/// Convert CommonCode to ShortCode based on AllCases data. -uint32_t ShortCode::fast_encode(uint64_t common_code) noexcept { +uint32_t ShortCode::fast_encode(uint64_t common_code) { auto head = common_code >> 32; auto &ranges = AllCases::instance().fetch()[head]; // match available ranges auto target = std::lower_bound(ranges.begin(), ranges.end(), (uint32_t)common_code); return ALL_CASES_OFFSET[head] + (target - ranges.begin()); } -/// Convert ShortCode to CommonCode based on AllCases data. -uint64_t ShortCode::fast_decode(uint32_t short_code) noexcept { +uint64_t ShortCode::fast_decode(uint32_t short_code) { auto offset = std::upper_bound(ALL_CASES_OFFSET, ALL_CASES_OFFSET + 16, short_code) - 1; uint64_t head = offset - ALL_CASES_OFFSET; return (head << 32) | AllCases::instance().fetch()[head][short_code - *offset]; } -/// Convert CommonCode to ShortCode based on BasicRanges data. -uint32_t ShortCode::tiny_encode(uint64_t common_code) noexcept { +uint32_t ShortCode::tiny_encode(uint64_t common_code) { uint32_t head = common_code >> 32; uint32_t prefix = (common_code >> 20) & 0xFFF; @@ -93,8 +89,7 @@ uint32_t ShortCode::tiny_encode(uint64_t common_code) noexcept { return ALL_CASES_OFFSET[head] + RANGE_PREFIX_OFFSET[head][prefix] + offset; } -/// NOTE: ensure that input short code is valid! -uint64_t ShortCode::tiny_decode(uint32_t short_code) noexcept { // short code --> common code +uint64_t ShortCode::tiny_decode(uint32_t short_code) { // short code --> common code auto offset = std::upper_bound(ALL_CASES_OFFSET, ALL_CASES_OFFSET + 16, short_code) - 1; auto head = offset - ALL_CASES_OFFSET; // head index short_code -= *offset; @@ -118,6 +113,3 @@ uint64_t ShortCode::tiny_decode(uint32_t short_code) noexcept { // short code -- } return (uint64_t)head << 32 | range_reverse(basic_ranges[index]); } - -} // namespace codec -} // namespace klotski diff --git a/src/core/short_code/offset/basic.h b/src/core/short_code/internal/offset/basic.h similarity index 99% rename from src/core/short_code/offset/basic.h rename to src/core/short_code/internal/offset/basic.h index 3c9dcce..72ed0de 100644 --- a/src/core/short_code/offset/basic.h +++ b/src/core/short_code/internal/offset/basic.h @@ -2,16 +2,14 @@ #include -namespace klotski { -namespace codec { -namespace offset { +namespace klotski::codec::offset { /// This is the head index, the offset [0, 29334498) in all cases is obtained /// according to the `head` (0 ~ 15). In other words, the short code range can /// be obtained according to the position of the 2x2 block. // TODO: using std::array -const uint32_t ALL_CASES_OFFSET[16] = { +constexpr uint32_t ALL_CASES_OFFSET[16] { 0, 2942906, 5203298, 8146204, 8146204, 10468254, 12345199, 14667249, 14667249, 16989299, 18866244, 21188294, @@ -23,7 +21,7 @@ const uint32_t ALL_CASES_OFFSET[16] = { /// 32-bit `range`. // TODO: using std::array -const uint32_t BASIC_RANGES_OFFSET[4096] = { +constexpr uint32_t BASIC_RANGES_OFFSET[4096] { 0, 18272, 24960, 31648, 49920, 56608, 59056, 61504, 68192, 74880, 77328, 79776, 86464, 104736, 111424, 118112, 136384, 143072, 145520, 147968, 154656, 157104, 158000, 158896, @@ -538,6 +536,4 @@ const uint32_t BASIC_RANGES_OFFSET[4096] = { 7253514, 7259861, 7261646, 7263431, 7268677, 7286266, 7291512, 7296758, }; -} // namespace offset -} // namespace codec -} // namespace klotski +} // namespace klotski::codec::offset diff --git a/src/core/short_code/offset/range_prefix.h b/src/core/short_code/internal/offset/range_prefix.h similarity index 85% rename from src/core/short_code/offset/range_prefix.h rename to src/core/short_code/internal/offset/range_prefix.h index a6730f3..6747994 100644 --- a/src/core/short_code/offset/range_prefix.h +++ b/src/core/short_code/internal/offset/range_prefix.h @@ -7,12 +7,10 @@ #include -namespace klotski { -namespace codec { -namespace offset { +namespace klotski::codec::offset { // TODO: using std::array -const uint32_t RANGE_PREFIX_OFFSET[16][4096] = {{ +constexpr uint32_t RANGE_PREFIX_OFFSET[16][4096] = {{ #include "range_prefix/offset_0x0.inc" }, { #include "range_prefix/offset_0x1.inc" @@ -46,6 +44,4 @@ const uint32_t RANGE_PREFIX_OFFSET[16][4096] = {{ /// --------------- 0xF --------------- }}; -} // namespace offset -} // namespace codec -} // namespace klotski +} // namespace klotski::codec::offset diff --git a/src/core/short_code/offset/range_prefix/offset_0x0.inc b/src/core/short_code/internal/offset/range_prefix/offset_0x0.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0x0.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0x0.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0x1.inc b/src/core/short_code/internal/offset/range_prefix/offset_0x1.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0x1.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0x1.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0x2.inc b/src/core/short_code/internal/offset/range_prefix/offset_0x2.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0x2.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0x2.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0x4.inc b/src/core/short_code/internal/offset/range_prefix/offset_0x4.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0x4.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0x4.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0x5.inc b/src/core/short_code/internal/offset/range_prefix/offset_0x5.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0x5.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0x5.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0x6.inc b/src/core/short_code/internal/offset/range_prefix/offset_0x6.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0x6.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0x6.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0x8.inc b/src/core/short_code/internal/offset/range_prefix/offset_0x8.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0x8.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0x8.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0x9.inc b/src/core/short_code/internal/offset/range_prefix/offset_0x9.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0x9.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0x9.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0xA.inc b/src/core/short_code/internal/offset/range_prefix/offset_0xA.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0xA.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0xA.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0xC.inc b/src/core/short_code/internal/offset/range_prefix/offset_0xC.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0xC.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0xC.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0xD.inc b/src/core/short_code/internal/offset/range_prefix/offset_0xD.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0xD.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0xD.inc diff --git a/src/core/short_code/offset/range_prefix/offset_0xE.inc b/src/core/short_code/internal/offset/range_prefix/offset_0xE.inc similarity index 100% rename from src/core/short_code/offset/range_prefix/offset_0xE.inc rename to src/core/short_code/internal/offset/range_prefix/offset_0xE.inc diff --git a/src/core/short_code/serialize.cc b/src/core/short_code/internal/serialize.cc similarity index 54% rename from src/core/short_code/serialize.cc rename to src/core/short_code/internal/serialize.cc index 2e93a9b..2795ca3 100644 --- a/src/core/short_code/serialize.cc +++ b/src/core/short_code/internal/serialize.cc @@ -1,26 +1,25 @@ -#include "short_code.h" #include "serialize_chars.h" +#include "short_code/short_code.h" -namespace klotski { -namespace codec { +using klotski::codec::ShortCode; -std::string ShortCode::string_encode(uint32_t short_code) noexcept { // encode as 5-bits string - char result[6]; // short code length 5 +std::string ShortCode::string_encode(uint32_t short_code) { + char result[6]; result[5] = '\0'; // string ending flag for (int n = 0; n < 5; ++n) { - result[4 - n] = SHORT_CODE_TABLE[short_code & 0b11111]; // aka _ % 32 - short_code >>= 5; // aka _ / 32 + result[4 - n] = SHORT_CODE_TABLE[short_code & 0b11111]; + short_code >>= 5; } return result; } -std::optional ShortCode::string_decode(const std::string &short_code) noexcept { // 5-bits string decode - if (short_code.length() != 5) { // check string length - return std::nullopt; +std::optional ShortCode::string_decode(const std::string &short_code) { + if (short_code.length() != 5) { + return std::nullopt; // invalid string length } uint64_t result = 0; for (auto bit : short_code) { - result <<= 5; // aka _ * 32 + result <<= 5; if (bit >= 'a' && bit <= 'z') { bit -= 32; // convert to uppercase } @@ -32,11 +31,8 @@ std::optional ShortCode::string_decode(const std::string &short_code) return std::nullopt; } } - if (!ShortCode::check(result)) { // check converted short code + if (!check(result)) { // check converted short code return std::nullopt; } return result; // apply convert result } - -} // namespace codec -} // namespace klotski diff --git a/src/core/short_code/serialize_chars.h b/src/core/short_code/internal/serialize_chars.h similarity index 88% rename from src/core/short_code/serialize_chars.h rename to src/core/short_code/internal/serialize_chars.h index 2a587da..07b1234 100644 --- a/src/core/short_code/serialize_chars.h +++ b/src/core/short_code/internal/serialize_chars.h @@ -17,10 +17,9 @@ #include -namespace klotski { -namespace codec { +namespace klotski::codec { -const int8_t SHORT_CODE_TABLE[32] = { +constexpr 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` @@ -28,8 +27,7 @@ const int8_t SHORT_CODE_TABLE[32] = { 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', }; -/// `1`(49) ~ `Z`(90) -const int8_t SHORT_CODE_TABLE_REV[42] = { +constexpr 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) @@ -37,5 +35,4 @@ const int8_t SHORT_CODE_TABLE_REV[42] = { 26, 27, 28, 29, 30, 31, // `U`(85) ~ `Z`(90) }; -} // namespace codec -} // namespace klotski +} // namespace klotski::codec diff --git a/src/core/short_code/internal/short_code.inl b/src/core/short_code/internal/short_code.inl new file mode 100644 index 0000000..7807161 --- /dev/null +++ b/src/core/short_code/internal/short_code.inl @@ -0,0 +1,120 @@ +#pragma once + +#include + +#include "common_code/common_code.h" + +namespace klotski::codec { + +// ------------------------------------------------------------------------------------- // + +inline ShortCode::ShortCode(const CommonCode common_code) { + // TODO: test the affect of CPU branch prediction. + if (cases::AllCases::instance().is_available()) { + code_ = fast_encode(common_code.unwrap()); + } else { + code_ = tiny_encode(common_code.unwrap()); + } +} + +inline ShortCode ShortCode::unsafe_create(const uint32_t short_code) { + return std::bit_cast(short_code); // init directly +} + +inline std::optional ShortCode::create(const uint32_t short_code) { + if (!check(short_code)) { + return std::nullopt; // invalid short code + } + return unsafe_create(short_code); +} + +// ------------------------------------------------------------------------------------- // + +inline ShortCode::operator uint32_t() const { + return code_; +} + +inline bool ShortCode::check(const uint32_t short_code) { + return short_code < SHORT_CODE_LIMIT; // [0, SHORT_CODE_LIMIT) +} + +inline void ShortCode::speed_up(const bool fast_mode) { + if (fast_mode) { + cases::AllCases::instance().build(); + } else { + cases::BasicRanges::instance().build(); + } +} + +#ifndef KLSK_NDEBUG +inline std::ostream& operator<<(std::ostream &out, const ShortCode self) { + out << ShortCode::string_encode(self.code_); + return out; +} +#endif + +// ----------------------------------------------------------------------------------------- // + +inline uint32_t ShortCode::unwrap() const { + return code_; +} + +inline std::string ShortCode::to_string() const { + return string_encode(code_); +} + +inline CommonCode ShortCode::to_common_code() const { + // TODO: test the affect of CPU branch prediction. + if (cases::AllCases::instance().is_available()) { + return CommonCode::unsafe_create(fast_decode(code_)); + } + return CommonCode::unsafe_create(tiny_decode(code_)); +} + +// ----------------------------------------------------------------------------------------- // + +inline std::optional ShortCode::from_string(const std::string &short_code) { + return string_decode(short_code).transform(unsafe_create); +} + +// ----------------------------------------------------------------------------------------- // + +inline ShortCode ShortCode::from_common_code(const CommonCode common_code) { + return common_code.to_short_code(); +} + +inline std::optional ShortCode::from_common_code(const uint64_t common_code) { + const auto convert = [](const CommonCode code) { + return code.to_short_code(); + }; + return CommonCode::create(common_code).transform(convert); +} + +inline std::optional ShortCode::from_common_code(const std::string &common_code) { + const auto convert = [](const CommonCode code) { + return code.to_short_code(); + }; + return CommonCode::from_string(common_code).transform(convert); +} + +// ------------------------------------------------------------------------------------- // + +constexpr auto operator==(const ShortCode &lhs, const uint32_t rhs) { + return lhs.code_ == rhs; +} + +constexpr auto operator<=>(const ShortCode &lhs, const uint32_t rhs) { + return lhs.code_ <=> rhs; +} + +constexpr auto operator==(const ShortCode &lhs, const ShortCode &rhs) { + return lhs.code_ == rhs.code_; +} + +constexpr auto operator<=>(const ShortCode &lhs, const ShortCode &rhs) { + return lhs.code_ <=> rhs.code_; +} + +// ----------------------------------------------------------------------------------------- // + +} // namespace klotski::codec diff --git a/src/core/short_code/short_code.cc b/src/core/short_code/short_code.cc deleted file mode 100644 index b2a8d7b..0000000 --- a/src/core/short_code/short_code.cc +++ /dev/null @@ -1,24 +0,0 @@ -#include "all_cases.h" -#include "short_code.h" - -using klotski::cases::AllCases; -using klotski::cases::BasicRanges; - -namespace klotski { -namespace codec { - -/// Check the validity of the original ShortCode. -bool ShortCode::check(uint32_t short_code) noexcept { - return short_code < SHORT_CODE_LIMIT; // 0 ~ (SHORT_CODE_LIMIT - 1) -} - -void ShortCode::speed_up(bool fast_mode) noexcept { - if (fast_mode) { - AllCases::instance().build(); - } else { - BasicRanges::instance().build(); - } -} - -} // namespace codec -} // namespace klotski diff --git a/src/core/short_code/short_code.h b/src/core/short_code/short_code.h index 85d4fef..9a6d5d8 100644 --- a/src/core/short_code/short_code.h +++ b/src/core/short_code/short_code.h @@ -1,4 +1,4 @@ -#pragma once +/// Klotski Engine by Dnomd343 @2024 /// ShortCode is a high-compression encoding scheme based on CommonCode. Since /// there are a total of 29334498 valid klotski cases, arrange then from small @@ -66,58 +66,119 @@ /// => "AXCZN" /// /// -------------------------------------------------------------------------------------------- /// +#pragma once + #include #include #include #include -#include "all_cases.h" -namespace klotski { -namespace codec { +#include "all_cases/all_cases.h" + +namespace klotski::codec { constexpr uint32_t SHORT_CODE_LIMIT = cases::ALL_CASES_NUM_; class CommonCode; + class ShortCode { public: - explicit operator uint32_t() const noexcept; - static bool check(uint32_t short_code) noexcept; - static void speed_up(bool fast_mode = false) noexcept; + // ------------------------------------------------------------------------------------- // + + ShortCode() = delete; + + /// Construct ShortCode from CommonCode. + explicit ShortCode(CommonCode common_code); + + /// Create ShortCode without any check. + static ShortCode unsafe_create(uint32_t short_code); + + /// Create ShortCode with validity check. + static std::optional create(uint32_t short_code); + + // ------------------------------------------------------------------------------------- // + + /// Explicit conversion to u32 code. + explicit operator uint32_t() const; + + /// Check the validity of the original ShortCode. + static bool check(uint32_t short_code); + + /// Build the conversion index for ShortCode. + static void speed_up(bool fast_mode = false); + +#ifndef KLSK_NDEBUG + /// Output string encoding of ShortCode only for debug. friend std::ostream& operator<<(std::ostream &out, ShortCode self); +#endif - [[nodiscard]] uint32_t unwrap() const noexcept; - [[nodiscard]] std::string to_string() const noexcept; - [[nodiscard]] CommonCode to_common_code() const noexcept; + // ------------------------------------------------------------------------------------- // -public: - ShortCode() = delete; - explicit ShortCode(CommonCode common_code) noexcept; + /// Get the original u32 code. + [[nodiscard]] uint32_t unwrap() const; + + /// Convert ShortCode to string form. + [[nodiscard]] std::string to_string() const; + + /// Convert ShortCode to CommonCode. + [[nodiscard]] CommonCode to_common_code() const; + + // ------------------------------------------------------------------------------------- // + + /// Create ShortCode from string form. + static std::optional from_string(const std::string &short_code); + + // ------------------------------------------------------------------------------------- // + + /// Create ShortCode from CommonCode. + static ShortCode from_common_code(CommonCode common_code); + + /// Create ShortCode from CommonCode in u64. + static std::optional from_common_code(uint64_t common_code); - static ShortCode unsafe_create(uint32_t short_code) noexcept; - static std::optional create(uint32_t short_code) noexcept; + /// Create ShortCode from CommonCode in string form. + static std::optional from_common_code(const std::string &common_code); - static std::optional from_string(std::string &&short_code) noexcept; - static std::optional from_string(const std::string &short_code) noexcept; + // ------------------------------------------------------------------------------------- // - static ShortCode from_common_code(CommonCode common_code) noexcept; - static std::optional from_common_code(uint64_t common_code) noexcept; - static std::optional from_common_code(std::string &&common_code) noexcept; - static std::optional from_common_code(const std::string &common_code) noexcept; + /// Compare ShortCode with u32 value. + friend constexpr auto operator==(const ShortCode &lhs, uint32_t rhs); + friend constexpr auto operator<=>(const ShortCode &lhs, uint32_t rhs); + + /// Compare the original values of two ShortCodes. + friend constexpr auto operator==(const ShortCode &lhs, const ShortCode &rhs); + friend constexpr auto operator<=>(const ShortCode &lhs, const ShortCode &rhs); + + // ------------------------------------------------------------------------------------- // private: uint32_t code_; - static uint64_t fast_decode(uint32_t short_code) noexcept; - static uint32_t fast_encode(uint64_t common_code) noexcept; + // ------------------------------------------------------------------------------------- // + + /// Convert ShortCode to CommonCode based on AllCases data. + static uint64_t fast_decode(uint32_t short_code); + + /// Convert CommonCode to ShortCode based on AllCases data. + static uint32_t fast_encode(uint64_t common_code); + + /// Convert ShortCode to CommonCode based on BasicRanges data. + static uint64_t tiny_decode(uint32_t short_code); + + /// Convert CommonCode to ShortCode based on BasicRanges data. + static uint32_t tiny_encode(uint64_t common_code); + + // ------------------------------------------------------------------------------------- // + + /// Serialize ShortCode into 5-bit length string. + static std::string string_encode(uint32_t short_code); - static uint64_t tiny_decode(uint32_t short_code) noexcept; - static uint32_t tiny_encode(uint64_t common_code) noexcept; + /// Deserialize ShortCode from string and return nullopt on error. + static std::optional string_decode(const std::string &short_code); - static std::string string_encode(uint32_t short_code) noexcept; - static std::optional string_decode(const std::string &short_code) noexcept; + // ------------------------------------------------------------------------------------- // }; -} // namespace codec -} // namespace klotski +} // namespace klotski::codec -#include "inline_impl.h" +#include "internal/short_code.inl" diff --git a/src/core/short_code/sundry.cc b/src/core/short_code/sundry.cc deleted file mode 100644 index ccf7c5d..0000000 --- a/src/core/short_code/sundry.cc +++ /dev/null @@ -1,71 +0,0 @@ -#include "short_code.h" -#include "common_code.h" - -using klotski::cases::AllCases; - -namespace klotski { -namespace codec { - -// ----------------------------------------------------------------------------------------- // - -ShortCode::ShortCode(CommonCode common_code) noexcept { - if (AllCases::instance().is_available()) { - code_ = fast_encode(common_code.unwrap()); - } else { - code_ = tiny_encode(common_code.unwrap()); - } -} - -// ----------------------------------------------------------------------------------------- // - -std::string ShortCode::to_string() const noexcept { - return string_encode(code_); -} - -CommonCode ShortCode::to_common_code() const noexcept { - if (AllCases::instance().is_available()) { - return CommonCode::unsafe_create(fast_decode(code_)); - } - return CommonCode::unsafe_create(tiny_decode(code_)); -} - -// ----------------------------------------------------------------------------------------- // - -std::optional ShortCode::from_string(std::string &&short_code) noexcept { - return ShortCode::from_string(short_code); -} - -std::optional ShortCode::from_string(const std::string &short_code) noexcept { - return ShortCode::string_decode(short_code).transform([](auto code) { - return ShortCode::unsafe_create(code); - }); -} - -// ----------------------------------------------------------------------------------------- // - -ShortCode ShortCode::from_common_code(CommonCode common_code) noexcept { - return common_code.to_short_code(); -} - -std::optional ShortCode::from_common_code(uint64_t common_code) noexcept { - return CommonCode::create(common_code).transform([](auto common_code) { - return common_code.to_short_code(); - }); -} - -std::optional ShortCode::from_common_code(std::string &&common_code) noexcept { - return CommonCode::from_string(std::move(common_code)).transform([](auto common_code) { - return common_code.to_short_code(); - }); -} - -std::optional ShortCode::from_common_code(const std::string &common_code) noexcept { - return CommonCode::from_string(common_code).transform([](auto common_code) { - return common_code.to_short_code(); - }); -} - -// ----------------------------------------------------------------------------------------- // - -} // namespace codec -} // namespace klotski