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_tests.h"
12 #include "constructor_stats.h"
13 #include <pybind11/stl.h>
14 
15 template <typename derived>
16 struct empty {
17  static const derived& get_one() { return instance_; }
18  static derived instance_;
19 };
20 
21 struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
22  lacking_copy_ctor() = default;
23  lacking_copy_ctor(const lacking_copy_ctor& other) = delete;
24 };
25 
27 
28 struct lacking_move_ctor : public empty<lacking_move_ctor> {
29  lacking_move_ctor() = default;
30  lacking_move_ctor(const lacking_move_ctor& other) = delete;
31  lacking_move_ctor(lacking_move_ctor&& other) = delete;
32 };
33 
35 
36 /* Custom type caster move/copy test classes */
37 class MoveOnlyInt {
38 public:
40  MoveOnlyInt(int v) : value{std::move(v)} { print_created(this, value); }
41  MoveOnlyInt(MoveOnlyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); }
42  MoveOnlyInt &operator=(MoveOnlyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; }
43  MoveOnlyInt(const MoveOnlyInt &) = delete;
44  MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
46 
47  int value;
48 };
50 public:
52  MoveOrCopyInt(int v) : value{std::move(v)} { print_created(this, value); }
54  MoveOrCopyInt &operator=(MoveOrCopyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; }
56  MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
58 
59  int value;
60 };
61 class CopyOnlyInt {
62 public:
64  CopyOnlyInt(int v) : value{std::move(v)} { print_created(this, value); }
66  CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
68 
69  int value;
70 };
73 template <> struct type_caster<MoveOnlyInt> {
74  PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt"));
75  bool load(handle src, bool) { value = MoveOnlyInt(src.cast<int>()); return true; }
76  static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
77 };
78 
79 template <> struct type_caster<MoveOrCopyInt> {
80  PYBIND11_TYPE_CASTER(MoveOrCopyInt, _("MoveOrCopyInt"));
81  bool load(handle src, bool) { value = MoveOrCopyInt(src.cast<int>()); return true; }
82  static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
83 };
84 
85 template <> struct type_caster<CopyOnlyInt> {
86 protected:
88 public:
89  static constexpr auto name = _("CopyOnlyInt");
90  bool load(handle src, bool) { value = CopyOnlyInt(src.cast<int>()); return true; }
91  static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
92  static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
93  if (!src) return none().release();
94  return cast(*src, policy, parent);
95  }
96  operator CopyOnlyInt*() { return &value; }
97  operator CopyOnlyInt&() { return value; }
98  template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>;
99 };
102 
103 TEST_SUBMODULE(copy_move_policies, m) {
104  // test_lacking_copy_ctor
105  py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
106  .def_static("get_one", &lacking_copy_ctor::get_one,
108  // test_lacking_move_ctor
109  py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
110  .def_static("get_one", &lacking_move_ctor::get_one,
112 
113  // test_move_and_copy_casts
114  m.def("move_and_copy_casts", [](py::object o) {
115  int r = 0;
116  r += py::cast<MoveOrCopyInt>(o).value; /* moves */
117  r += py::cast<MoveOnlyInt>(o).value; /* moves */
118  r += py::cast<CopyOnlyInt>(o).value; /* copies */
119  MoveOrCopyInt m1(py::cast<MoveOrCopyInt>(o)); /* moves */
120  MoveOnlyInt m2(py::cast<MoveOnlyInt>(o)); /* moves */
121  CopyOnlyInt m3(py::cast<CopyOnlyInt>(o)); /* copies */
122  r += m1.value + m2.value + m3.value;
123 
124  return r;
125  });
126 
127  // test_move_and_copy_loads
128  m.def("move_only", [](MoveOnlyInt m) { return m.value; });
129  m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
130  m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
131  m.def("move_pair", [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) {
132  return p.first.value + p.second.value;
133  });
134  m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
135  return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
136  });
137  m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
138  return std::get<0>(t).value + std::get<1>(t).value;
139  });
140  m.def("move_copy_nested", [](std::pair<MoveOnlyInt, std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>, MoveOrCopyInt>> x) {
141  return x.first.value + std::get<0>(x.second.first).value + std::get<1>(x.second.first).value +
142  std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
143  });
144  m.def("move_and_copy_cstats", []() {
146  // Reset counts to 0 so that previous tests don't affect later ones:
147  auto &mc = ConstructorStats::get<MoveOrCopyInt>();
148  mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions = 0;
149  auto &mo = ConstructorStats::get<MoveOnlyInt>();
150  mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions = 0;
151  auto &co = ConstructorStats::get<CopyOnlyInt>();
152  co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions = 0;
153  py::dict d;
154  d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
155  d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
156  d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference);
157  return d;
158  });
159 #ifdef PYBIND11_HAS_OPTIONAL
160  // test_move_and_copy_load_optional
161  m.attr("has_optional") = true;
162  m.def("move_optional", [](std::optional<MoveOnlyInt> o) {
163  return o->value;
164  });
165  m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) {
166  return o->value;
167  });
168  m.def("copy_optional", [](std::optional<CopyOnlyInt> o) {
169  return o->value;
170  });
171  m.def("move_optional_tuple", [](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
172  return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
173  });
174 #else
175  m.attr("has_optional") = false;
176 #endif
177 
178  // #70 compilation issue if operator new is not public - simple body added
179  // but not needed on most compilers; MSVC and nvcc don't like a local
180  // struct not having a method defined when declared, since it can not be
181  // added later.
182  struct PrivateOpNew {
183  int value = 1;
184  private:
185  void *operator new(size_t bytes) {
186  void *ptr = std::malloc(bytes);
187  if (ptr)
188  return ptr;
189  else
190  throw std::bad_alloc{};
191  }
192  };
193  py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
194  m.def("private_op_new_value", []() { return PrivateOpNew(); });
195  m.def("private_op_new_reference", []() -> const PrivateOpNew & {
196  static PrivateOpNew x{};
197  return x;
198  }, py::return_value_policy::reference);
199 
200  // test_move_fallback
201  // #389: rvp::move should fall-through to copy on non-movable objects
202  struct MoveIssue1 {
203  int v;
204  MoveIssue1(int v) : v{v} {}
205  MoveIssue1(const MoveIssue1 &c) = default;
206  MoveIssue1(MoveIssue1 &&) = delete;
207  };
208  py::class_<MoveIssue1>(m, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
209 
210  struct MoveIssue2 {
211  int v;
212  MoveIssue2(int v) : v{v} {}
213  MoveIssue2(MoveIssue2 &&) = default;
214  };
215  py::class_<MoveIssue2>(m, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
216 
217  m.def("get_moveissue1", [](int i) { return new MoveIssue1(i); }, py::return_value_policy::move);
218  m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
219 }
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()
ArrayXcf v
Definition: Cwise_arg.cpp:1
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)
MoveOrCopyInt(MoveOrCopyInt &&m)
static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p)
bool load(handle src, bool)
static derived instance_
T cast() const
Definition: cast.h:1752
detail::enable_if_t<!detail::move_never< T >::value, T > move(object &&obj)
Definition: cast.h:1756
pybind11::detail::cast_op_type< T > cast_op_type
void print_default_created(T *inst, Values &&...values)
Matrix3d m1
Definition: IOFormat.cpp:2
void print_move_assigned(T *inst, Values &&...values)
float * ptr
EIGEN_DEVICE_FUNC NewType cast(const OldType &x)
MoveOrCopyInt & operator=(MoveOrCopyInt &&m)
static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p)
CopyOnlyInt & operator=(const CopyOnlyInt &c)
void print_created(T *inst, Values &&...values)
MoveOnlyInt(MoveOnlyInt &&m)
float * p
bool load(handle src, bool)
MoveOnlyInt(int v)
Annotation for function names.
Definition: attr.h:36
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
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.
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition: mpreal.h:2986
#define PYBIND11_TYPE_CASTER(type, py_name)
Definition: cast.h:979
#define PYBIND11_NAMESPACE_END(name)
Definition: pytypes.h:995
Point2 t(10, 10)
MoveOrCopyInt(const MoveOrCopyInt &c)
#define PYBIND11_NAMESPACE_BEGIN(name)
MoveOnlyInt & operator=(MoveOnlyInt &&m)


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:46:03