test_copy_move.cpp
Go to the documentation of this file.
1 /*
2  tests/test_copy_move_policies.cpp -- 'copy' and 'move' return value policies
3  and related tests
4 
5  Copyright (c) 2016 Ben North <ben@redfrontdoor.org>
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/stl.h>
12 
13 #include "constructor_stats.h"
14 #include "pybind11_tests.h"
15 
16 template <typename derived>
17 struct empty {
18  static const derived &get_one() { return instance_; }
19  static derived instance_;
20 };
21 
22 struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
23  lacking_copy_ctor() = default;
24  lacking_copy_ctor(const lacking_copy_ctor &other) = delete;
25 };
26 
27 template <>
29 
30 struct lacking_move_ctor : public empty<lacking_move_ctor> {
31  lacking_move_ctor() = default;
32  lacking_move_ctor(const lacking_move_ctor &other) = delete;
33  lacking_move_ctor(lacking_move_ctor &&other) = delete;
34 };
35 
36 template <>
38 
39 /* Custom type caster move/copy test classes */
40 class MoveOnlyInt {
41 public:
43  explicit MoveOnlyInt(int v) : value{v} { print_created(this, value); }
44  MoveOnlyInt(MoveOnlyInt &&m) noexcept {
45  print_move_created(this, m.value);
46  std::swap(value, m.value);
47  }
49  print_move_assigned(this, m.value);
50  std::swap(value, m.value);
51  return *this;
52  }
53  MoveOnlyInt(const MoveOnlyInt &) = delete;
54  MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
56 
57  int value;
58 };
60 public:
62  explicit MoveOrCopyInt(int v) : value{v} { print_created(this, value); }
64  print_move_created(this, m.value);
65  std::swap(value, m.value);
66  }
68  print_move_assigned(this, m.value);
69  std::swap(value, m.value);
70  return *this;
71  }
73  print_copy_created(this, c.value);
74  // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
75  value = c.value;
76  }
78  print_copy_assigned(this, c.value);
79  value = c.value;
80  return *this;
81  }
83 
84  int value;
85 };
86 class CopyOnlyInt {
87 public:
89  explicit CopyOnlyInt(int v) : value{v} { print_created(this, value); }
91  print_copy_created(this, c.value);
92  // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
93  value = c.value;
94  }
96  print_copy_assigned(this, c.value);
97  value = c.value;
98  return *this;
99  }
101 
102  int value;
103 };
106 template <>
109  bool load(handle src, bool) {
110  value = MoveOnlyInt(src.cast<int>());
111  return true;
112  }
114  return pybind11::cast(m.value, r, p);
115  }
116 };
117 
118 template <>
120  PYBIND11_TYPE_CASTER(MoveOrCopyInt, const_name("MoveOrCopyInt"));
121  bool load(handle src, bool) {
122  value = MoveOrCopyInt(src.cast<int>());
123  return true;
124  }
126  return pybind11::cast(m.value, r, p);
127  }
128 };
129 
130 template <>
132 protected:
134 
135 public:
136  static constexpr auto name = const_name("CopyOnlyInt");
137  bool load(handle src, bool) {
138  value = CopyOnlyInt(src.cast<int>());
139  return true;
140  }
142  return pybind11::cast(m.value, r, p);
143  }
144  static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
145  if (!src) {
146  return none().release();
147  }
148  return cast(*src, policy, parent);
149  }
150  explicit operator CopyOnlyInt *() { return &value; }
151  explicit operator CopyOnlyInt &() { return value; }
152  template <typename T>
153  using cast_op_type = pybind11::detail::cast_op_type<T>;
154 };
157 
158 TEST_SUBMODULE(copy_move_policies, m) {
159  // test_lacking_copy_ctor
160  py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
162  // test_lacking_move_ctor
163  py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
165 
166  // test_move_and_copy_casts
167  // NOLINTNEXTLINE(performance-unnecessary-value-param)
168  m.def("move_and_copy_casts", [](const py::object &o) {
169  int r = 0;
170  r += py::cast<MoveOrCopyInt>(o).value; /* moves */
171  r += py::cast<MoveOnlyInt>(o).value; /* moves */
172  r += py::cast<CopyOnlyInt>(o).value; /* copies */
173  auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */
174  auto m2(py::cast<MoveOnlyInt>(o)); /* moves */
175  auto m3(py::cast<CopyOnlyInt>(o)); /* copies */
176  r += m1.value + m2.value + m3.value;
177 
178  return r;
179  });
180 
181  // test_move_and_copy_loads
182  m.def("move_only", [](MoveOnlyInt m) { return m.value; });
183  // Changing this breaks the existing test: needs careful review.
184  // NOLINTNEXTLINE(performance-unnecessary-value-param)
185  m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
186  // Changing this breaks the existing test: needs careful review.
187  // NOLINTNEXTLINE(performance-unnecessary-value-param)
188  m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
189  m.def("move_pair",
190  [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) { return p.first.value + p.second.value; });
191  m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
192  return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
193  });
194  m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
195  return std::get<0>(t).value + std::get<1>(t).value;
196  });
197  m.def("move_copy_nested",
198  [](std::pair<MoveOnlyInt,
199  std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>,
200  MoveOrCopyInt>> x) {
201  return x.first.value + std::get<0>(x.second.first).value
202  + std::get<1>(x.second.first).value
203  + std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
204  });
205  m.def("move_and_copy_cstats", []() {
207  // Reset counts to 0 so that previous tests don't affect later ones:
208  auto &mc = ConstructorStats::get<MoveOrCopyInt>();
209  mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions
210  = 0;
211  auto &mo = ConstructorStats::get<MoveOnlyInt>();
212  mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions
213  = 0;
214  auto &co = ConstructorStats::get<CopyOnlyInt>();
215  co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions
216  = 0;
217  py::dict d;
218  d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
219  d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
220  d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference);
221  return d;
222  });
223 #ifdef PYBIND11_HAS_OPTIONAL
224  // test_move_and_copy_load_optional
225  m.attr("has_optional") = true;
226  m.def("move_optional", [](std::optional<MoveOnlyInt> o) { return o->value; });
227  m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) { return o->value; });
228  m.def("copy_optional", [](std::optional<CopyOnlyInt> o) { return o->value; });
229  m.def("move_optional_tuple",
230  [](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
231  return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
232  });
233 #else
234  m.attr("has_optional") = false;
235 #endif
236 
237  // #70 compilation issue if operator new is not public - simple body added
238  // but not needed on most compilers; MSVC and nvcc don't like a local
239  // struct not having a method defined when declared, since it can not be
240  // added later.
241  struct PrivateOpNew {
242  int value = 1;
243 
244  private:
245  void *operator new(size_t bytes) {
246  void *ptr = std::malloc(bytes);
247  if (ptr) {
248  return ptr;
249  }
250  throw std::bad_alloc{};
251  }
252  };
253  py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
254  m.def("private_op_new_value", []() { return PrivateOpNew(); });
255  m.def(
256  "private_op_new_reference",
257  []() -> const PrivateOpNew & {
258  static PrivateOpNew x{};
259  return x;
260  },
261  py::return_value_policy::reference);
262 
263  // test_move_fallback
264  // #389: rvp::move should fall-through to copy on non-movable objects
265  struct MoveIssue1 {
266  int v;
267  explicit MoveIssue1(int v) : v{v} {}
268  MoveIssue1(const MoveIssue1 &c) = default;
269  MoveIssue1(MoveIssue1 &&) = delete;
270  };
271  py::class_<MoveIssue1>(m, "MoveIssue1")
272  .def(py::init<int>())
273  .def_readwrite("value", &MoveIssue1::v);
274 
275  struct MoveIssue2 {
276  int v;
277  explicit MoveIssue2(int v) : v{v} {}
278  MoveIssue2(MoveIssue2 &&) = default;
279  };
280  py::class_<MoveIssue2>(m, "MoveIssue2")
281  .def(py::init<int>())
282  .def_readwrite("value", &MoveIssue2::v);
283 
284  // #2742: Don't expect ownership of raw pointer to `new`ed object to be transferred with
285  // `py::return_value_policy::move`
286  m.def(
287  "get_moveissue1",
288  [](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
290  m.def(
291  "get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
292 
293  // Make sure that cast from pytype rvalue to other pytype works
294  m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
295 }
Matrix3f m
TEST_SUBMODULE(copy_move_policies, m)
static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p)
CopyOnlyInt(int v)
MatrixType m2(n_dims)
bool load(handle src, bool)
static const derived & get_one()
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
void print_destroyed(T *inst, Values &&...values)
MoveOrCopyInt & operator=(const MoveOrCopyInt &c)
void print_copy_assigned(T *inst, Values &&...values)
CopyOnlyInt(const CopyOnlyInt &c)
void print_copy_created(T *inst, Values &&...values)
T cast() const
Definition: cast.h:1071
Definition: pytypes.h:1614
static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p)
bool load(handle src, bool)
static derived instance_
detail::enable_if_t<!detail::move_never< T >::value, T > move(object &&obj)
Definition: cast.h:1080
MoveOrCopyInt(MoveOrCopyInt &&m) noexcept
pybind11::detail::cast_op_type< T > cast_op_type
void print_default_created(T *inst, Values &&...values)
Matrix3d m1
Definition: IOFormat.cpp:2
MoveOrCopyInt & operator=(MoveOrCopyInt &&m) noexcept
void print_move_assigned(T *inst, Values &&...values)
Array< int, Dynamic, 1 > v
EIGEN_DEVICE_FUNC NewType cast(const OldType &x)
static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p)
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)
CopyOnlyInt & operator=(const CopyOnlyInt &c)
handle release()
Definition: pytypes.h:330
void print_created(T *inst, Values &&...values)
float * p
bool load(handle src, bool)
MoveOnlyInt(int v)
MoveOnlyInt(MoveOnlyInt &&m) noexcept
Annotation for function names.
Definition: attr.h:48
int EIGEN_BLAS_FUNC() copy(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy)
Definition: level1_impl.h:29
void print_move_created(T *inst, Values &&...values)
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
constexpr descr< N - 1 > const_name(char const (&text)[N])
Definition: descr.h:60
static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent)
return_value_policy
Approach used to cast a previously unknown C++ instance into a Python object.
#define PYBIND11_TYPE_CASTER(type, py_name)
Definition: cast.h:82
#define PYBIND11_NAMESPACE_END(name)
MoveOnlyInt & operator=(MoveOnlyInt &&m) noexcept
Point2 t(10, 10)
MoveOrCopyInt(const MoveOrCopyInt &c)
#define PYBIND11_NAMESPACE_BEGIN(name)


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:37:45