blob: fb33377b2959240a5b23d2fa944408eb22c456d9 [file] [log] [blame]
Jason Lowe-Powerf07d5062017-11-17 17:02:05 -08001/*
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 publically 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(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); }
289 NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); }
290 ~NoisyAlloc() { py::print("~NoisyAlloc()"); }
291
292 static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); }
293 static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; }
294 static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); }
295 static void operator delete(void *, void *) { py::print("noisy placement delete"); }
296#if defined(_MSC_VER) && _MSC_VER < 1910
297 // MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017)
298 static void operator delete(void *p) { py::print("noisy delete"); ::operator delete(p); }
299#endif
300 };
301 py::class_<NoisyAlloc>(m, "NoisyAlloc")
302 // Since these overloads have the same number of arguments, the dispatcher will try each of
303 // them until the arguments convert. Thus we can get a pre-allocation here when passing a
304 // single non-integer:
305 .def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }) // Regular constructor, runs first, requires preallocation
306 .def(py::init([](double d) { return new NoisyAlloc(d); }))
307
308 // The two-argument version: first the factory pointer overload.
309 .def(py::init([](int i, int) { return new NoisyAlloc(i); }))
310 // Return-by-value:
311 .def(py::init([](double d, int) { return NoisyAlloc(d); }))
312 // Old-style placement new init; requires preallocation
313 .def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); })
314 // Requires deallocation of previous overload preallocated value:
315 .def(py::init([](int i, double) { return new NoisyAlloc(i); }))
316 // Regular again: requires yet another preallocation
317 .def("__init__", [](NoisyAlloc &a, int i, std::string) { new (&a) NoisyAlloc(i); })
318 ;
319
320
321
322
323 // static_assert testing (the following def's should all fail with appropriate compilation errors):
324#if 0
325 struct BadF1Base {};
326 struct BadF1 : BadF1Base {};
327 struct PyBadF1 : BadF1 {};
328 py::class_<BadF1, PyBadF1, std::shared_ptr<BadF1>> bf1(m, "BadF1");
329 // wrapped factory function must return a compatible pointer, holder, or value
330 bf1.def(py::init([]() { return 3; }));
331 // incompatible factory function pointer return type
332 bf1.def(py::init([]() { static int three = 3; return &three; }));
333 // incompatible factory function std::shared_ptr<T> return type: cannot convert shared_ptr<T> to holder
334 // (non-polymorphic base)
335 bf1.def(py::init([]() { return std::shared_ptr<BadF1Base>(new BadF1()); }));
336#endif
337}