From ea1cdf82cecd9fcb3b71dfd8cd2607ba5295db5e Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 20 Nov 2020 11:24:40 -0800 Subject: [PATCH] moving prototype code to pybind11/vptr_holder.h, adding type_caster specialization to make the bindings involving unique_ptr passing compile, but load and cast implementations are missing --- include/pybind11/vptr_holder.h | 72 ++++++++++++++++++++++++ tests/test_unique_ptr_member.cpp | 35 +++++++++++- tests/test_variant_unique_shared.cpp | 82 +++++----------------------- tests/test_variant_unique_shared.py | 2 +- 4 files changed, 121 insertions(+), 70 deletions(-) create mode 100644 include/pybind11/vptr_holder.h diff --git a/include/pybind11/vptr_holder.h b/include/pybind11/vptr_holder.h new file mode 100644 index 000000000..39ef5206d --- /dev/null +++ b/include/pybind11/vptr_holder.h @@ -0,0 +1,72 @@ +#pragma once + +#include + +#include +#include + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +// Could this be a holder for a `class_`-like `vclass`? +// To enable passing of unique_ptr as in pure C++. +template class vptr { + public: + explicit vptr(T *ptr = nullptr) : vptr_{std::unique_ptr(ptr)} {} + explicit vptr(std::unique_ptr u) : vptr_{std::move(u)} {} + explicit vptr(std::shared_ptr s) : vptr_{s} {} + + int ownership_type() const { + if (std::get_if<0>(&vptr_)) { + return 0; + } + if (std::get_if<1>(&vptr_)) { + return 1; + } + return -1; + } + + T *get() { + auto u = std::get_if<0>(&vptr_); + if (u) { + return u->get(); + } + auto s = std::get_if<1>(&vptr_); + if (s) { + return s->get(); + } + return nullptr; + } + + std::unique_ptr get_unique() { + auto u = std::get_if<0>(&vptr_); + if (u) { + return std::move(*u); + } + throw std::runtime_error("get_unique failure."); + } + + std::shared_ptr get_shared() { + auto s = std::get_if<1>(&vptr_); + if (s) { + return *s; + } + auto u = std::get_if<0>(&vptr_); + if (u) { + auto result = std::shared_ptr(std::move(*u)); + vptr_ = result; + return result; + } + throw std::runtime_error("get_shared failure."); + } + + private: + std::variant, std::shared_ptr> vptr_; +}; + +template class vptr_holder : public vptr { + using vptr::vptr; +}; + +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) + +PYBIND11_DECLARE_HOLDER_TYPE(T, pybind11::vptr_holder); diff --git a/tests/test_unique_ptr_member.cpp b/tests/test_unique_ptr_member.cpp index 316dac44e..38a99a679 100644 --- a/tests/test_unique_ptr_member.cpp +++ b/tests/test_unique_ptr_member.cpp @@ -1,5 +1,7 @@ #include "pybind11_tests.h" +#include + #include #include @@ -66,17 +68,46 @@ inline int cpp_pattern() { return result; } +} // namespace unique_ptr_member +} // namespace pybind11_tests + +namespace pybind11 { +namespace detail { +template <> +struct type_caster< + std::unique_ptr> { + public: + PYBIND11_TYPE_CASTER( + std::unique_ptr, + _("std::unique_ptr")); + + bool load(handle /* src */, bool) { + throw std::runtime_error("Not implemented: load"); + } + + static handle + cast(std::unique_ptr /* src */, + return_value_policy /* policy */, handle /* parent */) { + throw std::runtime_error("Not implemented: cast"); + } +}; +} // namespace detail +} // namespace pybind11 + +namespace pybind11_tests { +namespace unique_ptr_member { + TEST_SUBMODULE(unique_ptr_member, m) { m.def("to_cout", to_cout); - py::class_>(m, "pointee") + py::class_>(m, "pointee") .def(py::init<>()) .def("get_int", &pointee::get_int); m.def("make_unique_pointee", make_unique_pointee); py::class_(m, "ptr_owner") - //.def(py::init>(), py::arg("ptr")) + .def(py::init>(), py::arg("ptr")) .def("is_owner", &ptr_owner::is_owner) .def("give_up_ownership_via_unique_ptr", &ptr_owner::give_up_ownership_via_unique_ptr) diff --git a/tests/test_variant_unique_shared.cpp b/tests/test_variant_unique_shared.cpp index 7d7f0c945..40f3fa928 100644 --- a/tests/test_variant_unique_shared.cpp +++ b/tests/test_variant_unique_shared.cpp @@ -1,74 +1,22 @@ +#include "pybind11_tests.h" + +#include + #include #include -#include "pybind11_tests.h" - namespace pybind11_tests { -// Could this be a holder for a `class_`-like `vclass`? -// To enable passing of unique_ptr as in pure C++. -template class vptr_holder { - public: - explicit vptr_holder(T *ptr = nullptr) : vptr_{std::unique_ptr(ptr)} {} - explicit vptr_holder(std::unique_ptr u) : vptr_{std::move(u)} {} - explicit vptr_holder(std::shared_ptr s) : vptr_{s} {} +using pybind11::vptr; - int ownership_type() const { - if (std::get_if<0>(&vptr_)) { - return 0; - } - if (std::get_if<1>(&vptr_)) { - return 1; - } - return -1; - } +vptr from_raw() { return vptr{new double{3}}; } - T *get() { - auto u = std::get_if<0>(&vptr_); - if (u) { - return u->get(); - } - auto s = std::get_if<1>(&vptr_); - if (s) { - return s->get(); - } - return nullptr; - } - - std::unique_ptr get_unique() { - auto u = std::get_if<0>(&vptr_); - if (u) { - return std::move(*u); - } - throw std::runtime_error("get_unique failure."); - } - - std::shared_ptr get_shared() { - auto s = std::get_if<1>(&vptr_); - if (s) { - return *s; - } - auto u = std::get_if<0>(&vptr_); - if (u) { - auto result = std::shared_ptr(std::move(*u)); - vptr_ = result; - return result; - } - throw std::runtime_error("get_shared failure."); - } - - private: - std::variant, std::shared_ptr> vptr_; -}; - -vptr_holder from_raw() { return vptr_holder{new double{3}}; } - -vptr_holder from_unique() { - return vptr_holder{std::unique_ptr(new double{5})}; +vptr from_unique() { + return vptr{std::unique_ptr(new double{5})}; } -vptr_holder from_shared() { - return vptr_holder{std::shared_ptr(new double{7})}; +vptr from_shared() { + return vptr{std::shared_ptr(new double{7})}; } TEST_SUBMODULE(variant_unique_shared, m) { @@ -77,22 +25,22 @@ TEST_SUBMODULE(variant_unique_shared, m) { m.def("from_unique", from_unique); m.def("from_shared", from_shared); - py::class_>(m, "vptr_holder_double") + py::class_>(m, "vptr_double") .def(py::init<>()) - .def("ownership_type", &vptr_holder::ownership_type) + .def("ownership_type", &vptr::ownership_type) .def("get_value", - [](vptr_holder &v) { + [](vptr &v) { auto p = v.get(); if (p) return *p; return -1.; }) .def("get_unique", - [](vptr_holder &v) { + [](vptr &v) { v.get_unique(); return; }) - .def("get_shared", [](vptr_holder &v) { + .def("get_shared", [](vptr &v) { v.get_shared(); return; }); diff --git a/tests/test_variant_unique_shared.py b/tests/test_variant_unique_shared.py index 84dc2491b..7f5733be6 100644 --- a/tests/test_variant_unique_shared.py +++ b/tests/test_variant_unique_shared.py @@ -5,7 +5,7 @@ from pybind11_tests import variant_unique_shared as m def test_default_constructed(): - v = m.vptr_holder_double() + v = m.vptr_double() assert v.ownership_type() == 0 assert v.get_value() == -1