mirror of https://github.com/dnomd343/klotski.git
				
				
			
				 12 changed files with 102 additions and 188 deletions
			
			
		@ -1,91 +0,0 @@ | 
				
			|||||
#include <BS_thread_pool.hpp> | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include "codec.h" | 
					 | 
				
			||||
 | 
					 | 
				
			||||
using klotski::cases::AllCases; | 
					 | 
				
			||||
using klotski::cases::ALL_CASES_NUM_; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void head_parallel(std::function<void(uint64_t head)> &&func) { | 
					 | 
				
			||||
    constexpr auto heads = std::to_array({ | 
					 | 
				
			||||
        0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14 | 
					 | 
				
			||||
    }); | 
					 | 
				
			||||
    BS::thread_pool pool; | 
					 | 
				
			||||
    for (auto head : heads) { | 
					 | 
				
			||||
        pool.detach_task([head, &func] { | 
					 | 
				
			||||
            func(head); | 
					 | 
				
			||||
        }); | 
					 | 
				
			||||
    } | 
					 | 
				
			||||
    pool.wait(); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
std::vector<uint64_t> all_common_codes() { | 
					 | 
				
			||||
    // TODO: using `std::ranges`
 | 
					 | 
				
			||||
    std::vector<uint64_t> common_codes; | 
					 | 
				
			||||
    common_codes.reserve(ALL_CASES_NUM_); | 
					 | 
				
			||||
    for (uint64_t head = 0; head < 16; ++head) { | 
					 | 
				
			||||
        for (auto range : AllCases::instance().fetch()[head]) { | 
					 | 
				
			||||
            common_codes.emplace_back(head << 32 | range); | 
					 | 
				
			||||
        } | 
					 | 
				
			||||
    } | 
					 | 
				
			||||
    return common_codes; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void common_code_parallel(std::function<void(std::span<CommonCode>)> &&func) { | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    static auto codes = AllCases::instance().fetch().codes(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    BS::thread_pool pool; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    // TODO: enhance performance
 | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    pool.detach_blocks((uint64_t)0, codes.size(), [func = std::move(func)](auto start, auto end) { | 
					 | 
				
			||||
 | 
					 | 
				
			||||
        func(std::span<CommonCode> {codes.data() + start, end - start}); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    }, 16); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    pool.wait(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
static std::vector<RawCode> convert(const std::vector<CommonCode> &codes) { | 
					 | 
				
			||||
    std::vector<RawCode> result; | 
					 | 
				
			||||
    result.reserve(29334498); | 
					 | 
				
			||||
    for (auto code : codes) { | 
					 | 
				
			||||
        result.emplace_back(RawCode::from_common_code(code)); | 
					 | 
				
			||||
    } | 
					 | 
				
			||||
    return result; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void raw_code_parallel(std::function<void(std::span<RawCode>)> &&func) { | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    static auto codes = convert(AllCases::instance().fetch().codes()); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    BS::thread_pool pool; | 
					 | 
				
			||||
    pool.detach_blocks((uint64_t)0, codes.size(), [func = std::move(func)](auto start, auto end) { | 
					 | 
				
			||||
 | 
					 | 
				
			||||
        func(std::span<RawCode> {codes.data() + start, end - start}); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    }, 16); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    pool.wait(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void short_code_parallel(std::function<void(std::span<ShortCode>)> &&func) { | 
					 | 
				
			||||
    static auto codes = []() { | 
					 | 
				
			||||
        std::vector<uint32_t> 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 = std::move(func)](auto start, auto end) { | 
					 | 
				
			||||
 | 
					 | 
				
			||||
        auto span = std::span<uint32_t> {codes.data() + start, end - start}; | 
					 | 
				
			||||
        func(std::bit_cast<std::span<ShortCode>>(span)); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    }, 16); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
    pool.wait(); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
@ -1,66 +0,0 @@ | 
				
			|||||
#pragma once | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include <span> | 
					 | 
				
			||||
#include <functional> | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include "raw_code/raw_code.h" | 
					 | 
				
			||||
#include "all_cases/all_cases.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; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
/// Build all valid CommonCodes.
 | 
					 | 
				
			||||
std::vector<uint64_t> all_common_codes(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
// ----------------------------------------------------------------------------------------- //
 | 
					 | 
				
			||||
 | 
					 | 
				
			||||
/// Capture ostream output as string.
 | 
					 | 
				
			||||
template <typename T> | 
					 | 
				
			||||
std::string ostream_capture(T obj) { | 
					 | 
				
			||||
    std::ostringstream out; | 
					 | 
				
			||||
    out << obj; // ostream capture
 | 
					 | 
				
			||||
    return out.str(); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#define EXPECT_OSTREAM(obj, expect) EXPECT_EQ(ostream_capture(obj), expect) | 
					 | 
				
			||||
 | 
					 | 
				
			||||
// ----------------------------------------------------------------------------------------- //
 | 
					 | 
				
			||||
 | 
					 | 
				
			||||
/// Spawn all valid RawCodes in parallel.
 | 
					 | 
				
			||||
void raw_code_parallel(std::function<void(std::span<RawCode>)> &&func); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
/// Spawn all valid ShortCodes in parallel.
 | 
					 | 
				
			||||
void short_code_parallel(std::function<void(std::span<ShortCode>)> &&func); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
/// Spawn all valid CommonCodes in parallel.
 | 
					 | 
				
			||||
void common_code_parallel(std::function<void(std::span<CommonCode>)> &&func); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#define CODE_PARALLEL(Type, type, impl)                    \ | 
					 | 
				
			||||
    type##_code_parallel([](std::span<Type##Code> 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) | 
					 | 
				
			||||
 | 
					 | 
				
			||||
// ----------------------------------------------------------------------------------------- //
 | 
					 | 
				
			||||
 | 
					 | 
				
			||||
/// Calculate multiple ranges separately and combine the results.
 | 
					 | 
				
			||||
template<typename T, typename F> | 
					 | 
				
			||||
requires std::is_integral_v<T> && std::is_invocable_v<F, T, T> | 
					 | 
				
			||||
auto parallel_spawn(T limit, F &&func) -> std::invoke_result_t<F, T, T> { | 
					 | 
				
			||||
    BS::thread_pool pool; | 
					 | 
				
			||||
    std::invoke_result_t<F, T, T> result; | 
					 | 
				
			||||
    for (auto &&future : pool.submit_blocks((T)0, limit, func, 0x1000)) { | 
					 | 
				
			||||
        const auto data = future.get(); | 
					 | 
				
			||||
        result.insert(result.end(), std::begin(data), std::end(data)); // combine sections
 | 
					 | 
				
			||||
    } | 
					 | 
				
			||||
    pool.wait(); | 
					 | 
				
			||||
    return result; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
// ----------------------------------------------------------------------------------------- //
 | 
					 | 
				
			||||
@ -0,0 +1,18 @@ | 
				
			|||||
 | 
					#pragma once | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <string> | 
				
			||||
 | 
					#include <gtest/gtest.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// ----------------------------------------------------------------------------------------- //
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/// Capture ostream output as string.
 | 
				
			||||
 | 
					template <typename T> | 
				
			||||
 | 
					std::string ostream_capture(T obj) { | 
				
			||||
 | 
					    std::ostringstream out; | 
				
			||||
 | 
					    out << obj; // ostream capture
 | 
				
			||||
 | 
					    return out.str(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#define EXPECT_OSTREAM(obj, expect) EXPECT_EQ(ostream_capture(obj), expect) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// ----------------------------------------------------------------------------------------- //
 | 
				
			||||
@ -0,0 +1,20 @@ | 
				
			|||||
 | 
					#pragma once | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <BS_thread_pool.hpp> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace helper { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					template<typename T, typename F> | 
				
			||||
 | 
					requires std::is_integral_v<T> && std::is_invocable_v<F, T, T> | 
				
			||||
 | 
					auto scope_parallel(T limit, F &&func) -> std::invoke_result_t<F, T, T> { | 
				
			||||
 | 
					    BS::thread_pool pool; | 
				
			||||
 | 
					    std::invoke_result_t<F, T, T> result; | 
				
			||||
 | 
					    for (auto &&future : pool.submit_blocks((T)0, limit, func, 0x1000)) { | 
				
			||||
 | 
					        const auto data = future.get(); | 
				
			||||
 | 
					        result.insert(result.end(), std::begin(data), std::end(data)); // combine sections | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    pool.wait(); | 
				
			||||
 | 
					    return result; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} // namespace helper | 
				
			||||
@ -0,0 +1,3 @@ | 
				
			|||||
 | 
					#pragma once | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// TODO: mirror convert of RawCode
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue