Browse Source

refactor: interfaces of group module

master
Dnomd343 2 weeks ago
parent
commit
e126de4ccb
  1. 94
      src/core/group/group.h
  2. 2
      src/core/group/internal/case_info.inl
  3. 118
      src/core/group/internal/group.inl
  4. 90
      src/core/group/internal/group_mirror.inl
  5. 1
      src/core/group/internal/group_union.cc
  6. 64
      src/core/group/internal/group_union.inl
  7. 30
      src/core/group/internal/hash.inl

94
src/core/group/group.h

@ -114,7 +114,7 @@ public:
[[nodiscard]] cases::RangesUnion cases() const;
/// Get the group instance with the specified pattern id.
[[nodiscard]] constexpr std::optional<Groups> groups(uint32_t pattern_id) const;
[[nodiscard]] constexpr std::optional<Groups> groups(uint_fast16_t pattern_id) const;
// ------------------------------------------------------------------------------------- //
@ -153,19 +153,21 @@ private:
// ------------------------------------------------------------------------------------- //
};
static_assert(std::is_standard_layout_v<GroupUnion>);
static_assert(std::is_trivially_copyable_v<GroupUnion>);
class Group {
public:
// ------------------------------------------------------------------------------------- //
// TODO: enum with uint_fast8_t
enum class Toward {
enum class Toward : uint_fast8_t {
A = 0, // baseline
B = 1, // horizontal mirror
C = 2, // vertical mirror
D = 3, // diagonal mirror
};
enum class MirrorType {
enum class MirrorType : uint_fast8_t {
Full = 0, // fully self-symmetry
Horizontal = 1, // horizontal self-symmetry
Centro = 2, // centrosymmetric
@ -182,25 +184,22 @@ public:
[[nodiscard]] constexpr char toward_char() const;
/// Get the original type id.
[[nodiscard]] constexpr uint32_t type_id() const;
[[nodiscard]] constexpr uint_fast8_t type_id() const;
/// Get the original pattern id.
[[nodiscard]] constexpr uint32_t pattern_id() const;
/// Get the string form of current group.
[[nodiscard]] constexpr std::string to_string() const;
[[nodiscard]] constexpr uint_fast16_t pattern_id() const;
// ------------------------------------------------------------------------------------- //
Group() = delete;
/// Create Group without any check.
static constexpr Group unsafe_create(uint32_t type_id,
uint32_t pattern_id, Toward toward);
static constexpr Group unsafe_create(uint_fast8_t type_id,
uint_fast16_t pattern_id, Toward toward);
/// Create Group with validity check.
static constexpr std::optional<Group> create(uint32_t type_id,
uint32_t pattern_id, Toward toward);
static constexpr std::optional<Group> create(uint_fast8_t type_id,
uint_fast16_t pattern_id, Toward toward);
// ------------------------------------------------------------------------------------- //
@ -240,6 +239,9 @@ public:
// ------------------------------------------------------------------------------------- //
/// Get the group in string form.
[[nodiscard]] std::string to_string() const;
#ifndef KLSK_NDEBUG
/// Output group info only for debug.
friend std::ostream& operator<<(std::ostream &out, Group self);
@ -251,19 +253,22 @@ public:
// ------------------------------------------------------------------------------------- //
private:
uint32_t type_id_; // TODO: using uint_fast8_t
uint_fast8_t type_id_;
Toward toward_;
uint32_t pattern_id_;
uint_fast16_t pattern_id_;
/// Tiled merge of type_id and pattern_id.
[[nodiscard]] constexpr uint32_t flat_id() const;
/// Hidden constructor called from unsafe_create.
constexpr Group(uint32_t type_id, uint32_t pattern_id, Toward toward);
constexpr Group(uint_fast8_t type_id, Toward toward, uint_fast16_t pattern_id);
// ------------------------------------------------------------------------------------- //
};
static_assert(std::is_standard_layout_v<Group>);
static_assert(std::is_trivially_copyable_v<Group>);
class CaseInfo {
public:
// ------------------------------------------------------------------------------------- //
@ -274,9 +279,6 @@ public:
/// Get the original case id.
[[nodiscard]] constexpr uint32_t case_id() const;
/// Get the string form of current case.
[[nodiscard]] constexpr std::string to_string() const;
// ------------------------------------------------------------------------------------- //
CaseInfo() = delete;
@ -289,6 +291,9 @@ public:
// ------------------------------------------------------------------------------------- //
/// Get case info in string form.
[[nodiscard]] std::string to_string() const;
#ifndef KLSK_NDEBUG
/// Output case info only for debug.
friend std::ostream& operator<<(std::ostream &out, CaseInfo self);
@ -309,6 +314,9 @@ private:
// ------------------------------------------------------------------------------------- //
};
static_assert(std::is_standard_layout_v<CaseInfo>);
static_assert(std::is_trivially_copyable_v<CaseInfo>);
class GroupCases {
public:
// ------------------------------------------------------------------------------------- //
@ -382,15 +390,6 @@ private:
/// Spawn all the unsorted codes of the current group.
std::vector<codec::RawCode> Group_extend(codec::RawCode raw_code, uint32_t reserve = 0);
static_assert(std::is_standard_layout_v<Group>);
static_assert(std::is_trivially_copyable_v<Group>);
static_assert(std::is_standard_layout_v<GroupUnion>);
static_assert(std::is_trivially_copyable_v<GroupUnion>);
static_assert(std::is_standard_layout_v<CaseInfo>);
static_assert(std::is_trivially_copyable_v<CaseInfo>);
} // namespace klotski::group
#include "internal/type_id.inl"
@ -398,40 +397,5 @@ static_assert(std::is_trivially_copyable_v<CaseInfo>);
#include "internal/group_cases.inl"
#include "internal/group.inl"
#include "internal/case_info.inl"
// ----------------------------------------------------------------------------------------- //
// TODO: move to `hash.inl`
namespace std {
template <>
struct std::hash<klotski::group::Group> {
constexpr std::size_t operator()(const klotski::group::Group &g) const noexcept {
// TODO: perf hash alg
return std::hash<uint64_t>{}(g.type_id() ^ g.pattern_id() ^ (int)g.toward());
}
};
template <>
struct std::hash<klotski::group::GroupUnion> {
constexpr std::size_t operator()(const klotski::group::GroupUnion &gu) const noexcept {
return std::hash<uint32_t>{}(gu.unwrap());
}
};
// TODO: add `std::hash` for CaseInfo
template <>
struct std::hash<klotski::group::CaseInfo> {
constexpr std::size_t operator()(const klotski::group::CaseInfo &info) const noexcept {
// TODO: perf hash alg
const auto h1 = std::hash<klotski::group::Group>{}(info.group());
const auto h2 = std::hash<uint32_t>{}(info.case_id());
return h1 ^ h2;
}
};
} // namespace std
// ----------------------------------------------------------------------------------------- //
#include "internal/group_mirror.inl"
#include "internal/hash.inl"

2
src/core/group/internal/case_info.inl

@ -9,7 +9,7 @@ inline std::ostream& operator<<(std::ostream &out, CaseInfo self) {
return out;
}
constexpr std::string CaseInfo::to_string() const {
inline std::string CaseInfo::to_string() const {
return std::format("{}-{}", group_.to_string(), case_id_);
}

118
src/core/group/internal/group.inl

@ -4,11 +4,13 @@
namespace klotski::group {
constexpr uint32_t Group::type_id() const {
// ----------------------------------------------------------------------------------------- //
constexpr uint_fast8_t Group::type_id() const {
return type_id_;
}
constexpr uint32_t Group::pattern_id() const {
constexpr uint_fast16_t Group::pattern_id() const {
return pattern_id_;
}
@ -16,13 +18,6 @@ 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()) {
@ -46,9 +41,19 @@ constexpr char Group::toward_char() const {
}
return '\0'; // TODO: never reach
}
return '\0'; // TODO: never reach
}
constexpr std::string Group::to_string() const { // TODO: `std::string` not support constexpr
// ----------------------------------------------------------------------------------------- //
#ifndef KLSK_NDEBUG
inline std::ostream& operator<<(std::ostream &out, Group self) {
out << self.to_string();
return out;
}
#endif
inline std::string Group::to_string() const {
auto c = toward_char();
if (c == '\0') {
return std::format("{}-{}", type_id_, pattern_id_);
@ -62,11 +67,11 @@ constexpr auto operator==(const Group &lhs, const Group &rhs) {
&& lhs.toward_ == rhs.toward_;
}
constexpr Group Group::unsafe_create(uint32_t type_id, uint32_t pattern_id, Toward toward) {
return {type_id, pattern_id, toward};
constexpr Group Group::unsafe_create(uint_fast8_t type_id, uint_fast16_t pattern_id, Toward toward) {
return {type_id, toward, pattern_id};
}
constexpr std::optional<Group> Group::create(uint32_t type_id, uint32_t pattern_id, Toward toward) {
constexpr std::optional<Group> Group::create(uint_fast8_t type_id, uint_fast16_t pattern_id, Toward toward) {
if (type_id >= TYPE_ID_LIMIT) {
return std::nullopt;
}
@ -93,92 +98,7 @@ inline Group Group::from_common_code(codec::CommonCode common_code) {
return from_raw_code(common_code.to_raw_code());
}
constexpr auto Group::mirror_type() const -> MirrorType {
return static_cast<MirrorType>(PATTERN_DATA[flat_id()] & 0b111);
}
constexpr bool Group::is_vertical_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
return true;
case MirrorType::Horizontal:
return false;
case MirrorType::Centro:
return false;
case MirrorType::Vertical:
return true;
case MirrorType::Ordinary:
return false;
}
}
constexpr bool Group::is_horizontal_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
return true;
case MirrorType::Horizontal:
return true;
case MirrorType::Centro:
return false;
case MirrorType::Vertical:
return false;
case MirrorType::Ordinary:
return false;
}
}
constexpr Group Group::to_vertical_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
return *this;
case MirrorType::Horizontal:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Centro:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Vertical:
return *this;
case MirrorType::Ordinary:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
} else if (toward_ == Toward::B) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::D);
} else if (toward_ == Toward::C) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
}
constexpr Group Group::to_horizontal_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
case MirrorType::Horizontal:
return *this;
case MirrorType::Centro:
case MirrorType::Vertical:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Ordinary:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
} else if (toward_ == Toward::B) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
} else if (toward_ == Toward::C) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::D);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
}
}
constexpr Group::Group(uint32_t type_id, uint32_t pattern_id, Toward toward) {
constexpr Group::Group(uint_fast8_t type_id, Toward toward, uint_fast16_t pattern_id) {
type_id_ = type_id;
pattern_id_ = pattern_id;
toward_ = toward;

90
src/core/group/internal/group_mirror.inl

@ -0,0 +1,90 @@
#pragma once
namespace klotski::group {
constexpr auto Group::mirror_type() const -> MirrorType {
return static_cast<MirrorType>(PATTERN_DATA[flat_id()] & 0b111);
}
constexpr bool Group::is_vertical_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
return true;
case MirrorType::Horizontal:
return false;
case MirrorType::Centro:
return false;
case MirrorType::Vertical:
return true;
case MirrorType::Ordinary:
return false;
}
}
constexpr bool Group::is_horizontal_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
return true;
case MirrorType::Horizontal:
return true;
case MirrorType::Centro:
return false;
case MirrorType::Vertical:
return false;
case MirrorType::Ordinary:
return false;
}
}
constexpr Group Group::to_vertical_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
return *this;
case MirrorType::Horizontal:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Centro:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Vertical:
return *this;
case MirrorType::Ordinary:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
} else if (toward_ == Toward::B) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::D);
} else if (toward_ == Toward::C) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
}
constexpr Group Group::to_horizontal_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
case MirrorType::Horizontal:
return *this;
case MirrorType::Centro:
case MirrorType::Vertical:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Ordinary:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
} else if (toward_ == Toward::B) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
} else if (toward_ == Toward::C) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::D);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
}
}
} // namespace klotski::group

