You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
8.7 KiB

3 months ago
  1. /*
  2. tests/test_copy_move_policies.cpp -- 'copy' and 'move' return value policies
  3. and related tests
  4. Copyright (c) 2016 Ben North <ben@redfrontdoor.org>
  5. All rights reserved. Use of this source code is governed by a
  6. BSD-style license that can be found in the LICENSE file.
  7. */
  8. #include "pybind11_tests.h"
  9. #include "constructor_stats.h"
  10. #include <pybind11/stl.h>
  11. template <typename derived>
  12. struct empty {
  13. static const derived& get_one() { return instance_; }
  14. static derived instance_;
  15. };
  16. struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
  17. lacking_copy_ctor() {}
  18. lacking_copy_ctor(const lacking_copy_ctor& other) = delete;
  19. };
  20. template <> lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
  21. struct lacking_move_ctor : public empty<lacking_move_ctor> {
  22. lacking_move_ctor() {}
  23. lacking_move_ctor(const lacking_move_ctor& other) = delete;
  24. lacking_move_ctor(lacking_move_ctor&& other) = delete;
  25. };
  26. template <> lacking_move_ctor empty<lacking_move_ctor>::instance_ = {};
  27. /* Custom type caster move/copy test classes */
  28. class MoveOnlyInt {
  29. public:
  30. MoveOnlyInt() { print_default_created(this); }
  31. MoveOnlyInt(int v) : value{std::move(v)} { print_created(this, value); }
  32. MoveOnlyInt(MoveOnlyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); }
  33. MoveOnlyInt &operator=(MoveOnlyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; }
  34. MoveOnlyInt(const MoveOnlyInt &) = delete;
  35. MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
  36. ~MoveOnlyInt() { print_destroyed(this); }
  37. int value;
  38. };
  39. class MoveOrCopyInt {
  40. public:
  41. MoveOrCopyInt() { print_default_created(this); }
  42. MoveOrCopyInt(int v) : value{std::move(v)} { print_created(this, value); }
  43. MoveOrCopyInt(MoveOrCopyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); }
  44. MoveOrCopyInt &operator=(MoveOrCopyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; }
  45. MoveOrCopyInt(const MoveOrCopyInt &c) { print_copy_created(this, c.value); value = c.value; }
  46. MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
  47. ~MoveOrCopyInt() { print_destroyed(this); }
  48. int value;
  49. };
  50. class CopyOnlyInt {
  51. public:
  52. CopyOnlyInt() { print_default_created(this); }
  53. CopyOnlyInt(int v) : value{std::move(v)} { print_created(this, value); }
  54. CopyOnlyInt(const CopyOnlyInt &c) { print_copy_created(this, c.value); value = c.value; }
  55. CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
  56. ~CopyOnlyInt() { print_destroyed(this); }
  57. int value;
  58. };
  59. namespace pybind11 { namespace detail {
  60. template <> struct type_caster<MoveOnlyInt> {
  61. PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt"));
  62. bool load(handle src, bool) { value = MoveOnlyInt(src.cast<int>()); return true; }
  63. static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
  64. };
  65. template <> struct type_caster<MoveOrCopyInt> {
  66. PYBIND11_TYPE_CASTER(MoveOrCopyInt, _("MoveOrCopyInt"));
  67. bool load(handle src, bool) { value = MoveOrCopyInt(src.cast<int>()); return true; }
  68. static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
  69. };
  70. template <> struct type_caster<CopyOnlyInt> {
  71. protected:
  72. CopyOnlyInt value;
  73. public:
  74. static PYBIND11_DESCR name() { return _("CopyOnlyInt"); }
  75. bool load(handle src, bool) { value = CopyOnlyInt(src.cast<int>()); return true; }
  76. static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
  77. static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
  78. if (!src) return none().release();
  79. return cast(*src, policy, parent);
  80. }
  81. operator CopyOnlyInt*() { return &value; }
  82. operator CopyOnlyInt&() { return value; }
  83. template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>;
  84. };
  85. }}
  86. struct PrivateOpNew {
  87. int value = 1;
  88. private:
  89. void *operator new(size_t bytes);
  90. };
  91. test_initializer copy_move_policies([](py::module &m) {
  92. py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
  93. .def_static("get_one", &lacking_copy_ctor::get_one,
  94. py::return_value_policy::copy);
  95. py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
  96. .def_static("get_one", &lacking_move_ctor::get_one,
  97. py::return_value_policy::move);
  98. m.def("move_only", [](MoveOnlyInt m) {
  99. return m.value;
  100. });
  101. m.def("move_or_copy", [](MoveOrCopyInt m) {
  102. return m.value;
  103. });
  104. m.def("copy_only", [](CopyOnlyInt m) {
  105. return m.value;
  106. });
  107. m.def("move_and_copy_casts", [](py::object o) {
  108. int r = 0;
  109. r += py::cast<MoveOrCopyInt>(o).value; /* moves */
  110. r += py::cast<MoveOnlyInt>(o).value; /* moves */
  111. r += py::cast<CopyOnlyInt>(o).value; /* copies */
  112. MoveOrCopyInt m1(py::cast<MoveOrCopyInt>(o)); /* moves */
  113. MoveOnlyInt m2(py::cast<MoveOnlyInt>(o)); /* moves */
  114. CopyOnlyInt m3(py::cast<CopyOnlyInt>(o)); /* copies */
  115. r += m1.value + m2.value + m3.value;
  116. return r;
  117. });
  118. m.def("move_pair", [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) {
  119. return p.first.value + p.second.value;
  120. });
  121. m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
  122. return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
  123. });
  124. m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
  125. return std::get<0>(t).value + std::get<1>(t).value;
  126. });
  127. m.def("move_copy_nested", [](std::pair<MoveOnlyInt, std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>, MoveOrCopyInt>> x) {
  128. return x.first.value + std::get<0>(x.second.first).value + std::get<1>(x.second.first).value +
  129. std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
  130. });
  131. m.def("move_and_copy_cstats", []() {
  132. ConstructorStats::gc();
  133. // Reset counts to 0 so that previous tests don't affect later ones:
  134. auto &mc = ConstructorStats::get<MoveOrCopyInt>();
  135. mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions = 0;
  136. auto &mo = ConstructorStats::get<MoveOnlyInt>();
  137. mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions = 0;
  138. auto &co = ConstructorStats::get<CopyOnlyInt>();
  139. co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions = 0;
  140. py::dict d;
  141. d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
  142. d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
  143. d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference);
  144. return d;
  145. });
  146. #ifdef PYBIND11_HAS_OPTIONAL
  147. m.attr("has_optional") = true;
  148. m.def("move_optional", [](std::optional<MoveOnlyInt> o) {
  149. return o->value;
  150. });
  151. m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) {
  152. return o->value;
  153. });
  154. m.def("copy_optional", [](std::optional<CopyOnlyInt> o) {
  155. return o->value;
  156. });
  157. m.def("move_optional_tuple", [](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
  158. return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
  159. });
  160. #else
  161. m.attr("has_optional") = false;
  162. #endif
  163. // #70 compilation issue if operator new is not public
  164. py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
  165. m.def("private_op_new_value", []() { return PrivateOpNew(); });
  166. m.def("private_op_new_reference", []() -> const PrivateOpNew & {
  167. static PrivateOpNew x{};
  168. return x;
  169. }, py::return_value_policy::reference);
  170. // #389: rvp::move should fall-through to copy on non-movable objects
  171. struct MoveIssue1 {
  172. int v;
  173. MoveIssue1(int v) : v{v} {}
  174. MoveIssue1(const MoveIssue1 &c) = default;
  175. MoveIssue1(MoveIssue1 &&) = delete;
  176. };
  177. struct MoveIssue2 {
  178. int v;
  179. MoveIssue2(int v) : v{v} {}
  180. MoveIssue2(MoveIssue2 &&) = default;
  181. };
  182. py::class_<MoveIssue1>(m, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
  183. py::class_<MoveIssue2>(m, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
  184. m.def("get_moveissue1", [](int i) { return new MoveIssue1(i); }, py::return_value_policy::move);
  185. m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
  186. });