Browse Source

update: enhance `PyCases` wrapper

master
Dnomd343 4 weeks ago
parent
commit
d891a6fbbf
  1. 2
      src/core_ffi/CMakeLists.txt
  2. 28
      src/core_ffi/py_ffi/binder.cc
  3. 154
      src/core_ffi/py_ffi/include/py_cases.h
  4. 26
      src/core_ffi/py_ffi/include/py_exps.h
  5. 98
      src/core_ffi/py_ffi/wrapper/cases.cc
  6. 44
      src/core_ffi/py_ffi/wrapper/py_cases.cc

2
src/core_ffi/CMakeLists.txt

@ -15,7 +15,7 @@ if (KLSK_PYTHON_FFI)
py_ffi/binder.cc py_ffi/binder.cc
py_ffi/wrapper/short_code.cc py_ffi/wrapper/short_code.cc
py_ffi/wrapper/common_codec.cc py_ffi/wrapper/common_codec.cc
py_ffi/wrapper/py_cases.cc py_ffi/wrapper/cases.cc
py_ffi/wrapper/py_group_union.cc py_ffi/wrapper/py_group_union.cc
py_ffi/wrapper/py_group.cc py_ffi/wrapper/py_group.cc
) )

28
src/core_ffi/py_ffi/binder.cc