1
src/core/group/internal/group_union.cc

@ -1,4 +1,3 @@
#include "mover/mover.h"
#include "group/group.h"
#include "constant/group_union.h"

64
src/core/group/internal/group_union.inl

@ -8,6 +8,24 @@ namespace klotski::group {
// ----------------------------------------------------------------------------------------- //
constexpr uint32_t GroupUnion::size() const {
return GROUP_UNION_SIZE[type_id_];
}
constexpr uint32_t GroupUnion::group_num() const {
return GROUP_NUM[type_id_];
}
constexpr uint32_t GroupUnion::pattern_num() const {
return PATTERN_NUM[type_id_];
}
constexpr uint32_t GroupUnion::max_group_size() const {
return MAX_GROUP_SIZE[type_id_];
}
// ----------------------------------------------------------------------------------------- //
constexpr uint_fast8_t GroupUnion::unwrap() const {
return type_id_;
}
@ -25,31 +43,29 @@ constexpr std::optional<GroupUnion> GroupUnion::create(const uint_fast8_t type_i
// ----------------------------------------------------------------------------------------- //
constexpr uint32_t GroupUnion::size() const {
return GROUP_UNION_SIZE[type_id_];
#ifndef KLSK_NDEBUG
inline std::ostream& operator<<(std::ostream &out, GroupUnion self) {
out << self.type_id_;
return out;
}
#endif
constexpr uint32_t GroupUnion::group_num() const {
return GROUP_NUM[type_id_];
constexpr auto operator==(const GroupUnion &lhs, const GroupUnion &rhs) {
return lhs.type_id_ == rhs.type_id_;
}
constexpr uint32_t GroupUnion::pattern_num() const {
return PATTERN_NUM[type_id_];
}
// ----------------------------------------------------------------------------------------- //
constexpr uint32_t GroupUnion::max_group_size() const {
return MAX_GROUP_SIZE[type_id_];
constexpr GroupUnion GroupUnion::from_raw_code(const codec::RawCode raw_code) {
return unsafe_create(type_id(raw_code));
}
#ifndef KLSK_NDEBUG
inline std::ostream& operator<<(std::ostream &out, GroupUnion self) {
out << self.type_id_; // TODO: benchmark using `std::format`
return out;
constexpr GroupUnion GroupUnion::from_short_code(const codec::ShortCode short_code) {
return from_common_code(short_code.to_common_code());
}
#endif
constexpr auto operator==(const GroupUnion &lhs, const GroupUnion &rhs) {
return lhs.type_id_ == rhs.type_id_;
constexpr GroupUnion GroupUnion::from_common_code(const codec::CommonCode common_code) {
return unsafe_create(type_id(common_code));
}
// ----------------------------------------------------------------------------------------- //
@ -89,7 +105,7 @@ constexpr std::vector<Group> GroupUnion::groups() const {
return groups;
}
constexpr std::optional<std::vector<Group>> GroupUnion::groups(uint32_t pattern_id) const {
constexpr std::optional<std::vector<Group>> GroupUnion::groups(const uint_fast16_t pattern_id) const {
if (pattern_id >= pattern_num()) {
return std::nullopt;
}
@ -117,18 +133,4 @@ constexpr std::optional<std::vector<Group>> GroupUnion::groups(uint32_t pattern_
// ----------------------------------------------------------------------------------------- //
constexpr GroupUnion GroupUnion::from_raw_code(const codec::RawCode raw_code) {
return unsafe_create(type_id(raw_code));
}
constexpr GroupUnion GroupUnion::from_short_code(const codec::ShortCode short_code) {
return from_common_code(short_code.to_common_code());
}
constexpr GroupUnion GroupUnion::from_common_code(const codec::CommonCode common_code) {
return unsafe_create(type_id(common_code));
}
// ----------------------------------------------------------------------------------------- //
} // namespace klotski::group

30
src/core/group/internal/hash.inl

@ -0,0 +1,30 @@
#pragma once
namespace std {
template <>
struct std::hash<klotski::group::Group> {
constexpr std::size_t operator()(const klotski::group::Group &g) const noexcept {
// TODO: perf hash alg
return std::hash<uint64_t>{}(g.type_id() ^ g.pattern_id() ^ (int)g.toward());
}
};
template <>
struct std::hash<klotski::group::GroupUnion> {
constexpr std::size_t operator()(const klotski::group::GroupUnion &gu) const noexcept {
return std::hash<uint32_t>{}(gu.unwrap());
}
};
template <>
struct std::hash<klotski::group::CaseInfo> {
constexpr std::size_t operator()(const klotski::group::CaseInfo &info) const noexcept {
// TODO: perf hash alg
const auto h1 = std::hash<klotski::group::Group>{}(info.group());
const auto h2 = std::hash<uint32_t>{}(info.case_id());
return h1 ^ h2;
}
};
} // namespace std
Loading…
Cancel
Save