From ac4c10b76519cc5d5daab38ad7e22a603cfc5387 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sun, 10 Nov 2024 17:49:58 +0800 Subject: [PATCH] update: enhance `Ranges` and `RangesUnion` interfaces --- src/core/benchmark/ranges.cc | 18 ++- src/core/ranges/internal/ranges.cc | 141 ++++++++++++++++------ src/core/ranges/internal/ranges.inl | 16 +++ src/core/ranges/internal/ranges_union.inl | 35 ++++++ src/core/ranges/internal/spawn.cc | 7 +- src/core/ranges/ranges.h | 48 +++++--- src/core/utils/utility.h | 1 + 7 files changed, 210 insertions(+), 56 deletions(-) create mode 100644 src/core/ranges/internal/ranges.inl create mode 100644 src/core/ranges/internal/ranges_union.inl diff --git a/src/core/benchmark/ranges.cc b/src/core/benchmark/ranges.cc index e2f90c4..fe8f276 100644 --- a/src/core/benchmark/ranges.cc +++ b/src/core/benchmark/ranges.cc @@ -55,10 +55,26 @@ static void RangesSize(benchmark::State &state) { } } +static void RangesAt(benchmark::State &state) { + auto &all_cases = AllCases::instance().fetch(); + for (auto _ : state) { + volatile auto k0 = all_cases[1035968]; + volatile auto k1 = all_cases[3778871]; + volatile auto k2 = all_cases[7489354]; + volatile auto k3 = all_cases[10398492]; + volatile auto k4 = all_cases[19091276]; + volatile auto k5 = all_cases[21373726]; + volatile auto k6 = all_cases[27296711]; + volatile auto k7 = all_cases[28214648]; + } +} + // BENCHMARK(SpawnRanges)->Unit(benchmark::kMillisecond); // BENCHMARK(RangesUnionExport)->Unit(benchmark::kMillisecond); -BENCHMARK(RangesSize); +// BENCHMARK(RangesSize); + +BENCHMARK(RangesAt); BENCHMARK_MAIN(); diff --git a/src/core/ranges/internal/ranges.cc b/src/core/ranges/internal/ranges.cc index 85cdcd9..4319a7f 100644 --- a/src/core/ranges/internal/ranges.cc +++ b/src/core/ranges/internal/ranges.cc @@ -5,24 +5,8 @@ using klotski::cases::Ranges; using klotski::codec::CommonCode; using klotski::cases::RangesUnion; -static constexpr auto heads = std::to_array({ - 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, - 0x8, 0x9, 0xA, 0xC, 0xD, 0xE, -}); - -void Ranges::reverse() { - for (auto &x : *this) { - x = range_reverse(x); - } -} - -Ranges& Ranges::operator+=(const Ranges &ranges) { - this->insert(this->end(), ranges.begin(), ranges.end()); - return *this; -} - RangesUnion& RangesUnion::operator+=(const RangesUnion &ranges_union) { - for (const auto head : heads) { + for (const auto head : Heads) { // (*this)[head] += ranges_union[head]; std::array::operator[](head) += ranges_union.std::array::operator[](head); } @@ -32,7 +16,7 @@ RangesUnion& RangesUnion::operator+=(const RangesUnion &ranges_union) { std::vector RangesUnion::codes() const { std::vector codes; codes.reserve(size()); - for (const auto head : heads) { + for (const auto head : Heads) { // for (const auto range : (*this)[head]) { for (const auto range : ranges(head)) { codes.emplace_back(CommonCode::unsafe_create(head << 32 | range)); @@ -42,25 +26,108 @@ std::vector RangesUnion::codes() const { return codes; } -// TODO: move to `.inl` file -size_t RangesUnion::size() const { - size_type size = 0; - for (const auto head : heads) { - size += std::array::operator[](head).size(); - // size += (*this)[head].size(); +KLSK_INLINE CommonCode RangesUnion::operator[](size_type n) const { + uint64_t head = 0; + while (n >= ranges(head).size()) { + n -= ranges(head).size(); + ++head; } - return size; -} + KLSK_ASSUME(head < 16); + return CommonCode::unsafe_create(head << 32 | ranges(head)[n]); + + // size_t head = 0; + // if (n < ranges(head).size()) { + // return CommonCode::unsafe_create(head << 32 | ranges(head)[n]); // 0 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 1 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 2 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 3 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 4 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 5 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 6 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 7 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 8 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 9 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 10 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 11 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 12 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 13 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 14 + // } + // + // n -= ranges(head).size(); + // ++head; + // if (n < ranges(head).size()) { + // return ranges(head)[n]; // 15 + // } -uint32_t RangesUnion::operator[](size_type index) const { - size_t head = 0; - for (;;) { - if (index >= std::array::operator[](head).size()) { - index -= std::array::operator[](head).size(); - ++head; - } else { - break; - } - } - return std::array::operator[](head)[index]; } diff --git a/src/core/ranges/internal/ranges.inl b/src/core/ranges/internal/ranges.inl new file mode 100644 index 0000000..73f5304 --- /dev/null +++ b/src/core/ranges/internal/ranges.inl @@ -0,0 +1,16 @@ +#pragma once + +namespace klotski::cases { + +KLSK_INLINE_H void Ranges::reverse() { + for (auto &x : *this) { + x = range_reverse(x); + } +} + +inline Ranges& Ranges::operator+=(const Ranges &ranges) { + this->insert(this->end(), ranges.begin(), ranges.end()); + return *this; +} + +} // namespace klotski::cases diff --git a/src/core/ranges/internal/ranges_union.inl b/src/core/ranges/internal/ranges_union.inl new file mode 100644 index 0000000..f1f092b --- /dev/null +++ b/src/core/ranges/internal/ranges_union.inl @@ -0,0 +1,35 @@ +#pragma once + +namespace klotski::cases { + +inline Ranges& RangesUnion::ranges(const size_t head) { + return std::array::operator[](head); +} + +inline const Ranges& RangesUnion::ranges(const size_t head) const { + return std::array::operator[](head); +} + +KLSK_INLINE_H size_t RangesUnion::size() const { + size_type size = 0; + #pragma unroll + for (const auto head : Heads) { + size += ranges(head).size(); + } + return size; +} + +// KLSK_INLINE_H uint32_t RangesUnion::operator[](size_type n) const { +// size_t head = 0; +// for (;;) { +// if (n >= ranges(head).size()) { +// n -= ranges(head).size(); +// ++head; +// } else { +// break; +// } +// } +// return ranges(head)[n]; +// } + +} // namespace klotski::cases diff --git a/src/core/ranges/internal/spawn.cc b/src/core/ranges/internal/spawn.cc index f4c9861..9261269 100644 --- a/src/core/ranges/internal/spawn.cc +++ b/src/core/ranges/internal/spawn.cc @@ -6,9 +6,9 @@ using klotski::cases::Ranges; template -static void spawn_ranges(std::vector &ranges, int n_10, int n_11) { - int n_01 = N - n_10; - int n_00 = 16 - N * 2 - n_11; +static KLSK_INLINE void spawn_ranges(std::vector &ranges, int n_10, int n_11) { + const int n_01 = N - n_10; + const int n_00 = 16 - N * 2 - n_11; std::array series {}; std::fill_n(series.begin() + n_00, n_01, 0b01); @@ -36,5 +36,6 @@ void Ranges::spawn(const int n, const int n_2x1, const int n_1x1) { case 5: return spawn_ranges<5>(*this, n_2x1, n_1x1); case 6: return spawn_ranges<6>(*this, n_2x1, n_1x1); case 7: return spawn_ranges<7>(*this, n_2x1, n_1x1); + default: std::unreachable(); } } diff --git a/src/core/ranges/ranges.h b/src/core/ranges/ranges.h index bc79ccc..344283b 100644 --- a/src/core/ranges/ranges.h +++ b/src/core/ranges/ranges.h @@ -18,41 +18,59 @@ namespace klotski::cases { class Ranges final : public std::vector { public: + // ------------------------------------------------------------------------------------- // + /// Append the ranges from another instance. Ranges& operator+=(const Ranges &ranges); + /// Flip the ranges every two bits in low-high symmetry. + KLSK_INLINE void reverse(); + /// Spawn klotski-ranges that match the specified block numbers. void spawn(int n, int n_2x1, int n_1x1); - /// Flip the klotski-ranges every two bits in low-high symmetry. - void reverse(); - - /// Derive the legal klotski-ranges from reversed ranges with specified head. + /// Derive the legal ranges from reversed ranges with specified head. 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); + + // ------------------------------------------------------------------------------------- // }; class RangesUnion final : public std::array { public: - /// Append the ranges from another instance. - RangesUnion& operator+=(const RangesUnion &ranges_union); + // ------------------------------------------------------------------------------------- // + + /// Get the Ranges of specified head. + Ranges& ranges(size_t head); - /// Export the RangesUnion as CommonCode list. + /// Get the const Ranges of specified head. + [[nodiscard]] const Ranges& ranges(size_t head) const; + + /// Export the RangesUnion as a CommonCode list. [[nodiscard]] std::vector codes() const; - [[nodiscard]] const Ranges& ranges(const size_t head) const { - return std::array::operator[](head); - } + // ------------------------------------------------------------------------------------- // + + /// Get the number of ranges contained. + [[nodiscard]] KLSK_INLINE size_t size() const; - Ranges& ranges(const size_t head) { - return std::array::operator[](head); - } + /// Append the ranges from another instance. + RangesUnion& KLSK_INLINE operator+=(const RangesUnion &ranges_union); - [[nodiscard]] size_t size() const; + /// Obtain the CommonCode of the specified index. + [[nodiscard]] KLSK_INLINE codec::CommonCode operator[](size_type n) const; - [[nodiscard]] uint32_t operator[](size_type) const; + // ------------------------------------------------------------------------------------- // + +private: + static constexpr auto Heads = std::to_array({ + 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x8, 0x9, 0xA, 0xC, 0xD, 0xE, + }); }; } // namespace klotski::cases + +#include "internal/ranges.inl" +#include "internal/ranges_union.inl" diff --git a/src/core/utils/utility.h b/src/core/utils/utility.h index 64850eb..35ab59e 100644 --- a/src/core/utils/utility.h +++ b/src/core/utils/utility.h @@ -33,6 +33,7 @@ /// Force function declaration to be inline. #define KLSK_INLINE __attribute__ ((always_inline)) +#define KLSK_INLINE_H KLSK_INLINE inline #define KLSK_INLINE_CE KLSK_INLINE constexpr /// Prevent reordering for both compiler and processor.