From 878a0a5efc2bbd46409b40c5c328011141e4a125 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sun, 8 Jan 2023 10:59:39 +0800 Subject: [PATCH] feat: framework of BasicRanges --- all_cases/CMakeLists.txt | 3 +- all_cases/all_cases.h | 29 +++++--- all_cases/basic_ranges.cc | 141 ++++++++++++++++++++++++++++++++++++++ all_cases/basic_ranges.h | 32 +++++++++ all_cases/common.cc | 39 +++++++++++ all_cases/common.h | 9 +++ all_cases/main.cc | 21 +++--- 7 files changed, 252 insertions(+), 22 deletions(-) create mode 100644 all_cases/basic_ranges.cc create mode 100644 all_cases/basic_ranges.h create mode 100644 all_cases/common.cc create mode 100644 all_cases/common.h diff --git a/all_cases/CMakeLists.txt b/all_cases/CMakeLists.txt index f3cc81a..649363a 100644 --- a/all_cases/CMakeLists.txt +++ b/all_cases/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.0) set(CMAKE_CXX_STANDARD 14) -add_executable(klotski main.cc all_cases.cc) +#add_executable(klotski main.cc all_cases.cc) +add_executable(klotski main.cc basic_ranges.cc common.cc) target_link_libraries(klotski pthread) diff --git a/all_cases/all_cases.h b/all_cases/all_cases.h index ff1e870..ad127d3 100644 --- a/all_cases/all_cases.h +++ b/all_cases/all_cases.h @@ -4,14 +4,21 @@ #include #include -class AllCases { -public: - static std::vector basic_ranges; - - static void build_basic_ranges(); - - static bool basic_ranges_available; - - static std::mutex basic_ranges_building; - -}; +//class BasicRanges { +//public: +// +// +// +// static std::vector basic_ranges; +// +// static void build_basic_ranges(); +// +// static bool basic_ranges_available; +// +// static std::mutex basic_ranges_building; +// +//private: +// +// void generate_ranges(int n1, int n2, int n3, int n4); +// +//}; diff --git a/all_cases/basic_ranges.cc b/all_cases/basic_ranges.cc new file mode 100644 index 0000000..79cd2d7 --- /dev/null +++ b/all_cases/basic_ranges.cc @@ -0,0 +1,141 @@ +#include +#include "common.h" +#include "basic_ranges.h" + +std::mutex BasicRanges::basic_ranges_building; +std::vector BasicRanges::basic_ranges; +bool BasicRanges::basic_ranges_available = false; + +inline uint32_t binary_count(uint32_t bin) { // get number of non-zero bits + bin -= (bin >> 1) & 0x55555555; + bin = (bin & 0x33333333) + ((bin >> 2) & 0x33333333); + bin = ((bin >> 4) + bin) & 0x0F0F0F0F; + bin += bin >> 8; + bin += bin >> 16; + return bin & 0b111111; +} + +void BasicRanges::generate_ranges(int n1, int n2, int n3, int n4) { + int len, limit; + constexpr uint32_t M_01 = 0b01 << 30; + constexpr uint32_t M_10 = 0b10 << 30; + constexpr uint32_t M_11 = 0b11 << 30; + std::vector cache_1, cache_2; + + len = n1 + n2; + limit = 0b1 << len; + for (uint32_t bin = 0; bin < limit; ++bin) { + if (binary_count(bin) != n2) { // skip binary without `n2` non-zero bits + continue; + } + uint32_t range = 0; + for (int i = 0; i < len; ++i) { // generate range base on binary value + range >>= 2; + if ((bin >> i) & 0b1) { // non-zero bit + range |= M_01; // 01000... + } + } + cache_1.emplace_back(range); // insert into first layer + } + + len += n3; + limit <<= n3; + for (uint32_t bin = 0; bin < limit; ++bin) { + if (binary_count(bin) != n3) { // skip binary without `n3` non-zero bits + continue; + } + for (uint32_t base : cache_1) { // traverse first layer + uint32_t range = 0; + for (int i = 0; i < len; ++i) { // generate range base on binary value + if ((bin >> i) & 0b1) { // non-zero bit + (range >>= 2) |= M_10; // 10000... + continue; + } + (range >>= 2) |= base & M_11; + base <<= 2; + } + cache_2.emplace_back(range); // insert into second layer + } + } + + len += n4; + limit <<= n4; + for (uint32_t bin = 0; bin < limit; ++bin) { + if (binary_count(bin) != n4) { // skip binary without `n4` non-zero bits + continue; + } + for (uint32_t base : cache_2) { // traverse second layer + uint32_t range = 0; + for (int i = 0; i < len; ++i) { // generate range base on binary value + if ((bin >> i) & 0b1) { // non-zero bit + (range >>= 2) |= M_11; // 11000... + continue; + } + (range >>= 2) |= base & M_11; + base <<= 2; + } + basic_ranges.emplace_back(range); // insert into release ranges + } + } +} + +#include +#include + +void BasicRanges::build_basic_ranges() { + + std::cout << std::this_thread::get_id() << " enter build function" << std::endl; + + if (basic_ranges_available) { + std::cout << std::this_thread::get_id() << " data already built -> skip" << std::endl; + return; // basic ranges already built + } + + if (basic_ranges_building.try_lock()) { // lock success -> not building + + std::cout << std::this_thread::get_id() << " try lock success -> start build process" << std::endl; + + +// AllCases::basic_ranges.emplace_back(0); +// AllCases::basic_ranges.emplace_back(1); +// AllCases::basic_ranges.emplace_back(2); +// sleep(2); // assume using a lot of time + + 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) + int n_1x2 = n - n_2x1; + int n_space = 16 - n * 2 - n_1x1; + /// 0x0 -> 00 | 1x2 -> 01 | 2x1 -> 10 | 1x1 -> 11 + generate_ranges(n_space, n_1x2, n_2x1, n_1x1); // generate target ranges + } + } + } + + std::sort(basic_ranges.begin(), basic_ranges.end()); // sort basic ranges + for (uint32_t &range : basic_ranges) { + range = Common::range_reverse(range); // range reverse + } + + + basic_ranges_available = true; // enable available flag + + std::cout << std::this_thread::get_id() << " build complete -> continue" << std::endl; + + } else { // another thread building + + std::cout << std::this_thread::get_id() << " another thread building -> wait" << std::endl; + basic_ranges_building.lock(); // blocking wait + + } + std::cout << std::this_thread::get_id() << " work complete -> unlock" << std::endl; + basic_ranges_building.unlock(); + +} + +const std::vector* BasicRanges::get_basic_ranges() { + if (basic_ranges.empty()) { + build_basic_ranges(); // basic ranges initialize + } + return &basic_ranges; +} diff --git a/all_cases/basic_ranges.h b/all_cases/basic_ranges.h new file mode 100644 index 0000000..ade275c --- /dev/null +++ b/all_cases/basic_ranges.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +class BasicRanges { +public: + + enum Status { + NO_INIT, + BUILDING, + AVAILABLE, + }; + + static void build_basic_ranges(); + + static enum Status basic_ranges_status(); + + static const std::vector* get_basic_ranges(); + +private: + + static bool basic_ranges_available; + + static std::mutex basic_ranges_building; + + static std::vector basic_ranges; + + static void generate_ranges(int n1, int n2, int n3, int n4); + +}; diff --git a/all_cases/common.cc b/all_cases/common.cc new file mode 100644 index 0000000..13bc5a6 --- /dev/null +++ b/all_cases/common.cc @@ -0,0 +1,39 @@ +#include "common.h" + +uint32_t Common::range_reverse(uint32_t bin) { // reverse binary every 2-bits + bin = ((bin << 16) & 0xFFFF0000) | ((bin >> 16) & 0x0000FFFF); + bin = ((bin << 8) & 0xFF00FF00) | ((bin >> 8) & 0x00FF00FF); + bin = ((bin << 4) & 0xF0F0F0F0) | ((bin >> 4) & 0x0F0F0F0F); + return ((bin << 2) & 0xCCCCCCCC) | ((bin >> 2) & 0x33333333); +} + +bool Common::check_case(uint32_t head, uint32_t range) { // whether the head and range is valid + uint32_t mask = 0b110011 << head; // fill 2x2 block + for (int addr = 0; range; range >>= 2) { // traverse every 2-bits + while (mask >> addr & 0b1) { + ++addr; // search next not filled block + } + switch (range & 0b11) { + case 0b00: // space block + case 0b11: // 1x1 block + if (addr > 19) { // invalid address + return false; + } + mask |= 0b1 << addr; // fill 1x1 block + break; + case 0b10: // 2x1 block + if (addr > 15 || mask >> (addr + 4) & 0b1) { // invalid address + return false; + } + mask |= 0b10001 << addr; // fill 2x1 block + break; + case 0b01: // 1x2 block + if (addr > 18 || (addr & 0b11) == 0b11 || mask >> (addr + 1) & 0b1) { // invalid address + return false; + } + mask |= 0b11 << addr; // fill 1x2 block + break; + } + } + return true; // valid case +} diff --git a/all_cases/common.h b/all_cases/common.h new file mode 100644 index 0000000..8c80a6c --- /dev/null +++ b/all_cases/common.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +class Common { +public: + static uint32_t range_reverse(uint32_t bin); + static bool check_case(uint32_t head, uint32_t range); +}; diff --git a/all_cases/main.cc b/all_cases/main.cc index 856ee64..ceda4d2 100644 --- a/all_cases/main.cc +++ b/all_cases/main.cc @@ -1,27 +1,28 @@ #include -#include "all_cases.h" +//#include "all_cases.h" +#include "basic_ranges.h" #include #include int main() { - std::cout << AllCases::basic_ranges.size() << std::endl; + std::cout << BasicRanges::get_basic_ranges()->size() << std::endl; - std::thread t1(AllCases::build_basic_ranges); - usleep(100); - std::thread t2(AllCases::build_basic_ranges); - usleep(100); - std::thread t3(AllCases::build_basic_ranges); - usleep(100); + std::thread t1(BasicRanges::build_basic_ranges); +// usleep(10); + std::thread t2(BasicRanges::build_basic_ranges); +// usleep(10); + std::thread t3(BasicRanges::build_basic_ranges); +// usleep(10); t1.join(); t2.join(); t3.join(); - AllCases::build_basic_ranges(); + BasicRanges::build_basic_ranges(); - std::cout << AllCases::basic_ranges.size() << std::endl; + std::cout << BasicRanges::get_basic_ranges()->size() << std::endl; return 0; }