diff --git a/src/core/group/group.h b/src/core/group/group.h index 39b65a5..ec86d59 100644 --- a/src/core/group/group.h +++ b/src/core/group/group.h @@ -255,50 +255,63 @@ private: Toward toward_; uint32_t pattern_id_; - Group(uint32_t type_id, uint32_t pattern_id, Toward toward) { - type_id_ = type_id; - pattern_id_ = pattern_id; - toward_ = toward; - } - /// Tiled merge of type_id and pattern_id. [[nodiscard]] constexpr uint32_t flat_id() const; -}; -/// Spawn all the unsorted codes of the current group. -std::vector Group_extend(codec::RawCode raw_code, uint32_t reserve = 0); + /// Hidden constructor called from unsafe_create. + constexpr Group(uint32_t type_id, uint32_t pattern_id, Toward toward); -class GroupCases { + // ------------------------------------------------------------------------------------- // +}; + +class CaseInfo { public: // ------------------------------------------------------------------------------------- // - // TODO: move to `::klotski::group::CaseInfo` - class CaseInfo { - public: - CaseInfo() = delete; + /// Get the original group. + [[nodiscard]] constexpr Group group() const; - [[nodiscard]] constexpr Group group() const; + /// Get the original case id. + [[nodiscard]] constexpr uint32_t case_id() const; - [[nodiscard]] constexpr uint32_t case_id() const; + /// Get the string form of current case. + [[nodiscard]] constexpr std::string to_string() const; - static CaseInfo unsafe_create(Group group, uint32_t case_id); + // ------------------------------------------------------------------------------------- // - static std::optional create(Group group, uint32_t case_id); + CaseInfo() = delete; - [[nodiscard]] std::string to_string() const; + /// Create CaseInfo without any check. + static constexpr CaseInfo unsafe_create(Group group, uint32_t case_id); + + /// Create CaseInfo with validity check. + static constexpr std::optional create(Group group, uint32_t case_id); + + // ------------------------------------------------------------------------------------- // #ifndef KLSK_NDEBUG - friend std::ostream& operator<<(std::ostream &out, CaseInfo self); + /// Output case info only for debug. + friend std::ostream& operator<<(std::ostream &out, CaseInfo self); #endif - private: - CaseInfo(Group group, uint32_t case_id) : group_(group), case_id_(case_id) {} + /// Compare the internal values of two CaseInfo. + friend constexpr auto operator==(const CaseInfo &lhs, const CaseInfo &rhs); - Group group_; - uint32_t case_id_; - }; + // ------------------------------------------------------------------------------------- // + +private: + Group group_; + uint32_t case_id_; + + /// Hidden constructor called from unsafe_create. + constexpr CaseInfo(Group group, uint32_t case_id); // ------------------------------------------------------------------------------------- // +}; + +class GroupCases { +public: + // ------------------------------------------------------------------------------------- // /// Execute the build process. static void build(); @@ -308,15 +321,17 @@ public: // ------------------------------------------------------------------------------------- // - /// Get the CommonCode from CaseInfo. - static codec::CommonCode obtain_code(CaseInfo info); - /// Get the Group which ShortCode is located. static Group obtain_group(codec::ShortCode short_code); /// Get the Group which CommonCode is located. static Group obtain_group(codec::CommonCode common_code); + // ------------------------------------------------------------------------------------- // + + /// Get the CommonCode from CaseInfo. + static codec::CommonCode obtain_code(CaseInfo info); + /// Get the CaseInfo corresponding to the ShortCode. static CaseInfo obtain_info(codec::ShortCode short_code); @@ -364,14 +379,17 @@ private: // ------------------------------------------------------------------------------------- // }; +/// Spawn all the unsorted codes of the current group. +std::vector Group_extend(codec::RawCode raw_code, uint32_t reserve = 0); + static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); -static_assert(std::is_standard_layout_v); -static_assert(std::is_trivially_copyable_v); +static_assert(std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v); } // namespace klotski::group @@ -379,9 +397,12 @@ static_assert(std::is_trivially_copyable_v); #include "internal/group_union.inl" #include "internal/group_cases.inl" #include "internal/group.inl" +#include "internal/case_info.inl" // ----------------------------------------------------------------------------------------- // +// TODO: move to `hash.inl` + namespace std { template <> @@ -401,6 +422,16 @@ struct std::hash { // TODO: add `std::hash` for CaseInfo +template <> +struct std::hash { + constexpr std::size_t operator()(const klotski::group::CaseInfo &info) const noexcept { + // TODO: perf hash alg + const auto h1 = std::hash{}(info.group()); + const auto h2 = std::hash{}(info.case_id()); + return h1 ^ h2; + } +}; + } // namespace std // ----------------------------------------------------------------------------------------- // diff --git a/src/core/group/internal/case_info.inl b/src/core/group/internal/case_info.inl new file mode 100644 index 0000000..49eacf8 --- /dev/null +++ b/src/core/group/internal/case_info.inl @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace klotski::group { + +inline std::ostream& operator<<(std::ostream &out, CaseInfo self) { + out << self.to_string(); + return out; +} + +constexpr std::string CaseInfo::to_string() const { + return std::format("{}-{}", group_.to_string(), case_id_); +} + +constexpr Group CaseInfo::group() const { + return group_; +} + +constexpr uint32_t CaseInfo::case_id() const { + return case_id_; +} + +constexpr std::optional CaseInfo::create(Group group, uint32_t case_id) { + if (case_id >= group.size()) { + return std::nullopt; + } + return unsafe_create(group, case_id); +} + +constexpr CaseInfo CaseInfo::unsafe_create(Group group, uint32_t case_id) { + return {group, case_id}; +} + +constexpr CaseInfo::CaseInfo(Group group, uint32_t case_id) : group_(group), case_id_(case_id) {} + +} // namespace klotski::group diff --git a/src/core/group/internal/group.inl b/src/core/group/internal/group.inl index 96078fe..b1bff17 100644 --- a/src/core/group/internal/group.inl +++ b/src/core/group/internal/group.inl @@ -178,4 +178,10 @@ constexpr Group Group::to_horizontal_mirror() const { } } +constexpr Group::Group(uint32_t type_id, uint32_t pattern_id, Toward toward) { + type_id_ = type_id; + pattern_id_ = pattern_id; + toward_ = toward; +} + } // namespace klotski::group diff --git a/src/core/group/internal/group_cases.cc b/src/core/group/internal/group_cases.cc index 10c6c5b..364ebea 100644 --- a/src/core/group/internal/group_cases.cc +++ b/src/core/group/internal/group_cases.cc @@ -12,6 +12,8 @@ using klotski::group::GroupCases; using klotski::group::GroupUnion; using klotski::cases::RangesUnion; +using klotski::group::CaseInfo; + using klotski::group::ALL_GROUP_NUM; using klotski::group::TYPE_ID_LIMIT; using klotski::cases::ALL_CASES_NUM_; @@ -123,7 +125,7 @@ CommonCode GroupCases::fast_obtain_code(CaseInfo info) { return CommonCode::unsafe_create(head << 32 | range); } -GroupCases::CaseInfo GroupCases::fast_obtain_info(ShortCode short_code) { +CaseInfo GroupCases::fast_obtain_info(ShortCode short_code) { uint16_t type_id = GroupUnion::from_short_code(short_code).unwrap(); // NOTE: need to convert as CommonCode uint16_t pattern_id = (*rev_data)[short_code.unwrap()].pattern_id; uint16_t toward_id = (*rev_data)[short_code.unwrap()].toward_id; @@ -133,7 +135,7 @@ GroupCases::CaseInfo GroupCases::fast_obtain_info(ShortCode short_code) { return CaseInfo::unsafe_create(group, case_id); } -GroupCases::CaseInfo GroupCases::fast_obtain_info(CommonCode common_code) { +CaseInfo GroupCases::fast_obtain_info(CommonCode common_code) { auto short_code = common_code.to_short_code(); uint16_t type_id = GroupUnion::from_common_code(common_code).unwrap(); uint16_t pattern_id = (*rev_data)[short_code.unwrap()].pattern_id; @@ -193,7 +195,7 @@ static std::unordered_map build_map_data() { return data; } -GroupCases::CaseInfo GroupCases::tiny_obtain_info(CommonCode common_code) { +CaseInfo GroupCases::tiny_obtain_info(CommonCode common_code) { auto raw_codes = Group_extend(common_code.to_raw_code()); std::vector common_codes; common_codes.reserve(raw_codes.size()); diff --git a/src/core/group/internal/group_cases.inl b/src/core/group/internal/group_cases.inl index b8b181f..a6b1535 100644 --- a/src/core/group/internal/group_cases.inl +++ b/src/core/group/internal/group_cases.inl @@ -1,37 +1,7 @@ #pragma once -#include - namespace klotski::group { -inline std::ostream& operator<<(std::ostream &out, GroupCases::CaseInfo self) { - out << self.to_string(); - return out; -} - -inline std::string GroupCases::CaseInfo::to_string() const { - return std::format("{}-{}", group_.to_string(), case_id_); -} - -constexpr Group GroupCases::CaseInfo::group() const { - return group_; -} - -constexpr uint32_t GroupCases::CaseInfo::case_id() const { - return case_id_; -} - -inline std::optional GroupCases::CaseInfo::create(klotski::group::Group group, uint32_t case_id) { - if (case_id >= group.size()) { - return std::nullopt; - } - return unsafe_create(group, case_id); -} - -inline GroupCases::CaseInfo GroupCases::CaseInfo::unsafe_create(klotski::group::Group group, uint32_t case_id) { - return {group, case_id}; -} - inline codec::CommonCode GroupCases::obtain_code(CaseInfo info) { if (fast_) { return fast_obtain_code(info); @@ -39,7 +9,7 @@ inline codec::CommonCode GroupCases::obtain_code(CaseInfo info) { return tiny_obtain_code(info); } -inline GroupCases::CaseInfo GroupCases::obtain_info(codec::CommonCode common_code) { +inline CaseInfo GroupCases::obtain_info(codec::CommonCode common_code) { if (fast_) { return fast_obtain_info(common_code); } @@ -60,7 +30,7 @@ inline Group GroupCases::obtain_group(codec::ShortCode short_code) { return Group::from_short_code(short_code); } -inline GroupCases::CaseInfo GroupCases::obtain_info(codec::ShortCode short_code) { +inline CaseInfo GroupCases::obtain_info(codec::ShortCode short_code) { if (fast_) { return fast_obtain_info(short_code); }