@ -8,15 +8,19 @@
#include "py_cases.h" #include "py_cases.h"
#include "py_group.h" #include "py_group.h"
#include "py_exception.h"
namespace py = pybind11; namespace py = pybind11;
using klotski::ffi::PyCases; using klotski::ffi::PyCases;
using klotski::ffi::PyCasesIter; //using klotski::ffi::PyCasesIter;
using klotski::ffi::PyCodecExp; //using klotski::ffi::PyCodecExp;
using klotski::ffi::PyShortCode; using klotski::ffi::PyShortCode;
using klotski::ffi::PyCommonCode; using klotski::ffi::PyCommonCode;
using klotski::ffi::PyExc_CodecError;
using klotski::ffi::PyGroup; using klotski::ffi::PyGroup;
using klotski::ffi::PyGroupUnion; using klotski::ffi::PyGroupUnion;
@ -90,20 +94,24 @@ static PyCases all_cases() {
} }
PYBIND11_MODULE(klotski, m) { PYBIND11_MODULE(klotski, m) {
py::register_exception<PyCodecExp>(m, "CodecExp", PyExc_ValueError); // py::register_exception<PyCodecExp>(m, "CodecExp", PyExc_ValueError);
py::register_exception<PyExc_CodecError>(m, "CodecError", PyExc_ValueError);
m.def("all_cases", &all_cases); m.def("all_cases", &all_cases);
m.def("group_demo", &group_demo); m.def("group_demo", &group_demo);
py::class_<PyCases>(m, "PyCases") auto py_cases = py::class_<PyCases>(m, "Cases")
.def("size", &PyCases::size) .def("size", &PyCases::size)
.def("__iter__", [](const PyCases &self) { .def("__iter__", &PyCases::common_codes, py::keep_alive<0, 1>())
return PyCasesIter(self); .def("short_codes", &PyCases::short_codes, py::keep_alive<0, 1>());
}, py::keep_alive<0, 1>());
py::class_<PyCases::ShortCodeIter>(py_cases, "ShortCodeIter")
.def("__iter__", [](PyCases::ShortCodeIter &it) -> PyCases::ShortCodeIter& { return it; })
.def("__next__", &PyCases::ShortCodeIter::next);
py::class_<PyCasesIter>(m, "PyCasesIter") py::class_<PyCases::CommonCodeIter>(py_cases, "CommonCodeIter")
.def("__iter__", [](PyCasesIter &it) -> PyCasesIter& { return it; }) .def("__iter__", [](PyCases::CommonCodeIter &it) -> PyCases::CommonCodeIter& { return it; })
.def("__next__", &PyCasesIter::next); .def("__next__", &PyCases::CommonCodeIter::next);
bind_short_code(m); bind_short_code(m);
bind_common_code(m); bind_common_code(m);

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

@ -2,128 +2,82 @@
#pragma once #pragma once
#include <iostream>
#include <variant> #include <variant>
#include "ranges/ranges.h"
#include "py_common_code.h" #include "py_common_code.h"
#include "ranges/ranges.h"
namespace klotski::ffi { namespace klotski::ffi {
using klotski::cases::RangesUnion; using 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 { class PyCases {
public: public:
using Cases = RangesUnion; PyCases() = delete;
using CasesRef = std::reference_wrapper<const Cases>;
static PyCases from(RangesUnion &&data) { // ------------------------------------------------------------------------------------- //
return PyCases(std::move(data));
}
static PyCases from_ref(const RangesUnion &data) { class CommonCodeIter {
return PyCases(data); public:
} PyCommonCode next();
explicit CommonCodeIter(const RangesUnion &data);
[[nodiscard]] size_t size() const; private:
uint8_t head_ {0};
uint32_t index_ {0};
const RangesUnion &data_;
};
[[nodiscard]] const Cases& ref() const { class ShortCodeIter {
public:
PyShortCode next();
explicit ShortCodeIter(CommonCodeIter iter);
// if (std::holds_alternative<Cases>(data_)) { private:
// return std::get<Cases>(data_); CommonCodeIter iter_;
// } 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: /// Constructing from rvalue.
std::variant<Cases, CasesRef> data_; static PyCases from(RangesUnion &&data) noexcept;
explicit PyCases(const RangesUnion &data) : data_(std::cref(data)) { /// Constructing from longer-lived reference.
std::cout << "PyCases(const RangesUnion &) called" << std::endl; static PyCases from_ref(const RangesUnion &data) noexcept;
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 { /// Get the number of cases.
public: [[nodiscard]] size_t size() const;
explicit PyCasesIter(const PyCases &data) : data_(data) {}
PyCommonCode next(); /// Get ShortCode iterator of cases.
[[nodiscard]] ShortCodeIter short_codes() const;
/// Get CommonCode iterator of cases.
[[nodiscard]] CommonCodeIter common_codes() const;
/// Get the CommonCode of the specified index.
[[nodiscard]] PyCommonCode operator[](size_t index) const;
// ------------------------------------------------------------------------------------- //
// TODO: add len / repr
private: private:
uint64_t head_ {0}; explicit PyCases(RangesUnion &&data);
size_t index_ {0}; explicit PyCases(const RangesUnion &data);
const PyCases &data_;
// ------------------------------------------------------------------------------------- //
/// Get const reference of the cases data.
[[nodiscard]] const RangesUnion& data_ref() const noexcept;
/// Stores actual cases data or its references.
std::variant<RangesUnion, std::reference_wrapper<const RangesUnion>> data_;
// ------------------------------------------------------------------------------------- //
}; };
// TODO: allow compare
} // namespace klotski::ffi } // namespace klotski::ffi

26
src/core_ffi/py_ffi/include/py_exps.h

@ -4,19 +4,19 @@
namespace klotski::ffi { namespace klotski::ffi {
class PyCodecExp final : std::exception { //class PyCodecExp final : std::exception {
public: //public:
explicit PyCodecExp(const std::string_view &msg) : msg_(msg) {} // explicit PyCodecExp(const std::string_view &msg) : msg_(msg) {}
//
~PyCodecExp() override = default; // ~PyCodecExp() override = default;
//
[[nodiscard]] const char* what() const noexcept override { // [[nodiscard]] const char* what() const noexcept override {
return msg_.c_str(); // return msg_.c_str();
} // }
//
private: //private:
std::string msg_; // std::string msg_;
}; //};
class PyGroupExp final : std::exception { class PyGroupExp final : std::exception {
public: public:

98
src/core_ffi/py_ffi/wrapper/cases.cc

@ -0,0 +1,98 @@
#include <pybind11/pybind11.h>
#include "include/py_cases.h"
namespace py = pybind11;
using namespace klotski::ffi;
using ShortCodeIter = PyCases::ShortCodeIter;
using CommonCodeIter = PyCases::CommonCodeIter;
// ----------------------------------------------------------------------------------------- //
CommonCodeIter::CommonCodeIter(const RangesUnion &data) : data_(data) {}
ShortCodeIter::ShortCodeIter(PyCases::CommonCodeIter iter) : iter_(iter) {}
PyShortCode ShortCodeIter::next() {
return iter_.next().short_code();
}
PyCommonCode CommonCodeIter::next() {
while (head_ < 16) {
const auto &ranges = data_[head_];
if (index_ < ranges.size()) {
auto code = (static_cast<uint64_t>(head_) << 32) | ranges[index_++];
return std::bit_cast<PyCommonCode>(code);
}
++head_;
index_ = 0;
}
throw py::stop_iteration();
}
// ----------------------------------------------------------------------------------------- //
size_t PyCases::size() const {
size_t num = 0;
for (const auto &x : data_ref()) { // TODO: fetch from RangesUnion.size()
num += x.size();
}
return num;
}
auto PyCases::short_codes() const -> ShortCodeIter {
return ShortCodeIter(common_codes());
}
auto PyCases::common_codes() const -> CommonCodeIter {
return CommonCodeIter(data_ref());
}
PyCommonCode PyCases::operator[](size_t index) const {
if (index >= size()) {
throw py::index_error("cases index out of range");
}
uint64_t head = 0;
for (;;) {
if (index >= data_ref()[head].size()) {
index -= data_ref()[head].size();
++head;
} else {
break;
}
}
uint32_t range = data_ref()[head][index];
// TODO: fetch from RangesUnion[]
const auto code = CommonCode::unsafe_create(head << 32 | range);
return std::bit_cast<PyCommonCode>(code);
}
// ----------------------------------------------------------------------------------------- //
PyCases PyCases::from(RangesUnion &&data) noexcept {
return PyCases(std::move(data));
}
PyCases PyCases::from_ref(const RangesUnion &data) noexcept {
return PyCases(data);
}
const RangesUnion& PyCases::data_ref() const noexcept {
return std::visit([]<typename T>(T &&arg) -> const RangesUnion& {
if constexpr (std::is_same_v<std::decay_t<T>, RangesUnion>) {
return arg;
} else {
return arg.get();
}
}, data_);
}
PyCases::PyCases(RangesUnion &&data) : data_(std::move(data)) {}
PyCases::PyCases(const RangesUnion &data) : data_(std::cref(data)) {}
// ----------------------------------------------------------------------------------------- //

44
src/core_ffi/py_ffi/wrapper/py_cases.cc

@ -1,44 +0,0 @@
#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