cppyabm  1.0.17
An agent-based library to integrate C++ and Python
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;
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); }
53  MoveOrCopyInt(MoveOrCopyInt &&m) { print_move_created(this, m.value); std::swap(value, m.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> {
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,
107  py::return_value_policy::copy);
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  auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */
120  auto m2(py::cast<MoveOnlyInt>(o)); /* moves */
121  auto 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  // #2742: Don't expect ownership of raw pointer to `new`ed object to be transferred with `py::return_value_policy::move`
218  m.def("get_moveissue1", [](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); }, py::return_value_policy::move);
219  m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
220 }
type_caster< MoveOrCopyInt >::cast
static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p)
Definition: test_copy_move.cpp:82
test_multiple_inheritance.i
i
Definition: test_multiple_inheritance.py:22
MoveOnlyInt::value
int value
Definition: test_copy_move.cpp:47
MoveOrCopyInt
Definition: test_copy_move.cpp:49
MoveOrCopyInt::MoveOrCopyInt
MoveOrCopyInt(const MoveOrCopyInt &c)
Definition: test_copy_move.cpp:55
name
Annotation for function names.
Definition: attr.h:36
cast
T cast(const handle &handle)
Definition: cast.h:1769
PYBIND11_NAMESPACE_BEGIN
#define PYBIND11_NAMESPACE_BEGIN(name)
Definition: common.h:16
lacking_copy_ctor::lacking_copy_ctor
lacking_copy_ctor(const lacking_copy_ctor &other)=delete
type_caster< MoveOnlyInt >::load
bool load(handle src, bool)
Definition: test_copy_move.cpp:75
bytes
Definition: pytypes.h:1013
MoveOrCopyInt::value
int value
Definition: test_copy_move.cpp:59
test_builtin_casters.x
x
Definition: test_builtin_casters.py:467
PYBIND11_NAMESPACE_END
#define PYBIND11_NAMESPACE_END(name)
Definition: common.h:17
MoveOrCopyInt::~MoveOrCopyInt
~MoveOrCopyInt()
Definition: test_copy_move.cpp:57
CopyOnlyInt::CopyOnlyInt
CopyOnlyInt(const CopyOnlyInt &c)
Definition: test_copy_move.cpp:65
type_caster_generic::value
void * value
Definition: cast.h:767
MoveOrCopyInt::operator=
MoveOrCopyInt & operator=(MoveOrCopyInt &&m)
Definition: test_copy_move.cpp:54
stl.h
MoveOrCopyInt::MoveOrCopyInt
MoveOrCopyInt(int v)
Definition: test_copy_move.cpp:52
_
constexpr descr< N - 1 > _(char const(&text)[N])
Definition: descr.h:54
MoveOrCopyInt::operator=
MoveOrCopyInt & operator=(const MoveOrCopyInt &c)
Definition: test_copy_move.cpp:56
lacking_move_ctor
Definition: test_copy_move.cpp:28
type_caster< CopyOnlyInt >::cast_op_type
pybind11::detail::cast_op_type< T > cast_op_type
Definition: test_copy_move.cpp:98
constructor_stats.h
type_caster< CopyOnlyInt >::load
bool load(handle src, bool)
Definition: test_copy_move.cpp:90
type_caster< MoveOnlyInt >::PYBIND11_TYPE_CASTER
PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt"))
type_caster< MoveOrCopyInt >::load
bool load(handle src, bool)
Definition: test_copy_move.cpp:81
lacking_move_ctor::lacking_move_ctor
lacking_move_ctor(const lacking_move_ctor &other)=delete
print_copy_created
void print_copy_created(T *inst, Values &&...values)
Definition: constructor_stats.h:244
CopyOnlyInt::CopyOnlyInt
CopyOnlyInt()
Definition: test_copy_move.cpp:63
print_default_created
void print_default_created(T *inst, Values &&...values)
Definition: constructor_stats.h:260
type_caster_base::cast
static handle cast(const itype &src, return_value_policy policy, handle parent)
Definition: cast.h:878
handle
Definition: pytypes.h:176
type_caster
Definition: cast.h:954
type_caster< CopyOnlyInt >::value
CopyOnlyInt value
Definition: test_copy_move.cpp:87
handle::cast
T cast() const
Definition: cast.h:1794
MoveOnlyInt::operator=
MoveOnlyInt & operator=(MoveOnlyInt &&m)
Definition: test_copy_move.cpp:42
object::release
handle release()
Definition: pytypes.h:249
print_copy_assigned
void print_copy_assigned(T *inst, Values &&...values)
Definition: constructor_stats.h:252
MoveOrCopyInt::MoveOrCopyInt
MoveOrCopyInt()
Definition: test_copy_move.cpp:51
ConstructorStats::gc
static void gc()
Definition: constructor_stats.h:110
type_caster< MoveOnlyInt >::cast
static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p)
Definition: test_copy_move.cpp:76
lacking_move_ctor::lacking_move_ctor
lacking_move_ctor()=default
policy
Definition: policy.py:1
TEST_SUBMODULE
TEST_SUBMODULE(copy_move_policies, m)
Definition: test_copy_move.cpp:103
CopyOnlyInt::value
int value
Definition: test_copy_move.cpp:69
lacking_copy_ctor
Definition: test_copy_move.cpp:21
MoveOnlyInt::MoveOnlyInt
MoveOnlyInt(int v)
Definition: test_copy_move.cpp:40
empty::get_one
static const derived & get_one()
Definition: test_copy_move.cpp:17
move
detail::enable_if_t<!detail::move_never< T >::value, T > move(object &&obj)
Definition: cast.h:1798
empty
Definition: test_copy_move.cpp:16
MoveOnlyInt
Definition: test_copy_move.cpp:37
print_move_created
void print_move_created(T *inst, Values &&...values)
Definition: constructor_stats.h:248
type_caster< CopyOnlyInt >::cast
static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p)
Definition: test_copy_move.cpp:91
pybind11_tests.h
print_destroyed
void print_destroyed(T *inst, Values &&...values)
Definition: constructor_stats.h:268
return_value_policy
return_value_policy
Approach used to cast a previously unknown C++ instance into a Python object.
Definition: common.h:357
type_caster< CopyOnlyInt >::cast
static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent)
Definition: test_copy_move.cpp:92
CopyOnlyInt::~CopyOnlyInt
~CopyOnlyInt()
Definition: test_copy_move.cpp:67
MoveOnlyInt::MoveOnlyInt
MoveOnlyInt()
Definition: test_copy_move.cpp:39
pybind11
Definition: __init__.py:1
MoveOnlyInt::MoveOnlyInt
MoveOnlyInt(const MoveOnlyInt &)=delete
print_move_assigned
void print_move_assigned(T *inst, Values &&...values)
Definition: constructor_stats.h:256
lacking_copy_ctor::lacking_copy_ctor
lacking_copy_ctor()=default
empty::instance_
static derived instance_
Definition: test_copy_move.cpp:18
MoveOnlyInt::MoveOnlyInt
MoveOnlyInt(MoveOnlyInt &&m)
Definition: test_copy_move.cpp:41
CopyOnlyInt::operator=
CopyOnlyInt & operator=(const CopyOnlyInt &c)
Definition: test_copy_move.cpp:66
none
Definition: pytypes.h:1075
CopyOnlyInt
Definition: test_copy_move.cpp:61
MoveOrCopyInt::MoveOrCopyInt
MoveOrCopyInt(MoveOrCopyInt &&m)
Definition: test_copy_move.cpp:53
test_async.m
m
Definition: test_async.py:5
test_callbacks.value
value
Definition: test_callbacks.py:126
MoveOnlyInt::operator=
MoveOnlyInt & operator=(const MoveOnlyInt &)=delete
print_created
void print_created(T *inst, Values &&...values)
Definition: constructor_stats.h:264
CopyOnlyInt::CopyOnlyInt
CopyOnlyInt(int v)
Definition: test_copy_move.cpp:64
type_caster< MoveOrCopyInt >::PYBIND11_TYPE_CASTER
PYBIND11_TYPE_CASTER(MoveOrCopyInt, _("MoveOrCopyInt"))
MoveOnlyInt::~MoveOnlyInt
~MoveOnlyInt()
Definition: test_copy_move.cpp:45
lacking_move_ctor::lacking_move_ctor
lacking_move_ctor(lacking_move_ctor &&other)=delete