Browse Source

update: constexpr support of GroupUnion `from` interfaces

legacy
Dnomd343 2 months ago
parent
commit
1a89ebebd5
  1. 18
      src/core/group/group.h
  2. 4
      src/core/group/internal/constant/group_union.h
  3. 28
      src/core/group/internal/group_union.cc
  4. 37
      src/core/group/internal/group_union.inl
  5. 28
      src/core/group/internal/type_id.inl
  6. 1
      src/core/utils/utility.h

18
src/core/group/group.h

@ -72,11 +72,6 @@
namespace klotski::group { namespace klotski::group {
// TODO: move constants to `.inl` file
constexpr uint32_t TYPE_ID_LIMIT = 203;
constexpr uint32_t ALL_GROUP_NUM = 25422; // TODO: from GROUP_NUM
constexpr uint32_t ALL_PATTERN_NUM = 6577; // TODO: from PATTERN_NUM
class Group; class Group;
class GroupUnion { class GroupUnion {
@ -86,13 +81,13 @@ public:
GroupUnion() = delete; GroupUnion() = delete;
/// Get the original type id. /// Get the original type id.
[[nodiscard]] constexpr uint32_t unwrap() const; [[nodiscard]] constexpr uint_fast8_t unwrap() const;
/// Create GroupUnion without any check. /// Create GroupUnion without any check.
static constexpr GroupUnion unsafe_create(uint32_t type_id); static constexpr GroupUnion unsafe_create(uint_fast8_t type_id);
/// Create GroupUnion with validity check. /// Create GroupUnion with validity check.
static constexpr std::optional<GroupUnion> create(uint32_t type_id); static constexpr std::optional<GroupUnion> create(uint_fast8_t type_id);
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
@ -145,15 +140,15 @@ public:
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
private: private:
uint32_t type_id_; // TODO: using uint_fast8_t uint_fast8_t type_id_;
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
/// Get the type id of RawCode. /// Get the type id of RawCode.
static KLSK_INLINE uint_fast8_t type_id(codec::RawCode raw_code); static KLSK_INLINE_CE uint_fast8_t type_id(codec::RawCode raw_code);
/// Get the type id of CommonCode. /// Get the type id of CommonCode.
static KLSK_INLINE uint_fast8_t type_id(codec::CommonCode common_code); static KLSK_INLINE_CE uint_fast8_t type_id(codec::CommonCode common_code);
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
}; };
@ -380,6 +375,7 @@ static_assert(std::is_trivially_copyable_v<GroupCases::CaseInfo>);
} // namespace klotski::group } // namespace klotski::group
#include "internal/type_id.inl"
#include "internal/group_union.inl" #include "internal/group_union.inl"
#include "internal/group_cases.inl" #include "internal/group_cases.inl"
#include "internal/group.inl" #include "internal/group.inl"

4
src/core/group/internal/constant/group_union.h

@ -6,6 +6,10 @@
namespace klotski::group { namespace klotski::group {
constexpr uint32_t TYPE_ID_LIMIT = 203;
constexpr uint32_t ALL_GROUP_NUM = 25422; // TODO: from GROUP_NUM
constexpr uint32_t ALL_PATTERN_NUM = 6577; // TODO: from PATTERN_NUM
/// The number of groups contained in GroupUnion. /// The number of groups contained in GroupUnion.
constexpr auto GROUP_NUM = std::to_array<uint16_t>({ constexpr auto GROUP_NUM = std::to_array<uint16_t>({
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,

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

@ -3,40 +3,16 @@
#include "constant/group_union.h" #include "constant/group_union.h"
using klotski::cases::Ranges; using klotski::cases::Ranges;
using klotski::cases::RangesUnion;
using klotski::codec::RawCode; using klotski::codec::RawCode;
using klotski::codec::CommonCode; using klotski::codec::CommonCode;
using klotski::group::GroupUnion; using klotski::group::GroupUnion;
using klotski::cases::RangesUnion;
using klotski::cases::BASIC_RANGES_NUM; using klotski::cases::BASIC_RANGES_NUM;
#define RANGE_DERIVE(HEAD) ranges.derive(HEAD, cases[HEAD]) #define RANGE_DERIVE(HEAD) ranges.derive(HEAD, cases[HEAD])
static KLSK_INLINE uint_fast8_t to_type_id(const int n, const int n_2x1, const int n_1x1) { RangesUnion GroupUnion::cases() const {
KLSK_ASSUME(n >= 0 && n <= 7);
KLSK_ASSUME(n_2x1 >= 0 && n_2x1 <= n);
KLSK_ASSUME(n_1x1 >= 0 && n_1x1 <= (14 - n * 2));
constexpr int offset[8] = {0, 15, 41, 74, 110, 145, 175, 196};
return offset[n] + (15 - n * 2) * n_2x1 + n_1x1;
}
uint_fast8_t GroupUnion::type_id(const CommonCode common_code) {
const auto range = static_cast<uint32_t>(common_code.unwrap());
const auto n_1x1 = std::popcount((range >> 1) & range & 0x55555555);
const auto n_2x1 = std::popcount((range >> 1) & ~range & 0x55555555);
return to_type_id(std::popcount(range) - n_1x1 * 2, n_2x1, n_1x1);
}
uint_fast8_t GroupUnion::type_id(const RawCode raw_code) {
const auto code = raw_code.unwrap();
const auto n = std::popcount(((code >> 1) ^ code) & 0x0249249249249249);
const auto n_2x1 = std::popcount((code >> 1) & ~code & 0x0249249249249249);
const auto n_1x1 = std::popcount((code >> 1) & code & 0x0249249249249249) - n - 3;
return to_type_id(n, n_2x1, n_1x1);
}
klotski::cases::RangesUnion GroupUnion::cases() const {
auto [n, n_2x1, n_1x1] = BLOCK_NUM[type_id_]; auto [n, n_2x1, n_1x1] = BLOCK_NUM[type_id_];
auto [s_a, s_b, s_c, s_d] = GROUP_UNION_CASES_NUM[type_id_]; auto [s_a, s_b, s_c, s_d] = GROUP_UNION_CASES_NUM[type_id_];

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

@ -8,15 +8,15 @@ namespace klotski::group {
// ----------------------------------------------------------------------------------------- // // ----------------------------------------------------------------------------------------- //
constexpr uint32_t GroupUnion::unwrap() const { constexpr uint_fast8_t GroupUnion::unwrap() const {
return type_id_; return type_id_;
} }
constexpr GroupUnion GroupUnion::unsafe_create(const uint32_t type_id) { constexpr GroupUnion GroupUnion::unsafe_create(const uint_fast8_t type_id) {
return std::bit_cast<GroupUnion>(type_id); return std::bit_cast<GroupUnion>(type_id);
} }
constexpr std::optional<GroupUnion> GroupUnion::create(const uint32_t type_id) { constexpr std::optional<GroupUnion> GroupUnion::create(const uint_fast8_t type_id) {
if (type_id < TYPE_ID_LIMIT) { if (type_id < TYPE_ID_LIMIT) {
return unsafe_create(type_id); return unsafe_create(type_id);
} }
@ -33,26 +33,14 @@ constexpr uint32_t GroupUnion::group_num() const {
return GROUP_NUM[type_id_]; 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 { constexpr uint32_t GroupUnion::max_group_size() const {
return MAX_GROUP_SIZE[type_id_]; return MAX_GROUP_SIZE[type_id_];
} }
//inline std::vector<Group> GroupUnion::groups() const {
// auto build = [this](const uint32_t group_id) {
// return Group::unsafe_create(type_id_, group_id);
// };
// return std::views::iota(0U, group_num())
// | std::views::transform(build)
// | std::ranges::to<std::vector>();
//}
//inline std::optional<Group> GroupUnion::group(const uint32_t group_id) const {
// if (group_id < group_num()) {
// return Group::unsafe_create(type_id_, group_id);
// }
// return std::nullopt;
//}
#ifndef KLSK_NDEBUG #ifndef KLSK_NDEBUG
inline std::ostream& operator<<(std::ostream &out, GroupUnion self) { inline std::ostream& operator<<(std::ostream &out, GroupUnion self) {
out << self.type_id_; // TODO: benchmark using `std::format` out << self.type_id_; // TODO: benchmark using `std::format`
@ -66,9 +54,14 @@ constexpr auto operator==(const GroupUnion &lhs, const GroupUnion &rhs) {
// ----------------------------------------------------------------------------------------- // // ----------------------------------------------------------------------------------------- //
constexpr uint32_t GroupUnion::pattern_num() const { //inline std::vector<Group> GroupUnion::groups() const {
return PATTERN_NUM[type_id_]; // auto build = [this](const uint32_t group_id) {
} // return Group::unsafe_create(type_id_, group_id);
// };
// return std::views::iota(0U, group_num())
// | std::views::transform(build)
// | std::ranges::to<std::vector>();
//}
constexpr std::vector<Group> GroupUnion::groups() const { constexpr std::vector<Group> GroupUnion::groups() const {
std::vector<Group> groups; std::vector<Group> groups;

28
src/core/group/internal/type_id.inl

@ -0,0 +1,28 @@
#pragma once
namespace klotski::group {
KLSK_INLINE_CE uint_fast8_t to_type_id(const int n, const int n_2x1, const int n_1x1) {
KLSK_ASSUME(n >= 0 && n <= 7);
KLSK_ASSUME(n_2x1 >= 0 && n_2x1 <= n);
KLSK_ASSUME(n_1x1 >= 0 && n_1x1 <= (14 - n * 2));
constexpr int offset[8] = {0, 15, 41, 74, 110, 145, 175, 196};
return offset[n] + (15 - n * 2) * n_2x1 + n_1x1;
}
KLSK_INLINE_CE uint_fast8_t GroupUnion::type_id(const codec::CommonCode common_code) {
const auto range = static_cast<uint32_t>(common_code.unwrap());
const auto n_1x1 = std::popcount((range >> 1) & range & 0x55555555);
const auto n_2x1 = std::popcount((range >> 1) & ~range & 0x55555555);
return to_type_id(std::popcount(range) - n_1x1 * 2, n_2x1, n_1x1);
}
KLSK_INLINE_CE uint_fast8_t GroupUnion::type_id(const codec::RawCode raw_code) {
const auto code = raw_code.unwrap();
const auto n = std::popcount(((code >> 1) ^ code) & 0x0249249249249249);
const auto n_2x1 = std::popcount((code >> 1) & ~code & 0x0249249249249249);
const auto n_1x1 = std::popcount((code >> 1) & code & 0x0249249249249249) - n - 3;
return to_type_id(n, n_2x1, n_1x1);
}
} // namespace klotski::group

1
src/core/utils/utility.h

@ -31,6 +31,7 @@
/// Force function declaration to be inline. /// Force function declaration to be inline.
#define KLSK_INLINE __attribute__ ((always_inline)) #define KLSK_INLINE __attribute__ ((always_inline))
#define KLSK_INLINE_CE KLSK_INLINE constexpr
/// Prevent reordering for both compiler and processor. /// Prevent reordering for both compiler and processor.
#define KLSK_MEM_BARRIER std::atomic_thread_fence(std::memory_order_seq_cst) #define KLSK_MEM_BARRIER std::atomic_thread_fence(std::memory_order_seq_cst)

Loading…
Cancel
Save