File indexing completed on 2025-01-18 10:17:52
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <pybind11/stl.h>
0012
0013 #include "constructor_stats.h"
0014 #include "pybind11_tests.h"
0015
0016 template <typename derived>
0017 struct empty {
0018 static const derived &get_one() { return instance_; }
0019 static derived instance_;
0020 };
0021
0022 struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
0023 lacking_copy_ctor() = default;
0024 lacking_copy_ctor(const lacking_copy_ctor &other) = delete;
0025 };
0026
0027 template <>
0028 lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
0029
0030 struct lacking_move_ctor : public empty<lacking_move_ctor> {
0031 lacking_move_ctor() = default;
0032 lacking_move_ctor(const lacking_move_ctor &other) = delete;
0033 lacking_move_ctor(lacking_move_ctor &&other) = delete;
0034 };
0035
0036 template <>
0037 lacking_move_ctor empty<lacking_move_ctor>::instance_ = {};
0038
0039
0040 class MoveOnlyInt {
0041 public:
0042 MoveOnlyInt() { print_default_created(this); }
0043 explicit MoveOnlyInt(int v) : value{v} { print_created(this, value); }
0044 MoveOnlyInt(MoveOnlyInt &&m) noexcept {
0045 print_move_created(this, m.value);
0046 std::swap(value, m.value);
0047 }
0048 MoveOnlyInt &operator=(MoveOnlyInt &&m) noexcept {
0049 print_move_assigned(this, m.value);
0050 std::swap(value, m.value);
0051 return *this;
0052 }
0053 MoveOnlyInt(const MoveOnlyInt &) = delete;
0054 MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
0055 ~MoveOnlyInt() { print_destroyed(this); }
0056
0057 int value;
0058 };
0059 class MoveOrCopyInt {
0060 public:
0061 MoveOrCopyInt() { print_default_created(this); }
0062 explicit MoveOrCopyInt(int v) : value{v} { print_created(this, value); }
0063 MoveOrCopyInt(MoveOrCopyInt &&m) noexcept {
0064 print_move_created(this, m.value);
0065 std::swap(value, m.value);
0066 }
0067 MoveOrCopyInt &operator=(MoveOrCopyInt &&m) noexcept {
0068 print_move_assigned(this, m.value);
0069 std::swap(value, m.value);
0070 return *this;
0071 }
0072 MoveOrCopyInt(const MoveOrCopyInt &c) {
0073 print_copy_created(this, c.value);
0074
0075 value = c.value;
0076 }
0077 MoveOrCopyInt &operator=(const MoveOrCopyInt &c) {
0078 print_copy_assigned(this, c.value);
0079 value = c.value;
0080 return *this;
0081 }
0082 ~MoveOrCopyInt() { print_destroyed(this); }
0083
0084 int value;
0085 };
0086 class CopyOnlyInt {
0087 public:
0088 CopyOnlyInt() { print_default_created(this); }
0089 explicit CopyOnlyInt(int v) : value{v} { print_created(this, value); }
0090 CopyOnlyInt(const CopyOnlyInt &c) {
0091 print_copy_created(this, c.value);
0092
0093 value = c.value;
0094 }
0095 CopyOnlyInt &operator=(const CopyOnlyInt &c) {
0096 print_copy_assigned(this, c.value);
0097 value = c.value;
0098 return *this;
0099 }
0100 ~CopyOnlyInt() { print_destroyed(this); }
0101
0102 int value;
0103 };
0104 PYBIND11_NAMESPACE_BEGIN(pybind11)
0105 PYBIND11_NAMESPACE_BEGIN(detail)
0106 template <>
0107 struct type_caster<MoveOnlyInt> {
0108 PYBIND11_TYPE_CASTER(MoveOnlyInt, const_name("MoveOnlyInt"));
0109 bool load(handle src, bool) {
0110 value = MoveOnlyInt(src.cast<int>());
0111 return true;
0112 }
0113 static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) {
0114 return pybind11::cast(m.value, r, p);
0115 }
0116 };
0117
0118 template <>
0119 struct type_caster<MoveOrCopyInt> {
0120 PYBIND11_TYPE_CASTER(MoveOrCopyInt, const_name("MoveOrCopyInt"));
0121 bool load(handle src, bool) {
0122 value = MoveOrCopyInt(src.cast<int>());
0123 return true;
0124 }
0125 static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) {
0126 return pybind11::cast(m.value, r, p);
0127 }
0128 };
0129
0130 template <>
0131 struct type_caster<CopyOnlyInt> {
0132 protected:
0133 CopyOnlyInt value;
0134
0135 public:
0136 static constexpr auto name = const_name("CopyOnlyInt");
0137 bool load(handle src, bool) {
0138 value = CopyOnlyInt(src.cast<int>());
0139 return true;
0140 }
0141 static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) {
0142 return pybind11::cast(m.value, r, p);
0143 }
0144 static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
0145 if (!src) {
0146 return none().release();
0147 }
0148 return cast(*src, policy, parent);
0149 }
0150 explicit operator CopyOnlyInt *() { return &value; }
0151 explicit operator CopyOnlyInt &() { return value; }
0152 template <typename T>
0153 using cast_op_type = pybind11::detail::cast_op_type<T>;
0154 };
0155 PYBIND11_NAMESPACE_END(detail)
0156 PYBIND11_NAMESPACE_END(pybind11)
0157
0158 TEST_SUBMODULE(copy_move_policies, m) {
0159
0160 py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
0161 .def_static("get_one", &lacking_copy_ctor::get_one, py::return_value_policy::copy);
0162
0163 py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
0164 .def_static("get_one", &lacking_move_ctor::get_one, py::return_value_policy::move);
0165
0166
0167
0168 m.def("move_and_copy_casts", [](const py::object &o) {
0169 int r = 0;
0170 r += py::cast<MoveOrCopyInt>(o).value;
0171 r += py::cast<MoveOnlyInt>(o).value;
0172 r += py::cast<CopyOnlyInt>(o).value;
0173 auto m1(py::cast<MoveOrCopyInt>(o));
0174 auto m2(py::cast<MoveOnlyInt>(o));
0175 auto m3(py::cast<CopyOnlyInt>(o));
0176 r += m1.value + m2.value + m3.value;
0177
0178 return r;
0179 });
0180
0181
0182 m.def("move_only", [](MoveOnlyInt m) { return m.value; });
0183
0184
0185 m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
0186
0187
0188 m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
0189 m.def("move_pair",
0190 [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) { return p.first.value + p.second.value; });
0191 m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
0192 return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
0193 });
0194 m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
0195 return std::get<0>(t).value + std::get<1>(t).value;
0196 });
0197 m.def("move_copy_nested",
0198 [](std::pair<MoveOnlyInt,
0199 std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>,
0200 MoveOrCopyInt>> x) {
0201 return x.first.value + std::get<0>(x.second.first).value
0202 + std::get<1>(x.second.first).value
0203 + std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
0204 });
0205 m.def("move_and_copy_cstats", []() {
0206 ConstructorStats::gc();
0207
0208 auto &mc = ConstructorStats::get<MoveOrCopyInt>();
0209 mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions
0210 = 0;
0211 auto &mo = ConstructorStats::get<MoveOnlyInt>();
0212 mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions
0213 = 0;
0214 auto &co = ConstructorStats::get<CopyOnlyInt>();
0215 co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions
0216 = 0;
0217 py::dict d;
0218 d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
0219 d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
0220 d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference);
0221 return d;
0222 });
0223 #ifdef PYBIND11_HAS_OPTIONAL
0224
0225 m.attr("has_optional") = true;
0226 m.def("move_optional", [](std::optional<MoveOnlyInt> o) { return o->value; });
0227 m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) { return o->value; });
0228 m.def("copy_optional", [](std::optional<CopyOnlyInt> o) { return o->value; });
0229 m.def("move_optional_tuple",
0230 [](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
0231 return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
0232 });
0233 #else
0234 m.attr("has_optional") = false;
0235 #endif
0236
0237
0238
0239
0240
0241 struct PrivateOpNew {
0242 int value = 1;
0243
0244 private:
0245 void *operator new(size_t bytes) {
0246 void *ptr = std::malloc(bytes);
0247 if (ptr) {
0248 return ptr;
0249 }
0250 throw std::bad_alloc{};
0251 }
0252 };
0253 py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
0254 m.def("private_op_new_value", []() { return PrivateOpNew(); });
0255 m.def(
0256 "private_op_new_reference",
0257 []() -> const PrivateOpNew & {
0258 static PrivateOpNew x{};
0259 return x;
0260 },
0261 py::return_value_policy::reference);
0262
0263
0264
0265 struct MoveIssue1 {
0266 int v;
0267 explicit MoveIssue1(int v) : v{v} {}
0268 MoveIssue1(const MoveIssue1 &c) = default;
0269 MoveIssue1(MoveIssue1 &&) = delete;
0270 };
0271 py::class_<MoveIssue1>(m, "MoveIssue1")
0272 .def(py::init<int>())
0273 .def_readwrite("value", &MoveIssue1::v);
0274
0275 struct MoveIssue2 {
0276 int v;
0277 explicit MoveIssue2(int v) : v{v} {}
0278 MoveIssue2(MoveIssue2 &&) = default;
0279 };
0280 py::class_<MoveIssue2>(m, "MoveIssue2")
0281 .def(py::init<int>())
0282 .def_readwrite("value", &MoveIssue2::v);
0283
0284
0285
0286 m.def(
0287 "get_moveissue1",
0288 [](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
0289 py::return_value_policy::move);
0290 m.def(
0291 "get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
0292
0293
0294 m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
0295 }