From ca945b450fb76a27c19e4b008043038420f5a408 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sun, 22 Sep 2024 14:18:43 +0800 Subject: [PATCH] test: add global helper module --- src/core_test/CMakeLists.txt | 10 ++- src/core_test/cases/group_union.cc | 109 +++++++++++--------------- src/core_test/cases/helper/cases.h | 2 - src/core_test/cases/helper/helper.cc | 22 ------ src/core_test/helper/internal/impl.cc | 86 ++++++++++++++++++++ src/core_test/helper/parallel.h | 51 ++++++++++++ 6 files changed, 191 insertions(+), 89 deletions(-) delete mode 100644 src/core_test/cases/helper/helper.cc create mode 100644 src/core_test/helper/internal/impl.cc create mode 100644 src/core_test/helper/parallel.h diff --git a/src/core_test/CMakeLists.txt b/src/core_test/CMakeLists.txt index 581d8ff..252f3de 100644 --- a/src/core_test/CMakeLists.txt +++ b/src/core_test/CMakeLists.txt @@ -12,6 +12,13 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) # ------------------------------------------------------------------------------------ # +add_library(test_helper + helper/internal/impl.cc +) +target_link_libraries(test_helper PRIVATE klotski_core bs::thread_pool) + +# ------------------------------------------------------------------------------------ # + set(KLSK_TEST_CASES_SRC cases/ranges.cc cases/ranges_union.cc @@ -19,13 +26,12 @@ set(KLSK_TEST_CASES_SRC cases/all_cases.cc cases/group_union.cc cases/group.cc - cases/helper/helper.cc cases/helper/block_num.cc cases/helper/group_impl.cc ) add_executable(test_klotski_cases ${KLSK_TEST_CASES_SRC}) -target_link_libraries(test_klotski_cases PRIVATE ${KLSK_TEST_DEPS}) +target_link_libraries(test_klotski_cases PRIVATE ${KLSK_TEST_DEPS} test_helper) add_test(NAME klotski_cases COMMAND test_klotski_cases) # ------------------------------------------------------------------------------------ # diff --git a/src/core_test/cases/group_union.cc b/src/core_test/cases/group_union.cc index f2b1fe6..1f7038b 100644 --- a/src/core_test/cases/group_union.cc +++ b/src/core_test/cases/group_union.cc @@ -9,6 +9,8 @@ #include "helper/cases.h" #include "common_code/common_code.h" +#include "helper/parallel.h" + using klotski::codec::ShortCode; using klotski::cases::Group; @@ -23,96 +25,77 @@ using klotski::cases::ALL_GROUP_NUM; EXPECT_SORTED_AND_UNIQUE(R); \ EXPECT_EQ(R.back(), R.size() - 1) -TEST(GroupUnion, basic) { - - EXPECT_FALSE(GroupUnion::create(TYPE_ID_LIMIT).has_value()); - - type_id_parallel([](uint32_t type_id) { +#define EXPECT_REPEAT(R, val) \ + EXPECT_FALSE(R.empty()); \ + EXPECT_EQ(R.front(), val); \ + EXPECT_EQ(std::adjacent_find(R.begin(), R.end(), std::not_equal_to<>()), R.end()) +TEST(GroupUnion, basic) { + TYPE_ID_PARALLEL({ EXPECT_TRUE(GroupUnion::create(type_id).has_value()); EXPECT_EQ(GroupUnion::create(type_id).value().unwrap(), type_id); EXPECT_EQ(GroupUnion::unsafe_create(type_id).unwrap(), type_id); + }); + EXPECT_FALSE(GroupUnion::create(TYPE_ID_LIMIT).has_value()); - auto group_union = GroupUnion::unsafe_create(type_id); - auto groups = group_union.groups(); - for (const auto group : groups) { - EXPECT_EQ(group.type_id(), type_id); - } + GROUP_UNION_PARALLEL({ + const auto groups = group_union.groups(); + EXPECT_EQ(groups.size(), group_union.group_num()); + + auto get_type_id = [](const auto g) { return g.type_id(); }; + const auto type_ids = groups | std::views::transform(get_type_id) | std::ranges::to(); + EXPECT_REPEAT(type_ids, group_union.unwrap()); - auto group_ids = groups | std::views::transform([](Group g) { - return g.group_id(); - }) | std::ranges::to(); + auto get_group_id = [](const auto g) { return g.group_id(); }; + const auto group_ids = groups | std::views::transform(get_group_id) | std::ranges::to(); EXPECT_IOTA(group_ids); - for (auto group_id : group_ids) { + for (const auto g : group_union.groups()) { + auto type_id = g.type_id(); + auto group_id = g.group_id(); EXPECT_TRUE(group_union.group(group_id).has_value()); - EXPECT_EQ(group_union.group(group_id).value().type_id(), type_id); - EXPECT_EQ(group_union.group(group_id).value().group_id(), group_id); + EXPECT_EQ(group_union.group(group_id)->type_id(), type_id); + EXPECT_EQ(group_union.group(group_id)->group_id(), group_id); } - - EXPECT_FALSE(group_union.group(group_ids.size()).has_value()); - + EXPECT_FALSE(group_union.group(group_union.group_num()).has_value()); }); } TEST(GroupUnion, constant) { - EXPECT_EQ(TYPE_ID_LIMIT, 203); - EXPECT_EQ(ALL_GROUP_NUM, 25422); - // TODO: verify from local builder + EXPECT_EQ(TYPE_ID_LIMIT, group_union_num()); - // TODO: verify TYPE_ID_LIMIT / ALL_GROUP_NUM data + uint32_t sum = 0; + for (uint32_t i = 0; i < group_union_num(); ++i) { + sum += group_num(i); + } + EXPECT_EQ(ALL_GROUP_NUM, sum); // TODO: verify GROUP_UNION_SIZE (size) / GROUP_NUM (group_num) / MAX_GROUP_SIZE (max_group_size) // test from member function directly? - - EXPECT_EQ(TYPE_ID_LIMIT, group_union_num()); - } TEST(GroupUnion, values) { + GROUP_UNION_PARALLEL({ + auto type_id = group_union.unwrap(); + auto &cases = group_union_cases(type_id); - type_id_parallel([](uint32_t type_id) { - - auto &kk = group_union_cases(type_id); - EXPECT_EQ(GroupUnion::unsafe_create(type_id).size(), kk.size()); - EXPECT_EQ(GroupUnion::unsafe_create(type_id).group_num(), group_num(type_id)); - - auto groups = GroupUnion::unsafe_create(type_id).groups(); - - auto kk_view = groups | std::views::transform([](Group group) { - return group.size(); - }); - - auto max_it = *std::ranges::max_element(kk_view); - - EXPECT_EQ(GroupUnion::unsafe_create(type_id).max_group_size(), max_it); + EXPECT_EQ(group_union.size(), cases.size()); + EXPECT_EQ(group_union.cases().codes(), cases); + EXPECT_EQ(group_union.group_num(), group_num(type_id)); - }); - -} - -TEST(GroupUnion, cases) { - type_id_parallel([](uint32_t type_id) { - auto cases = group_union_cases(type_id); - EXPECT_EQ(cases, GroupUnion::unsafe_create(type_id).cases().codes()); + auto get_group_size = [](auto g) { return g.size(); }; + const auto sizes = group_union.groups() | std::views::transform(get_group_size); + EXPECT_EQ(group_union.max_group_size(), *std::ranges::max_element(sizes)); }); } TEST(GroupUnion, type_id) { ShortCode::speed_up(true); - - // TODO: using `common_code_parallel` - for (uint64_t head = 0; head < 16; ++head) { - for (const auto range : AllCases::instance().fetch()[head]) { - auto common_code = CommonCode::unsafe_create(head << 32 | range); - auto short_code = common_code.to_short_code(); - auto raw_code = common_code.to_raw_code(); - - auto expect = to_type_id(cal_block_num(range)); - EXPECT_EQ(GroupUnion::from_raw_code(raw_code).unwrap(), expect); - EXPECT_EQ(GroupUnion::from_short_code(short_code).unwrap(), expect); - EXPECT_EQ(GroupUnion::from_common_code(common_code).unwrap(), expect); - } - } + COMMON_CODE_PARALLEL({ + auto type_id = to_type_id(cal_block_num(code.unwrap())); + EXPECT_EQ(GroupUnion::from_common_code(code).unwrap(), type_id); + EXPECT_EQ(GroupUnion::from_raw_code(code.to_raw_code()).unwrap(), type_id); + EXPECT_EQ(GroupUnion::from_short_code(code.to_short_code()).unwrap(), type_id); + }); } diff --git a/src/core_test/cases/helper/cases.h b/src/core_test/cases/helper/cases.h index de76804..685873b 100644 --- a/src/core_test/cases/helper/cases.h +++ b/src/core_test/cases/helper/cases.h @@ -116,5 +116,3 @@ const std::vector& group_union_cases(uint32_t type_id); const std::vector& group_cases(uint32_t type_id, uint32_t group_id); // ----------------------------------------------------------------------------------------- // - -void type_id_parallel(std::function &&func); diff --git a/src/core_test/cases/helper/helper.cc b/src/core_test/cases/helper/helper.cc deleted file mode 100644 index 313b770..0000000 --- a/src/core_test/cases/helper/helper.cc +++ /dev/null @@ -1,22 +0,0 @@ -#include - -#include "cases.h" - -using klotski::cases::TYPE_ID_LIMIT; - -void type_id_parallel(std::function &&func) { - - BS::thread_pool pool; - - // TODO: using `detach_sequence` - for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { - - pool.detach_task([type_id, func = std::move(func)]() { - func(type_id); - }); - - } - - pool.wait(); - -} diff --git a/src/core_test/helper/internal/impl.cc b/src/core_test/helper/internal/impl.cc new file mode 100644 index 0000000..cbafd1b --- /dev/null +++ b/src/core_test/helper/internal/impl.cc @@ -0,0 +1,86 @@ +#include + +#include + +#include "group/group.h" +#include "helper/parallel.h" +#include "all_cases/all_cases.h" + +using klotski::cases::AllCases; +using klotski::cases::TYPE_ID_LIMIT; +using klotski::cases::ALL_CASES_NUM_; + +void helper::type_id_parallel(std::function &&func) { + + BS::thread_pool pool; + + // TODO: using `detach_sequence` + for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { + + pool.detach_task([type_id, &func]() { + func(type_id); + }); + + } + + pool.wait(); + +} + +void helper::group_union_parallel(std::function &&func) { + type_id_parallel([&func](uint32_t type_id) { + func(GroupUnion::unsafe_create(type_id)); + }); +} + +void helper::common_code_parallel(std::function)> &&func) { + + static auto codes = AllCases::instance().fetch().codes(); + + BS::thread_pool pool; + + // TODO: enhance performance + + pool.detach_blocks((uint64_t)0, codes.size(), [&func](auto start, auto end) { + + func(std::span {codes.data() + start, end - start}); + + }, 16); + + pool.wait(); + +} + +void helper::raw_code_parallel(std::function)> &&func) { + + auto common_codes = AllCases::instance().fetch().codes(); + static auto codes = std::vector {common_codes.begin(), common_codes.end()}; + + BS::thread_pool pool; + pool.detach_blocks((uint64_t)0, codes.size(), [&func](auto start, auto end) { + + func(std::span {codes.data() + start, end - start}); + + }, 16); + + pool.wait(); + +} + +void helper::short_code_parallel(std::function)> &&func) { + static auto codes = []() { + std::vector v (klotski::codec::SHORT_CODE_LIMIT); + std::iota(v.begin(), v.end(), 0); + return v; + }(); + + BS::thread_pool pool; + pool.detach_blocks((uint64_t)0, codes.size(), [&func](auto start, auto end) { + + auto span = std::span {codes.data() + start, end - start}; + func(std::bit_cast>(span)); + + }, 16); + + pool.wait(); +} diff --git a/src/core_test/helper/parallel.h b/src/core_test/helper/parallel.h new file mode 100644 index 0000000..cf241a9 --- /dev/null +++ b/src/core_test/helper/parallel.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include "raw_code/raw_code.h" +#include "short_code/short_code.h" +#include "common_code/common_code.h" + +using klotski::codec::RawCode; +using klotski::codec::ShortCode; +using klotski::codec::CommonCode; + +using klotski::cases::GroupUnion; + +namespace helper { + +// ----------------------------------------------------------------------------------------- // + +void type_id_parallel(std::function &&func); + +void group_union_parallel(std::function &&func); + +#define TYPE_ID_PARALLEL(impl) \ + helper::type_id_parallel([](uint32_t type_id) {impl}) + +#define GROUP_UNION_PARALLEL(impl) \ + helper::group_union_parallel([](GroupUnion group_union) {impl}) + +// ----------------------------------------------------------------------------------------- // + +/// Spawn all valid RawCodes in parallel. +void raw_code_parallel(std::function)> &&func); + +/// Spawn all valid ShortCodes in parallel. +void short_code_parallel(std::function)> &&func); + +/// Spawn all valid CommonCodes in parallel. +void common_code_parallel(std::function)> &&func); + +#define CODE_PARALLEL(Type, type, impl) \ + helper::type##_code_parallel([](std::span codes) { \ + for (auto code : codes) {impl} \ + }) + +#define RAW_CODE_PARALLEL(impl) CODE_PARALLEL(Raw, raw, impl) +#define SHORT_CODE_PARALLEL(impl) CODE_PARALLEL(Short, short, impl) +#define COMMON_CODE_PARALLEL(impl) CODE_PARALLEL(Common, common, impl) + +// ----------------------------------------------------------------------------------------- // + +} // namespace helper