From 74aaef4c218c66e76a29bce838e26f22bdd2e967 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sun, 24 Nov 2024 17:22:17 +0800 Subject: [PATCH] refactor: forward declaration of range module --- src/core/all_cases/all_cases.h | 6 ++- src/core/all_cases/internal/basic_ranges.inl | 2 + src/core/common_code/common_code_fwd.h | 9 ++++ src/core/ranges/internal/check.inl | 33 ++++++++++++ src/core/ranges/internal/derive.cc | 56 ++------------------ src/core/ranges/internal/ranges.cc | 32 +++++------ src/core/ranges/internal/ranges.inl | 27 +++++++++- src/core/ranges/ranges.h | 12 ++--- src/core/ranges/ranges_fwd.h | 10 ++++ src/core/short_code/internal/short_code.inl | 1 + src/core/short_code/short_code.h | 13 ++++- src/core/utils/utility.h | 12 +++-- 12 files changed, 129 insertions(+), 84 deletions(-) create mode 100644 src/core/common_code/common_code_fwd.h create mode 100644 src/core/ranges/internal/check.inl create mode 100644 src/core/ranges/ranges_fwd.h diff --git a/src/core/all_cases/all_cases.h b/src/core/all_cases/all_cases.h index 8f5e15c..6aca0da 100644 --- a/src/core/all_cases/all_cases.h +++ b/src/core/all_cases/all_cases.h @@ -42,9 +42,13 @@ #include #include "utils/utility.h" -#include "ranges/ranges.h" #include "internal/constant.inl" +namespace klotski::cases { +class Ranges; +class RangesUnion; +} // namespace klotski::cases + namespace klotski::cases { // ----------------------------------------------------------------------------------------- // diff --git a/src/core/all_cases/internal/basic_ranges.inl b/src/core/all_cases/internal/basic_ranges.inl index d7850a3..7a8b049 100644 --- a/src/core/all_cases/internal/basic_ranges.inl +++ b/src/core/all_cases/internal/basic_ranges.inl @@ -1,5 +1,7 @@ #pragma once +#include "ranges/ranges.h" + namespace klotski::cases { inline Ranges& BasicRanges::get_ranges() { diff --git a/src/core/common_code/common_code_fwd.h b/src/core/common_code/common_code_fwd.h new file mode 100644 index 0000000..163ca62 --- /dev/null +++ b/src/core/common_code/common_code_fwd.h @@ -0,0 +1,9 @@ +/// Klotski Engine by Dnomd343 @2024 + +#pragma once + +namespace klotski::codec { + +class CommonCode; + +} // namespace klotski::codec diff --git a/src/core/ranges/internal/check.inl b/src/core/ranges/internal/check.inl new file mode 100644 index 0000000..c04beb2 --- /dev/null +++ b/src/core/ranges/internal/check.inl @@ -0,0 +1,33 @@ +#pragma once + +namespace klotski::cases { + +KLSK_INLINE_CE int Ranges::check(const int head, uint32_t range) { + KLSK_ASSUME(head >= 0 && head < 16 && head % 4 != 3); + uint32_t flags = 0b110011 << head; // fill 2x2 block + for (int addr = 0, offset = 1; range; range >>= 2, ++offset) { // traverse every 2-bit + const auto num = std::countr_one(flags); + addr += num; // next unfilled block + flags >>= num; + switch (range & 0b11) { + case 0b00: // space + case 0b11: // 1x1 block + flags |= 0b1; + continue; + case 0b01: // 1x2 block + if (flags & 0b10 || addr % 4 == 3) { // invalid case + return offset; // broken offset + } + flags |= 0b11; + continue; + case 0b10: // 2x1 block + if (flags & 0b10000 || addr > 15) { // invalid case + return offset; // broken offset + } + flags |= 0b10001; + } + } + return 0; // pass check +} + +} // namespace klotski::cases diff --git a/src/core/ranges/internal/derive.cc b/src/core/ranges/internal/derive.cc index a5f84b6..e960d24 100644 --- a/src/core/ranges/internal/derive.cc +++ b/src/core/ranges/internal/derive.cc @@ -1,52 +1,4 @@ -#include "utils/utility.h" -#include "ranges/ranges.h" - -using klotski::cases::Ranges; - -int Ranges::check(const int head, uint32_t range) { - KLSK_ASSUME(head >= 0 && head < 16 && head % 4 != 3); - uint32_t flags = 0b110011 << head; // fill 2x2 block - for (int addr = 0, offset = 1; range; range >>= 2, ++offset) { // traverse every 2-bit - const auto num = std::countr_one(flags); - addr += num; // next unfilled block - flags >>= num; - switch (range & 0b11) { - case 0b00: // space - case 0b11: // 1x1 block - flags |= 0b1; - continue; - case 0b01: // 1x2 block - if (flags & 0b10 || addr % 4 == 3) { // invalid case - return offset; // broken offset - } - flags |= 0b11; - continue; - case 0b10: // 2x1 block - if (flags & 0b10000 || addr > 15) { // invalid case - return offset; // broken offset - } - flags |= 0b10001; - } - } - return 0; // pass check -} - -void Ranges::derive(const int head, Ranges &output) const { - const uint32_t max_val = range_reverse(this->back()); - for (uint32_t index = 0; index < size(); ++index) { - if (const auto offset = check(head, (*this)[index])) { // invalid case - /// !! <- broken - /// ( xx xx xx ) xx xx xx ... [reversed range] - /// +1 00 00 00 ... (delta) - const uint32_t delta = 1U << (32 - offset * 2); // distance to next possible range - const auto min_next = delta + (range_reverse((*this)[index]) & ~(delta - 1)); - if (min_next > max_val) { - break; // index has overflowed - } - while (range_reverse((*this)[++index]) < min_next) {} // located next range - --index; - continue; - } - output.emplace_back(range_reverse((*this)[index])); // release valid case - } -} +// #include "utils/utility.h" +// #include "ranges/ranges.h" +// +// using klotski::cases::Ranges; diff --git a/src/core/ranges/internal/ranges.cc b/src/core/ranges/internal/ranges.cc index 16ee782..39b522c 100644 --- a/src/core/ranges/internal/ranges.cc +++ b/src/core/ranges/internal/ranges.cc @@ -1,5 +1,3 @@ -#include - #include "ranges/ranges.h" #include "common_code/common_code.h" @@ -19,20 +17,22 @@ std::vector RangesUnion::codes() const { return codes; } -KLSK_INLINE CommonCode RangesUnion::operator[](size_type n) const { - if (n < ranges(0).size()) { - return CommonCode::unsafe_create(ranges(0)[n]); - } - n -= ranges(0).size(); - - KLSK_UNROLL(Heads.size() - 2) - for (const uint64_t head : std::span {Heads.data() + 1, Heads.size() - 2}) { - if (n < ranges(head).size()) { - return CommonCode::unsafe_create(head << 32 | ranges(head)[n]); +void Ranges::derive(const int head, Ranges &output) const { + const uint32_t max_val = range_reverse(this->back()); + for (uint32_t index = 0; index < size(); ++index) { + if (const auto offset = check(head, (*this)[index])) { // invalid case + /// !! <- broken + /// ( xx xx xx ) xx xx xx ... [reversed range] + /// +1 00 00 00 ... (delta) + const uint32_t delta = 1U << (32 - offset * 2); // distance to next possible range + const auto min_next = delta + (range_reverse((*this)[index]) & ~(delta - 1)); + if (min_next > max_val) { + break; // index has overflowed + } + while (range_reverse((*this)[++index]) < min_next) {} // located next range + --index; + continue; } - n -= ranges(head).size(); + output.emplace_back(range_reverse((*this)[index])); // release valid case } - - constexpr auto head = static_cast(0xE); - return CommonCode::unsafe_create(head << 32 | ranges(0xE)[n]); } diff --git a/src/core/ranges/internal/ranges.inl b/src/core/ranges/internal/ranges.inl index 8aafb86..0f78498 100644 --- a/src/core/ranges/internal/ranges.inl +++ b/src/core/ranges/internal/ranges.inl @@ -1,9 +1,14 @@ #pragma once +#include + +#include "utils/utility.h" +#include "common_code/common_code.h" + namespace klotski::cases { KLSK_INLINE_H void Ranges::reverse() { - #pragma clang loop vectorize(enable) + KLSK_IVDEP for (auto &x : *this) { x = range_reverse(x); } @@ -22,7 +27,7 @@ inline Ranges& Ranges::operator+=(const Ranges &ranges) { return *this; } -inline RangesUnion& RangesUnion::operator+=(const RangesUnion &ranges_union) { +KLSK_INLINE_H RangesUnion& RangesUnion::operator+=(const RangesUnion &ranges_union) { for (const auto head : Heads) { ranges(head) += ranges_union.ranges(head); } @@ -38,4 +43,22 @@ KLSK_INLINE_H size_t RangesUnion::size() const { return size; } +KLSK_INLINE_H codec::CommonCode RangesUnion::operator[](size_type n) const { + if (n < ranges(0).size()) { + return codec::CommonCode::unsafe_create(ranges(0)[n]); + } + n -= ranges(0).size(); + + KLSK_UNROLL(Heads.size() - 2) + for (const uint64_t head : std::span {Heads.data() + 1, Heads.size() - 2}) { + if (n < ranges(head).size()) { + return codec::CommonCode::unsafe_create(head << 32 | ranges(head)[n]); + } + n -= ranges(head).size(); + } + + constexpr auto head = static_cast(0xE); + return codec::CommonCode::unsafe_create(head << 32 | ranges(0xE)[n]); +} + } // namespace klotski::cases diff --git a/src/core/ranges/ranges.h b/src/core/ranges/ranges.h index f4de799..f60b526 100644 --- a/src/core/ranges/ranges.h +++ b/src/core/ranges/ranges.h @@ -12,7 +12,7 @@ /// 3. n_space >= 2 /// /// That is: -/// n_1x1 + (n_2x1 + n_1x2) * 2 <= 14 (n_2x1 != 7) +/// n_1x1 + (n_2x1 + n_1x2) * 2 <= 14 (n_2x1 != 7) /// /// In the above inequality, the variables are all positive integers, so we can /// get 203 combinations. In each combination, four kinds of 2-bit items can be @@ -38,10 +38,7 @@ #include #include "utils/utility.h" - -namespace klotski::codec { -class CommonCode; -} // namespace klotski::codec +#include "common_code/common_code_fwd.h" namespace klotski::cases { @@ -62,7 +59,7 @@ public: void derive(int head, Ranges &output) const; /// Check whether the combination of head and reversed range is valid. - static KLSK_INLINE int check(int head, uint32_t range); + static KLSK_INLINE_CE int check(int head, uint32_t range); // ------------------------------------------------------------------------------------- // }; @@ -95,10 +92,11 @@ public: private: static constexpr auto Heads = std::to_array({ - 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x8, 0x9, 0xA, 0xC, 0xD, 0xE, + 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x8, 0x9, 0xA, 0xC, 0xD, 0xE }); }; } // namespace klotski::cases #include "internal/ranges.inl" +#include "internal/check.inl" diff --git a/src/core/ranges/ranges_fwd.h b/src/core/ranges/ranges_fwd.h new file mode 100644 index 0000000..3e9a985 --- /dev/null +++ b/src/core/ranges/ranges_fwd.h @@ -0,0 +1,10 @@ +/// Klotski Engine by Dnomd343 @2024 + +#pragma once + +namespace klotski::cases { + +class Ranges; +class RangesUnion; + +} // namespace klotski::cases diff --git a/src/core/short_code/internal/short_code.inl b/src/core/short_code/internal/short_code.inl index bf428cb..a4bf6bb 100644 --- a/src/core/short_code/internal/short_code.inl +++ b/src/core/short_code/internal/short_code.inl @@ -1,5 +1,6 @@ #pragma once +#include "all_cases/all_cases.h" #include "common_code/common_code.h" namespace klotski::codec { diff --git a/src/core/short_code/short_code.h b/src/core/short_code/short_code.h index 61965fa..c386e8d 100644 --- a/src/core/short_code/short_code.h +++ b/src/core/short_code/short_code.h @@ -60,16 +60,25 @@ #pragma once +#include #include #include #include #include -#include "all_cases/all_cases.h" +#include "utils/utility.h" +// #include "all_cases/all_cases.h" + +namespace klotski::cases { +class AllCases; +class Ranges; +class RangesUnion; +} // namespace klotski::cases namespace klotski::codec { -constexpr uint32_t SHORT_CODE_LIMIT = cases::ALL_CASES_NUM_; +constexpr uint32_t SHORT_CODE_LIMIT = 29334498; +// constexpr uint32_t SHORT_CODE_LIMIT = cases::ALL_CASES_NUM_; class CommonCode; diff --git a/src/core/utils/utility.h b/src/core/utils/utility.h index 0bbc691..e1ffa35 100644 --- a/src/core/utils/utility.h +++ b/src/core/utils/utility.h @@ -25,9 +25,9 @@ /// Marking compiler assumptions. #if defined(__clang__) - #define KLSK_ASSUME(expr) __builtin_assume(expr) + #define KLSK_ASSUME(expr) __builtin_assume(expr) #elif defined(__GNUC__) - #define KLSK_ASSUME(expr) [[assume(expr)]] + #define KLSK_ASSUME(expr) [[assume(expr)]] #endif #define KLSK_UNREACHABLE __builtin_unreachable() // TODO: using `std::unreachable` @@ -47,8 +47,12 @@ #define KLSK_UNROLL(N) _Pragma(KLSK_STRING(unroll N)) #elif defined(__GNUC__) #define KLSK_UNROLL(N) _Pragma(KLSK_STRING(GCC unroll N)) -#else - #define KLSK_UNROLL(N) +#endif + +#if defined(__clang__) + #define KLSK_IVDEP _Pragma("clang loop vectorize(enable)") +#elif defined(__GNUC__) + #define KLSK_IVDEP _Pragma("GCC ivdep") #endif /// Prevent reordering for both compiler and processor.