diff --git a/src/core/all_cases/basic_ranges.cc b/src/core/all_cases/basic_ranges.cc index 76a4d95..c160be1 100644 --- a/src/core/all_cases/basic_ranges.cc +++ b/src/core/all_cases/basic_ranges.cc @@ -1,157 +1,64 @@ -#include -#include #include +#include #include -#include "basic_ranges.h" - -static uint32_t range_reverse(uint32_t bin) noexcept { -// bin = ((bin << 16) & 0xFFFF0000) | ((bin >> 16) & 0x0000FFFF); -// bin = ((bin << 8) & 0xFF00FF00) | ((bin >> 8) & 0x00FF00FF); - bin = __builtin_bswap32(bin); - bin = ((bin << 4) & 0xF0F0F0F0) | ((bin >> 4) & 0x0F0F0F0F); - return ((bin << 2) & 0xCCCCCCCC) | ((bin >> 2) & 0x33333333); -} -void build(std::vector &result, int n1, int n2, int n3, int n4) { +#include "basic_ranges.h" - std::vector demo; - demo.reserve(n1 + n2 + n3 + n4); +#include - int move_num = 32 - (n1 + n2 + n3 + n4) * 2; +typedef uint32_t Range; +typedef std::vector Ranges; +typedef std::vector::iterator RangeIter; +typedef std::tuple RangeType; - demo.insert(demo.end(), n1, 0b00); - demo.insert(demo.end(), n2, 0b01); - demo.insert(demo.end(), n3, 0b10); - demo.insert(demo.end(), n4, 0b11); +static const auto RangeTypeNum = 204; -// for (int i = 0; i < n1; ++i) { -// demo.emplace_back(0b00); -// } -// for (int i = 0; i < n2; ++i) { -// demo.emplace_back(0b01); -// } -// for (int i = 0; i < n3; ++i) { -// demo.emplace_back(0b10); -// } -// for (int i = 0; i < n4; ++i) { -// demo.emplace_back(0b11); -// } +static const uint32_t BASIC_RANGES_NUM = 7311921; -// for (auto x : demo) { -// std::cout << x << " "; -// } -// std::cout << std::endl; +class BasicRanges { +public: + static void build_ranges(); - do { + static const Ranges& fetch(); - uint32_t tmp = 0; - for (auto x : demo) { - tmp <<= 2; - tmp |= x; - } - tmp <<= move_num; -// volatile auto r = tmp; - result.emplace_back(tmp); +private: + static Ranges data_; - } while (next_permutation(demo.begin(), demo.end())); -} - -template -void sort(T begin, T end, T kk) { - - std::vector tmp; - tmp.reserve(end - begin); - auto k1 = begin; - auto k2 = kk; - - while (1 == 1) { - if (*k1 < *k2) { - tmp.emplace_back(*k1); - ++k1; - if (k1 == kk) { - tmp.insert(tmp.end(), k2, end); - break; - } - } else { - tmp.emplace_back(*k2); - ++k2; - if (k2 == end) { - tmp.insert(tmp.end(), k1, kk); - break; - } - } - } + static void spawn_ranges(int, int, int, int); +}; - auto p = begin; - for (auto x : tmp) { - *p = x; - ++p; - } +Ranges BasicRanges::data_; +static Range range_reverse(Range bin) noexcept { +#if defined(__GNUC__) || defined(__clang__) + bin = __builtin_bswap32(bin); + // TODO: using `std::byteswap` (c++23) +#else + // FIXME: `_byteswap_ulong` under MSVC + bin = ((bin << 16) & 0xFFFF0000) | ((bin >> 16) & 0x0000FFFF); + bin = ((bin << 8) & 0xFF00FF00) | ((bin >> 8) & 0x00FF00FF); +#endif + bin = ((bin << 4) & 0xF0F0F0F0) | ((bin >> 4) & 0x0F0F0F0F); + return ((bin << 2) & 0xCCCCCCCC) | ((bin >> 2) & 0x33333333); } -template -void sort_v2(ITER_T begin, ITER_T end, ITER_T mid) { - - std::vector tmp {begin, mid}; - auto k1 = tmp.begin(); - auto k2 = mid; - auto target = begin; - - while (1 == 1) { - -// std::cout << *k1 << " vs " << *k2 << std::endl; - - if (*k1 < *k2) { - *target = *k1; - ++target; -// tmp.emplace_back(*k1); - ++k1; - if (k1 == tmp.end()) { - -// memcpy(&*target, &*k2, end - k2); - -// tmp.insert(tmp.end(), k2, end); - break; - } - } else { - *target = *k2; - ++target; -// tmp.emplace_back(*k2); - ++k2; - if (k2 == end) { - -// std::cout << "get it" << std::endl; - -// std::cout << "size = " << (tmp.end() - k1) << std::endl; -// std::cout << (target - begin) - - memcpy(&*target, &*k1, (tmp.end() - k1) * 4); - -// tmp.insert(tmp.end(), k1, kk); - break; - } - } - } -// -// auto p = begin; -// for (auto x : tmp) { -// *p = x; -// ++p; -// } - +consteval static std::array basic_types() { + std::array data; + for (int i = 0, n = 0; n <= 7; ++n) // number of 1x2 and 2x1 block -> 0 ~ 7 + for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) // number of 2x1 block -> 0 ~ n + for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) // number of 1x1 block -> 0 ~ (14 - 2n) + data[i++] = {16 - n * 2 - n_1x1, n - n_2x1, n_2x1, n_1x1}; + return data; } -template -void sort_v3(ITER_T begin, ITER_T end, ITER_T mid) { - std::vector tmp = {begin, mid}; +static void combine_sort(RangeIter begin, RangeIter mid, RangeIter end) { + Ranges tmp = {begin, mid}; auto p = tmp.begin(); for (;;) { if (*p < *mid) { *(begin++) = *(p++); - if (p == tmp.end()) { + if (p == tmp.end()) return; - } } else { *(begin++) = *(mid++); if (mid == end) { @@ -162,88 +69,53 @@ void sort_v3(ITER_T begin, ITER_T end, ITER_T mid) { } } -void demo() { - -// std::vector demo = {1, 2, 5, 9, 11, 3, 6, 7}; -// auto kk = demo.begin() + 5; -// for (auto p = demo.begin(); p < kk; ++p) { -// std::cout << *p << std::endl; -// } -// sort_v3(demo.begin(), demo.end(), kk); -// -// for (auto x : demo) { -// std::cout << x << std::endl; -// } -// return; - - -// uint32_t tmp = 0x5129B263; // 0xC98E6845 -// -// for (uint64_t i = 0; i < 0xFFFFFFFF; ++i) { -// volatile auto r = range_reverse(tmp); -// } - -// printf("%08X\n", tmp); - - std::vector result; - - result.reserve(7311921); - -// build(result, 4, 2, 1, 6); - - std::list pp; - pp.emplace_back(result.begin()); - - for (int n = 0; n <= 7; ++n) // number of 1x2 and 2x1 block -> 0 ~ 7 - for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) // number of 2x1 block -> 0 ~ n - for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) { // number of 1x1 block -> 0 ~ (14 - 2n) - build(result, 16 - n * 2 - n_1x1, n - n_2x1, n_2x1, n_1x1); - pp.emplace_back(result.end()); - } +void BasicRanges::spawn_ranges(int n1, int n2, int n3, int n4) { + std::vector series; + auto n = n1 + n2 + n3 + n4; + auto offset = (16 - n) << 1; + series.insert(series.end(), n1, 0b00); + series.insert(series.end(), n2, 0b01); + series.insert(series.end(), n3, 0b10); + series.insert(series.end(), n4, 0b11); -// std::stable_sort(result.begin(), result.end()); -// return; + do { + uint32_t range = 0; + for (auto x : series) + (range <<= 2) |= x; + data_.emplace_back(range << offset); + } while (next_permutation(series.begin(), series.end())); +} -// sort(result.begin() + 363149, result.begin() + 459674, result.begin() + 408194); +void BasicRanges::build_ranges() { + data_.reserve(BASIC_RANGES_NUM); + std::list flags {data_.begin()}; - while (1 == 1) { - auto begin = pp.begin(); - while (1 == 1) { - auto mid = begin; - ++mid; - if (mid == pp.end()) { - break; - } - auto end = mid; - ++end; - if (end == pp.end()) { - break; - } -// std::cout << (*begin - result.begin()) << " " << (*mid - result.begin()) << " " << (*end - result.begin()) << std::endl; - sort_v3(*begin, *end, *mid); - ++begin; - ++begin; - pp.erase(mid); - } - if (pp.size() == 2) { - break; - } + for (auto &t : basic_types()) { + spawn_ranges(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t)); + flags.emplace_back(data_.end()); } + do { + std::list::iterator begin = flags.begin(), mid, end; + while (++(mid = begin) != flags.end() && ++(end = mid) != flags.end()) { + combine_sort(*begin, *mid, *end); + flags.erase(mid); + begin = end; + } + } while (flags.size() > 2); - -// std::sort(result.begin(), result.end()); -// std::stable_sort(result.begin(), result.end()); - - for (auto &x : result) { + for (auto &x : data_) { x = range_reverse(x); } +} - for (auto x : result) { - printf("%08X\n", x); - } +const Ranges& BasicRanges::fetch() { + return data_; +} -// for (uint32_t i = 0; i < 0xFF; ++i) { -// build(result, 4, 2, 1, 6); -// } +void demo() { + BasicRanges::build_ranges(); + for (auto x : BasicRanges::fetch()) { + printf("%08X\n", x); + } } diff --git a/src/core/all_cases/basic_ranges.h b/src/core/all_cases/basic_ranges.h index 153c3b6..baa32a5 100644 --- a/src/core/all_cases/basic_ranges.h +++ b/src/core/all_cases/basic_ranges.h @@ -37,44 +37,44 @@ namespace klotski { /// basic ranges count const uint32_t BASIC_RANGES_SIZE = 7311921; - class BasicRanges { - public: - /// Three basic states, one-way transition. - /// {NOT_INIT} -> {BUILDING} -> {AVAILABLE} - enum Status { - NOT_INIT, - BUILDING, - AVAILABLE, - }; - typedef std::vector basic_ranges_t; - - /// Trigger the build process, from `NOT_INIT` to `BUILDING`. - static void build(); - - /// Get current status of BasicRanges. - static Status status() noexcept; - - /// Blocking access to constructed data. - static const basic_ranges_t& fetch(); - - private: - static bool available_; - static std::mutex building_; - static basic_ranges_t data_; - - static void build_data(); - - public: - /// The number of types of blocks. - struct generate_t { - int n1; // number of `00` -> space - int n2; // number of `01` -> 1x2 block - int n3; // number of `10` -> 2x1 block - int n4; // number of `11` -> 1x1 block - }; - - /// Generate all basic-ranges of the specified type. - static void generate(basic_ranges_t &release, generate_t info); - }; +// class BasicRanges { +// public: +// /// Three basic states, one-way transition. +// /// {NOT_INIT} -> {BUILDING} -> {AVAILABLE} +// enum Status { +// NOT_INIT, +// BUILDING, +// AVAILABLE, +// }; +// typedef std::vector basic_ranges_t; +// +// /// Trigger the build process, from `NOT_INIT` to `BUILDING`. +// static void build(); +// +// /// Get current status of BasicRanges. +// static Status status() noexcept; +// +// /// Blocking access to constructed data. +// static const basic_ranges_t& fetch(); +// +// private: +// static bool available_; +// static std::mutex building_; +// static basic_ranges_t data_; +// +// static void build_data(); +// +// public: +// /// The number of types of blocks. +// struct generate_t { +// int n1; // number of `00` -> space +// int n2; // number of `01` -> 1x2 block +// int n3; // number of `10` -> 2x1 block +// int n4; // number of `11` -> 1x1 block +// }; +// +// /// Generate all basic-ranges of the specified type. +// static void generate(basic_ranges_t &release, generate_t info); +// }; } // namespace klotski