Browse Source

refactor: project structure of common code

master
Dnomd343 2 months ago
parent
commit
46bde9ec1d
  1. 6
      src/core/CMakeLists.txt
  2. 119
      src/core/common_code/common_code.h
  3. 56
      src/core/common_code/inline_impl.h
  4. 9
      src/core/common_code/internal/common_code.cc
  5. 71
      src/core/common_code/internal/common_code.inl
  6. 15
      src/core/common_code/internal/serialize.cc
  7. 61
      src/core/common_code/internal/sundry.cc
  8. 86
      src/core/common_code/sundry.cc

6
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

119
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 <string>
#include <cstdint>
#include <ostream>
#include <optional>
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<CommonCode> 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<CommonCode> from_string(std::string &&common_code) noexcept;
static std::optional<CommonCode> from_string(const std::string &common_code) noexcept;
/// Create CommonCode with validity check.
static std::optional<CommonCode> create(uint64_t common_code);
static CommonCode from_raw_code(RawCode raw_code) noexcept;
static std::optional<CommonCode> from_raw_code(uint64_t raw_code) noexcept;
// ------------------------------------------------------------------------------------- //
static CommonCode from_short_code(ShortCode short_code) noexcept;
static std::optional<CommonCode> from_short_code(uint32_t short_code) noexcept;
static std::optional<CommonCode> from_short_code(std::string &&short_code) noexcept;
static std::optional<CommonCode> from_short_code(const std::string &short_code) noexcept;
/// Create CommonCode from string form.
static std::optional<CommonCode> 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<CommonCode> 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<CommonCode> from_short_code(uint32_t short_code);
/// Create CommonCode from ShortCode in string form.
static std::optional<CommonCode> 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<uint64_t> 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<uint64_t> string_decode(const std::string &common_code);
};
} // namespace codec
} // namespace klotski
} // namespace klotski::codec
#include "inline_impl.h"
#include "internal/common_code.inl"

56
src/core/common_code/inline_impl.h

@ -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<CommonCode*>(&common_code); // init directly
}
/// CommonCode create with valid check.
inline std::optional<CommonCode> 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

9
src/core/common_code/common_code.cc → 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

71
src/core/common_code/internal/common_code.inl

@ -0,0 +1,71 @@
#pragma once
#include <bit>
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<CommonCode>(common_code); // init directly
}
inline std::optional<CommonCode> 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> 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

15
src/core/common_code/serialize.cc → 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<uint64_t> CommonCode::string_decode(const std::string &common_code) noexcept {
std::optional<uint64_t> 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<uint64_t> 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

61
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> 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> 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> 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

86
src/core/common_code/sundry.cc

@ -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> CommonCode::from_string(std::string &&common_code) noexcept {
return CommonCode::from_string(common_code);
}
std::optional<CommonCode> 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> 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> 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> 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> 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
Loading…
Cancel
Save