diff --git a/src/core/group/internal/group.cc b/src/core/group/internal/group.cc index ebd1bd5..1d0a90b 100644 --- a/src/core/group/internal/group.cc +++ b/src/core/group/internal/group.cc @@ -17,6 +17,12 @@ using klotski::mover::MaskMover; using klotski::group::GROUP_DATA; using klotski::group::PATTERN_DATA; +#define RELEASE_TO(RU) \ + [&data](const RawCode raw_code) { \ + const auto code = raw_code.to_common_code().unwrap(); \ + data.ranges(code >> 32).emplace_back(static_cast(code)); \ + } + template KLSK_NOINLINE static void extend(const RawCode seed, const size_t reserve, MF add_mirror, RF release) { std::vector queue, mirrors; @@ -53,53 +59,52 @@ KLSK_NOINLINE static void extend(const RawCode seed, const size_t reserve, MF ad for (const auto code : mirrors) { release(code); } } -#define RELEASE_TO(RU) \ - [&data](const RawCode raw_code) { \ - const auto code = raw_code.to_common_code().unwrap(); \ - data.ranges(code >> 32).emplace_back(static_cast(code)); \ - } - template -static RangesUnion extend_type_xxx(const RawCode seed, const size_t reserve) { - RangesUnion data {}; +static RangesUnion spawn_group(const RawCode seed, const size_t reserve) { + const auto ctr_mirror = [](const RawCode code, auto spawn) { + spawn(code.to_diagonal_mirror()); + }; + + const auto vrt_mirror = [](const RawCode code, auto spawn) { + spawn(code.to_vertical_mirror()); + }; + + const auto hor_mirror = [](const RawCode code, auto spawn) { + if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { + spawn(m_hor); + } + }; + + const auto full_mirror = [](const RawCode code, auto spawn) { + const auto m_vrt = code.to_vertical_mirror(); + spawn(m_vrt); + if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { + spawn(m_hor); + spawn(m_vrt.to_horizontal_mirror()); + } + }; - if constexpr(TYPE == Group::MirrorType::Ordinary) { + RangesUnion data {}; // TODO: how to reserve `data` - extend(seed, reserve, [](RawCode, auto) {}, RELEASE_TO(data)); + // TODO: it seems that reserve will actually lose speed, why??? + // auto val = reserve / 8; + // data.ranges(0).reserve(val); data.ranges(1).reserve(val); data.ranges(2).reserve(val); + // data.ranges(4).reserve(val); data.ranges(5).reserve(val); data.ranges(6).reserve(val); + // data.ranges(8).reserve(val); data.ranges(9).reserve(val); data.ranges(10).reserve(val); + // data.ranges(12).reserve(val); data.ranges(13).reserve(val); data.ranges(14).reserve(val); + // TODO: maybe we don't need `else` + if constexpr(TYPE == Group::MirrorType::Full) { + extend(seed, reserve, full_mirror, RELEASE_TO(data)); } else if constexpr(TYPE == Group::MirrorType::Horizontal) { - - extend(seed, reserve, [](const RawCode code, auto callback) { - if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { - callback(m_hor); - } - }, RELEASE_TO(data)); - - } else if constexpr(TYPE == Group::MirrorType::Vertical) { - - extend(seed, reserve, [](const RawCode code, auto callback) { - callback(code.to_vertical_mirror()); - }, RELEASE_TO(data)); - + extend(seed, reserve, hor_mirror, RELEASE_TO(data)); } else if constexpr(TYPE == Group::MirrorType::Centro) { - - extend(seed, reserve, [](const RawCode code, auto callback) { - callback(code.to_diagonal_mirror()); - }, RELEASE_TO(data)); - - } else if constexpr(TYPE == Group::MirrorType::Full) { - - extend(seed, reserve, [](const RawCode code, auto callback) { - const auto m_vrt = code.to_vertical_mirror(); - callback(m_vrt); - if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { - callback(m_hor); - callback(m_vrt.to_horizontal_mirror()); - } - }, RELEASE_TO(data)); - + extend(seed, reserve, ctr_mirror, RELEASE_TO(data)); + } else if constexpr(TYPE == Group::MirrorType::Vertical) { + extend(seed, reserve, vrt_mirror, RELEASE_TO(data)); + } else if constexpr(TYPE == Group::MirrorType::Ordinary) { + extend(seed, reserve, [](RawCode, auto) {}, RELEASE_TO(data)); } - return data; } @@ -148,112 +153,112 @@ static RangesUnion extend_type_xxx(const RawCode seed, const size_t reserve) { // return data; // } -template -KLSK_NOINLINE static void spawn_pattern(RawCode seed, const size_t reserve, MFunc add_mirror, RFunc release) { - std::vector queue; - std::vector mirrors; - phmap::flat_hash_map cases; - - queue.reserve(reserve); - mirrors.reserve(reserve); - cases.reserve(static_cast(reserve * 1.56)); - - auto mover = MaskMover([&queue, &cases, &mirrors, add_mirror](RawCode code, uint64_t hint) { - if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { - iter->second |= hint; // update hint - return; - } - queue.emplace_back(code); - add_mirror(code, [&cases, &mirrors](RawCode mirror) { - cases.emplace(mirror, 0); // without hint - mirrors.emplace_back(mirror); - }); - }); - - uint64_t offset = 0; - queue.emplace_back(seed); - cases.emplace(seed, 0); - add_mirror(seed, [&mirrors, &cases](RawCode mirror) { - cases.emplace(mirror, 0); // without hint - mirrors.emplace_back(mirror); - }); - while (offset != queue.size()) { - const auto curr = queue[offset++]; - mover.next_cases(curr, cases.find(curr)->second); - } - - for (const auto code : queue) { release(code); } - for (const auto code : mirrors) { release(code); } -} - -#define OUTPUT(VAR, EXPL, OUT) \ - const auto VAR = (EXPL).to_common_code().unwrap(); \ - OUT.ranges(VAR >> 32).emplace_back(static_cast(VAR)) - -#define KLSK_CONCAT_IMPL(X, Y) X##Y - -#define KLSK_CONCAT(X, Y) KLSK_CONCAT_IMPL(X, Y) +// template +// KLSK_NOINLINE static void extend_2(const RawCode seed, const size_t reserve, MF add_mirror, RF release) { +// std::vector queue, mirrors; +// phmap::flat_hash_map cases; +// +// queue.reserve(reserve); mirrors.reserve(reserve); +// cases.reserve(static_cast(static_cast(reserve) * 1.56)); // reduce load factor +// +// auto mover = MaskMover([&queue, &cases, &mirrors, add_mirror](RawCode code, uint64_t hint) { +// if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { +// iter->second |= hint; // update hint +// return; +// } +// queue.emplace_back(code); +// add_mirror(code, [&cases, &mirrors](RawCode mirror) { +// cases.emplace(mirror, 0); // without hint +// mirrors.emplace_back(mirror); +// }); +// }); +// +// queue.emplace_back(seed); +// cases.emplace(seed, 0); +// add_mirror(seed, [&mirrors, &cases](RawCode mirror) { +// cases.emplace(mirror, 0); // without hint +// mirrors.emplace_back(mirror); +// }); +// +// uint64_t offset = 0; +// while (offset != queue.size()) { +// const auto curr = queue[offset++]; +// mover.next_cases(curr, cases.find(curr)->second); +// } +// +// for (const auto code : queue) { release(code); } +// for (const auto code : mirrors) { release(code); } +// } #define OUTPUT_IMPL(VAR, EXPL, OUT) \ const auto VAR = (EXPL).to_common_code().unwrap(); \ OUT.ranges(VAR >> 32).emplace_back(static_cast(VAR)) #define OUTPUT(EXPL, OUT) \ - OUTPUT_IMPL(KLSK_CONCAT(c_, __COUNTER__), EXPL, OUT) - -KLSK_NOINLINE static void spawn_full_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { - spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { - // const auto code = raw_code.to_common_code().unwrap(); - // output.ranges(code >> 32).emplace_back(static_cast(code)); - // OUTPUT(code, raw_code, output); - OUTPUT(raw_code, output); - }); -} - -KLSK_NOINLINE static void spawn_hor_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { - spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { - // const auto code = raw_code.to_common_code().unwrap(); - // output.ranges(code >> 32).emplace_back(static_cast(code)); - OUTPUT(raw_code, output); - - // const auto code_ = raw_code.to_vertical_mirror().to_common_code().unwrap(); - // output.ranges(code_ >> 32).emplace_back(static_cast(code_)); - OUTPUT(raw_code.to_vertical_mirror(), output); - }); -} - -KLSK_NOINLINE static void spawn_ver_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { - spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { - // const auto code = raw_code.to_common_code().unwrap(); - // output.ranges(code >> 32).emplace_back(static_cast(code)); - OUTPUT(raw_code, output); + OUTPUT_IMPL(KLSK_UNIQUE(tmp), EXPL, OUT) - // const auto code_ = raw_code.to_horizontal_mirror().to_common_code().unwrap(); - // output.ranges(code_ >> 32).emplace_back(static_cast(code_)); - OUTPUT(raw_code.to_horizontal_mirror(), output); - }); -} +template +KLSK_NOINLINE static void spawn_xxx_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { -KLSK_NOINLINE static void spawn_ord_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { - spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { - // const auto code = raw_code.to_common_code().unwrap(); - // output.ranges(code >> 32).emplace_back(static_cast(code)); - OUTPUT(raw_code, output); + if constexpr(TYPE == Group::MirrorType::Full) { + extend(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { + OUTPUT(raw_code, output); + }); + } - // const auto code_1 = raw_code.to_vertical_mirror().to_common_code().unwrap(); - // output.ranges(code_1 >> 32).emplace_back(static_cast(code_1)); - OUTPUT(raw_code.to_vertical_mirror(), output); + if constexpr(TYPE == Group::MirrorType::Horizontal) { + extend(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { + OUTPUT(raw_code, output); + OUTPUT(raw_code.to_vertical_mirror(), output); + }); + } - // const auto code_2 = raw_code.to_horizontal_mirror().to_common_code().unwrap(); - // output.ranges(code_2 >> 32).emplace_back(static_cast(code_2)); - OUTPUT(raw_code.to_horizontal_mirror(), output); + if constexpr(TYPE == Group::MirrorType::Vertical) { + extend(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { + OUTPUT(raw_code, output); + OUTPUT(raw_code.to_horizontal_mirror(), output); + }); + } - // const auto code_3 = raw_code.to_diagonal_mirror().to_common_code().unwrap(); - // output.ranges(code_3 >> 32).emplace_back(static_cast(code_3)); - OUTPUT(raw_code.to_diagonal_mirror(), output); // TODO: perf it - }); + if constexpr(TYPE == Group::MirrorType::Ordinary) { + extend(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { + OUTPUT(raw_code, output); + OUTPUT(raw_code.to_vertical_mirror(), output); + OUTPUT(raw_code.to_horizontal_mirror(), output); + OUTPUT(raw_code.to_diagonal_mirror(), output); // TODO: perf it + }); + } } +// KLSK_NOINLINE static void spawn_full_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { +// extend(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { +// OUTPUT(raw_code, output); +// }); +// } +// +// KLSK_NOINLINE static void spawn_hor_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { +// extend(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { +// OUTPUT(raw_code, output); +// OUTPUT(raw_code.to_vertical_mirror(), output); +// }); +// } +// +// KLSK_NOINLINE static void spawn_ver_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { +// extend(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { +// OUTPUT(raw_code, output); +// OUTPUT(raw_code.to_horizontal_mirror(), output); +// }); +// } +// +// KLSK_NOINLINE static void spawn_ord_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { +// extend(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { +// OUTPUT(raw_code, output); +// OUTPUT(raw_code.to_vertical_mirror(), output); +// OUTPUT(raw_code.to_horizontal_mirror(), output); +// OUTPUT(raw_code.to_diagonal_mirror(), output); // TODO: perf it +// }); +// } + KLSK_NOINLINE static RangesUnion extend_pro(uint8_t type_id) { RangesUnion others {}; auto gu = GroupUnion::unsafe_create(type_id); @@ -265,13 +270,17 @@ KLSK_NOINLINE static RangesUnion extend_pro(uint8_t type_id) { auto size = (PATTERN_DATA[flat_id] >> 3) & 0xFFFFF; if (mirror_type == Group::MirrorType::Full) { - spawn_full_pattern(seed, size, others); + spawn_xxx_pattern(seed, size, others); + // spawn_full_pattern(seed, size, others); } else if (mirror_type == Group::MirrorType::Horizontal) { - spawn_hor_pattern(seed, size, others); + // spawn_hor_pattern(seed, size, others); + spawn_xxx_pattern(seed, size, others); } else if (mirror_type == Group::MirrorType::Vertical) { - spawn_ver_pattern(seed, size, others); + // spawn_ver_pattern(seed, size, others); + spawn_xxx_pattern(seed, size, others); } else if (mirror_type == Group::MirrorType::Ordinary) { - spawn_ord_pattern(seed, size, others); + // spawn_ord_pattern(seed, size, others); + spawn_xxx_pattern(seed, size, others); } } @@ -285,10 +294,12 @@ KLSK_NOINLINE static RangesUnion extend_pro(uint8_t type_id) { RangesUnion Group::cases() const { if (const auto gu = GroupUnion::unsafe_create(type_id_); gu.group_num() == 1) { + // std::println("type_a: {}", size()); return gu.cases(); } if (pattern_id_ == 0 && mirror_type() == MirrorType::Full) { // TODO: black-list filter + // std::println("type_b: {}", size()); return extend_pro(type_id_); // return GroupUnion::unsafe_create(type_id_).cases(); } @@ -303,98 +314,22 @@ RangesUnion Group::cases() const { seed = seed.to_diagonal_mirror(); } - // const auto centro_mirror = [](const RawCode code, auto callback) { - // callback(code.to_diagonal_mirror()); - // }; - // const auto vertical_mirror = [](const RawCode code, auto callback) { - // callback(code.to_vertical_mirror()); - // }; - // const auto horizontal_mirror = [](const RawCode code, auto callback) { - // if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { - // callback(m_hor); - // } - // }; - // const auto full_mirror = [](const RawCode code, auto callback) { - // const auto m_vrt = code.to_vertical_mirror(); - // callback(m_vrt); - // if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { - // callback(m_hor); - // callback(m_vrt.to_horizontal_mirror()); - // } - // }; - - // TODO: how to reserve `data` RangesUnion data; - - // if (mirror_type() == MirrorType::Ordinary) { - // // std::println("Ordinary"); // 24892 - // // extend(seed, size(), [](RawCode, auto) {}, RELEASE_TO(data)); - // - // data = extend_ord(seed, size()); - // - // } else if (mirror_type() == MirrorType::Horizontal) { - // // std::println("Horizontal"); // 294 - // // extend(seed, size(), [](const RawCode code, auto callback) { - // // if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { - // // callback(m_hor); - // // } - // // }, RELEASE_TO(data)); - // // return extend_hor(seed, size()); - // - // data = extend_hor(seed, size()); - // - // } else if (mirror_type() == MirrorType::Vertical) { - // // std::println("Vertical"); // 54 - // // extend(seed, size(), vertical_mirror, RELEASE_TO(data)); - // - // data = extend_ver(seed, size()); - // - // } else if (mirror_type() == MirrorType::Full) { - // // std::println("Full"); // 3 - // // extend(seed, size(), full_mirror, RELEASE_TO(data)); - // - // data = extend_type_x(seed, size()); - // - // } else { - // // std::println("Centro"); // 4 - // // extend(seed, size(), centro_mirror, RELEASE_TO(data)); - // - // data = extend_diag(seed, size()); - // - // } - if (mirror_type() == MirrorType::Full) { - // data = extend_type_full(seed, size()); - data = extend_type_xxx(seed, size()); + data = spawn_group(seed, size()); } else if (mirror_type() == MirrorType::Horizontal) { - // data = extend_type_hor(seed, size()); - data = extend_type_xxx(seed, size()); + data = spawn_group(seed, size()); } else if (mirror_type() == MirrorType::Vertical) { - // data = extend_type_vrt(seed, size()); - data = extend_type_xxx(seed, size()); + data = spawn_group(seed, size()); } else if (mirror_type() == MirrorType::Centro) { - // data = extend_type_diag(seed, size()); - data = extend_type_xxx(seed, size()); + data = spawn_group(seed, size()); } else { - // data = extend_type_ord(seed, size()); - data = extend_type_xxx(seed, size()); + data = spawn_group(seed, size()); } - - // if (mirror_type() == MirrorType::Ordinary) { - // data = extend_type_ord(seed, size()); - // } else if (mirror_type() == MirrorType::Horizontal) { - // data = extend_type_hor(seed, size()); - // } else if (mirror_type() == MirrorType::Vertical) { - // data = extend_type_vrt(seed, size()); - // } else if (mirror_type() == MirrorType::Full) { - // data = extend_type_full(seed, size()); - // } else { - // data = extend_type_diag(seed, size()); - // } - for (const auto head : RangesUnion::Heads) { std::stable_sort(data.ranges(head).begin(), data.ranges(head).end()); } + // std::println("type_c: {}", size()); return data; } diff --git a/src/core/utils/utility.h b/src/core/utils/utility.h index 628134e..e596591 100644 --- a/src/core/utils/utility.h +++ b/src/core/utils/utility.h @@ -46,6 +46,12 @@ #define KLSK_STRING(x) #x +#define KLSK_CONCAT_IMPL(X, Y) X##Y + +#define KLSK_CONCAT(X, Y) KLSK_CONCAT_IMPL(X, Y) + +#define KLSK_UNIQUE(PREFIX) KLSK_CONCAT(PREFIX##_, __COUNTER__) + #if defined(__clang__) #define KLSK_UNROLL(N) _Pragma(KLSK_STRING(unroll N)) #elif defined(__GNUC__)