From 2ef5f160543bcbdd3c52e6489c9ea6c003c59c5d Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 18 May 2024 17:24:48 +0800 Subject: [PATCH] feat: python binder with ShortCode and CommonCode --- src/core_ffi/CMakeLists.txt | 7 +- src/core_ffi/py_ffi/binder.cc | 51 ++++++++++++++ src/core_ffi/py_ffi/codec/common_codec.cc | 76 +++++++++++++++++++++ src/core_ffi/py_ffi/codec/short_code.cc | 77 +++++++++++++++++++++ src/core_ffi/py_ffi/demo.cc | 39 ----------- src/core_ffi/py_ffi/include/py_codec.h | 81 +++++++++++++++++++++++ src/core_ffi/py_ffi/include/py_exps.h | 21 ++++++ 7 files changed, 312 insertions(+), 40 deletions(-) create mode 100644 src/core_ffi/py_ffi/binder.cc create mode 100644 src/core_ffi/py_ffi/codec/common_codec.cc create mode 100644 src/core_ffi/py_ffi/codec/short_code.cc delete mode 100644 src/core_ffi/py_ffi/demo.cc create mode 100644 src/core_ffi/py_ffi/include/py_codec.h create mode 100644 src/core_ffi/py_ffi/include/py_exps.h diff --git a/src/core_ffi/CMakeLists.txt b/src/core_ffi/CMakeLists.txt index c735a97..7b20296 100644 --- a/src/core_ffi/CMakeLists.txt +++ b/src/core_ffi/CMakeLists.txt @@ -11,7 +11,12 @@ if (KLSK_C_FFI) endif() if (KLSK_PYTHON_FFI) - pybind11_add_module(klotski_py py_ffi/demo.cc) + pybind11_add_module(klotski_py + py_ffi/binder.cc + py_ffi/codec/short_code.cc + py_ffi/codec/common_codec.cc + ) + target_include_directories(klotski_py PRIVATE py_ffi/include) target_link_libraries(klotski_py PRIVATE klotski::core) set_target_properties(klotski_py PROPERTIES OUTPUT_NAME klotski) endif() diff --git a/src/core_ffi/py_ffi/binder.cc b/src/core_ffi/py_ffi/binder.cc new file mode 100644 index 0000000..dcfaea4 --- /dev/null +++ b/src/core_ffi/py_ffi/binder.cc @@ -0,0 +1,51 @@ +#include + +// #include +// #include + +#include "py_exps.h" +#include "py_codec.h" + +namespace py = pybind11; + +using klotski::ffi::PyShortCode; +using klotski::ffi::PyCommonCode; + +using klotski::ffi::PyCodecExp; + +PYBIND11_MODULE(klotski, m) { + + py::register_exception(m, "CodecExp", PyExc_ValueError); + + py::class_(m, "ShortCode") + .def(py::init()) + .def(py::init()) + .def(py::init()) + + .def("__str__", &PyShortCode::str) + .def("__repr__", &PyShortCode::repr) + + .def_property_readonly("value", &PyShortCode::value) + .def_property_readonly("common_code", &PyShortCode::common_code) + + .def_static("check", static_cast(&PyShortCode::check)) + .def_static("check", static_cast(&PyShortCode::check)) + .def_static("speed_up", &PyShortCode::speed_up, py::arg("fast_mode") = false); + + py::class_(m, "CommonCode") + .def(py::init()) + .def(py::init()) + .def(py::init()) + + .def("__str__", &PyCommonCode::str) + .def("__repr__", &PyCommonCode::repr) + + .def_property_readonly("value", &PyCommonCode::value) + .def_property_readonly("short_code", &PyCommonCode::short_code) + .def("string", &PyCommonCode::string, py::arg("shorten") = false) + + .def_static("check", static_cast(&PyCommonCode::check)) + .def_static("check", static_cast(&PyCommonCode::check)); + + m.attr("__version__") = "version field"; +} diff --git a/src/core_ffi/py_ffi/codec/common_codec.cc b/src/core_ffi/py_ffi/codec/common_codec.cc new file mode 100644 index 0000000..1e533b2 --- /dev/null +++ b/src/core_ffi/py_ffi/codec/common_codec.cc @@ -0,0 +1,76 @@ +#include + +#include "py_exps.h" +#include "py_codec.h" + +using klotski::ffi::PyCodecExp; + +using klotski::ffi::PyShortCode; +using klotski::ffi::PyCommonCode; + +using klotski::codec::ShortCode; +using klotski::codec::CommonCode; + +// ----------------------------------------------------------------------------------------- // + +uint64_t PyCommonCode::value() const { + return code_.unwrap(); +} + +std::string PyCommonCode::string(const bool shorten) const { + return code_.to_string(shorten); +} + +PyShortCode PyCommonCode::short_code() const { + return std::bit_cast(code_.to_short_code()); +} + +// ----------------------------------------------------------------------------------------- // + +bool PyCommonCode::check(const uint64_t code) { + return CommonCode::check(code); +} + +bool PyCommonCode::check(const std::string_view code) { + // TODO: using `std::string_view` in from_string + return CommonCode::from_string(std::string {code}).has_value(); +} + +// ----------------------------------------------------------------------------------------- // + +std::string PyCommonCode::str(const PyCommonCode code) { + return code.string(false); +} + +std::string PyCommonCode::repr(const PyCommonCode code) { + return std::format("", str(code)); +} + +// ----------------------------------------------------------------------------------------- // + +static CommonCode convert(const PyShortCode code) { + return std::bit_cast(code).to_common_code(); +} + +static CommonCode convert(const uint64_t code) { + if (CommonCode::check(code)) { + return CommonCode::unsafe_create(code); + } + throw PyCodecExp(std::format("invalid common code -> {}", code)); +} + +static CommonCode convert(const std::string_view code) { + // TODO: using `std::string_view` in from_string + if (const auto str = CommonCode::from_string(std::string {code})) { + return str.value(); + } + throw PyCodecExp(std::format("invalid common code -> `{}`", code)); +} + +PyCommonCode::PyCommonCode(const uint64_t code) : code_(convert(code)) {} + +PyCommonCode::PyCommonCode(const PyShortCode code) : code_(convert(code)) {} + +PyCommonCode::PyCommonCode(const std::string_view code) : code_(convert(code)) {} + +// ----------------------------------------------------------------------------------------- // diff --git a/src/core_ffi/py_ffi/codec/short_code.cc b/src/core_ffi/py_ffi/codec/short_code.cc new file mode 100644 index 0000000..672b5df --- /dev/null +++ b/src/core_ffi/py_ffi/codec/short_code.cc @@ -0,0 +1,77 @@ +#include + +#include "py_exps.h" +#include "py_codec.h" + +using klotski::ffi::PyCodecExp; + +using klotski::ffi::PyShortCode; +using klotski::ffi::PyCommonCode; + +using klotski::codec::ShortCode; +using klotski::codec::CommonCode; + +// ----------------------------------------------------------------------------------------- // + +uint32_t PyShortCode::value() const { + return code_.unwrap(); +} + +PyCommonCode PyShortCode::common_code() const { + return std::bit_cast(code_.to_common_code()); +} + +// ----------------------------------------------------------------------------------------- // + +bool PyShortCode::check(const uint32_t code) { + return ShortCode::check(code); +} + +bool PyShortCode::check(const std::string_view code) { + // TODO: using `std::string_view` in from_string + return ShortCode::from_string(std::string {code}).has_value(); +} + +void PyShortCode::speed_up(const bool fast_mode) { + ShortCode::speed_up(fast_mode); +} + +// ----------------------------------------------------------------------------------------- // + +std::string PyShortCode::str(const PyShortCode code) { + return std::bit_cast(code).to_string(); +} + +std::string PyShortCode::repr(const PyShortCode code) { + const auto str = code.code_.to_string(); + return std::format("", code.value(), str); +} + +// ----------------------------------------------------------------------------------------- // + +static ShortCode convert(const PyCommonCode code) { + return std::bit_cast(code).to_short_code(); +} + +static ShortCode convert(const uint32_t code) { + if (ShortCode::check(code)) { + return ShortCode::unsafe_create(code); + } + throw PyCodecExp(std::format("invalid short code -> {}", code)); +} + +static ShortCode convert(const std::string_view code) { + // TODO: using `std::string_view` in from_string + if (const auto str = ShortCode::from_string(std::string {code})) { + return str.value(); + } + throw PyCodecExp(std::format("invalid short code -> `{}`", code)); +} + +PyShortCode::PyShortCode(const uint32_t code) : code_(convert(code)) {} + +PyShortCode::PyShortCode(const PyCommonCode code) : code_(convert(code)) {} + +PyShortCode::PyShortCode(const std::string_view code) : code_(convert(code)) {} + +// ----------------------------------------------------------------------------------------- // diff --git a/src/core_ffi/py_ffi/demo.cc b/src/core_ffi/py_ffi/demo.cc deleted file mode 100644 index 2b4793a..0000000 --- a/src/core_ffi/py_ffi/demo.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -#include - -namespace py = pybind11; - -// class CommonCode { -// public: -// explicit CommonCode(uint64_t val) : value_(val) {} -// -// uint64_t Value() const { -// return value_; -// } -// -// static std::optional Create(uint64_t val) { -// if (val == 343) { -// return CommonCode {val}; -// } -// return std::nullopt; -// } -// -// private: -// uint64_t value_ {343}; -// }; - -using klotski::codec::CommonCode; - -PYBIND11_MODULE(klotski, m) { - - py::class_(m, "CommonCode") - // .def(py::init()) - .def("to_string", &CommonCode::to_string, py::arg("shorten") = false) - .def_property_readonly("value", &CommonCode::unwrap) - // .def_static("from_val", &CommonCode::Create); - .def_static("create", &CommonCode::create); - - m.attr("__version__") = "version field"; -} diff --git a/src/core_ffi/py_ffi/include/py_codec.h b/src/core_ffi/py_ffi/include/py_codec.h new file mode 100644 index 0000000..fcf8755 --- /dev/null +++ b/src/core_ffi/py_ffi/include/py_codec.h @@ -0,0 +1,81 @@ +#pragma once + +#include "short_code/short_code.h" +#include "common_code/common_code.h" + +namespace klotski::ffi { + +using codec::ShortCode; +using codec::CommonCode; + +class PyCommonCode; + +// ------------------------------------------------------------------------------------- // + +class PyShortCode { +public: + explicit PyShortCode(uint32_t code); + explicit PyShortCode(PyCommonCode code); + explicit PyShortCode(std::string_view code); + + /// Get original value. + [[nodiscard]] uint32_t value() const; + + /// Convert ShortCode to CommonCode. + [[nodiscard]] PyCommonCode common_code() const; + + /// Verify ShortCode in u32 form. + static bool check(uint32_t code); + + /// Verify ShortCode in string form. + static bool check(std::string_view code); + + /// Build conversion index for ShortCode. + static void speed_up(bool fast_mode); + + /// Wrapper of `__str__` method in Python. + static std::string str(PyShortCode code); + + /// Wrapper of `__repr__` method in Python. + static std::string repr(PyShortCode code); + +private: + ShortCode code_; +}; + +// ------------------------------------------------------------------------------------- // + +class PyCommonCode { +public: + explicit PyCommonCode(uint64_t code); + explicit PyCommonCode(PyShortCode code); + explicit PyCommonCode(std::string_view code); + + /// Get original value. + [[nodiscard]] uint64_t value() const; + + /// Convert CommonCode to ShortCode. + [[nodiscard]] PyShortCode short_code() const; + + /// Convert as string form. + [[nodiscard]] std::string string(bool shorten) const; + + /// Verify CommonCode in u64 form. + static bool check(uint64_t code); + + /// Verify CommonCode in string form. + static bool check(std::string_view code); + + /// Wrapper of `__str__` method in Python. + static std::string str(PyCommonCode code); + + /// Wrapper of `__repr__` method in Python. + static std::string repr(PyCommonCode code); + +private: + CommonCode code_; +}; + +// ------------------------------------------------------------------------------------- // + +} // namespace klotski::ffi diff --git a/src/core_ffi/py_ffi/include/py_exps.h b/src/core_ffi/py_ffi/include/py_exps.h new file mode 100644 index 0000000..0b56ae1 --- /dev/null +++ b/src/core_ffi/py_ffi/include/py_exps.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +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_; +}; + +} // namespace klotski::ffi