Browse Source

fix: klotski c-ffi implementation

legacy
Dnomd343 7 months ago
parent
commit
393e2ddb94
  1. 47
      src/core_ffi/c_ffi/all_cases.cc
  2. 11
      src/core_ffi/c_ffi/include/klotski.h
  3. 90
      src/core_test/ffi/all_cases.cc

47
src/core_ffi/c_ffi/all_cases.cc

@ -5,7 +5,7 @@ using klotski::cases::AllCases;
using klotski::cases::BasicRanges; using klotski::cases::BasicRanges;
using klotski::cases::ALL_CASES_NUM; using klotski::cases::ALL_CASES_NUM;
typedef std::function<void()> Runner; typedef std::function<void()> Task;
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
@ -14,11 +14,15 @@ void all_cases_prebuild() {
} }
void all_cases_prebuild_async(const executor_t executor, const notifier_t callback) { void all_cases_prebuild_async(const executor_t executor, const notifier_t callback) {
const auto func = [](void *arg) { auto worker = [executor](Task &&task) {
all_cases_prebuild(); const auto func = [](void *arg) {
reinterpret_cast<notifier_t>(arg)(); const auto *ptr = static_cast<Task*>(arg);
(*ptr)();
delete ptr;
};
executor(func, new Task {std::move(task)});
}; };
executor(func, reinterpret_cast<void*>(callback)); BasicRanges::instance().build_async(worker, callback);
} }
int all_cases_prebuild_available() { int all_cases_prebuild_available() {
@ -32,34 +36,15 @@ void all_cases_build() {
} }
void all_cases_build_async(const executor_t executor, const notifier_t callback) { void all_cases_build_async(const executor_t executor, const notifier_t callback) {
const auto func = [](void *arg) { auto worker = [executor](Task &&task) {
all_cases_build();
reinterpret_cast<notifier_t>(arg)();
};
executor(func, reinterpret_cast<void*>(callback));
}
void all_cases_build_parallel(executor_t executor) {
// AllCases::instance().build_parallel([executor](Runner &&runner) {
// const auto func = [](void *arg) {
// (*static_cast<Runner*>(arg))();
// delete static_cast<Runner*>(arg);
// };
// executor(func, new Runner {std::move(runner)});
// });
}
void all_cases_build_parallel_async(executor_t executor, notifier_t callback) {
auto all_done = [callback] {
callback();
};
AllCases::instance().build_parallel_async([executor](Runner &&runner) {
const auto func = [](void *arg) { const auto func = [](void *arg) {
(*static_cast<Runner*>(arg))(); const auto *ptr = static_cast<Task*>(arg);
delete static_cast<Runner*>(arg); (*ptr)();
delete ptr;
}; };
executor(func, new Runner {std::move(runner)}); executor(func, new Task {std::move(task)});
}, std::move(all_done)); };
AllCases::instance().build_async(worker, callback);
} }
int all_cases_available() { int all_cases_available() {

11
src/core_ffi/c_ffi/include/klotski.h

@ -44,17 +44,6 @@ KLSK_EXPORT void all_cases_build();
/// data is ready, the callback will still be triggered. /// data is ready, the callback will still be triggered.
KLSK_EXPORT void all_cases_build_async(executor_t executor, notifier_t callback); KLSK_EXPORT void all_cases_build_async(executor_t executor, notifier_t callback);
/// Build all_cases in parallel, the tasks will be split and sent to the
/// executor, you can put them on different threads to work, but note that the
/// task can only be executed once, otherwise it will lead to unknown
/// consequences, the function will be blocked until all mission completed.
KLSK_EXPORT void all_cases_build_parallel(executor_t executor);
/// Similar to `all_cases_build_parallel`, but it is non-blocking. The callback
/// will be triggered after the build is completed. Note that the callback will
/// still be triggered even if the data is ready.
KLSK_EXPORT void all_cases_build_parallel_async(executor_t executor, notifier_t callback);
/// Returns whether the all_cases is ready, 0 means not completed, non-0 means /// Returns whether the all_cases is ready, 0 means not completed, non-0 means
/// the data is ready. /// the data is ready.
KLSK_EXPORT int all_cases_available(); KLSK_EXPORT int all_cases_available();

90
src/core_test/ffi/all_cases.cc

@ -1,21 +1,19 @@
#include <future> #include <format>
#include <string>
#include <thread> #include <thread>
#include <gtest/gtest.h>
#include "hash.h" #include "hash.h"
#include "exposer.h" #include "exposer.h"
#include "klotski.h" #include "klotski.h"
#include "all_cases.h" #include "all_cases/all_cases.h"
#include "gtest/gtest.h"
using klotski::cases::AllCases; using klotski::cases::AllCases;
using klotski::cases::BasicRanges; using klotski::cases::BasicRanges;
using klotski::cases::ALL_CASES_NUM; using klotski::cases::ALL_CASES_NUM;
/// The efficiency of string hashing is not very high, but there is a memorable /// The efficiency of string hashing is not very high, but there is a memorable
/// story, and this scheme is still retained here. /// story, and this scheme is still retained here.
static const std::string ALL_CASES_MD5 = "3888e9fab8d3cbb50908b12b147cfb23"; static constexpr std::string_view ALL_CASES_MD5 = "3888e9fab8d3cbb50908b12b147cfb23";
/// Forcibly modify private variables to reset state. /// Forcibly modify private variables to reset state.
FORCIBLY_ACCESS(AllCases, available_, bool) FORCIBLY_ACCESS(AllCases, available_, bool)
@ -42,13 +40,15 @@ TEST(AllCases, all_cases_prebuild) {
TEST(AllCases, all_cases_prebuild_async) { TEST(AllCases, all_cases_prebuild_async) {
basic_ranges_reset(); basic_ranges_reset();
static std::atomic_flag flag; static std::atomic_flag flag;
auto executor = [](void (*fn)(void*), void *arg) {
std::thread worker {fn, arg};
worker.detach();
};
flag.clear(); flag.clear();
all_cases_prebuild_async([](void (*fn)(void*), void *arg) { all_cases_prebuild_async(executor, [] {
std::thread worker(fn, arg);
worker.detach();
}, []() { // callback function
flag.test_and_set(); flag.test_and_set();
flag.notify_all(); flag.notify_all();
}); });
@ -57,10 +57,7 @@ TEST(AllCases, all_cases_prebuild_async) {
EXPECT_TRUE(all_cases_prebuild_available()); EXPECT_TRUE(all_cases_prebuild_available());
flag.clear(); flag.clear();
all_cases_prebuild_async([](void (*fn)(void*), void *arg) { all_cases_prebuild_async(executor, [] {
std::thread worker(fn, arg);
worker.detach();
}, []() { // callback function
flag.test_and_set(); flag.test_and_set();
flag.notify_all(); flag.notify_all();
}); });
@ -80,57 +77,15 @@ TEST(AllCases, all_cases_build) {
TEST(AllCases, all_cases_build_async) { TEST(AllCases, all_cases_build_async) {
all_cases_reset(); all_cases_reset();
static std::atomic_flag flag;
flag.clear();
all_cases_build_async([](void (*fn)(void*), void *arg) {
std::thread worker(fn, arg);
worker.detach();
}, []() { // callback function
flag.test_and_set();
flag.notify_all();
});
EXPECT_FALSE(all_cases_available());
flag.wait(false);
EXPECT_TRUE(all_cases_available());
flag.clear();
all_cases_build_async([](void (*fn)(void*), void *arg) {
std::thread worker(fn, arg);
worker.detach();
}, []() { // callback function
flag.test_and_set();
flag.notify_all();
});
EXPECT_TRUE(all_cases_available());
flag.wait(false);
EXPECT_TRUE(all_cases_available());
}
TEST(AllCases, all_cases_build_parallel) {
all_cases_reset();
EXPECT_FALSE(all_cases_available());
all_cases_build_parallel([](void (*fn)(void*), void *arg) {
std::thread worker(fn, arg);
worker.detach();
});
EXPECT_TRUE(all_cases_available());
all_cases_build_parallel([](void (*fn)(void*), void *arg) {
std::thread worker(fn, arg);
worker.detach();
});
EXPECT_TRUE(all_cases_available());
}
TEST(AllCases, all_cases_build_parallel_async) {
all_cases_reset();
static std::atomic_flag flag; static std::atomic_flag flag;
auto executor = [](void (*fn)(void*), void *arg) {
std::thread worker {fn, arg};
worker.detach();
};
flag.clear(); flag.clear();
all_cases_build_parallel_async([](void (*fn)(void*), void *arg) { all_cases_build_async(executor, [] {
std::thread worker(fn, arg);
worker.detach();
}, []() { // callback function
flag.test_and_set(); flag.test_and_set();
flag.notify_all(); flag.notify_all();
}); });
@ -139,10 +94,7 @@ TEST(AllCases, all_cases_build_parallel_async) {
EXPECT_TRUE(all_cases_available()); EXPECT_TRUE(all_cases_available());
flag.clear(); flag.clear();
all_cases_build_parallel_async([](void (*fn)(void*), void *arg) { all_cases_build_async(executor, [] {
std::thread worker(fn, arg);
worker.detach();
}, []() { // callback function
flag.test_and_set(); flag.test_and_set();
flag.notify_all(); flag.notify_all();
}); });
@ -169,12 +121,10 @@ TEST(AllCases, all_cases_export) {
std::string all_cases_str; std::string all_cases_str;
for (uint64_t head = 0; head < 15; ++head) { for (uint64_t head = 0; head < 15; ++head) {
auto num = all_cases_num((int)head); const auto num = all_cases_num(static_cast<int>(head));
auto *ranges = all_cases_export((int)head); auto *ranges = all_cases_export(static_cast<int>(head));
for (auto i = 0; i < num; ++i) { for (auto i = 0; i < num; ++i) {
char *tmp; all_cases_str += std::format("{:09X}\n", head << 32 | ranges[i]);
asprintf(&tmp, "%09llX\n", head << 32 | ranges[i]);
all_cases_str += tmp;
} }
} }
EXPECT_EQ(hash::md5(all_cases_str), ALL_CASES_MD5); EXPECT_EQ(hash::md5(all_cases_str), ALL_CASES_MD5);

Loading…
Cancel
Save