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

This commit is contained in:
Ralf W. Grosse-Kunstleve 2020-11-20 11:24:40 -08:00
parent d2c8e3ccde
commit ea1cdf82ce
4 changed files with 121 additions and 70 deletions

View File

@ -0,0 +1,72 @@
#pragma once
#include <pybind11/pybind11.h>
#include <memory>
#include <variant>
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 <typename T> class vptr {
public:
explicit vptr(T *ptr = nullptr) : vptr_{std::unique_ptr<T>(ptr)} {}
explicit vptr(std::unique_ptr<T> u) : vptr_{std::move(u)} {}
explicit vptr(std::shared_ptr<T> 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<T> 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<T> 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<T>(std::move(*u));
vptr_ = result;
return result;
}
throw std::runtime_error("get_shared failure.");
}
private:
std::variant<std::unique_ptr<T>, std::shared_ptr<T>> vptr_;
};
template <typename T> class vptr_holder : public vptr<T> {
using vptr<T>::vptr;
};
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
PYBIND11_DECLARE_HOLDER_TYPE(T, pybind11::vptr_holder<T>);

View File

@ -1,5 +1,7 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <pybind11/vptr_holder.h>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
@ -66,17 +68,46 @@ inline int cpp_pattern() {
return result; return result;
} }
} // namespace unique_ptr_member
} // namespace pybind11_tests
namespace pybind11 {
namespace detail {
template <>
struct type_caster<
std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>> {
public:
PYBIND11_TYPE_CASTER(
std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>,
_("std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>"));
bool load(handle /* src */, bool) {
throw std::runtime_error("Not implemented: load");
}
static handle
cast(std::unique_ptr<pybind11_tests::unique_ptr_member::pointee> /* 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) { TEST_SUBMODULE(unique_ptr_member, m) {
m.def("to_cout", to_cout); m.def("to_cout", to_cout);
py::class_<pointee, std::shared_ptr<pointee>>(m, "pointee") py::class_<pointee, py::vptr_holder<pointee>>(m, "pointee")
.def(py::init<>()) .def(py::init<>())
.def("get_int", &pointee::get_int); .def("get_int", &pointee::get_int);
m.def("make_unique_pointee", make_unique_pointee); m.def("make_unique_pointee", make_unique_pointee);
py::class_<ptr_owner>(m, "ptr_owner") py::class_<ptr_owner>(m, "ptr_owner")
//.def(py::init<std::unique_ptr<pointee>>(), py::arg("ptr")) .def(py::init<std::unique_ptr<pointee>>(), py::arg("ptr"))
.def("is_owner", &ptr_owner::is_owner) .def("is_owner", &ptr_owner::is_owner)
.def("give_up_ownership_via_unique_ptr", .def("give_up_ownership_via_unique_ptr",
&ptr_owner::give_up_ownership_via_unique_ptr) &ptr_owner::give_up_ownership_via_unique_ptr)

View File

@ -1,74 +1,22 @@
#include "pybind11_tests.h"
#include <pybind11/vptr_holder.h>
#include <memory> #include <memory>
#include <variant> #include <variant>
#include "pybind11_tests.h"
namespace pybind11_tests { namespace pybind11_tests {
// Could this be a holder for a `class_`-like `vclass`? using pybind11::vptr;
// To enable passing of unique_ptr as in pure C++.
template <typename T> class vptr_holder {
public:
explicit vptr_holder(T *ptr = nullptr) : vptr_{std::unique_ptr<T>(ptr)} {}
explicit vptr_holder(std::unique_ptr<T> u) : vptr_{std::move(u)} {}
explicit vptr_holder(std::shared_ptr<T> s) : vptr_{s} {}
int ownership_type() const { vptr<double> from_raw() { return vptr<double>{new double{3}}; }
if (std::get_if<0>(&vptr_)) {
return 0; vptr<double> from_unique() {
} return vptr<double>{std::unique_ptr<double>(new double{5})};
if (std::get_if<1>(&vptr_)) {
return 1;
}
return -1;
} }
T *get() { vptr<double> from_shared() {
auto u = std::get_if<0>(&vptr_); return vptr<double>{std::shared_ptr<double>(new double{7})};
if (u) {
return u->get();
}
auto s = std::get_if<1>(&vptr_);
if (s) {
return s->get();
}
return nullptr;
}
std::unique_ptr<T> 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<T> 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<T>(std::move(*u));
vptr_ = result;
return result;
}
throw std::runtime_error("get_shared failure.");
}
private:
std::variant<std::unique_ptr<T>, std::shared_ptr<T>> vptr_;
};
vptr_holder<double> from_raw() { return vptr_holder<double>{new double{3}}; }
vptr_holder<double> from_unique() {
return vptr_holder<double>{std::unique_ptr<double>(new double{5})};
}
vptr_holder<double> from_shared() {
return vptr_holder<double>{std::shared_ptr<double>(new double{7})};
} }
TEST_SUBMODULE(variant_unique_shared, m) { 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_unique", from_unique);
m.def("from_shared", from_shared); m.def("from_shared", from_shared);
py::class_<vptr_holder<double>>(m, "vptr_holder_double") py::class_<vptr<double>>(m, "vptr_double")
.def(py::init<>()) .def(py::init<>())
.def("ownership_type", &vptr_holder<double>::ownership_type) .def("ownership_type", &vptr<double>::ownership_type)
.def("get_value", .def("get_value",
[](vptr_holder<double> &v) { [](vptr<double> &v) {
auto p = v.get(); auto p = v.get();
if (p) if (p)
return *p; return *p;
return -1.; return -1.;
}) })
.def("get_unique", .def("get_unique",
[](vptr_holder<double> &v) { [](vptr<double> &v) {
v.get_unique(); v.get_unique();
return; return;
}) })
.def("get_shared", [](vptr_holder<double> &v) { .def("get_shared", [](vptr<double> &v) {
v.get_shared(); v.get_shared();
return; return;
}); });

View File

@ -5,7 +5,7 @@ from pybind11_tests import variant_unique_shared as m
def test_default_constructed(): def test_default_constructed():
v = m.vptr_holder_double() v = m.vptr_double()
assert v.ownership_type() == 0 assert v.ownership_type() == 0
assert v.get_value() == -1 assert v.get_value() == -1