test_smart_ptr.cpp revision 12037
19793Sakash.bagdia@arm.com/* 28706Sandreas.hansson@arm.com tests/test_smart_ptr.cpp -- binding classes with custom reference counting, 38706Sandreas.hansson@arm.com implicit conversions between types 48706Sandreas.hansson@arm.com 58706Sandreas.hansson@arm.com Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> 68706Sandreas.hansson@arm.com 78706Sandreas.hansson@arm.com All rights reserved. Use of this source code is governed by a 88706Sandreas.hansson@arm.com BSD-style license that can be found in the LICENSE file. 98706Sandreas.hansson@arm.com*/ 108706Sandreas.hansson@arm.com 118706Sandreas.hansson@arm.com#include "pybind11_tests.h" 128706Sandreas.hansson@arm.com#include "object.h" 135369Ssaidi@eecs.umich.edu 143005Sstever@eecs.umich.edu/// Custom object with builtin reference counting (see 'object.h' for the implementation) 153005Sstever@eecs.umich.educlass MyObject1 : public Object { 163005Sstever@eecs.umich.edupublic: 173005Sstever@eecs.umich.edu MyObject1(int value) : value(value) { 183005Sstever@eecs.umich.edu print_created(this, toString()); 193005Sstever@eecs.umich.edu } 203005Sstever@eecs.umich.edu 213005Sstever@eecs.umich.edu std::string toString() const { 223005Sstever@eecs.umich.edu return "MyObject1[" + std::to_string(value) + "]"; 233005Sstever@eecs.umich.edu } 243005Sstever@eecs.umich.edu 253005Sstever@eecs.umich.eduprotected: 263005Sstever@eecs.umich.edu virtual ~MyObject1() { 273005Sstever@eecs.umich.edu print_destroyed(this); 283005Sstever@eecs.umich.edu } 293005Sstever@eecs.umich.edu 303005Sstever@eecs.umich.eduprivate: 313005Sstever@eecs.umich.edu int value; 323005Sstever@eecs.umich.edu}; 333005Sstever@eecs.umich.edu 343005Sstever@eecs.umich.edu/// Object managed by a std::shared_ptr<> 353005Sstever@eecs.umich.educlass MyObject2 { 363005Sstever@eecs.umich.edupublic: 373005Sstever@eecs.umich.edu MyObject2(int value) : value(value) { 383005Sstever@eecs.umich.edu print_created(this, toString()); 393005Sstever@eecs.umich.edu } 403005Sstever@eecs.umich.edu 412710SN/A std::string toString() const { 422710SN/A return "MyObject2[" + std::to_string(value) + "]"; 433005Sstever@eecs.umich.edu } 442889SN/A 4512564Sgabeblack@google.com virtual ~MyObject2() { 4613774Sandreas.sandberg@arm.com print_destroyed(this); 4712564Sgabeblack@google.com } 486654Snate@binkert.org 496654Snate@binkert.orgprivate: 509907Snilay@cs.wisc.edu int value; 516654Snate@binkert.org}; 522667SN/A 536654Snate@binkert.org/// Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<> 546654Snate@binkert.orgclass MyObject3 : public std::enable_shared_from_this<MyObject3> { 5512395Sswapnilster@gmail.compublic: 565457Ssaidi@eecs.umich.edu MyObject3(int value) : value(value) { 5711670Sandreas.hansson@arm.com print_created(this, toString()); 5811670Sandreas.hansson@arm.com } 5911670Sandreas.hansson@arm.com 608169SLisa.Hsu@amd.com std::string toString() const { 6111682Sandreas.hansson@arm.com return "MyObject3[" + std::to_string(value) + "]"; 6211682Sandreas.hansson@arm.com } 6311682Sandreas.hansson@arm.com 6411682Sandreas.hansson@arm.com virtual ~MyObject3() { 6513432Spau.cabre@metempsy.com print_destroyed(this); 6611682Sandreas.hansson@arm.com } 6713980Sjason@lowepower.com 6811682Sandreas.hansson@arm.comprivate: 6911682Sandreas.hansson@arm.com int value; 703394Shsul@eecs.umich.edu}; 719197Snilay@cs.wisc.edu 729197Snilay@cs.wisc.educlass MyObject4 { 739197Snilay@cs.wisc.edupublic: 749197Snilay@cs.wisc.edu MyObject4(int value) : value{value} { 759197Snilay@cs.wisc.edu print_created(this); 769197Snilay@cs.wisc.edu } 779197Snilay@cs.wisc.edu int value; 789197Snilay@cs.wisc.eduprivate: 799197Snilay@cs.wisc.edu ~MyObject4() { 809197Snilay@cs.wisc.edu print_destroyed(this); 819197Snilay@cs.wisc.edu } 829197Snilay@cs.wisc.edu}; 839197Snilay@cs.wisc.edu 849197Snilay@cs.wisc.edu/// Make pybind aware of the ref-counted wrapper type (s) 859197Snilay@cs.wisc.edu 869197Snilay@cs.wisc.edu// ref<T> is a wrapper for 'Object' which uses intrusive reference counting 879197Snilay@cs.wisc.edu// It is always possible to construct a ref<T> from an Object* pointer without 889197Snilay@cs.wisc.edu// possible incosistencies, hence the 'true' argument at the end. 899197Snilay@cs.wisc.eduPYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true); 909197Snilay@cs.wisc.eduPYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>); // Not required any more for std::shared_ptr, 919197Snilay@cs.wisc.edu // but it should compile without error 9212146Spau.cabre@metempsy.com 939197Snilay@cs.wisc.edu// Make pybind11 aware of the non-standard getter member function 949907Snilay@cs.wisc.edunamespace pybind11 { namespace detail { 959197Snilay@cs.wisc.edu template <typename T> 9610803Sbrandon.potter@amd.com struct holder_helper<ref<T>> { 9710803Sbrandon.potter@amd.com static const T *get(const ref<T> &p) { return p.get_ptr(); } 9810803Sbrandon.potter@amd.com }; 9910803Sbrandon.potter@amd.com}} 1009197Snilay@cs.wisc.edu 1019217Snilay@cs.wisc.eduObject *make_object_1() { return new MyObject1(1); } 1029197Snilay@cs.wisc.eduref<Object> make_object_2() { return new MyObject1(2); } 1039197Snilay@cs.wisc.edu 1049197Snilay@cs.wisc.eduMyObject1 *make_myobject1_1() { return new MyObject1(4); } 1059197Snilay@cs.wisc.eduref<MyObject1> make_myobject1_2() { return new MyObject1(5); } 1069197Snilay@cs.wisc.edu 1079197Snilay@cs.wisc.eduMyObject2 *make_myobject2_1() { return new MyObject2(6); } 1089197Snilay@cs.wisc.edustd::shared_ptr<MyObject2> make_myobject2_2() { return std::make_shared<MyObject2>(7); } 1099197Snilay@cs.wisc.edu 1109197Snilay@cs.wisc.eduMyObject3 *make_myobject3_1() { return new MyObject3(8); } 1119197Snilay@cs.wisc.edustd::shared_ptr<MyObject3> make_myobject3_2() { return std::make_shared<MyObject3>(9); } 1129197Snilay@cs.wisc.edu 1139197Snilay@cs.wisc.eduvoid print_object_1(const Object *obj) { py::print(obj->toString()); } 1149197Snilay@cs.wisc.eduvoid print_object_2(ref<Object> obj) { py::print(obj->toString()); } 1159197Snilay@cs.wisc.eduvoid print_object_3(const ref<Object> &obj) { py::print(obj->toString()); } 11612014Sgabeblack@google.comvoid print_object_4(const ref<Object> *obj) { py::print((*obj)->toString()); } 1179197Snilay@cs.wisc.edu 1189197Snilay@cs.wisc.eduvoid print_myobject1_1(const MyObject1 *obj) { py::print(obj->toString()); } 1199197Snilay@cs.wisc.eduvoid print_myobject1_2(ref<MyObject1> obj) { py::print(obj->toString()); } 1209197Snilay@cs.wisc.eduvoid print_myobject1_3(const ref<MyObject1> &obj) { py::print(obj->toString()); } 1219197Snilay@cs.wisc.eduvoid print_myobject1_4(const ref<MyObject1> *obj) { py::print((*obj)->toString()); } 1222957SN/A 1238920Snilay@cs.wisc.eduvoid print_myobject2_1(const MyObject2 *obj) { py::print(obj->toString()); } 1248920Snilay@cs.wisc.eduvoid print_myobject2_2(std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); } 1252957SN/Avoid print_myobject2_3(const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); } 1268862Snilay@cs.wisc.eduvoid print_myobject2_4(const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); } 1278862Snilay@cs.wisc.edu 1288467Snilay@cs.wisc.eduvoid print_myobject3_1(const MyObject3 *obj) { py::print(obj->toString()); } 1292957SN/Avoid print_myobject3_2(std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); } 1302957SN/Avoid print_myobject3_3(const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); } 1312957SN/Avoid print_myobject3_4(const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); } 13212564Sgabeblack@google.com 1332957SN/Atest_initializer smart_ptr([](py::module &m) { 1342957SN/A py::class_<Object, ref<Object>> obj(m, "Object"); 1358167SLisa.Hsu@amd.com obj.def("getRefCount", &Object::getRefCount); 1369197Snilay@cs.wisc.edu 1378167SLisa.Hsu@amd.com py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj) 1385369Ssaidi@eecs.umich.edu .def(py::init<int>()); 1398167SLisa.Hsu@amd.com 1408167SLisa.Hsu@amd.com m.def("test_object1_refcounting", 14112564Sgabeblack@google.com []() -> bool { 1428167SLisa.Hsu@amd.com ref<MyObject1> o = new MyObject1(0); 1438167SLisa.Hsu@amd.com bool good = o->getRefCount() == 1; 1448167SLisa.Hsu@amd.com py::object o2 = py::cast(o, py::return_value_policy::reference); 1458167SLisa.Hsu@amd.com // always request (partial) ownership for objects with intrusive 1468168SLisa.Hsu@amd.com // reference counting even when using the 'reference' RVP 14710037SARM gem5 Developers good &= o->getRefCount() == 2; 14810037SARM gem5 Developers return good; 14910037SARM gem5 Developers } 15010037SARM gem5 Developers ); 15110037SARM gem5 Developers 1528168SLisa.Hsu@amd.com m.def("make_object_1", &make_object_1); 15310037SARM gem5 Developers m.def("make_object_2", &make_object_2); 15410037SARM gem5 Developers m.def("make_myobject1_1", &make_myobject1_1); 15511851Sbrandon.potter@amd.com m.def("make_myobject1_2", &make_myobject1_2); 1568167SLisa.Hsu@amd.com m.def("print_object_1", &print_object_1); 15712564Sgabeblack@google.com m.def("print_object_2", &print_object_2); 15812564Sgabeblack@google.com m.def("print_object_3", &print_object_3); 15912564Sgabeblack@google.com m.def("print_object_4", &print_object_4); 1605369Ssaidi@eecs.umich.edu m.def("print_myobject1_1", &print_myobject1_1); 1618920Snilay@cs.wisc.edu m.def("print_myobject1_2", &print_myobject1_2); 1629197Snilay@cs.wisc.edu m.def("print_myobject1_3", &print_myobject1_3); 1638920Snilay@cs.wisc.edu m.def("print_myobject1_4", &print_myobject1_4); 16412564Sgabeblack@google.com 1658920Snilay@cs.wisc.edu py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2") 1665369Ssaidi@eecs.umich.edu .def(py::init<int>()); 1675369Ssaidi@eecs.umich.edu m.def("make_myobject2_1", &make_myobject2_1); 1688718Snilay@cs.wisc.edu m.def("make_myobject2_2", &make_myobject2_2); 1699197Snilay@cs.wisc.edu m.def("print_myobject2_1", &print_myobject2_1); 1709197Snilay@cs.wisc.edu m.def("print_myobject2_2", &print_myobject2_2); 1719197Snilay@cs.wisc.edu m.def("print_myobject2_3", &print_myobject2_3); 1729197Snilay@cs.wisc.edu m.def("print_myobject2_4", &print_myobject2_4); 1739197Snilay@cs.wisc.edu 1743005Sstever@eecs.umich.edu py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3") 1753395Shsul@eecs.umich.edu .def(py::init<int>()); 17613731Sandreas.sandberg@arm.com m.def("make_myobject3_1", &make_myobject3_1); 1779793Sakash.bagdia@arm.com m.def("make_myobject3_2", &make_myobject3_2); 1789836Sandreas.hansson@arm.com m.def("print_myobject3_1", &print_myobject3_1); 1799815SAndreas Hansson <andreas.hansson> m.def("print_myobject3_2", &print_myobject3_2); 1809793Sakash.bagdia@arm.com m.def("print_myobject3_3", &print_myobject3_3); 18111147Smitch.hayenga@arm.com m.def("print_myobject3_4", &print_myobject3_4); 18211147Smitch.hayenga@arm.com 18311147Smitch.hayenga@arm.com py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4") 1849827Sakash.bagdia@arm.com .def(py::init<int>()) 1859827Sakash.bagdia@arm.com .def_readwrite("value", &MyObject4::value); 1869827Sakash.bagdia@arm.com 1879827Sakash.bagdia@arm.com py::implicitly_convertible<py::int_, MyObject1>(); 1889827Sakash.bagdia@arm.com 1899827Sakash.bagdia@arm.com // Expose constructor stats for the ref type 1909827Sakash.bagdia@arm.com m.def("cstats_ref", &ConstructorStats::get<ref_tag>); 1919827Sakash.bagdia@arm.com}); 1929827Sakash.bagdia@arm.com 1939827Sakash.bagdia@arm.comstruct SharedPtrRef { 1949793Sakash.bagdia@arm.com struct A { 1959827Sakash.bagdia@arm.com A() { print_created(this); } 1969827Sakash.bagdia@arm.com A(const A &) { print_copy_created(this); } 1979827Sakash.bagdia@arm.com A(A &&) { print_move_created(this); } 1989793Sakash.bagdia@arm.com ~A() { print_destroyed(this); } 19911251Sradhika.jagtap@ARM.com }; 20011251Sradhika.jagtap@ARM.com 20111251Sradhika.jagtap@ARM.com A value = {}; 20211251Sradhika.jagtap@ARM.com std::shared_ptr<A> shared = std::make_shared<A>(); 20311251Sradhika.jagtap@ARM.com}; 2049793Sakash.bagdia@arm.com 2059793Sakash.bagdia@arm.comstruct SharedFromThisRef { 2069793Sakash.bagdia@arm.com struct B : std::enable_shared_from_this<B> { 2079793Sakash.bagdia@arm.com B() { print_created(this); } 2083395Shsul@eecs.umich.edu B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); } 20912941Sandreas.sandberg@arm.com B(B &&) : std::enable_shared_from_this<B>() { print_move_created(this); } 21010555Salexandru.dutu@amd.com ~B() { print_destroyed(this); } 21111839SCurtis.Dunham@arm.com }; 21210555Salexandru.dutu@amd.com 21310555Salexandru.dutu@amd.com B value = {}; 21410555Salexandru.dutu@amd.com std::shared_ptr<B> shared = std::make_shared<B>(); 21510555Salexandru.dutu@amd.com}; 21610555Salexandru.dutu@amd.com 21710555Salexandru.dutu@amd.comtemplate <typename T> 2188926Sandreas.hansson@arm.comclass CustomUniquePtr { 2199647Sdam.sunwoo@arm.com std::unique_ptr<T> impl; 22013684Sgiacomo.travaglini@arm.com 22113012Sandreas.sandberg@arm.compublic: 2229647Sdam.sunwoo@arm.com CustomUniquePtr(T* p) : impl(p) { } 2239647Sdam.sunwoo@arm.com T* get() const { return impl.get(); } 2249647Sdam.sunwoo@arm.com T* release_ptr() { return impl.release(); } 22513731Sandreas.sandberg@arm.com}; 2269197Snilay@cs.wisc.edu 2279197Snilay@cs.wisc.eduPYBIND11_DECLARE_HOLDER_TYPE(T, CustomUniquePtr<T>); 2289197Snilay@cs.wisc.edu 2298957Sjayneel@cs.wisc.edutest_initializer smart_ptr_and_references([](py::module &pm) { 2308957Sjayneel@cs.wisc.edu auto m = pm.def_submodule("smart_ptr"); 2318957Sjayneel@cs.wisc.edu 2323005Sstever@eecs.umich.edu using A = SharedPtrRef::A; 2339647Sdam.sunwoo@arm.com py::class_<A, std::shared_ptr<A>>(m, "A"); 23410381Sdam.sunwoo@arm.com 2359647Sdam.sunwoo@arm.com py::class_<SharedPtrRef>(m, "SharedPtrRef") 2368887Sgeoffrey.blake@arm.com .def(py::init<>()) 2378887Sgeoffrey.blake@arm.com .def_readonly("ref", &SharedPtrRef::value) 2388887Sgeoffrey.blake@arm.com .def_property_readonly("copy", [](const SharedPtrRef &s) { return s.value; }, 23913432Spau.cabre@metempsy.com py::return_value_policy::copy) 24013432Spau.cabre@metempsy.com .def_readonly("holder_ref", &SharedPtrRef::shared) 24113432Spau.cabre@metempsy.com .def_property_readonly("holder_copy", [](const SharedPtrRef &s) { return s.shared; }, 24213432Spau.cabre@metempsy.com py::return_value_policy::copy) 24313958Sjairo.balart@metempsy.com .def("set_ref", [](SharedPtrRef &, const A &) { return true; }) 24413958Sjairo.balart@metempsy.com .def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; }); 24513958Sjairo.balart@metempsy.com 24613958Sjairo.balart@metempsy.com using B = SharedFromThisRef::B; 2479384SAndreas.Sandberg@arm.com py::class_<B, std::shared_ptr<B>>(m, "B"); 2489384SAndreas.Sandberg@arm.com 2498887Sgeoffrey.blake@arm.com py::class_<SharedFromThisRef>(m, "SharedFromThisRef") 25010519Snilay@cs.wisc.edu .def(py::init<>()) 25110120Snilay@cs.wisc.edu .def_readonly("bad_wp", &SharedFromThisRef::value) 2528896Snilay@cs.wisc.edu .def_property_readonly("ref", [](const SharedFromThisRef &s) -> const B & { return *s.shared; }) 25310300Scastilloe@unican.es .def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; }, 25410300Scastilloe@unican.es py::return_value_policy::copy) 25513731Sandreas.sandberg@arm.com .def_readonly("holder_ref", &SharedFromThisRef::shared) 25610120Snilay@cs.wisc.edu .def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; }, 2578896Snilay@cs.wisc.edu py::return_value_policy::copy) 2588896Snilay@cs.wisc.edu .def("set_ref", [](SharedFromThisRef &, const B &) { return true; }) 2599268Smalek.musleh@gmail.com .def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; }); 2609268Smalek.musleh@gmail.com 2618896Snilay@cs.wisc.edu struct C { 2628896Snilay@cs.wisc.edu C() { print_created(this); } 2638896Snilay@cs.wisc.edu ~C() { print_destroyed(this); } 2648896Snilay@cs.wisc.edu }; 2658896Snilay@cs.wisc.edu 2669222Shestness@cs.wisc.edu py::class_<C, CustomUniquePtr<C>>(m, "TypeWithMoveOnlyHolder") 26711150Smitch.hayenga@arm.com .def_static("make", []() { return CustomUniquePtr<C>(new C); }); 26811150Smitch.hayenga@arm.com 26911150Smitch.hayenga@arm.com struct HeldByDefaultHolder { }; 2709222Shestness@cs.wisc.edu 2719222Shestness@cs.wisc.edu py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder") 2728887Sgeoffrey.blake@arm.com .def(py::init<>()) 27310150Snilay@cs.wisc.edu .def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {}); 27410720Sandreas.hansson@arm.com}); 2758887Sgeoffrey.blake@arm.com