File indexing completed on 2025-01-18 10:17:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "constructor_stats.h"
0012 #include "pybind11_tests.h"
0013
0014 #include <cmath>
0015 #include <new>
0016 #include <utility>
0017
0018
0019
0020 class TestFactory1 {
0021 friend class TestFactoryHelper;
0022 TestFactory1() : value("(empty)") { print_default_created(this); }
0023 explicit TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); }
0024 explicit TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); }
0025
0026 public:
0027 std::string value;
0028 TestFactory1(TestFactory1 &&) = delete;
0029 TestFactory1(const TestFactory1 &) = delete;
0030 TestFactory1 &operator=(TestFactory1 &&) = delete;
0031 TestFactory1 &operator=(const TestFactory1 &) = delete;
0032 ~TestFactory1() { print_destroyed(this); }
0033 };
0034
0035 class TestFactory2 {
0036 friend class TestFactoryHelper;
0037 TestFactory2() : value("(empty2)") { print_default_created(this); }
0038 explicit TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); }
0039 explicit TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); }
0040
0041 public:
0042 TestFactory2(TestFactory2 &&m) noexcept : value{std::move(m.value)} {
0043 print_move_created(this);
0044 }
0045 TestFactory2 &operator=(TestFactory2 &&m) noexcept {
0046 value = std::move(m.value);
0047 print_move_assigned(this);
0048 return *this;
0049 }
0050 std::string value;
0051 ~TestFactory2() { print_destroyed(this); }
0052 };
0053
0054 class TestFactory3 {
0055 protected:
0056 friend class TestFactoryHelper;
0057 TestFactory3() : value("(empty3)") { print_default_created(this); }
0058 explicit TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); }
0059
0060 public:
0061 explicit TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); }
0062 TestFactory3(TestFactory3 &&m) noexcept : value{std::move(m.value)} {
0063 print_move_created(this);
0064 }
0065 TestFactory3 &operator=(TestFactory3 &&m) noexcept {
0066 value = std::move(m.value);
0067 print_move_assigned(this);
0068 return *this;
0069 }
0070 std::string value;
0071 virtual ~TestFactory3() { print_destroyed(this); }
0072 };
0073
0074 class TestFactory4 : public TestFactory3 {
0075 public:
0076 TestFactory4() : TestFactory3() { print_default_created(this); }
0077 explicit TestFactory4(int v) : TestFactory3(v) { print_created(this, v); }
0078 ~TestFactory4() override { print_destroyed(this); }
0079 };
0080
0081 class TestFactory5 : public TestFactory3 {
0082 public:
0083 explicit TestFactory5(int i) : TestFactory3(i) { print_created(this, i); }
0084 ~TestFactory5() override { print_destroyed(this); }
0085 };
0086
0087 class TestFactory6 {
0088 protected:
0089 int value;
0090 bool alias = false;
0091
0092 public:
0093 explicit TestFactory6(int i) : value{i} { print_created(this, i); }
0094 TestFactory6(TestFactory6 &&f) noexcept {
0095 print_move_created(this);
0096
0097 value = f.value;
0098
0099 alias = f.alias;
0100 }
0101 TestFactory6(const TestFactory6 &f) {
0102 print_copy_created(this);
0103
0104 value = f.value;
0105
0106 alias = f.alias;
0107 }
0108 virtual ~TestFactory6() { print_destroyed(this); }
0109 virtual int get() { return value; }
0110 bool has_alias() const { return alias; }
0111 };
0112 class PyTF6 : public TestFactory6 {
0113 public:
0114
0115
0116 explicit PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) {
0117 alias = true;
0118 print_created(this, "move", value);
0119 }
0120 explicit PyTF6(int i) : TestFactory6(i) {
0121 alias = true;
0122 print_created(this, i);
0123 }
0124 PyTF6(PyTF6 &&f) noexcept : TestFactory6(std::move(f)) { print_move_created(this); }
0125 PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); }
0126 explicit PyTF6(std::string s) : TestFactory6((int) s.size()) {
0127 alias = true;
0128 print_created(this, s);
0129 }
0130 ~PyTF6() override { print_destroyed(this); }
0131 int get() override { PYBIND11_OVERRIDE(int, TestFactory6, get, ); }
0132 };
0133
0134 class TestFactory7 {
0135 protected:
0136 int value;
0137 bool alias = false;
0138
0139 public:
0140 explicit TestFactory7(int i) : value{i} { print_created(this, i); }
0141 TestFactory7(TestFactory7 &&f) noexcept {
0142 print_move_created(this);
0143
0144 value = f.value;
0145
0146 alias = f.alias;
0147 }
0148 TestFactory7(const TestFactory7 &f) {
0149 print_copy_created(this);
0150
0151 value = f.value;
0152
0153 alias = f.alias;
0154 }
0155 virtual ~TestFactory7() { print_destroyed(this); }
0156 virtual int get() { return value; }
0157 bool has_alias() const { return alias; }
0158 };
0159 class PyTF7 : public TestFactory7 {
0160 public:
0161 explicit PyTF7(int i) : TestFactory7(i) {
0162
0163 alias = true;
0164 print_created(this, i);
0165 }
0166 PyTF7(PyTF7 &&f) noexcept : TestFactory7(std::move(f)) { print_move_created(this); }
0167 PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); }
0168 ~PyTF7() override { print_destroyed(this); }
0169 int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, ); }
0170 };
0171
0172 class TestFactoryHelper {
0173 public:
0174
0175
0176 static TestFactory1 *construct1() { return new TestFactory1(); }
0177
0178 static std::unique_ptr<TestFactory1> construct1(int a) {
0179 return std::unique_ptr<TestFactory1>(new TestFactory1(a));
0180 }
0181
0182 static TestFactory1 *construct1_string(std::string a) {
0183 return new TestFactory1(std::move(a));
0184 }
0185
0186
0187
0188 static TestFactory2 *construct2() { return new TestFactory2(); }
0189
0190 static std::unique_ptr<TestFactory2> construct2(int a) {
0191 return std::unique_ptr<TestFactory2>(new TestFactory2(a));
0192 }
0193
0194 static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(a)); }
0195
0196
0197
0198 static TestFactory3 *construct3() { return new TestFactory3(); }
0199
0200 static std::shared_ptr<TestFactory3> construct3(int a) {
0201 return std::shared_ptr<TestFactory3>(new TestFactory3(a));
0202 }
0203 };
0204
0205 TEST_SUBMODULE(factory_constructors, m) {
0206
0207
0208 py::module_ m_tag = m.def_submodule("tag");
0209 #define MAKE_TAG_TYPE(Name) \
0210 struct Name##_tag {}; \
0211 py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \
0212 m_tag.attr(#Name) = py::cast(Name##_tag{})
0213 MAKE_TAG_TYPE(pointer);
0214 MAKE_TAG_TYPE(unique_ptr);
0215 MAKE_TAG_TYPE(move);
0216 MAKE_TAG_TYPE(shared_ptr);
0217 MAKE_TAG_TYPE(derived);
0218 MAKE_TAG_TYPE(TF4);
0219 MAKE_TAG_TYPE(TF5);
0220 MAKE_TAG_TYPE(null_ptr);
0221 MAKE_TAG_TYPE(null_unique_ptr);
0222 MAKE_TAG_TYPE(null_shared_ptr);
0223 MAKE_TAG_TYPE(base);
0224 MAKE_TAG_TYPE(invalid_base);
0225 MAKE_TAG_TYPE(alias);
0226 MAKE_TAG_TYPE(unaliasable);
0227 MAKE_TAG_TYPE(mixed);
0228
0229
0230 py::class_<TestFactory1>(m, "TestFactory1")
0231 .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); }))
0232 .def(py::init(&TestFactoryHelper::construct1_string))
0233 .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); }))
0234 .def(py::init(
0235 [](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); }))
0236 .def_readwrite("value", &TestFactory1::value);
0237 py::class_<TestFactory2>(m, "TestFactory2")
0238 .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); }))
0239 .def(py::init([](unique_ptr_tag, std::string v) {
0240 return TestFactoryHelper::construct2(std::move(v));
0241 }))
0242 .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); }))
0243 .def_readwrite("value", &TestFactory2::value);
0244
0245
0246 int c = 1;
0247 auto c4a = [c](pointer_tag, TF4_tag, int a) {
0248 (void) c;
0249 return new TestFactory4(a);
0250 };
0251
0252
0253 py::class_<TestFactory3, std::shared_ptr<TestFactory3>> pyTestFactory3(m, "TestFactory3");
0254 pyTestFactory3
0255 .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); }))
0256 .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); }));
0257 ignoreOldStyleInitWarnings([&pyTestFactory3]() {
0258 pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) {
0259 new (&self) TestFactory3(std::move(v));
0260 });
0261 });
0262 pyTestFactory3
0263
0264 .def(py::init(c4a))
0265 .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); }))
0266
0267 .def(py::init(
0268 [](shared_ptr_tag, TF4_tag, int a) { return std::make_shared<TestFactory4>(a); }))
0269 .def(py::init(
0270 [](shared_ptr_tag, TF5_tag, int a) { return std::make_shared<TestFactory5>(a); }))
0271
0272
0273 .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; }))
0274 .def(py::init([](null_unique_ptr_tag) { return std::unique_ptr<TestFactory3>(); }))
0275 .def(py::init([](null_shared_ptr_tag) { return std::shared_ptr<TestFactory3>(); }))
0276
0277 .def_readwrite("value", &TestFactory3::value);
0278
0279
0280 py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4")
0281 .def(py::init(c4a))
0282 ;
0283
0284
0285 py::class_<TestFactory5, TestFactory3, std::shared_ptr<TestFactory5>>(m, "TestFactory5");
0286
0287
0288
0289 py::class_<TestFactory6, PyTF6>(m, "TestFactory6")
0290 .def(py::init([](base_tag, int i) { return TestFactory6(i); }))
0291 .def(py::init([](alias_tag, int i) { return PyTF6(i); }))
0292 .def(py::init([](alias_tag, std::string s) { return PyTF6(std::move(s)); }))
0293 .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); }))
0294 .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); }))
0295 .def(py::init(
0296 [](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); }))
0297
0298 .def("get", &TestFactory6::get)
0299 .def("has_alias", &TestFactory6::has_alias)
0300
0301 .def_static(
0302 "get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference)
0303 .def_static(
0304 "get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference);
0305
0306
0307
0308 py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7")
0309 .def(py::init([](int i) { return TestFactory7(i); }, [](int i) { return PyTF7(i); }))
0310 .def(py::init([](pointer_tag, int i) { return new TestFactory7(i); },
0311 [](pointer_tag, int i) { return new PyTF7(i); }))
0312 .def(py::init([](mixed_tag, int i) { return new TestFactory7(i); },
0313 [](mixed_tag, int i) { return PyTF7(i); }))
0314 .def(py::init([](mixed_tag, const std::string &s) { return TestFactory7((int) s.size()); },
0315 [](mixed_tag, const std::string &s) { return new PyTF7((int) s.size()); }))
0316 .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory7(i); },
0317 [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); }))
0318 .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF7(i); },
0319 [](alias_tag, pointer_tag, int i) { return new PyTF7(10 * i); }))
0320 .def(py::init(
0321 [](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); },
0322 [](shared_ptr_tag, base_tag, int i) {
0323 auto *p = new PyTF7(i);
0324 return std::shared_ptr<TestFactory7>(p);
0325 }))
0326 .def(py::init([](shared_ptr_tag,
0327 invalid_base_tag,
0328 int i) { return std::make_shared<TestFactory7>(i); },
0329 [](shared_ptr_tag, invalid_base_tag, int i) {
0330 return std::make_shared<TestFactory7>(i);
0331 }))
0332
0333 .def("get", &TestFactory7::get)
0334 .def("has_alias", &TestFactory7::has_alias)
0335
0336 .def_static(
0337 "get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference)
0338 .def_static(
0339 "get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference);
0340
0341
0342
0343 class NoPlacementNew {
0344 public:
0345 explicit NoPlacementNew(int i) : i(i) {}
0346 static void *operator new(std::size_t s) {
0347 auto *p = ::operator new(s);
0348 py::print("operator new called, returning", reinterpret_cast<uintptr_t>(p));
0349 return p;
0350 }
0351 static void operator delete(void *p) {
0352 py::print("operator delete called on", reinterpret_cast<uintptr_t>(p));
0353 ::operator delete(p);
0354 }
0355 int i;
0356 };
0357
0358 py::class_<NoPlacementNew>(m, "NoPlacementNew")
0359 .def(py::init<int>())
0360 .def(py::init([]() { return new NoPlacementNew(100); }))
0361 .def_readwrite("i", &NoPlacementNew::i);
0362
0363
0364
0365 struct NoisyAlloc {
0366 NoisyAlloc(const NoisyAlloc &) = default;
0367 explicit NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); }
0368 explicit NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); }
0369 ~NoisyAlloc() { py::print("~NoisyAlloc()"); }
0370
0371 static void *operator new(size_t s) {
0372 py::print("noisy new");
0373 return ::operator new(s);
0374 }
0375 static void *operator new(size_t, void *p) {
0376 py::print("noisy placement new");
0377 return p;
0378 }
0379 static void operator delete(void *p, size_t) {
0380 py::print("noisy delete");
0381 ::operator delete(p);
0382 }
0383 static void operator delete(void *, void *) { py::print("noisy placement delete"); }
0384 };
0385
0386 py::class_<NoisyAlloc> pyNoisyAlloc(m, "NoisyAlloc");
0387
0388
0389
0390 ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
0391 pyNoisyAlloc.def("__init__", [](NoisyAlloc *a, int i) {
0392 new (a) NoisyAlloc(i);
0393 });
0394 });
0395
0396 pyNoisyAlloc.def(py::init([](double d) { return new NoisyAlloc(d); }));
0397
0398
0399 pyNoisyAlloc.def(py::init([](int i, int) { return new NoisyAlloc(i); }));
0400
0401 pyNoisyAlloc.def(py::init([](double d, int) { return NoisyAlloc(d); }));
0402
0403 ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
0404 pyNoisyAlloc.def("__init__",
0405 [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); });
0406 });
0407
0408 pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); }));
0409
0410 ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
0411 pyNoisyAlloc.def(
0412 "__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); });
0413 });
0414
0415
0416
0417 #if 0
0418 struct BadF1Base {};
0419 struct BadF1 : BadF1Base {};
0420 struct PyBadF1 : BadF1 {};
0421 py::class_<BadF1, PyBadF1, std::shared_ptr<BadF1>> bf1(m, "BadF1");
0422
0423 bf1.def(py::init([]() { return 3; }));
0424
0425 bf1.def(py::init([]() { static int three = 3; return &three; }));
0426
0427
0428 bf1.def(py::init([]() { return std::shared_ptr<BadF1Base>(new BadF1()); }));
0429 #endif
0430 }