1/*
2    tests/test_smart_ptr.cpp -- binding classes with custom reference counting,
3    implicit conversions between types
4
5    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
6
7    All rights reserved. Use of this source code is governed by a
8    BSD-style license that can be found in the LICENSE file.
9*/
10
11#if defined(_MSC_VER) && _MSC_VER < 1910
12#  pragma warning(disable: 4702) // unreachable code in system header
13#endif
14
15#include "pybind11_tests.h"
16#include "object.h"
17
18// Make pybind aware of the ref-counted wrapper type (s):
19
20// ref<T> is a wrapper for 'Object' which uses intrusive reference counting
21// It is always possible to construct a ref<T> from an Object* pointer without
22// possible inconsistencies, hence the 'true' argument at the end.
23PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
24// Make pybind11 aware of the non-standard getter member function
25namespace pybind11 { namespace detail {
26    template <typename T>
27    struct holder_helper<ref<T>> {
28        static const T *get(const ref<T> &p) { return p.get_ptr(); }
29    };
30}}
31
32// The following is not required anymore for std::shared_ptr, but it should compile without error:
33PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
34
35// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
36// holder size to trigger the non-simple-layout internal instance layout for single inheritance with
37// large holder type:
38template <typename T> class huge_unique_ptr {
39    std::unique_ptr<T> ptr;
40    uint64_t padding[10];
41public:
42    huge_unique_ptr(T *p) : ptr(p) {};
43    T *get() { return ptr.get(); }
44};
45PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
46
47// Simple custom holder that works like unique_ptr
48template <typename T>
49class custom_unique_ptr {
50    std::unique_ptr<T> impl;
51public:
52    custom_unique_ptr(T* p) : impl(p) { }
53    T* get() const { return impl.get(); }
54    T* release_ptr() { return impl.release(); }
55};
56PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
57
58// Simple custom holder that works like shared_ptr and has operator& overload
59// To obtain address of an instance of this holder pybind should use std::addressof
60// Attempt to get address via operator& may leads to segmentation fault
61template <typename T>
62class shared_ptr_with_addressof_operator {
63    std::shared_ptr<T> impl;
64public:
65    shared_ptr_with_addressof_operator( ) = default;
66    shared_ptr_with_addressof_operator(T* p) : impl(p) { }
67    T* get() const { return impl.get(); }
68    T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
69};
70PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
71
72// Simple custom holder that works like unique_ptr and has operator& overload
73// To obtain address of an instance of this holder pybind should use std::addressof
74// Attempt to get address via operator& may leads to segmentation fault
75template <typename T>
76class unique_ptr_with_addressof_operator {
77    std::unique_ptr<T> impl;
78public:
79    unique_ptr_with_addressof_operator() = default;
80    unique_ptr_with_addressof_operator(T* p) : impl(p) { }
81    T* get() const { return impl.get(); }
82    T* release_ptr() { return impl.release(); }
83    T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
84};
85PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
86
87
88TEST_SUBMODULE(smart_ptr, m) {
89
90    // test_smart_ptr
91
92    // Object implementation in `object.h`
93    py::class_<Object, ref<Object>> obj(m, "Object");
94    obj.def("getRefCount", &Object::getRefCount);
95
96    // Custom object with builtin reference counting (see 'object.h' for the implementation)
97    class MyObject1 : public Object {
98    public:
99        MyObject1(int value) : value(value) { print_created(this, toString()); }
100        std::string toString() const { return "MyObject1[" + std::to_string(value) + "]"; }
101    protected:
102        virtual ~MyObject1() { print_destroyed(this); }
103    private:
104        int value;
105    };
106    py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj)
107        .def(py::init<int>());
108    py::implicitly_convertible<py::int_, MyObject1>();
109
110    m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
111    m.def("make_object_2", []() -> ref<Object> { return new MyObject1(2); });
112    m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); });
113    m.def("make_myobject1_2", []() -> ref<MyObject1> { return new MyObject1(5); });
114    m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); });
115    m.def("print_object_2", [](ref<Object> obj) { py::print(obj->toString()); });
116    m.def("print_object_3", [](const ref<Object> &obj) { py::print(obj->toString()); });
117    m.def("print_object_4", [](const ref<Object> *obj) { py::print((*obj)->toString()); });
118    m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); });
119    m.def("print_myobject1_2", [](ref<MyObject1> obj) { py::print(obj->toString()); });
120    m.def("print_myobject1_3", [](const ref<MyObject1> &obj) { py::print(obj->toString()); });
121    m.def("print_myobject1_4", [](const ref<MyObject1> *obj) { py::print((*obj)->toString()); });
122
123    // Expose constructor stats for the ref type
124    m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
125
126
127    // Object managed by a std::shared_ptr<>
128    class MyObject2 {
129    public:
130        MyObject2(const MyObject2 &) = default;
131        MyObject2(int value) : value(value) { print_created(this, toString()); }
132        std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; }
133        virtual ~MyObject2() { print_destroyed(this); }
134    private:
135        int value;
136    };
137    py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2")
138        .def(py::init<int>());
139    m.def("make_myobject2_1", []() { return new MyObject2(6); });
140    m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); });
141    m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); });
142    m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); });
143    m.def("print_myobject2_3", [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); });
144    m.def("print_myobject2_4", [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); });
145
146    // Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<>
147    class MyObject3 : public std::enable_shared_from_this<MyObject3> {
148    public:
149        MyObject3(const MyObject3 &) = default;
150        MyObject3(int value) : value(value) { print_created(this, toString()); }
151        std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; }
152        virtual ~MyObject3() { print_destroyed(this); }
153    private:
154        int value;
155    };
156    py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3")
157        .def(py::init<int>());
158    m.def("make_myobject3_1", []() { return new MyObject3(8); });
159    m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); });
160    m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); });
161    m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); });
162    m.def("print_myobject3_3", [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); });
163    m.def("print_myobject3_4", [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); });
164
165    // test_smart_ptr_refcounting
166    m.def("test_object1_refcounting", []() {
167        ref<MyObject1> o = new MyObject1(0);
168        bool good = o->getRefCount() == 1;
169        py::object o2 = py::cast(o, py::return_value_policy::reference);
170        // always request (partial) ownership for objects with intrusive
171        // reference counting even when using the 'reference' RVP
172        good &= o->getRefCount() == 2;
173        return good;
174    });
175
176    // test_unique_nodelete
177    // Object with a private destructor
178    class MyObject4 {
179    public:
180        MyObject4(int value) : value{value} { print_created(this); }
181        int value;
182    private:
183        ~MyObject4() { print_destroyed(this); }
184    };
185    py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4")
186        .def(py::init<int>())
187        .def_readwrite("value", &MyObject4::value);
188
189    // test_unique_deleter
190    // Object with std::unique_ptr<T, D> where D is not matching the base class
191    // Object with a protected destructor
192    class MyObject4a {
193    public:
194        MyObject4a(int i) {
195            value = i;
196            print_created(this);
197        };
198        int value;
199    protected:
200        virtual ~MyObject4a() { print_destroyed(this); }
201    };
202    py::class_<MyObject4a, std::unique_ptr<MyObject4a, py::nodelete>>(m, "MyObject4a")
203        .def(py::init<int>())
204        .def_readwrite("value", &MyObject4a::value);
205
206    // Object derived but with public destructor and no Deleter in default holder
207    class MyObject4b : public MyObject4a {
208    public:
209        MyObject4b(int i) : MyObject4a(i) { print_created(this); }
210        ~MyObject4b() { print_destroyed(this); }
211    };
212    py::class_<MyObject4b, MyObject4a>(m, "MyObject4b")
213        .def(py::init<int>());
214
215    // test_large_holder
216    class MyObject5 { // managed by huge_unique_ptr
217    public:
218        MyObject5(int value) : value{value} { print_created(this); }
219        ~MyObject5() { print_destroyed(this); }
220        int value;
221    };
222    py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5")
223        .def(py::init<int>())
224        .def_readwrite("value", &MyObject5::value);
225
226    // test_shared_ptr_and_references
227    struct SharedPtrRef {
228        struct A {
229            A() { print_created(this); }
230            A(const A &) { print_copy_created(this); }
231            A(A &&) { print_move_created(this); }
232            ~A() { print_destroyed(this); }
233        };
234
235        A value = {};
236        std::shared_ptr<A> shared = std::make_shared<A>();
237    };
238    using A = SharedPtrRef::A;
239    py::class_<A, std::shared_ptr<A>>(m, "A");
240    py::class_<SharedPtrRef>(m, "SharedPtrRef")
241        .def(py::init<>())
242        .def_readonly("ref", &SharedPtrRef::value)
243        .def_property_readonly("copy", [](const SharedPtrRef &s) { return s.value; },
244                               py::return_value_policy::copy)
245        .def_readonly("holder_ref", &SharedPtrRef::shared)
246        .def_property_readonly("holder_copy", [](const SharedPtrRef &s) { return s.shared; },
247                               py::return_value_policy::copy)
248        .def("set_ref", [](SharedPtrRef &, const A &) { return true; })
249        .def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; });
250
251    // test_shared_ptr_from_this_and_references
252    struct SharedFromThisRef {
253        struct B : std::enable_shared_from_this<B> {
254            B() { print_created(this); }
255            B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); }
256            B(B &&) : std::enable_shared_from_this<B>() { print_move_created(this); }
257            ~B() { print_destroyed(this); }
258        };
259
260        B value = {};
261        std::shared_ptr<B> shared = std::make_shared<B>();
262    };
263    using B = SharedFromThisRef::B;
264    py::class_<B, std::shared_ptr<B>>(m, "B");
265    py::class_<SharedFromThisRef>(m, "SharedFromThisRef")
266        .def(py::init<>())
267        .def_readonly("bad_wp", &SharedFromThisRef::value)
268        .def_property_readonly("ref", [](const SharedFromThisRef &s) -> const B & { return *s.shared; })
269        .def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; },
270                               py::return_value_policy::copy)
271        .def_readonly("holder_ref", &SharedFromThisRef::shared)
272        .def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; },
273                               py::return_value_policy::copy)
274        .def("set_ref", [](SharedFromThisRef &, const B &) { return true; })
275        .def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; });
276
277    // Issue #865: shared_from_this doesn't work with virtual inheritance
278    struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> {
279        SharedFromThisVBase() = default;
280        SharedFromThisVBase(const SharedFromThisVBase &) = default;
281        virtual ~SharedFromThisVBase() = default;
282    };
283    struct SharedFromThisVirt : virtual SharedFromThisVBase {};
284    static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt());
285    py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt")
286        .def_static("get", []() { return sft.get(); });
287
288    // test_move_only_holder
289    struct C {
290        C() { print_created(this); }
291        ~C() { print_destroyed(this); }
292    };
293    py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder")
294        .def_static("make", []() { return custom_unique_ptr<C>(new C); });
295
296    // test_holder_with_addressof_operator
297    struct TypeForHolderWithAddressOf {
298        TypeForHolderWithAddressOf() { print_created(this); }
299        TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); }
300        TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) { print_move_created(this); }
301        ~TypeForHolderWithAddressOf() { print_destroyed(this); }
302        std::string toString() const {
303            return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]";
304        }
305        int value = 42;
306    };
307    using HolderWithAddressOf = shared_ptr_with_addressof_operator<TypeForHolderWithAddressOf>;
308    py::class_<TypeForHolderWithAddressOf, HolderWithAddressOf>(m, "TypeForHolderWithAddressOf")
309        .def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); })
310        .def("get", [](const HolderWithAddressOf &self) { return self.get(); })
311        .def("print_object_1", [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); })
312        .def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); })
313        .def("print_object_3", [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); })
314        .def("print_object_4", [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); });
315
316    // test_move_only_holder_with_addressof_operator
317    struct TypeForMoveOnlyHolderWithAddressOf {
318        TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); }
319        ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); }
320        std::string toString() const {
321            return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]";
322        }
323        int value;
324    };
325    using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>;
326    py::class_<TypeForMoveOnlyHolderWithAddressOf, MoveOnlyHolderWithAddressOf>(m, "TypeForMoveOnlyHolderWithAddressOf")
327        .def_static("make", []() { return MoveOnlyHolderWithAddressOf(new TypeForMoveOnlyHolderWithAddressOf(0)); })
328        .def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value)
329        .def("print_object", [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); });
330
331    // test_smart_ptr_from_default
332    struct HeldByDefaultHolder { };
333    py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
334        .def(py::init<>())
335        .def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
336
337    // test_shared_ptr_gc
338    // #187: issue involving std::shared_ptr<> return value policy & garbage collection
339    struct ElementBase {
340        virtual ~ElementBase() { } /* Force creation of virtual table */
341    };
342    py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase");
343
344    struct ElementA : ElementBase {
345        ElementA(int v) : v(v) { }
346        int value() { return v; }
347        int v;
348    };
349    py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA")
350        .def(py::init<int>())
351        .def("value", &ElementA::value);
352
353    struct ElementList {
354        void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
355        std::vector<std::shared_ptr<ElementBase>> l;
356    };
357    py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList")
358        .def(py::init<>())
359        .def("add", &ElementList::add)
360        .def("get", [](ElementList &el) {
361            py::list list;
362            for (auto &e : el.l)
363                list.append(py::cast(e));
364            return list;
365        });
366}
367