diff --git a/src/core/group/group.h b/src/core/group/group.h index 042c603..773c825 100644 --- a/src/core/group/group.h +++ b/src/core/group/group.h @@ -84,6 +84,9 @@ public: using Groups = std::vector; +#ifndef KLSK_NDEBUG + friend std::ostream& operator<<(std::ostream &out, GroupUnion self); +#endif // ------------------------------------------------------------------------------------- // /// Get the original type id. @@ -152,16 +155,15 @@ private: // ------------------------------------------------------------------------------------- // }; -// TODO: add debug output - class Group { public: Group() = delete; - // TODO: add stream output for debug - [[nodiscard]] constexpr std::string to_string() const; +#ifndef KLSK_NDEBUG + friend std::ostream& operator<<(std::ostream &out, Group self); +#endif // ------------------------------------------------------------------------------------- // enum class Toward { @@ -268,15 +270,29 @@ class GroupCases { public: // ------------------------------------------------------------------------------------- // - struct CaseInfo { - Group group; - uint32_t case_id; + class CaseInfo { + public: + CaseInfo() = delete; + + [[nodiscard]] constexpr Group group() const; + + [[nodiscard]] constexpr uint32_t case_id() const; - // TODO: add create interface + static CaseInfo unsafe_create(Group group, uint32_t case_id); + + static std::optional create(Group group, uint32_t case_id); + + [[nodiscard]] std::string to_string() const; #ifndef KLSK_NDEBUG friend std::ostream& operator<<(std::ostream &out, CaseInfo self); #endif + + private: + CaseInfo(Group group, uint32_t case_id) : group_(group), case_id_(case_id) {} + + Group group_; + uint32_t case_id_; }; // ------------------------------------------------------------------------------------- // @@ -341,6 +357,15 @@ private: // ------------------------------------------------------------------------------------- // }; +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::cases #include "internal/group_union.inl" diff --git a/src/core/group/internal/group.inl b/src/core/group/internal/group.inl index 36a81eb..f2040d5 100644 --- a/src/core/group/internal/group.inl +++ b/src/core/group/internal/group.inl @@ -16,6 +16,13 @@ constexpr auto Group::toward() const -> Toward { return toward_; } +#ifndef KLSK_NDEBUG +inline std::ostream& operator<<(std::ostream &out, Group self) { + out << self.to_string(); + return out; +} +#endif + constexpr char Group::toward_char() const { // TODO: select chars from pre-build std::array switch (mirror_type()) { diff --git a/src/core/group/internal/group_cases.cc b/src/core/group/internal/group_cases.cc index ae6b7c2..24867fd 100644 --- a/src/core/group/internal/group_cases.cc +++ b/src/core/group/internal/group_cases.cc @@ -102,23 +102,24 @@ void GroupCases::build_async(Executor &&executor, Notifier &&callback) { CommonCode GroupCases::fast_obtain_code(CaseInfo info) { - auto flat_id = PATTERN_OFFSET[info.group.type_id()] + info.group.pattern_id(); + auto flat_id = PATTERN_OFFSET[info.group().type_id()] + info.group().pattern_id(); - auto &cases = (*ru_data)[flat_id][(int)info.group.toward()]; + auto &cases = (*ru_data)[flat_id][(int)info.group().toward()]; // TODO: make offset table for perf uint64_t head = 0; + auto case_id = info.case_id(); for (;;) { - if (info.case_id >= cases[head].size()) { - info.case_id -= cases[head].size(); + if (case_id >= cases[head].size()) { + case_id -= cases[head].size(); ++head; } else { break; } } - auto range = cases[head][info.case_id]; + auto range = cases[head][case_id]; return CommonCode::unsafe_create(head << 32 | range); } @@ -128,10 +129,8 @@ GroupCases::CaseInfo GroupCases::fast_obtain_info(ShortCode short_code) { uint16_t toward_id = (*rev_data)[short_code.unwrap()].toward_id; auto case_id = (*rev_data)[short_code.unwrap()].case_id; - return CaseInfo { - .group = Group::unsafe_create(type_id, pattern_id, (Group::Toward)toward_id), - .case_id = case_id, - }; + auto group = Group::unsafe_create(type_id, pattern_id, (Group::Toward)toward_id); + return CaseInfo::unsafe_create(group, case_id); } GroupCases::CaseInfo GroupCases::fast_obtain_info(CommonCode common_code) { @@ -141,10 +140,8 @@ GroupCases::CaseInfo GroupCases::fast_obtain_info(CommonCode common_code) { uint16_t toward_id = (*rev_data)[short_code.unwrap()].toward_id; auto case_id = (*rev_data)[short_code.unwrap()].case_id; - return CaseInfo { - .group = Group::unsafe_create(type_id, pattern_id, (Group::Toward)toward_id), - .case_id = case_id, - }; + auto group = Group::unsafe_create(type_id, pattern_id, (Group::Toward)toward_id); + return CaseInfo::unsafe_create(group, case_id); } Group GroupCases::fast_obtain_group(codec::ShortCode short_code) { @@ -163,19 +160,20 @@ Group GroupCases::fast_obtain_group(codec::CommonCode common_code) { } CommonCode GroupCases::tiny_obtain_code(CaseInfo info) { - auto cases = info.group.cases(); + auto cases = info.group().cases(); uint64_t head = 0; + auto case_id = info.case_id(); for (;;) { - if (info.case_id >= cases[head].size()) { - info.case_id -= cases[head].size(); + if (case_id >= cases[head].size()) { + case_id -= cases[head].size(); ++head; } else { break; } } - auto range = cases[head][info.case_id]; + auto range = cases[head][case_id]; return CommonCode::unsafe_create(head << 32 | range); } @@ -213,8 +211,5 @@ GroupCases::CaseInfo GroupCases::tiny_obtain_info(CommonCode common_code) { auto tmp = std::lower_bound(common_codes.begin(), common_codes.end(), common_code); auto case_id = tmp - common_codes.begin(); - return CaseInfo { - .group = group, - .case_id = (uint32_t)case_id, - }; + return CaseInfo::unsafe_create(group, case_id); } diff --git a/src/core/group/internal/group_cases.inl b/src/core/group/internal/group_cases.inl index bb8aa6c..02054f6 100644 --- a/src/core/group/internal/group_cases.inl +++ b/src/core/group/internal/group_cases.inl @@ -1,7 +1,37 @@ #pragma once +#include + namespace klotski::cases { +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::cases::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::cases::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); diff --git a/src/core/group/internal/group_union.inl b/src/core/group/internal/group_union.inl index 9de5699..8d50620 100644 --- a/src/core/group/internal/group_union.inl +++ b/src/core/group/internal/group_union.inl @@ -53,6 +53,13 @@ constexpr uint32_t GroupUnion::max_group_size() const { // return std::nullopt; //} +#ifndef KLSK_NDEBUG +inline std::ostream& operator<<(std::ostream &out, GroupUnion self) { + out << self.type_id_; // TODO: benchmark using `std::format` + return out; +} +#endif + constexpr auto operator==(const GroupUnion &lhs, const GroupUnion &rhs) { return lhs.type_id_ == rhs.type_id_; } diff --git a/src/core/main.cc b/src/core/main.cc index dd8be80..4d68c03 100644 --- a/src/core/main.cc +++ b/src/core/main.cc @@ -59,34 +59,38 @@ int main() { // std::cout << data_s.size() << std::endl; // std::cout << data_c.size() << std::endl; + auto group_union = GroupUnion::unsafe_create(169); + std::cout << group_union << std::endl; + auto group = Group::from_common_code(CommonCode::unsafe_create(0x1A9BF0C00)); - std::cout << group.type_id() << std::endl; - std::cout << group.pattern_id() << std::endl; - std::cout << (int)group.toward() << std::endl; - std::cout << group.toward_char() << std::endl; - std::cout << group.to_string() << std::endl; - -// auto info_1 = GroupCases::obtain_info(CommonCode::unsafe_create(0x1A9BF0C00)); -// std::cout << std::format("{}-{}-{}-{}\n", info_1.group.type_id(), info_1.group.pattern_id(), (int)info_1.group.toward(), info_1.case_id); -// auto code_1 = GroupCases::obtain_code(info_1); -// std::cout << code_1 << std::endl; -// -// auto info_2 = GroupCases::obtain_info(CommonCode::unsafe_create(0x1A9BF0C00).to_short_code()); -// std::cout << std::format("{}-{}-{}-{}\n", info_2.group.type_id(), info_2.group.pattern_id(), (int)info_2.group.toward(), info_2.case_id); -// auto code_2 = GroupCases::obtain_code(info_2); -// std::cout << code_2 << std::endl; -// -// GroupCases::build(); -// -// auto info_3 = GroupCases::obtain_info(CommonCode::unsafe_create(0x1A9BF0C00)); -// std::cout << std::format("{}-{}-{}-{}\n", info_3.group.type_id(), info_3.group.pattern_id(), (int)info_3.group.toward(), info_3.case_id); -// auto code_3 = GroupCases::obtain_code(info_3); -// std::cout << code_3 << std::endl; -// -// auto info_4 = GroupCases::obtain_info(CommonCode::unsafe_create(0x1A9BF0C00).to_short_code()); -// std::cout << std::format("{}-{}-{}-{}\n", info_4.group.type_id(), info_4.group.pattern_id(), (int)info_4.group.toward(), info_4.case_id); -// auto code_4 = GroupCases::obtain_code(info_4); -// std::cout << code_4 << std::endl; + std::cout << group << std::endl; +// std::cout << group.type_id() << std::endl; +// std::cout << group.pattern_id() << std::endl; +// std::cout << (int)group.toward() << std::endl; +// std::cout << group.toward_char() << std::endl; +// std::cout << group.to_string() << std::endl; + + auto info_1 = GroupCases::obtain_info(CommonCode::unsafe_create(0x1A9BF0C00)); + std::cout << info_1 << std::endl; + auto code_1 = GroupCases::obtain_code(info_1); + std::cout << code_1 << std::endl; + + auto info_2 = GroupCases::obtain_info(CommonCode::unsafe_create(0x1A9BF0C00).to_short_code()); + std::cout << info_2 << std::endl; + auto code_2 = GroupCases::obtain_code(info_2); + std::cout << code_2 << std::endl; + + GroupCases::build(); + + auto info_3 = GroupCases::obtain_info(CommonCode::unsafe_create(0x1A9BF0C00)); + std::cout << info_3 << std::endl; + auto code_3 = GroupCases::obtain_code(info_3); + std::cout << code_3 << std::endl; + + auto info_4 = GroupCases::obtain_info(CommonCode::unsafe_create(0x1A9BF0C00).to_short_code()); + std::cout << info_4 << std::endl; + auto code_4 = GroupCases::obtain_code(info_4); + std::cout << code_4 << std::endl; // const auto common_code = CommonCode::unsafe_create(0x1A9BF0C00); // const auto group = Group::from_common_code(common_code);