diff --git a/src/core/ranges/ranges.h b/src/core/ranges/ranges.h index f60b526..2a680b7 100644 --- a/src/core/ranges/ranges.h +++ b/src/core/ranges/ranges.h @@ -90,12 +90,16 @@ public: // ------------------------------------------------------------------------------------- // -private: static constexpr auto Heads = std::to_array({ 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x8, 0x9, 0xA, 0xC, 0xD, 0xE }); + + // ------------------------------------------------------------------------------------- // }; +static_assert(sizeof(Ranges) == sizeof(std::vector)); +static_assert(sizeof(Ranges) * 16 == sizeof(RangesUnion)); + } // namespace klotski::cases #include "internal/ranges.inl" diff --git a/src/core_test/cases/ranges.cc b/src/core_test/cases/ranges.cc index 542eda9..5b29abf 100644 --- a/src/core_test/cases/ranges.cc +++ b/src/core_test/cases/ranges.cc @@ -1,51 +1,64 @@ #include -#include "helper/cases.h" +#include "group/group.h" +#include "ranges/ranges.h" + #include "helper/expect.h" +#include "helper/parallel.h" #include "helper/block_num.h" -#include "group/group.h" -#include "ranges/ranges.h" +using klotski::cases::Ranges; +using klotski::cases::AllCases; +using klotski::codec::CommonCode; +using klotski::cases::BasicRanges; +using klotski::cases::RangesUnion; using klotski::range_reverse; +using klotski::group::BLOCK_NUM; +using klotski::cases::ALL_CASES_NUM; +using klotski::cases::BASIC_RANGES_NUM_; + +constexpr auto Heads = RangesUnion::Heads; static_assert(std::is_base_of_v, Ranges>); TEST(Ranges, check) { - RangesUnion all_cases; - for (const auto head : Heads) { - for (auto range : BasicRanges::instance().fetch()) { - if (Ranges::check(head, range_reverse(range)) == 0) { - all_cases.ranges(head).emplace_back(range); // found valid cases + HEAD_PARALLEL({ + Ranges cases; + cases.reserve(ALL_CASES_NUM[head]); + for (const auto range : BasicRanges::instance().fetch()) { + if (Ranges::check(static_cast(head), range_reverse(range)) == 0) { + cases.emplace_back(range); // found valid cases } } - } - EXPECT_EQ(all_cases, AllCases::instance().fetch()); + EXPECT_EQ(cases, AllCases::instance().fetch().ranges(head)); + }); } TEST(Ranges, spawn) { - for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) { + BLOCK_NUM_PARALLEL({ Ranges ranges; ranges.spawn(n, n_2x1, n_1x1); EXPECT_SORTED_AND_UNIQUE(ranges); // sorted and unique + for (const auto range : ranges) { - const auto [val_1x1, val_1x2, val_2x1] = helper::cal_block_num(range); - EXPECT_EQ(val_1x1, n_1x1); - EXPECT_EQ(val_2x1, n_2x1); - EXPECT_EQ(val_1x2 + val_2x1, n); // verify block nums + const auto val = helper::cal_block_num(range); + EXPECT_EQ(n_1x1, val.n_1x1); + EXPECT_EQ(n_2x1, val.n_2x1); + EXPECT_EQ(n, val.n_1x2 + val.n_2x1); // verify block nums } - } + }); } TEST(Ranges, derive) { - for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) { + BLOCK_NUM_PARALLEL({ Ranges ranges; ranges.spawn(n, n_2x1, n_1x1); ranges.reverse(); // reverse ranges for derive RangesUnion cases; for (const auto head : Heads) { - ranges.derive(head, cases.ranges(head)); + ranges.derive(static_cast(head), cases.ranges(head)); EXPECT_SORTED_AND_UNIQUE(cases.ranges(head)); // sorted and unique EXPECT_COMMON_CODES(head, cases.ranges(head)); // verify common codes } @@ -54,7 +67,7 @@ TEST(Ranges, derive) { for (const auto head : Heads) { EXPECT_SUBSET(ranges, cases.ranges(head)); // derive ranges is subset } - } + }); } TEST(Ranges, append) { @@ -65,13 +78,15 @@ TEST(Ranges, append) { auto &tmp = ranges += r; EXPECT_EQ(tmp, ranges); // reference of ranges } - std::stable_sort(ranges.begin(), ranges.end()); + std::ranges::stable_sort(ranges.begin(), ranges.end()); EXPECT_EQ(ranges, BasicRanges::instance().fetch()); } TEST(Ranges, reverse) { auto ranges = BasicRanges::instance().fetch(); - auto reverse = ranges | std::views::transform(range_reverse) | std::ranges::to(); + const auto reverse = ranges + | std::views::transform(range_reverse) + | std::ranges::to(); ranges.reverse(); EXPECT_EQ(ranges, reverse); ranges.reverse(); @@ -91,8 +106,8 @@ TEST(Ranges, combine) { ranges.spawn(n, n_2x1, n_1x1); all_ranges += ranges; ranges.reverse(); // reverse ranges for derive - for (const auto head : Heads) { - ranges.derive(head, all_cases.ranges(head)); // derive from sub ranges + for (const auto head : Heads) { // derive from sub ranges + ranges.derive(static_cast(head), all_cases.ranges(head)); } } @@ -104,9 +119,17 @@ TEST(Ranges, combine) { EXPECT_EQ(all_cases, AllCases::instance().fetch()); // verify all cases all_ranges.reverse(); // reverse ranges for derive - for (const auto head : Heads) { + for (const auto head : Heads) { // derive from all ranges all_cases.ranges(head).clear(); - all_ranges.derive(head, all_cases.ranges(head)); // derive from all ranges + all_ranges.derive(static_cast(head), all_cases.ranges(head)); } EXPECT_EQ(all_cases, AllCases::instance().fetch()); // verify content } + +TEST(Ranges, constexpr) { + static_assert(Ranges::check(1, 0x0030FE6A) == 0); + static_assert(Ranges::check(4, 0x001C4ABF) == 0); + + static_assert(Ranges::check(1, 0xA9BF0C00) == 14); + static_assert(Ranges::check(4, 0xFEA13400) == 6); +} diff --git a/src/core_test/helper/internal/parallel.cc b/src/core_test/helper/internal/parallel.cc index 665c398..a4ef4ee 100644 --- a/src/core_test/helper/internal/parallel.cc +++ b/src/core_test/helper/internal/parallel.cc @@ -9,6 +9,28 @@ using klotski::cases::AllCases; using klotski::group::TYPE_ID_LIMIT; using klotski::cases::ALL_CASES_NUM_; +using klotski::cases::RangesUnion; + +void helper::head_parallel(std::function &&func) { + BS::thread_pool pool; + for (auto head : RangesUnion::Heads) { + pool.detach_task([head, &func] { + func(head); + }); + } + pool.wait(); +} + +void helper::block_num_parallel(std::function &&func) { + BS::thread_pool pool; + for (auto [n, n_2x1, n_1x1] : klotski::group::BLOCK_NUM) { + pool.detach_task([n, n_2x1, n_1x1, &func] { + func(n, n_2x1, n_1x1); + }); + } + pool.wait(); +} + void helper::group_parallel(std::function &&func) { // TODO: spawn all Groups } diff --git a/src/core_test/helper/parallel.h b/src/core_test/helper/parallel.h index 4e97c91..f1f1808 100644 --- a/src/core_test/helper/parallel.h +++ b/src/core_test/helper/parallel.h @@ -20,6 +20,18 @@ namespace helper { // ----------------------------------------------------------------------------------------- // +void head_parallel(std::function &&func); + +void block_num_parallel(std::function &&func); + +#define HEAD_PARALLEL(impl) \ + ::helper::head_parallel([](uint64_t head) {impl}) + +#define BLOCK_NUM_PARALLEL(impl) \ + ::helper::block_num_parallel([](int n, int n_2x1, int n_1x1) {impl}) + +// ----------------------------------------------------------------------------------------- // + /// Spawn all valid Groups in parallel. void group_parallel(std::function &&func);