Browse Source

feat: python wrapper of `RangesUnion`

master
Dnomd343 4 weeks ago
parent
commit
35cee7a663
  1. 1
      src/core_ffi/CMakeLists.txt
  2. 30
      src/core_ffi/py_ffi/binder.cc
  3. 129
      src/core_ffi/py_ffi/include/py_cases.h
  4. 44
      src/core_ffi/py_ffi/py_cases.cc

1
src/core_ffi/CMakeLists.txt

@ -15,6 +15,7 @@ if (KLSK_PYTHON_FFI)
py_ffi/binder.cc
py_ffi/codec/short_code.cc
py_ffi/codec/common_codec.cc
py_ffi/py_cases.cc
)
target_include_directories(klotski_py PRIVATE py_ffi/include)
target_link_libraries(klotski_py PRIVATE klotski::core)

30
src/core_ffi/py_ffi/binder.cc

@ -3,9 +3,13 @@
#include "py_exps.h"
#include "py_codec.h"
#include "py_cases.h"
namespace py = pybind11;
using klotski::ffi::PyCases;
using klotski::ffi::PyCasesIter;
using klotski::ffi::PyCodecExp;
using klotski::ffi::PyShortCode;
using klotski::ffi::PyCommonCode;
@ -64,9 +68,35 @@ void bind_short_code(const py::module_ &m) {
.def_static("speed_up", &PyShortCode::speed_up, py::arg("fast_mode") = false);
}
#include "group/group.h"
#include "all_cases/all_cases.h"
static PyCases group_demo() {
auto group_union = klotski::cases::GroupUnion::unsafe_create(169);
auto cases = PyCases::from(group_union.cases());
return cases;
}
static PyCases all_cases() {
return PyCases::from_ref(klotski::cases::AllCases::instance().fetch());
}
PYBIND11_MODULE(klotski, m) {
py::register_exception<PyCodecExp>(m, "CodecExp", PyExc_ValueError);
m.def("all_cases", &all_cases);
m.def("group_demo", &group_demo);
py::class_<PyCases>(m, "PyCases")
.def("size", &PyCases::size)
.def("__iter__", [](const PyCases &self) {
return PyCasesIter(self);
}, py::keep_alive<0, 1>());
py::class_<PyCasesIter>(m, "PyCasesIter")
.def("__iter__", [](PyCasesIter &it) -> PyCasesIter& { return it; })
.def("__next__", &PyCasesIter::next);
bind_short_code(m);
bind_common_code(m);

129
src/core_ffi/py_ffi/include/py_cases.h

@ -0,0 +1,129 @@
/// Klotski Engine Python FFI by Dnomd343 @2024
#pragma once
#include <iostream>
#include <variant>
#include "ranges/ranges.h"
#include "py_codec.h"
namespace klotski::ffi {
using klotski::cases::RangesUnion;
//class PyCases {
//public:
// PyCases() = delete;
//
// PyCases(PyCases &&cases) noexcept : real_data_(std::move(cases.real_data_)), data_(real_data_) {
// std::cout << "PyCases(PyCases &&) called" << std::endl;
// std::cout << "real_data / data_ref -> " << &real_data_ << " " << &data_ << std::endl;
// }
//
// PyCases(const PyCases &cases) : real_data_(cases.real_data_), data_(real_data_) {
// std::cout << "PyCases(const PyCases &) called" << std::endl;
// std::cout << "real_data / data_ref -> " << &real_data_ << " " << &data_ << std::endl;
// }
//
// PyCases& operator==(PyCases &&cases) {
// std::cout << "PyCases& operator==(PyCases &&) called" << std::endl;
// if (this != &cases) {
// real_data_ = std::move(cases.real_data_);
// }
// std::cout << "real_data / data_ref -> " << &real_data_ << " " << &data_ << std::endl;
// return *this;
// }
//
// PyCases& operator==(const PyCases &&cases) {
// std::cout << "PyCases& operator==(const PyCases &&) called" << std::endl;
// if (this != &cases) {
// real_data_ = cases.real_data_;
// }
// std::cout << "real_data / data_ref -> " << &real_data_ << " " << &data_ << std::endl;
// return *this;
// }
//
// [[nodiscard]] size_t size() const;
//
// static PyCases from(RangesUnion &&data);
//
// static PyCases from_ref(const RangesUnion &data);
//
// [[nodiscard]] const RangesUnion& data_ref() const;
//
//private:
// explicit PyCases(RangesUnion &&data) : real_data_(std::move(data)), data_(real_data_) {
// std::cout << "PyCases init from r-value" << std::endl;
// std::cout << "real_data / data_ref -> " << &real_data_ << " " << &data_ << std::endl;
// }
//
// explicit PyCases(const RangesUnion &data) : data_(data) {
// std::cout << "PyCases init from l-value" << std::endl;
// }
//
// RangesUnion real_data_;
// const RangesUnion &data_;
//};
class PyCases {
public:
using Cases = RangesUnion;
using CasesRef = std::reference_wrapper<const Cases>;
static PyCases from(RangesUnion &&data) {
return PyCases(std::move(data));
}
static PyCases from_ref(const RangesUnion &data) {
return PyCases(data);
}
[[nodiscard]] size_t size() const;
[[nodiscard]] const Cases& ref() const {
// if (std::holds_alternative<Cases>(data_)) {
// return std::get<Cases>(data_);
// } else {
// return std::get<CasesRef>(data_);
// }
return std::visit([]<typename T>(T &&arg) -> const Cases& {
if constexpr (std::is_same_v<std::decay_t<T>, Cases>) {
return arg;
} else {
return arg.get();
}
}, data_);
}
private:
std::variant<Cases, CasesRef> data_;
explicit PyCases(const RangesUnion &data) : data_(std::cref(data)) {
std::cout << "PyCases(const RangesUnion &) called" << std::endl;
std::cout << "variant data index: " << data_.index() << std::endl;
}
explicit PyCases(RangesUnion &&data) : data_(std::move(data)) {
std::cout << "PyCases(RangesUnion &&) called" << std::endl;
std::cout << "variant data index: " << data_.index() << std::endl;
}
};
class PyCasesIter {
public:
explicit PyCasesIter(const PyCases &data) : data_(data) {}
PyCommonCode next();
private:
uint64_t head_ {0};
size_t index_ {0};
const PyCases &data_;
};
} // namespace klotski::ffi

44
src/core_ffi/py_ffi/py_cases.cc

@ -0,0 +1,44 @@
#include <pybind11/pybind11.h>
#include "include/py_cases.h"
namespace py = pybind11;
using klotski::ffi::PyCases;
using klotski::ffi::PyCasesIter;
using klotski::ffi::PyCommonCode;
using klotski::cases::RangesUnion;
size_t PyCases::size() const {
size_t num = 0;
for (const auto &x : ref()) {
num += x.size();
}
return num;
}
//PyCases PyCases::from(RangesUnion &&data) {
// return PyCases(std::move(data));
//}
//
//PyCases PyCases::from_ref(const RangesUnion &data) {
// return PyCases(data);
//}
//
//const RangesUnion& PyCases::data_ref() const {
// return data_;
//}
PyCommonCode PyCasesIter::next() {
while (head_ < 16) {
const auto &ranges = data_.ref()[head_];
if (index_ < ranges.size()) {
auto code = (head_ << 32) | ranges[index_++];
return std::bit_cast<PyCommonCode>(code);
}
++head_;
index_ = 0;
}
throw py::stop_iteration();
}
Loading…
Cancel
Save