Skip to content

Commit 2ac4d69

Browse files
committed
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
1 parent f64db3e commit 2ac4d69

File tree

4 files changed

+121
-70
lines changed

4 files changed

+121
-70
lines changed

include/pybind11/vptr_holder.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#pragma once
2+
3+
#include <pybind11/pybind11.h>
4+
5+
#include <memory>
6+
#include <variant>
7+
8+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
9+
10+
// Could this be a holder for a `class_`-like `vclass`?
11+
// To enable passing of unique_ptr as in pure C++.
12+
template <typename T> class vptr {
13+
public:
14+
explicit vptr(T *ptr = nullptr) : vptr_{std::unique_ptr<T>(ptr)} {}
15+
explicit vptr(std::unique_ptr<T> u) : vptr_{std::move(u)} {}
16+
explicit vptr(std::shared_ptr<T> s) : vptr_{s} {}
17+
18+
int ownership_type() const {
19+
if (std::get_if<0>(&vptr_)) {
20+
return 0;
21+
}
22+
if (std::get_if<1>(&vptr_)) {
23+
return 1;
24+
}
25+
return -1;
26+
}
27+
28+
T *get() {
29+
auto u = std::get_if<0>(&vptr_);
30+
if (u) {
31+
return u->get();
32+
}
33+
auto s = std::get_if<1>(&vptr_);
34+
if (s) {
35+
return s->get();
36+
}
37+
return nullptr;
38+
}
39+
40+
std::unique_ptr<T> get_unique() {
41+
auto u = std::get_if<0>(&vptr_);
42+
if (u) {
43+
return std::move(*u);
44+
}
45+
throw std::runtime_error("get_unique failure.");
46+
}
47+
48+
std::shared_ptr<T> get_shared() {
49+
auto s = std::get_if<1>(&vptr_);
50+
if (s) {
51+
return *s;
52+
}
53+
auto u = std::get_if<0>(&vptr_);
54+
if (u) {
55+
auto result = std::shared_ptr<T>(std::move(*u));
56+
vptr_ = result;
57+
return result;
58+
}
59+
throw std::runtime_error("get_shared failure.");
60+
}
61+
62+
private:
63+
std::variant<std::unique_ptr<T>, std::shared_ptr<T>> vptr_;
64+
};
65+
66+
template <typename T> class vptr_holder : public vptr<T> {
67+
using vptr<T>::vptr;
68+
};
69+
70+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
71+
72+
PYBIND11_DECLARE_HOLDER_TYPE(T, pybind11::vptr_holder<T>);

tests/test_unique_ptr_member.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "pybind11_tests.h"
22

3+
#include <pybind11/vptr_holder.h>
4+
35
#include <iostream>
46
#include <memory>
57

@@ -66,17 +68,46 @@ inline int cpp_pattern() {
6668
return result;
6769
}
6870

