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/wrapper/short_code.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.cc
)

28
src/core_ffi/py_ffi/binder.cc

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

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

@ -2,128 +2,82 @@
#pragma once
#include <iostream>
#include <variant>
#include "ranges/ranges.h"
#include "py_common_code.h"
#include "ranges/ranges.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_;
//};
using cases::RangesUnion;
class PyCases {
public:
using Cases = RangesUnion;
using CasesRef = std::reference_wrapper<const Cases>;
PyCases() = delete;
static PyCases from(RangesUnion &&data) {
return PyCases(std::move(data));
}
// ------------------------------------------------------------------------------------- //
static PyCases from_ref(const RangesUnion &data) {
return PyCases(data);
}
class CommonCodeIter {
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_)) {
// return std::get<Cases>(data_);
// } else {
// return std::get<CasesRef>(data_);
// }
private:
CommonCodeIter iter_;
};
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_;
/// Constructing from rvalue.
static PyCases from(RangesUnion &&data) noexcept;
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;
}
/// Constructing from longer-lived reference.
static PyCases from_ref(const RangesUnion &data) noexcept;
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) {}
/// Get the number of cases.
[[nodiscard]] size_t size() const;
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:
uint64_t head_ {0};
size_t index_ {0};
const PyCases &data_;
explicit PyCases(RangesUnion &&data);
explicit PyCases(const RangesUnion &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

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

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