1/* 2 tests/test_factory_constructors.cpp -- tests construction from a factory function 3 via py::init_factory() 4 5 Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca> 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#include "pybind11_tests.h" 12#include "constructor_stats.h" 13#include <cmath> 14 15// Classes for testing python construction via C++ factory function: 16// Not publicly constructible, copyable, or movable: 17class TestFactory1 { 18 friend class TestFactoryHelper; 19 TestFactory1() : value("(empty)") { print_default_created(this); } 20 TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); } 21 TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); } 22 TestFactory1(TestFactory1 &&) = delete; 23 TestFactory1(const TestFactory1 &) = delete; 24 TestFactory1 &operator=(TestFactory1 &&) = delete; 25 TestFactory1 &operator=(const TestFactory1 &) = delete; 26public: 27 std::string value; 28 ~TestFactory1() { print_destroyed(this); } 29}; 30// Non-public construction, but moveable: 31class TestFactory2 { 32 friend class TestFactoryHelper; 33 TestFactory2() : value("(empty2)") { print_default_created(this); } 34 TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); } 35 TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); } 36public: 37 TestFactory2(TestFactory2 &&m) { value = std::move(m.value); print_move_created(this); } 38 TestFactory2 &operator=(TestFactory2 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } 39 std::string value; 40 ~TestFactory2() { print_destroyed(this); } 41}; 42// Mixed direct/factory construction: 43class TestFactory3 { 44protected: 45 friend class TestFactoryHelper; 46 TestFactory3() : value("(empty3)") { print_default_created(this); } 47 TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); } 48public: 49 TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); } 50 TestFactory3(TestFactory3 &&m) { value = std::move(m.value); print_move_created(this); } 51 TestFactory3 &operator=(TestFactory3 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } 52 std::string value; 53 virtual ~TestFactory3() { print_destroyed(this); } 54}; 55// Inheritance test 56class TestFactory4 : public TestFactory3 { 57public: 58 TestFactory4() : TestFactory3() { print_default_created(this); } 59 TestFactory4(int v) : TestFactory3(v) { print_created(this, v); } 60 virtual ~TestFactory4() { print_destroyed(this); } 61}; 62// Another class for an invalid downcast test 63class TestFactory5 : public TestFactory3 { 64public: 65 TestFactory5(int i) : TestFactory3(i) { print_created(this, i); } 66 virtual ~TestFactory5() { print_destroyed(this); } 67}; 68 69class TestFactory6 { 70protected: 71 int value; 72 bool alias = false; 73public: 74 TestFactory6(int i) : value{i} { print_created(this, i); } 75 TestFactory6(TestFactory6 &&f) { print_move_created(this); value = f.value; alias = f.alias; } 76 TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; } 77 virtual ~TestFactory6() { print_destroyed(this); } 78 virtual int get() { return value; } 79 bool has_alias() { return alias; } 80}; 81class PyTF6 : public TestFactory6 { 82public: 83 // Special constructor that allows the factory to construct a PyTF6 from a TestFactory6 only 84 // when an alias is needed: 85 PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); } 86 PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); } 87 PyTF6(PyTF6 &&f) : TestFactory6(std::move(f)) { print_move_created(this); } 88 PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); } 89 PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); } 90 virtual ~PyTF6() { print_destroyed(this); } 91 int get() override { PYBIND11_OVERLOAD(int, TestFactory6, get, /*no args*/); } 92}; 93 94class TestFactory7 { 95protected: 96 int value; 97 bool alias = false; 98public: 99 TestFactory7(int i) : value{i} { print_created(this, i); } 100 TestFactory7(TestFactory7 &&f) { print_move_created(this); value = f.value; alias = f.alias; } 101 TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; } 102 virtual ~TestFactory7() { print_destroyed(this); } 103 virtual int get() { return value; } 104 bool has_alias() { return alias; } 105}; 106class PyTF7 : public TestFactory7 { 107public: 108 PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); } 109 PyTF7(PyTF7 &&f) : TestFactory7(std::move(f)) { print_move_created(this); } 110 PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } 111 virtual ~PyTF7() { print_destroyed(this); } 112 int get() override { PYBIND11_OVERLOAD(int, TestFactory7, get, /*no args*/); } 113}; 114 115 116class TestFactoryHelper { 117public: 118 // Non-movable, non-copyable type: 119 // Return via pointer: 120 static TestFactory1 *construct1() { return new TestFactory1(); } 121 // Holder: 122 static std::unique_ptr<TestFactory1> construct1(int a) { return std::unique_ptr<TestFactory1>(new TestFactory1(a)); } 123 // pointer again 124 static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(a); } 125 126 // Moveable type: 127 // pointer: 128 static TestFactory2 *construct2() { return new TestFactory2(); } 129 // holder: 130 static std::unique_ptr<TestFactory2> construct2(int a) { return std::unique_ptr<TestFactory2>(new TestFactory2(a)); } 131 // by value moving: 132 static TestFactory2 construct2(std::string a) { return TestFactory2(a); } 133 134 // shared_ptr holder type: 135 // pointer: 136 static TestFactory3 *construct3() { return new TestFactory3(); } 137 // holder: 138 static std::shared_ptr<TestFactory3> construct3(int a) { return std::shared_ptr<TestFactory3>(new TestFactory3(a)); } 139}; 140 141TEST_SUBMODULE(factory_constructors, m) { 142 143 // Define various trivial types to allow simpler overload resolution: 144 py::module m_tag = m.def_submodule("tag"); 145#define MAKE_TAG_TYPE(Name) \ 146 struct Name##_tag {}; \ 147 py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \ 148 m_tag.attr(#Name) = py::cast(Name##_tag{}) 149 MAKE_TAG_TYPE(pointer); 150 MAKE_TAG_TYPE(unique_ptr); 151 MAKE_TAG_TYPE(move); 152 MAKE_TAG_TYPE(shared_ptr); 153 MAKE_TAG_TYPE(derived); 154 MAKE_TAG_TYPE(TF4); 155 MAKE_TAG_TYPE(TF5); 156 MAKE_TAG_TYPE(null_ptr); 157 MAKE_TAG_TYPE(base); 158 MAKE_TAG_TYPE(invalid_base); 159 MAKE_TAG_TYPE(alias); 160 MAKE_TAG_TYPE(unaliasable); 161 MAKE_TAG_TYPE(mixed); 162 163 // test_init_factory_basic, test_bad_type 164 py::class_<TestFactory1>(m, "TestFactory1") 165 .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); })) 166 .def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer 167 .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); })) 168 .def(py::init([](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); })) 169 .def_readwrite("value", &TestFactory1::value) 170 ; 171 py::class_<TestFactory2>(m, "TestFactory2") 172 .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) 173 .def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); })) 174 .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); })) 175 .def_readwrite("value", &TestFactory2::value) 176 ; 177 178 // Stateful & reused: 179 int c = 1; 180 auto c4a = [c](pointer_tag, TF4_tag, int a) { (void) c; return new TestFactory4(a);}; 181 182 // test_init_factory_basic, test_init_factory_casting 183 py::class_<TestFactory3, std::shared_ptr<TestFactory3>>(m, "TestFactory3") 184 .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) 185 .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })) 186 .def("__init__", [](TestFactory3 &self, std::string v) { new (&self) TestFactory3(v); }) // placement-new ctor 187 188 // factories returning a derived type: 189 .def(py::init(c4a)) // derived ptr 190 .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); })) 191 // derived shared ptr: 192 .def(py::init([](shared_ptr_tag, TF4_tag, int a) { return std::make_shared<TestFactory4>(a); })) 193 .def(py::init([](shared_ptr_tag, TF5_tag, int a) { return std::make_shared<TestFactory5>(a); })) 194 195 // Returns nullptr: 196 .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; })) 197 198 .def_readwrite("value", &TestFactory3::value) 199 ; 200 201 // test_init_factory_casting 202 py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4") 203 .def(py::init(c4a)) // pointer 204 ; 205 206 // Doesn't need to be registered, but registering makes getting ConstructorStats easier: 207 py::class_<TestFactory5, TestFactory3, std::shared_ptr<TestFactory5>>(m, "TestFactory5"); 208 209 // test_init_factory_alias 210 // Alias testing 211 py::class_<TestFactory6, PyTF6>(m, "TestFactory6") 212 .def(py::init([](base_tag, int i) { return TestFactory6(i); })) 213 .def(py::init([](alias_tag, int i) { return PyTF6(i); })) 214 .def(py::init([](alias_tag, std::string s) { return PyTF6(s); })) 215 .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); })) 216 .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); })) 217 .def(py::init([](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) 218 219 .def("get", &TestFactory6::get) 220 .def("has_alias", &TestFactory6::has_alias) 221 222 .def_static("get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference) 223 .def_static("get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference) 224 ; 225 226 // test_init_factory_dual 227 // Separate alias constructor testing 228 py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7") 229 .def(py::init( 230 [](int i) { return TestFactory7(i); }, 231 [](int i) { return PyTF7(i); })) 232 .def(py::init( 233 [](pointer_tag, int i) { return new TestFactory7(i); }, 234 [](pointer_tag, int i) { return new PyTF7(i); })) 235 .def(py::init( 236 [](mixed_tag, int i) { return new TestFactory7(i); }, 237 [](mixed_tag, int i) { return PyTF7(i); })) 238 .def(py::init( 239 [](mixed_tag, std::string s) { return TestFactory7((int) s.size()); }, 240 [](mixed_tag, std::string s) { return new PyTF7((int) s.size()); })) 241 .def(py::init( 242 [](base_tag, pointer_tag, int i) { return new TestFactory7(i); }, 243 [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); })) 244 .def(py::init( 245 [](alias_tag, pointer_tag, int i) { return new PyTF7(i); }, 246 [](alias_tag, pointer_tag, int i) { return new PyTF7(10*i); })) 247 .def(py::init( 248 [](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); }, 249 [](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr<TestFactory7>(p); })) 250 .def(py::init( 251 [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); }, 252 [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); })) // <-- invalid alias factory 253 254 .def("get", &TestFactory7::get) 255 .def("has_alias", &TestFactory7::has_alias) 256 257 .def_static("get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference) 258 .def_static("get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference) 259 ; 260 261 // test_placement_new_alternative 262 // Class with a custom new operator but *without* a placement new operator (issue #948) 263 class NoPlacementNew { 264 public: 265 NoPlacementNew(int i) : i(i) { } 266 static void *operator new(std::size_t s) { 267 auto *p = ::operator new(s); 268 py::print("operator new called, returning", reinterpret_cast<uintptr_t>(p)); 269 return p; 270 } 271 static void operator delete(void *p) { 272 py::print("operator delete called on", reinterpret_cast<uintptr_t>(p)); 273 ::operator delete(p); 274 } 275 int i; 276 }; 277 // As of 2.2, `py::init<args>` no longer requires placement new 278 py::class_<NoPlacementNew>(m, "NoPlacementNew") 279 .def(py::init<int>()) 280 .def(py::init([]() { return new NoPlacementNew(100); })) 281 .def_readwrite("i", &NoPlacementNew::i) 282 ; 283 284 285 // test_reallocations 286 // Class that has verbose operator_new/operator_delete calls 287 struct NoisyAlloc { 288 NoisyAlloc(const NoisyAlloc &) = default; 289 NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); } 290 NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); } 291 ~NoisyAlloc() { py::print("~NoisyAlloc()"); } 292 293 static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); } 294 static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; } 295 static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); } 296 static void operator delete(void *, void *) { py::print("noisy placement delete"); } 297#if defined(_MSC_VER) && _MSC_VER < 1910 298 // MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017) 299 static void operator delete(void *p) { py::print("noisy delete"); ::operator delete(p); } 300#endif 301 }; 302 py::class_<NoisyAlloc>(m, "NoisyAlloc") 303 // Since these overloads have the same number of arguments, the dispatcher will try each of 304 // them until the arguments convert. Thus we can get a pre-allocation here when passing a 305 // single non-integer: 306 .def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }) // Regular constructor, runs first, requires preallocation 307 .def(py::init([](double d) { return new NoisyAlloc(d); })) 308 309 // The two-argument version: first the factory pointer overload. 310 .def(py::init([](int i, int) { return new NoisyAlloc(i); })) 311 // Return-by-value: 312 .def(py::init([](double d, int) { return NoisyAlloc(d); })) 313 // Old-style placement new init; requires preallocation 314 .def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); }) 315 // Requires deallocation of previous overload preallocated value: 316 .def(py::init([](int i, double) { return new NoisyAlloc(i); })) 317 // Regular again: requires yet another preallocation 318 .def("__init__", [](NoisyAlloc &a, int i, std::string) { new (&a) NoisyAlloc(i); }) 319 ; 320 321 322 323 324 // static_assert testing (the following def's should all fail with appropriate compilation errors): 325#if 0 326 struct BadF1Base {}; 327 struct BadF1 : BadF1Base {}; 328 struct PyBadF1 : BadF1 {}; 329 py::class_<BadF1, PyBadF1, std::shared_ptr<BadF1>> bf1(m, "BadF1"); 330 // wrapped factory function must return a compatible pointer, holder, or value 331 bf1.def(py::init([]() { return 3; })); 332 // incompatible factory function pointer return type 333 bf1.def(py::init([]() { static int three = 3; return &three; })); 334 // incompatible factory function std::shared_ptr<T> return type: cannot convert shared_ptr<T> to holder 335 // (non-polymorphic base) 336 bf1.def(py::init([]() { return std::shared_ptr<BadF1Base>(new BadF1()); })); 337#endif 338} 339