71+
} // namespace unique_ptr_member
72+
} // namespace pybind11_tests
73+
74+
namespace pybind11 {
75+
namespace detail {
76+
template <>
77+
struct type_caster<
78+
std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>> {
79+
public:
80+
PYBIND11_TYPE_CASTER(
81+
std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>,
82+
_("std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>"));
83+
84+
bool load(handle /* src */, bool) {
85+
throw std::runtime_error("Not implemented: load");
86+
}
87+
88+
static handle
89+
cast(std::unique_ptr<pybind11_tests::unique_ptr_member::pointee> /* src */,
90+
return_value_policy /* policy */, handle /* parent */) {
91+
throw std::runtime_error("Not implemented: cast");
92+
}
93+
};
94+
} // namespace detail
95+
} // namespace pybind11
96+
97+
namespace pybind11_tests {
98+
namespace unique_ptr_member {
99+
69100
TEST_SUBMODULE(unique_ptr_member, m) {
70101
m.def("to_cout", to_cout);
71102

72-
py::class_<pointee, std::shared_ptr<pointee>>(m, "pointee")
103+
py::class_<pointee, py::vptr_holder<pointee>>(m, "pointee")
73104
.def(py::init<>())
74105
.def("get_int", &pointee::get_int);
75106

76107
m.def("make_unique_pointee", make_unique_pointee);
77108

78109
py::class_<ptr_owner>(m, "ptr_owner")
79-
//.def(py::init<std::unique_ptr<pointee>>(), py::arg("ptr"))
110+
.def(py::init<std::unique_ptr<pointee>>(), py::arg("ptr"))
80111
.def("is_owner", &ptr_owner::is_owner)
81112
.def("give_up_ownership_via_unique_ptr",
82113
&ptr_owner::give_up_ownership_via_unique_ptr)

tests/test_variant_unique_shared.cpp

Lines changed: 15 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,22 @@
1-
#include <memory>
2-
#include <variant>
3-
41
#include "pybind11_tests.h"
52

6-
namespace pybind11_tests {
7-
8-
// Could this be a holder for a `class_`-like `vclass`?
9-
// To enable passing of unique_ptr as in pure C++.
10-
template <typename T> class vptr_holder {
11-
public:
12-
explicit vptr_holder(T *ptr = nullptr) : vptr_{std::unique_ptr<T>(ptr)} {}
13-
explicit vptr_holder(std::unique_ptr<T> u) : vptr_{std::move(u)} {}
14-
explicit vptr_holder(std::shared_ptr<T> s) : vptr_{s} {}
3+
#include <pybind11/vptr_holder.h>
154

16-
int ownership_type() const {
17-
if (std::get_if<0>(&vptr_)) {
18-
return 0;
19-
}
20-
if (std::get_if<1>(&vptr_)) {
21-
return 1;
22-
}
23-
return -1;
24-
}
25-
26-
T *get() {
27-
auto u = std::get_if<0>(&vptr_);
28-
if (u) {
29-
return u->get();
30-
}
31-
auto s = std::get_if<1>(&vptr_);
32-
if (s) {
33-
return s->get();
34-
}
35-
return nullptr;
36-
}
37-
38-
std::unique_ptr<T> get_unique() {
39-
auto u = std::get_if<0>(&vptr_);
40-
if (u) {
41-
return std::move(*u);
42-
}
43-
throw std::runtime_error("get_unique failure.");
44-
}
5+
#include <memory>
6+
#include <variant>
457

46-
std::shared_ptr<T> get_shared() {
47-
auto s = std::get_if<1>(&vptr_);
48-
if (s) {
49-
return *s;
50-
}
51-
auto u = std::get_if<0>(&vptr_);
52-
if (u) {
53-
auto result = std::shared_ptr<T>(std::move(*u));
54-
vptr_ = result;
55-
return result;
56-
}
57-
throw std::runtime_error("get_shared failure.");
58-
}
8+
namespace pybind11_tests {
599

60-
private:
61-
std::variant<std::unique_ptr<T>, std::shared_ptr<T>> vptr_;
62-
};
10+
using pybind11::vptr;
6311

64-
vptr_holder<double> from_raw() { return vptr_holder<double>{new double{3}}; }
12+
vptr<double> from_raw() { return vptr<double>{new double{3}}; }
6513

66-
vptr_holder<double> from_unique() {
67-
return vptr_holder<double>{std::unique_ptr<double>(new double{5})};
14+
vptr<double> from_unique() {
15+
return vptr<double>{std::unique_ptr<double>(new double{5})};
6816
}
6917

70-
vptr_holder<double> from_shared() {
71-
return vptr_holder<double>{std::shared_ptr<double>(new double{7})};
18+
vptr<double> from_shared() {
19+
return vptr<double>{std::shared_ptr<double>(new double{7})};
7220
}
7321

7422
TEST_SUBMODULE(variant_unique_shared, m) {
@@ -77,22 +25,22 @@ TEST_SUBMODULE(variant_unique_shared, m) {
7725
m.def("from_unique", from_unique);
7826
m.def("from_shared", from_shared);
7927

80-
py::class_<vptr_holder<double>>(m, "vptr_holder_double")
28+
py::class_<vptr<double>>(m, "vptr_double")
8129
.def(py::init<>())
82-
.def("ownership_type", &vptr_holder<double>::ownership_type)
30+
.def("ownership_type", &vptr<double>::ownership_type)
8331
.def("get_value",
84-
[](vptr_holder<double> &v) {
32+
[](vptr<double> &v) {
8533
auto p = v.get();
8634
if (p)
8735
return *p;
8836
return -1.;
8937
})
9038
.def("get_unique",
91-
[](vptr_holder<double> &v) {
39+
[](vptr<double> &v) {
9240
v.get_unique();
9341
return;
9442
})
95-
.def("get_shared", [](vptr_holder<double> &v) {
43+
.def("get_shared", [](vptr<double> &v) {
9644
v.get_shared();
9745
return;
9846
});

tests/test_variant_unique_shared.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
def test_default_constructed():
8-
v = m.vptr_holder_double()
8+
v = m.vptr_double()
99
assert v.ownership_type() == 0
1010
assert v.get_value() == -1
1111

0 commit comments

Comments
 (0)