111986Sandreas.sandberg@arm.com/*
211986Sandreas.sandberg@arm.com    tests/test_smart_ptr.cpp -- binding classes with custom reference counting,
311986Sandreas.sandberg@arm.com    implicit conversions between types
411986Sandreas.sandberg@arm.com
511986Sandreas.sandberg@arm.com    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
611986Sandreas.sandberg@arm.com
711986Sandreas.sandberg@arm.com    All rights reserved. Use of this source code is governed by a
811986Sandreas.sandberg@arm.com    BSD-style license that can be found in the LICENSE file.
911986Sandreas.sandberg@arm.com*/
1011986Sandreas.sandberg@arm.com
1112391Sjason@lowepower.com#if defined(_MSC_VER) && _MSC_VER < 1910
1212391Sjason@lowepower.com#  pragma warning(disable: 4702) // unreachable code in system header
1312391Sjason@lowepower.com#endif
1412391Sjason@lowepower.com
1511986Sandreas.sandberg@arm.com#include "pybind11_tests.h"
1611986Sandreas.sandberg@arm.com#include "object.h"
1711986Sandreas.sandberg@arm.com
1812391Sjason@lowepower.com// Make pybind aware of the ref-counted wrapper type (s):
1912037Sandreas.sandberg@arm.com
2012037Sandreas.sandberg@arm.com// ref<T> is a wrapper for 'Object' which uses intrusive reference counting
2112037Sandreas.sandberg@arm.com// It is always possible to construct a ref<T> from an Object* pointer without
2214299Sbbruce@ucdavis.edu// possible inconsistencies, hence the 'true' argument at the end.
2312037Sandreas.sandberg@arm.comPYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
2412037Sandreas.sandberg@arm.com// Make pybind11 aware of the non-standard getter member function
2512037Sandreas.sandberg@arm.comnamespace pybind11 { namespace detail {
2612037Sandreas.sandberg@arm.com    template <typename T>
2712037Sandreas.sandberg@arm.com    struct holder_helper<ref<T>> {
2812037Sandreas.sandberg@arm.com        static const T *get(const ref<T> &p) { return p.get_ptr(); }
2912037Sandreas.sandberg@arm.com    };
3012037Sandreas.sandberg@arm.com}}
3112037Sandreas.sandberg@arm.com
3212391Sjason@lowepower.com// The following is not required anymore for std::shared_ptr, but it should compile without error:
3312391Sjason@lowepower.comPYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
3411986Sandreas.sandberg@arm.com
3512391Sjason@lowepower.com// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
3612391Sjason@lowepower.com// holder size to trigger the non-simple-layout internal instance layout for single inheritance with
3712391Sjason@lowepower.com// large holder type:
3812391Sjason@lowepower.comtemplate <typename T> class huge_unique_ptr {
3912391Sjason@lowepower.com    std::unique_ptr<T> ptr;
4012391Sjason@lowepower.com    uint64_t padding[10];
4112391Sjason@lowepower.compublic:
4212391Sjason@lowepower.com    huge_unique_ptr(T *p) : ptr(p) {};
4312391Sjason@lowepower.com    T *get() { return ptr.get(); }
4412391Sjason@lowepower.com};
4512391Sjason@lowepower.comPYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
4611986Sandreas.sandberg@arm.com
4712391Sjason@lowepower.com// Simple custom holder that works like unique_ptr
4812391Sjason@lowepower.comtemplate <typename T>
4912391Sjason@lowepower.comclass custom_unique_ptr {
5012391Sjason@lowepower.com    std::unique_ptr<T> impl;
5112391Sjason@lowepower.compublic:
5212391Sjason@lowepower.com    custom_unique_ptr(T* p) : impl(p) { }
5312391Sjason@lowepower.com    T* get() const { return impl.get(); }
5412391Sjason@lowepower.com    T* release_ptr() { return impl.release(); }
5512391Sjason@lowepower.com};
5612391Sjason@lowepower.comPYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
5711986Sandreas.sandberg@arm.com
5814299Sbbruce@ucdavis.edu// Simple custom holder that works like shared_ptr and has operator& overload
5914299Sbbruce@ucdavis.edu// To obtain address of an instance of this holder pybind should use std::addressof
6014299Sbbruce@ucdavis.edu// Attempt to get address via operator& may leads to segmentation fault
6114299Sbbruce@ucdavis.edutemplate <typename T>
6214299Sbbruce@ucdavis.educlass shared_ptr_with_addressof_operator {
6314299Sbbruce@ucdavis.edu    std::shared_ptr<T> impl;
6414299Sbbruce@ucdavis.edupublic:
6514299Sbbruce@ucdavis.edu    shared_ptr_with_addressof_operator( ) = default;
6614299Sbbruce@ucdavis.edu    shared_ptr_with_addressof_operator(T* p) : impl(p) { }
6714299Sbbruce@ucdavis.edu    T* get() const { return impl.get(); }
6814299Sbbruce@ucdavis.edu    T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
6914299Sbbruce@ucdavis.edu};
7014299Sbbruce@ucdavis.eduPYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
7114299Sbbruce@ucdavis.edu
7214299Sbbruce@ucdavis.edu// Simple custom holder that works like unique_ptr and has operator& overload
7314299Sbbruce@ucdavis.edu// To obtain address of an instance of this holder pybind should use std::addressof
7414299Sbbruce@ucdavis.edu// Attempt to get address via operator& may leads to segmentation fault
7514299Sbbruce@ucdavis.edutemplate <typename T>
7614299Sbbruce@ucdavis.educlass unique_ptr_with_addressof_operator {
7714299Sbbruce@ucdavis.edu    std::unique_ptr<T> impl;
7814299Sbbruce@ucdavis.edupublic:
7914299Sbbruce@ucdavis.edu    unique_ptr_with_addressof_operator() = default;
8014299Sbbruce@ucdavis.edu    unique_ptr_with_addressof_operator(T* p) : impl(p) { }
8114299Sbbruce@ucdavis.edu    T* get() const { return impl.get(); }
8214299Sbbruce@ucdavis.edu    T* release_ptr() { return impl.release(); }
8314299Sbbruce@ucdavis.edu    T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
8414299Sbbruce@ucdavis.edu};
8514299Sbbruce@ucdavis.eduPYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
8614299Sbbruce@ucdavis.edu
8711986Sandreas.sandberg@arm.com
8812391Sjason@lowepower.comTEST_SUBMODULE(smart_ptr, m) {
8911986Sandreas.sandberg@arm.com
9012391Sjason@lowepower.com    // test_smart_ptr
9111986Sandreas.sandberg@arm.com
9212391Sjason@lowepower.com    // Object implementation in `object.h`
9311986Sandreas.sandberg@arm.com    py::class_<Object, ref<Object>> obj(m, "Object");
9411986Sandreas.sandberg@arm.com    obj.def("getRefCount", &Object::getRefCount);
9511986Sandreas.sandberg@arm.com
9612391Sjason@lowepower.com    // Custom object with builtin reference counting (see 'object.h' for the implementation)
9712391Sjason@lowepower.com    class MyObject1 : public Object {
9812391Sjason@lowepower.com    public:
9912391Sjason@lowepower.com        MyObject1(int value) : value(value) { print_created(this, toString()); }
10012391Sjason@lowepower.com        std::string toString() const { return "MyObject1[" + std::to_string(value) + "]"; }
10112391Sjason@lowepower.com    protected:
10212391Sjason@lowepower.com        virtual ~MyObject1() { print_destroyed(this); }
10312391Sjason@lowepower.com    private:
10412391Sjason@lowepower.com        int value;
10512391Sjason@lowepower.com    };
10611986Sandreas.sandberg@arm.com    py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj)
10711986Sandreas.sandberg@arm.com        .def(py::init<int>());
10812391Sjason@lowepower.com    py::implicitly_convertible<py::int_, MyObject1>();
10911986Sandreas.sandberg@arm.com
11012391Sjason@lowepower.com    m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
11112391Sjason@lowepower.com    m.def("make_object_2", []() -> ref<Object> { return new MyObject1(2); });
11212391Sjason@lowepower.com    m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); });
11312391Sjason@lowepower.com    m.def("make_myobject1_2", []() -> ref<MyObject1> { return new MyObject1(5); });
11412391Sjason@lowepower.com    m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); });
11512391Sjason@lowepower.com    m.def("print_object_2", [](ref<Object> obj) { py::print(obj->toString()); });
11612391Sjason@lowepower.com    m.def("print_object_3", [](const ref<Object> &obj) { py::print(obj->toString()); });
11712391Sjason@lowepower.com    m.def("print_object_4", [](const ref<Object> *obj) { py::print((*obj)->toString()); });
11812391Sjason@lowepower.com    m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); });
11912391Sjason@lowepower.com    m.def("print_myobject1_2", [](ref<MyObject1> obj) { py::print(obj->toString()); });
12012391Sjason@lowepower.com    m.def("print_myobject1_3", [](const ref<MyObject1> &obj) { py::print(obj->toString()); });
12112391Sjason@lowepower.com    m.def("print_myobject1_4", [](const ref<MyObject1> *obj) { py::print((*obj)->toString()); });
12212037Sandreas.sandberg@arm.com
12312391Sjason@lowepower.com    // Expose constructor stats for the ref type
12412391Sjason@lowepower.com    m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
12511986Sandreas.sandberg@arm.com
12612391Sjason@lowepower.com
12712391Sjason@lowepower.com    // Object managed by a std::shared_ptr<>
12812391Sjason@lowepower.com    class MyObject2 {
12912391Sjason@lowepower.com    public:
13014299Sbbruce@ucdavis.edu        MyObject2(const MyObject2 &) = default;
13112391Sjason@lowepower.com        MyObject2(int value) : value(value) { print_created(this, toString()); }
13212391Sjason@lowepower.com        std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; }
13312391Sjason@lowepower.com        virtual ~MyObject2() { print_destroyed(this); }
13412391Sjason@lowepower.com    private:
13512391Sjason@lowepower.com        int value;
13612391Sjason@lowepower.com    };
13711986Sandreas.sandberg@arm.com    py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2")
13811986Sandreas.sandberg@arm.com        .def(py::init<int>());
13912391Sjason@lowepower.com    m.def("make_myobject2_1", []() { return new MyObject2(6); });
14012391Sjason@lowepower.com    m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); });
14112391Sjason@lowepower.com    m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); });
14212391Sjason@lowepower.com    m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); });
14312391Sjason@lowepower.com    m.def("print_myobject2_3", [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); });
14412391Sjason@lowepower.com    m.def("print_myobject2_4", [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); });
14511986Sandreas.sandberg@arm.com
14612391Sjason@lowepower.com    // Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<>
14712391Sjason@lowepower.com    class MyObject3 : public std::enable_shared_from_this<MyObject3> {
14812391Sjason@lowepower.com    public:
14914299Sbbruce@ucdavis.edu        MyObject3(const MyObject3 &) = default;
15012391Sjason@lowepower.com        MyObject3(int value) : value(value) { print_created(this, toString()); }
15112391Sjason@lowepower.com        std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; }
15212391Sjason@lowepower.com        virtual ~MyObject3() { print_destroyed(this); }
15312391Sjason@lowepower.com    private:
15412391Sjason@lowepower.com        int value;
15512391Sjason@lowepower.com    };
15611986Sandreas.sandberg@arm.com    py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3")
15711986Sandreas.sandberg@arm.com        .def(py::init<int>());
15812391Sjason@lowepower.com    m.def("make_myobject3_1", []() { return new MyObject3(8); });
15912391Sjason@lowepower.com    m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); });
16012391Sjason@lowepower.com    m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); });
16112391Sjason@lowepower.com    m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); });
16212391Sjason@lowepower.com    m.def("print_myobject3_3", [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); });
16312391Sjason@lowepower.com    m.def("print_myobject3_4", [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); });
16411986Sandreas.sandberg@arm.com
16512391Sjason@lowepower.com    // test_smart_ptr_refcounting
16612391Sjason@lowepower.com    m.def("test_object1_refcounting", []() {
16712391Sjason@lowepower.com        ref<MyObject1> o = new MyObject1(0);
16812391Sjason@lowepower.com        bool good = o->getRefCount() == 1;
16912391Sjason@lowepower.com        py::object o2 = py::cast(o, py::return_value_policy::reference);
17012391Sjason@lowepower.com        // always request (partial) ownership for objects with intrusive
17112391Sjason@lowepower.com        // reference counting even when using the 'reference' RVP
17212391Sjason@lowepower.com        good &= o->getRefCount() == 2;
17312391Sjason@lowepower.com        return good;
17412391Sjason@lowepower.com    });
17512391Sjason@lowepower.com
17612391Sjason@lowepower.com    // test_unique_nodelete
17712391Sjason@lowepower.com    // Object with a private destructor
17812391Sjason@lowepower.com    class MyObject4 {
17912391Sjason@lowepower.com    public:
18012391Sjason@lowepower.com        MyObject4(int value) : value{value} { print_created(this); }
18112391Sjason@lowepower.com        int value;
18212391Sjason@lowepower.com    private:
18312391Sjason@lowepower.com        ~MyObject4() { print_destroyed(this); }
18412391Sjason@lowepower.com    };
18511986Sandreas.sandberg@arm.com    py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4")
18611986Sandreas.sandberg@arm.com        .def(py::init<int>())
18711986Sandreas.sandberg@arm.com        .def_readwrite("value", &MyObject4::value);
18811986Sandreas.sandberg@arm.com
18914299Sbbruce@ucdavis.edu    // test_unique_deleter
19014299Sbbruce@ucdavis.edu    // Object with std::unique_ptr<T, D> where D is not matching the base class
19114299Sbbruce@ucdavis.edu    // Object with a protected destructor
19214299Sbbruce@ucdavis.edu    class MyObject4a {
19314299Sbbruce@ucdavis.edu    public:
19414299Sbbruce@ucdavis.edu        MyObject4a(int i) {
19514299Sbbruce@ucdavis.edu            value = i;
19614299Sbbruce@ucdavis.edu            print_created(this);
19714299Sbbruce@ucdavis.edu        };
19814299Sbbruce@ucdavis.edu        int value;
19914299Sbbruce@ucdavis.edu    protected:
20014299Sbbruce@ucdavis.edu        virtual ~MyObject4a() { print_destroyed(this); }
20114299Sbbruce@ucdavis.edu    };
20214299Sbbruce@ucdavis.edu    py::class_<MyObject4a, std::unique_ptr<MyObject4a, py::nodelete>>(m, "MyObject4a")
20314299Sbbruce@ucdavis.edu        .def(py::init<int>())
20414299Sbbruce@ucdavis.edu        .def_readwrite("value", &MyObject4a::value);
20514299Sbbruce@ucdavis.edu
20614299Sbbruce@ucdavis.edu    // Object derived but with public destructor and no Deleter in default holder
20714299Sbbruce@ucdavis.edu    class MyObject4b : public MyObject4a {
20814299Sbbruce@ucdavis.edu    public:
20914299Sbbruce@ucdavis.edu        MyObject4b(int i) : MyObject4a(i) { print_created(this); }
21014299Sbbruce@ucdavis.edu        ~MyObject4b() { print_destroyed(this); }
21114299Sbbruce@ucdavis.edu    };
21214299Sbbruce@ucdavis.edu    py::class_<MyObject4b, MyObject4a>(m, "MyObject4b")
21314299Sbbruce@ucdavis.edu        .def(py::init<int>());
21414299Sbbruce@ucdavis.edu
21512391Sjason@lowepower.com    // test_large_holder
21612391Sjason@lowepower.com    class MyObject5 { // managed by huge_unique_ptr
21712391Sjason@lowepower.com    public:
21812391Sjason@lowepower.com        MyObject5(int value) : value{value} { print_created(this); }
21912391Sjason@lowepower.com        ~MyObject5() { print_destroyed(this); }
22012391Sjason@lowepower.com        int value;
22112391Sjason@lowepower.com    };
22212391Sjason@lowepower.com    py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5")
22312391Sjason@lowepower.com        .def(py::init<int>())
22412391Sjason@lowepower.com        .def_readwrite("value", &MyObject5::value);
22511986Sandreas.sandberg@arm.com
22612391Sjason@lowepower.com    // test_shared_ptr_and_references
22712391Sjason@lowepower.com    struct SharedPtrRef {
22812391Sjason@lowepower.com        struct A {
22912391Sjason@lowepower.com            A() { print_created(this); }
23012391Sjason@lowepower.com            A(const A &) { print_copy_created(this); }
23112391Sjason@lowepower.com            A(A &&) { print_move_created(this); }
23212391Sjason@lowepower.com            ~A() { print_destroyed(this); }
23312391Sjason@lowepower.com        };
23411986Sandreas.sandberg@arm.com
23512391Sjason@lowepower.com        A value = {};
23612391Sjason@lowepower.com        std::shared_ptr<A> shared = std::make_shared<A>();
23711986Sandreas.sandberg@arm.com    };
23811986Sandreas.sandberg@arm.com    using A = SharedPtrRef::A;
23911986Sandreas.sandberg@arm.com    py::class_<A, std::shared_ptr<A>>(m, "A");
24011986Sandreas.sandberg@arm.com    py::class_<SharedPtrRef>(m, "SharedPtrRef")
24111986Sandreas.sandberg@arm.com        .def(py::init<>())
24211986Sandreas.sandberg@arm.com        .def_readonly("ref", &SharedPtrRef::value)
24311986Sandreas.sandberg@arm.com        .def_property_readonly("copy", [](const SharedPtrRef &s) { return s.value; },
24411986Sandreas.sandberg@arm.com                               py::return_value_policy::copy)
24511986Sandreas.sandberg@arm.com        .def_readonly("holder_ref", &SharedPtrRef::shared)
24611986Sandreas.sandberg@arm.com        .def_property_readonly("holder_copy", [](const SharedPtrRef &s) { return s.shared; },
24711986Sandreas.sandberg@arm.com                               py::return_value_policy::copy)
24811986Sandreas.sandberg@arm.com        .def("set_ref", [](SharedPtrRef &, const A &) { return true; })
24911986Sandreas.sandberg@arm.com        .def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; });
25011986Sandreas.sandberg@arm.com
25112391Sjason@lowepower.com    // test_shared_ptr_from_this_and_references
25212391Sjason@lowepower.com    struct SharedFromThisRef {
25312391Sjason@lowepower.com        struct B : std::enable_shared_from_this<B> {
25412391Sjason@lowepower.com            B() { print_created(this); }
25512391Sjason@lowepower.com            B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); }
25612391Sjason@lowepower.com            B(B &&) : std::enable_shared_from_this<B>() { print_move_created(this); }
25712391Sjason@lowepower.com            ~B() { print_destroyed(this); }
25812391Sjason@lowepower.com        };
25912391Sjason@lowepower.com
26012391Sjason@lowepower.com        B value = {};
26112391Sjason@lowepower.com        std::shared_ptr<B> shared = std::make_shared<B>();
26212391Sjason@lowepower.com    };
26311986Sandreas.sandberg@arm.com    using B = SharedFromThisRef::B;
26411986Sandreas.sandberg@arm.com    py::class_<B, std::shared_ptr<B>>(m, "B");
26511986Sandreas.sandberg@arm.com    py::class_<SharedFromThisRef>(m, "SharedFromThisRef")
26611986Sandreas.sandberg@arm.com        .def(py::init<>())
26711986Sandreas.sandberg@arm.com        .def_readonly("bad_wp", &SharedFromThisRef::value)
26811986Sandreas.sandberg@arm.com        .def_property_readonly("ref", [](const SharedFromThisRef &s) -> const B & { return *s.shared; })
26911986Sandreas.sandberg@arm.com        .def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; },
27011986Sandreas.sandberg@arm.com                               py::return_value_policy::copy)
27111986Sandreas.sandberg@arm.com        .def_readonly("holder_ref", &SharedFromThisRef::shared)
27211986Sandreas.sandberg@arm.com        .def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; },
27311986Sandreas.sandberg@arm.com                               py::return_value_policy::copy)
27411986Sandreas.sandberg@arm.com        .def("set_ref", [](SharedFromThisRef &, const B &) { return true; })
27511986Sandreas.sandberg@arm.com        .def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; });
27612037Sandreas.sandberg@arm.com
27712391Sjason@lowepower.com    // Issue #865: shared_from_this doesn't work with virtual inheritance
27812391Sjason@lowepower.com    struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> {
27914299Sbbruce@ucdavis.edu        SharedFromThisVBase() = default;
28014299Sbbruce@ucdavis.edu        SharedFromThisVBase(const SharedFromThisVBase &) = default;
28112391Sjason@lowepower.com        virtual ~SharedFromThisVBase() = default;
28212391Sjason@lowepower.com    };
28312391Sjason@lowepower.com    struct SharedFromThisVirt : virtual SharedFromThisVBase {};
28412391Sjason@lowepower.com    static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt());
28512391Sjason@lowepower.com    py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt")
28612391Sjason@lowepower.com        .def_static("get", []() { return sft.get(); });
28712391Sjason@lowepower.com
28812391Sjason@lowepower.com    // test_move_only_holder
28912037Sandreas.sandberg@arm.com    struct C {
29012037Sandreas.sandberg@arm.com        C() { print_created(this); }
29112037Sandreas.sandberg@arm.com        ~C() { print_destroyed(this); }
29212037Sandreas.sandberg@arm.com    };
29312391Sjason@lowepower.com    py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder")
29412391Sjason@lowepower.com        .def_static("make", []() { return custom_unique_ptr<C>(new C); });
29512037Sandreas.sandberg@arm.com
29614299Sbbruce@ucdavis.edu    // test_holder_with_addressof_operator
29714299Sbbruce@ucdavis.edu    struct TypeForHolderWithAddressOf {
29814299Sbbruce@ucdavis.edu        TypeForHolderWithAddressOf() { print_created(this); }
29914299Sbbruce@ucdavis.edu        TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); }
30014299Sbbruce@ucdavis.edu        TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) { print_move_created(this); }
30114299Sbbruce@ucdavis.edu        ~TypeForHolderWithAddressOf() { print_destroyed(this); }
30214299Sbbruce@ucdavis.edu        std::string toString() const {
30314299Sbbruce@ucdavis.edu            return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]";
30414299Sbbruce@ucdavis.edu        }
30514299Sbbruce@ucdavis.edu        int value = 42;
30614299Sbbruce@ucdavis.edu    };
30714299Sbbruce@ucdavis.edu    using HolderWithAddressOf = shared_ptr_with_addressof_operator<TypeForHolderWithAddressOf>;
30814299Sbbruce@ucdavis.edu    py::class_<TypeForHolderWithAddressOf, HolderWithAddressOf>(m, "TypeForHolderWithAddressOf")
30914299Sbbruce@ucdavis.edu        .def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); })
31014299Sbbruce@ucdavis.edu        .def("get", [](const HolderWithAddressOf &self) { return self.get(); })
31114299Sbbruce@ucdavis.edu        .def("print_object_1", [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); })
31214299Sbbruce@ucdavis.edu        .def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); })
31314299Sbbruce@ucdavis.edu        .def("print_object_3", [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); })
31414299Sbbruce@ucdavis.edu        .def("print_object_4", [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); });
31514299Sbbruce@ucdavis.edu
31614299Sbbruce@ucdavis.edu    // test_move_only_holder_with_addressof_operator
31714299Sbbruce@ucdavis.edu    struct TypeForMoveOnlyHolderWithAddressOf {
31814299Sbbruce@ucdavis.edu        TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); }
31914299Sbbruce@ucdavis.edu        ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); }
32014299Sbbruce@ucdavis.edu        std::string toString() const {
32114299Sbbruce@ucdavis.edu            return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]";
32214299Sbbruce@ucdavis.edu        }
32314299Sbbruce@ucdavis.edu        int value;
32414299Sbbruce@ucdavis.edu    };
32514299Sbbruce@ucdavis.edu    using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>;
32614299Sbbruce@ucdavis.edu    py::class_<TypeForMoveOnlyHolderWithAddressOf, MoveOnlyHolderWithAddressOf>(m, "TypeForMoveOnlyHolderWithAddressOf")
32714299Sbbruce@ucdavis.edu        .def_static("make", []() { return MoveOnlyHolderWithAddressOf(new TypeForMoveOnlyHolderWithAddressOf(0)); })
32814299Sbbruce@ucdavis.edu        .def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value)
32914299Sbbruce@ucdavis.edu        .def("print_object", [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); });
33014299Sbbruce@ucdavis.edu
33112391Sjason@lowepower.com    // test_smart_ptr_from_default
33212037Sandreas.sandberg@arm.com    struct HeldByDefaultHolder { };
33312037Sandreas.sandberg@arm.com    py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
33412037Sandreas.sandberg@arm.com        .def(py::init<>())
33512037Sandreas.sandberg@arm.com        .def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
33612391Sjason@lowepower.com
33712391Sjason@lowepower.com    // test_shared_ptr_gc
33812391Sjason@lowepower.com    // #187: issue involving std::shared_ptr<> return value policy & garbage collection
33914299Sbbruce@ucdavis.edu    struct ElementBase {
34014299Sbbruce@ucdavis.edu        virtual ~ElementBase() { } /* Force creation of virtual table */
34114299Sbbruce@ucdavis.edu    };
34212391Sjason@lowepower.com    py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase");
34312391Sjason@lowepower.com
34412391Sjason@lowepower.com    struct ElementA : ElementBase {
34512391Sjason@lowepower.com        ElementA(int v) : v(v) { }
34612391Sjason@lowepower.com        int value() { return v; }
34712391Sjason@lowepower.com        int v;
34812391Sjason@lowepower.com    };
34912391Sjason@lowepower.com    py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA")
35012391Sjason@lowepower.com        .def(py::init<int>())
35112391Sjason@lowepower.com        .def("value", &ElementA::value);
35212391Sjason@lowepower.com
35312391Sjason@lowepower.com    struct ElementList {
35412391Sjason@lowepower.com        void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
35512391Sjason@lowepower.com        std::vector<std::shared_ptr<ElementBase>> l;
35612391Sjason@lowepower.com    };
35712391Sjason@lowepower.com    py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList")
35812391Sjason@lowepower.com        .def(py::init<>())
35912391Sjason@lowepower.com        .def("add", &ElementList::add)
36012391Sjason@lowepower.com        .def("get", [](ElementList &el) {
36112391Sjason@lowepower.com            py::list list;
36212391Sjason@lowepower.com            for (auto &e : el.l)
36312391Sjason@lowepower.com                list.append(py::cast(e));
36412391Sjason@lowepower.com            return list;
36512391Sjason@lowepower.com        });
36612391Sjason@lowepower.com}
367