From 46bde9ec1d171ea27f7d946a9ae8c9ec46a16b08 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 4 May 2024 12:24:15 +0800 Subject: [PATCH] refactor: project structure of common code --- src/core/CMakeLists.txt | 6 +- src/core/common_code/common_code.h | 119 +++++++++++++----- src/core/common_code/inline_impl.h | 56 --------- .../common_code/{ => internal}/common_code.cc | 9 +- src/core/common_code/internal/common_code.inl | 71 +++++++++++ .../common_code/{ => internal}/serialize.cc | 15 +-- src/core/common_code/internal/sundry.cc | 61 +++++++++ src/core/common_code/sundry.cc | 86 ------------- 8 files changed, 232 insertions(+), 191 deletions(-) delete mode 100644 src/core/common_code/inline_impl.h rename src/core/common_code/{ => internal}/common_code.cc (91%) create mode 100644 src/core/common_code/internal/common_code.inl rename src/core/common_code/{ => internal}/serialize.cc (80%) create mode 100644 src/core/common_code/internal/sundry.cc delete mode 100644 src/core/common_code/sundry.cc diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9628e45..e7ebcd8 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -7,9 +7,9 @@ set(KLOTSKI_CORE_SRC all_cases/internal/basic_ranges.cc all_cases/internal/all_cases.cc - common_code/common_code.cc - common_code/serialize.cc - common_code/sundry.cc + common_code/internal/common_code.cc + common_code/internal/serialize.cc + common_code/internal/sundry.cc raw_code/raw_code.cc raw_code/convert.cc diff --git a/src/core/common_code/common_code.h b/src/core/common_code/common_code.h index fd2f67c..0d096e2 100644 --- a/src/core/common_code/common_code.h +++ b/src/core/common_code/common_code.h @@ -1,4 +1,4 @@ -#pragma once +/// Klotski Engine by Dnomd343 @2024 /// CommonCode is a generic klotski encoding that records an valid case using /// 36-bit lengths, and stored in a `uint64_t`. Since there is only one `2x2` @@ -16,8 +16,10 @@ /// which are `00` `01` `10` `11`. Arrange them according to their position and /// size, and we can get a binary sequence. /// -/// ( 2x2 -> # # ) | ( 2x1 -> # ) | ( 1x2 -> # # ) | ( 1x1 -> # ) -/// ( # # ) | ( # ) | | +/// -------------------------------------------------------- +/// | 2x2 -> # # | 2x1 -> # | 1x2 -> # # | 1x1 -> # | +/// | # # | # | | | +/// -------------------------------------------------------- /// This sequence can have up to 16 blocks, aka 32-bit in length. Therefore, in /// order to be compatible with all klotski cases, the length of this part of @@ -54,54 +56,111 @@ /// CommonCode = 0x4FEA13400 -> "4FEA134" /// /// ----------------------------------------------------------------------------------- /// +#pragma once + #include #include #include #include -namespace klotski { -namespace codec { +namespace klotski::codec { class RawCode; class ShortCode; + class CommonCode { public: - explicit operator uint64_t() const noexcept; - static bool check(uint64_t common_code) noexcept; + // ------------------------------------------------------------------------------------- // + + /// Explicit conversion to u64 code. + explicit operator uint64_t() const; + + /// Check the validity of the original CommonCode. + static bool check(uint64_t common_code); + + // TODO: add macro check here + /// Output string encoding of CommonCode only for debug. friend std::ostream& operator<<(std::ostream &out, CommonCode self); - [[nodiscard]] uint64_t unwrap() const noexcept; - [[nodiscard]] RawCode to_raw_code() const noexcept; - [[nodiscard]] ShortCode to_short_code() const noexcept; - [[nodiscard]] std::string to_string(bool shorten = false) const noexcept; + // ------------------------------------------------------------------------------------- // + + /// Get the original u64 code. + [[nodiscard]] uint64_t unwrap() const; + + /// Convert CommonCode to RawCode. + [[nodiscard]] RawCode to_raw_code() const; + + /// Convert CommonCode to ShortCode. + [[nodiscard]] ShortCode to_short_code() const; + + /// Convert CommonCode to string form. + [[nodiscard]] std::string to_string(bool shorten = false) const; + + // ------------------------------------------------------------------------------------- // -public: CommonCode() = delete; - explicit CommonCode(RawCode raw_code) noexcept; - explicit CommonCode(ShortCode short_code) noexcept; - static CommonCode unsafe_create(uint64_t common_code) noexcept; - static std::optional create(uint64_t common_code) noexcept; + /// Construct CommonCode from RawCode. + explicit CommonCode(RawCode raw_code); + + /// Construct CommonCode from ShortCode. + explicit CommonCode(ShortCode short_code); + + /// Create CommonCode without any check. + static CommonCode unsafe_create(uint64_t common_code); - static std::optional from_string(std::string &&common_code) noexcept; - static std::optional from_string(const std::string &common_code) noexcept; + /// Create CommonCode with validity check. + static std::optional create(uint64_t common_code); - static CommonCode from_raw_code(RawCode raw_code) noexcept; - static std::optional from_raw_code(uint64_t raw_code) noexcept; + // ------------------------------------------------------------------------------------- // - static CommonCode from_short_code(ShortCode short_code) noexcept; - static std::optional from_short_code(uint32_t short_code) noexcept; - static std::optional from_short_code(std::string &&short_code) noexcept; - static std::optional from_short_code(const std::string &short_code) noexcept; + /// Create CommonCode from string form. + static std::optional from_string(const std::string &common_code); + + // ------------------------------------------------------------------------------------- // + + /// Create CommonCode from RawCode. + static CommonCode from_raw_code(RawCode raw_code); + + /// Create CommonCode from RawCode in u64. + static std::optional from_raw_code(uint64_t raw_code); + + // ------------------------------------------------------------------------------------- // + + /// Create CommonCode from ShortCode. + static CommonCode from_short_code(ShortCode short_code); + + /// Create CommonCode from ShortCode in u32. + static std::optional from_short_code(uint32_t short_code); + + /// Create CommonCode from ShortCode in string form. + static std::optional from_short_code(const std::string &short_code); + + // ------------------------------------------------------------------------------------- // + + /// Compare CommonCode with u64 values. + friend constexpr auto operator==(const CommonCode &c1, uint64_t c2); + friend constexpr auto operator<=>(const CommonCode &c1, uint64_t c2); + + /// Compare the original values of two CommonCodes. + friend constexpr auto operator==(const CommonCode &c1, const CommonCode &c2); + friend constexpr auto operator<=>(const CommonCode &c1, const CommonCode &c2); + + // ------------------------------------------------------------------------------------- // private: uint64_t code_; - static std::string string_encode(uint64_t common_code) noexcept; - static std::string string_encode_shorten(uint64_t common_code) noexcept; - static std::optional string_decode(const std::string &common_code) noexcept; + + /// Serialize CommonCode into a 9-bit length string. + static std::string string_encode(uint64_t common_code); + + /// Serialize CommonCode into a variable-length string, removing the trailing zero. + static std::string string_encode_shorten(uint64_t common_code); + + /// Deserialize CommonCode from string and return std::nullopt on error. + static std::optional string_decode(const std::string &common_code); }; -} // namespace codec -} // namespace klotski +} // namespace klotski::codec -#include "inline_impl.h" +#include "internal/common_code.inl" diff --git a/src/core/common_code/inline_impl.h b/src/core/common_code/inline_impl.h deleted file mode 100644 index 6cfe1a3..0000000 --- a/src/core/common_code/inline_impl.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -namespace klotski { -namespace codec { - -/// Get the original 64-bit code. -inline uint64_t CommonCode::unwrap() const noexcept { - return code_; -} - -/// Implicit conversion to 64-bit code. -inline CommonCode::operator uint64_t() const noexcept { - return code_; -} - -/// Equality comparison between CommonCode and numbers. -inline bool operator==(CommonCode c1, uint64_t c2) noexcept { - return c1.unwrap() == c2; -} - -/// CommonCode equal comparison implement. -inline bool operator==(CommonCode c1, CommonCode c2) noexcept { - return c1.unwrap() == c2.unwrap(); -} - -/// CommonCode less than comparison implement. -inline bool operator<(CommonCode c1, CommonCode c2) noexcept { - return c1.unwrap() < c2.unwrap(); -} - -/// CommonCode greater than comparison implement. -inline bool operator>(CommonCode c1, CommonCode c2) noexcept { - return c1.unwrap() > c2.unwrap(); -} - -/// CommonCode create without any check. -inline CommonCode CommonCode::unsafe_create(uint64_t common_code) noexcept { - return *reinterpret_cast(&common_code); // init directly -} - -/// CommonCode create with valid check. -inline std::optional CommonCode::create(uint64_t common_code) noexcept { - if (!CommonCode::check(common_code)) { - return std::nullopt; // invalid common code - } - return CommonCode::unsafe_create(common_code); -} - -/// Output string encoding of CommonCode. -inline std::ostream& operator<<(std::ostream &out, CommonCode self) { - out << CommonCode::string_encode(self.code_); - return out; -} - -} // namespace codec -} // namespace klotski diff --git a/src/core/common_code/common_code.cc b/src/core/common_code/internal/common_code.cc similarity index 91% rename from src/core/common_code/common_code.cc rename to src/core/common_code/internal/common_code.cc index 1b8d361..e6e477d 100644 --- a/src/core/common_code/common_code.cc +++ b/src/core/common_code/internal/common_code.cc @@ -1,11 +1,9 @@ #include "utility.h" #include "common_code.h" -namespace klotski { -namespace codec { +namespace klotski::codec { -/// Check the validity of the original CommonCode. -bool CommonCode::check(uint64_t common_code) noexcept { +bool CommonCode::check(uint64_t common_code) { // TODO: optimization of synchronizing all_cases. /// M_1x1 | M_1x2 | M_2x1 | M_2x2 @@ -59,5 +57,4 @@ bool CommonCode::check(uint64_t common_code) noexcept { } } -} // namespace codec -} // namespace klotski +} // namespace klotski::codec diff --git a/src/core/common_code/internal/common_code.inl b/src/core/common_code/internal/common_code.inl new file mode 100644 index 0000000..90b1a65 --- /dev/null +++ b/src/core/common_code/internal/common_code.inl @@ -0,0 +1,71 @@ +#pragma once + +#include + +namespace klotski::codec { + +// ------------------------------------------------------------------------------------- // + +inline uint64_t CommonCode::unwrap() const { + return code_; +} + +inline CommonCode::operator uint64_t() const { + return code_; +} + +inline std::ostream& operator<<(std::ostream &out, const CommonCode self) { + out << CommonCode::string_encode(self.code_); + return out; +} + +// ------------------------------------------------------------------------------------- // + +constexpr auto operator==(const CommonCode &c1, const uint64_t c2) { + return c1.code_ == c2; +} + +constexpr auto operator<=>(const CommonCode &c1, const uint64_t c2) { + return c1.code_ <=> c2; +} + +constexpr auto operator==(const CommonCode &c1, const CommonCode &c2) { + return c1.code_ == c2.code_; +} + +constexpr auto operator<=>(const CommonCode &c1, const CommonCode &c2) { + return c1.code_ <=> c2.code_; +} + +// ------------------------------------------------------------------------------------- // + +inline CommonCode CommonCode::unsafe_create(const uint64_t common_code) { + return std::bit_cast(common_code); // init directly +} + +inline std::optional CommonCode::create(const uint64_t common_code) { + if (!check(common_code)) { + return std::nullopt; // invalid common code + } + return unsafe_create(common_code); +} + +// ------------------------------------------------------------------------------------- // + +inline std::string CommonCode::to_string(const bool shorten) const { + if (!shorten) { + return string_encode(code_); // with full length + } + return string_encode_shorten(code_); // without trailing zero +} + +inline std::optional CommonCode::from_string(const std::string &common_code) { + auto construct = [](const uint64_t code) { + return unsafe_create(code); + }; + return string_decode(common_code).transform(construct); +} + +// ------------------------------------------------------------------------------------- // + +} // namespace klotski::codec diff --git a/src/core/common_code/serialize.cc b/src/core/common_code/internal/serialize.cc similarity index 80% rename from src/core/common_code/serialize.cc rename to src/core/common_code/internal/serialize.cc index db9c8eb..e7911fc 100644 --- a/src/core/common_code/serialize.cc +++ b/src/core/common_code/internal/serialize.cc @@ -1,7 +1,6 @@ #include "common_code.h" -namespace klotski { -namespace codec { +namespace klotski::codec { /// Convert a single hexadecimal digit to a character. inline static char to_hex_char(uint64_t hex_bit) { @@ -11,8 +10,7 @@ inline static char to_hex_char(uint64_t hex_bit) { return char(hex_bit + 'A' - 10); } -/// Serialize CommonCode into a 9-bit length string. -std::string CommonCode::string_encode(uint64_t common_code) noexcept { +std::string CommonCode::string_encode(uint64_t common_code) { char code_str[9]; for (int i = 0; i < 9; ++i) { code_str[8 - i] = to_hex_char(common_code & 0b1111); @@ -21,8 +19,7 @@ std::string CommonCode::string_encode(uint64_t common_code) noexcept { return std::string{code_str, code_str + 9}; } -/// Serialize CommonCode into a variable-length string, removing the trailing zero. -std::string CommonCode::string_encode_shorten(uint64_t common_code) noexcept { +std::string CommonCode::string_encode_shorten(uint64_t common_code) { if (common_code == 0) { return "0"; // special case } @@ -40,8 +37,7 @@ std::string CommonCode::string_encode_shorten(uint64_t common_code) noexcept { return std::string{code_str, code_str + zero_start}; } -/// Deserialize CommonCode from string and return std::nullopt on error. -std::optional CommonCode::string_decode(const std::string &common_code) noexcept { +std::optional CommonCode::string_decode(const std::string &common_code) { if (common_code.length() > 9 || common_code.empty()) { return std::nullopt; // invalid string length } @@ -60,5 +56,4 @@ std::optional CommonCode::string_decode(const std::string &common_code return result << (36 - common_code.length() * 4); // low-bits fill with zero } -} // namespace codec -} // namespace klotski +} // namespace klotski::codec diff --git a/src/core/common_code/internal/sundry.cc b/src/core/common_code/internal/sundry.cc new file mode 100644 index 0000000..e30bba1 --- /dev/null +++ b/src/core/common_code/internal/sundry.cc @@ -0,0 +1,61 @@ +#include "raw_code.h" +#include "short_code.h" +#include "common_code.h" + +// TODO: move to inline header + +namespace klotski::codec { + +// ----------------------------------------------------------------------------------------- // + +CommonCode::CommonCode(RawCode raw_code) { + code_ = raw_code.to_common_code().code_; +} + +CommonCode::CommonCode(ShortCode short_code) { + code_ = short_code.to_common_code().code_; +} + +// ----------------------------------------------------------------------------------------- // + +RawCode CommonCode::to_raw_code() const { + return RawCode(*this); +} + +ShortCode CommonCode::to_short_code() const { + return ShortCode(*this); +} + +// ----------------------------------------------------------------------------------------- // + +CommonCode CommonCode::from_raw_code(RawCode raw_code) { + return raw_code.to_common_code(); +} + +std::optional CommonCode::from_raw_code(uint64_t raw_code) { + return RawCode::create(raw_code).transform([](auto raw_code) { + return raw_code.to_common_code(); + }); +} + +// ----------------------------------------------------------------------------------------- // + +CommonCode CommonCode::from_short_code(ShortCode short_code) { + return short_code.to_common_code(); +} + +std::optional CommonCode::from_short_code(uint32_t short_code) { + return ShortCode::create(short_code).transform([](auto short_code) { + return short_code.to_common_code(); + }); +} + +std::optional CommonCode::from_short_code(const std::string &short_code) { + return ShortCode::from_string(short_code).transform([](auto short_code) { + return short_code.to_common_code(); + }); +} + +// ----------------------------------------------------------------------------------------- // + +} // namespace klotski::codec diff --git a/src/core/common_code/sundry.cc b/src/core/common_code/sundry.cc deleted file mode 100644 index 660b258..0000000 --- a/src/core/common_code/sundry.cc +++ /dev/null @@ -1,86 +0,0 @@ -#include "raw_code.h" -#include "short_code.h" -#include "common_code.h" - -namespace klotski { -namespace codec { - -// ----------------------------------------------------------------------------------------- // - -CommonCode::CommonCode(RawCode raw_code) noexcept { - code_ = raw_code.to_common_code().code_; -} - -CommonCode::CommonCode(ShortCode short_code) noexcept { - code_ = short_code.to_common_code().code_; -} - -// ----------------------------------------------------------------------------------------- // - -RawCode CommonCode::to_raw_code() const noexcept { - return RawCode(*this); -} - -ShortCode CommonCode::to_short_code() const noexcept { - return ShortCode(*this); -} - -std::string CommonCode::to_string(bool shorten) const noexcept { - if (!shorten) { - return string_encode(code_); // with full length - } - return string_encode_shorten(code_); // without trailing zero -} - -// ----------------------------------------------------------------------------------------- // - -std::optional CommonCode::from_string(std::string &&common_code) noexcept { - return CommonCode::from_string(common_code); -} - -std::optional CommonCode::from_string(const std::string &common_code) noexcept { - return string_decode(common_code).transform([](auto code) { - return CommonCode::unsafe_create(code); - }); -} - -// ----------------------------------------------------------------------------------------- // - -CommonCode CommonCode::from_raw_code(RawCode raw_code) noexcept { - return raw_code.to_common_code(); -} - -std::optional CommonCode::from_raw_code(uint64_t raw_code) noexcept { - return RawCode::create(raw_code).transform([](auto raw_code) { - return raw_code.to_common_code(); - }); -} - -// ----------------------------------------------------------------------------------------- // - -CommonCode CommonCode::from_short_code(ShortCode short_code) noexcept { - return short_code.to_common_code(); -} - -std::optional CommonCode::from_short_code(uint32_t short_code) noexcept { - return ShortCode::create(short_code).transform([](auto short_code) { - return short_code.to_common_code(); - }); -} - -std::optional CommonCode::from_short_code(std::string &&short_code) noexcept { - return ShortCode::from_string(std::move(short_code)).transform([](auto short_code) { - return short_code.to_common_code(); - }); -} - -std::optional CommonCode::from_short_code(const std::string &short_code) noexcept { - return ShortCode::from_string(short_code).transform([](auto short_code) { - return short_code.to_common_code(); - }); -} - -// ----------------------------------------------------------------------------------------- // - -} // namespace codec -} // namespace klotski