test_operator_overloading.cpp
Go to the documentation of this file.
1 /*
2  tests/test_operator_overloading.cpp -- operator overloading
3 
4  Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
5 
6  All rights reserved. Use of this source code is governed by a
7  BSD-style license that can be found in the LICENSE file.
8 */
9 
10 #include <pybind11/operators.h>
11 #include <pybind11/stl.h>
12 
13 #include "constructor_stats.h"
14 #include "pybind11_tests.h"
15 
16 #include <functional>
17 
18 class Vector2 {
19 public:
20  Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
21  Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
22  Vector2(Vector2 &&v) noexcept : x(v.x), y(v.y) {
23  print_move_created(this);
24  v.x = v.y = 0;
25  }
27  x = v.x;
28  y = v.y;
29  print_copy_assigned(this);
30  return *this;
31  }
32  Vector2 &operator=(Vector2 &&v) noexcept {
33  x = v.x;
34  y = v.y;
35  v.x = v.y = 0;
36  print_move_assigned(this);
37  return *this;
38  }
40 
41  std::string toString() const {
42  return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
43  }
44 
45  Vector2 operator-() const { return Vector2(-x, -y); }
46  Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
47  Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
48  Vector2 operator-(float value) const { return Vector2(x - value, y - value); }
49  Vector2 operator+(float value) const { return Vector2(x + value, y + value); }
50  Vector2 operator*(float value) const { return Vector2(x * value, y * value); }
51  Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
52  Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); }
53  Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); }
55  x += v.x;
56  y += v.y;
57  return *this;
58  }
60  x -= v.x;
61  y -= v.y;
62  return *this;
63  }
64  Vector2 &operator*=(float v) {
65  x *= v;
66  y *= v;
67  return *this;
68  }
69  Vector2 &operator/=(float v) {
70  x /= v;
71  y /= v;
72  return *this;
73  }
75  x *= v.x;
76  y *= v.y;
77  return *this;
78  }
80  x /= v.x;
81  y /= v.y;
82  return *this;
83  }
84 
85  friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); }
86  friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); }
87  friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); }
88  friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); }
89 
90  bool operator==(const Vector2 &v) const { return x == v.x && y == v.y; }
91  bool operator!=(const Vector2 &v) const { return x != v.x || y != v.y; }
92 
93 private:
94  float x, y;
95 };
96 
97 class C1 {};
98 class C2 {};
99 
100 int operator+(const C1 &, const C1 &) { return 11; }
101 int operator+(const C2 &, const C2 &) { return 22; }
102 int operator+(const C2 &, const C1 &) { return 21; }
103 int operator+(const C1 &, const C2 &) { return 12; }
104 
105 struct HashMe {
106  std::string member;
107 };
108 
109 bool operator==(const HashMe &lhs, const HashMe &rhs) { return lhs.member == rhs.member; }
110 
111 // Note: Specializing explicit within `namespace std { ... }` is done due to a
112 // bug in GCC<7. If you are supporting compilers later than this, consider
113 // specializing `using template<> struct std::hash<...>` in the global
114 // namespace instead, per this recommendation:
115 // https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations
116 namespace std {
117 template <>
118 struct hash<Vector2> {
119  // Not a good hash function, but easy to test
120  size_t operator()(const Vector2 &) { return 4; }
121 };
122 
123 // HashMe has a hash function in C++ but no `__hash__` for Python.
124 template <>
125 struct hash<HashMe> {
126  std::size_t operator()(const HashMe &selector) const {
127  return std::hash<std::string>()(selector.member);
128  }
129 };
130 } // namespace std
131 
132 // Not a good abs function, but easy to test.
133 std::string abs(const Vector2 &) { return "abs(Vector2)"; }
134 
135 // clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to
136 // `-Wall`, which is used here for overloading (e.g. `py::self += py::self `).
137 // Here, we suppress the warning
138 // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46
139 // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`).
140 #if defined(__APPLE__) && defined(__clang__)
141 # if (__clang_major__ >= 10)
142 PYBIND11_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
143 # endif
144 #elif defined(__clang__)
145 # if (__clang_major__ >= 7)
146 PYBIND11_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
147 # endif
148 #endif
149 
150 TEST_SUBMODULE(operators, m) {
151 
152  // test_operator_overloading
153  py::class_<Vector2>(m, "Vector2")
154  .def(py::init<float, float>())
155  .def(py::self + py::self)
156  .def(py::self + float())
157  .def(py::self - py::self)
158  .def(py::self - float())
159  .def(py::self * float())
160  .def(py::self / float())
161  .def(py::self * py::self)
162  .def(py::self / py::self)
163  .def(py::self += py::self)
164  .def(py::self -= py::self)
165  .def(py::self *= float())
166  .def(py::self /= float())
167  .def(py::self *= py::self)
168  .def(py::self /= py::self)
169  .def(float() + py::self)
170  .def(float() - py::self)
171  .def(float() * py::self)
172  .def(float() / py::self)
173  .def(-py::self)
174  .def("__str__", &Vector2::toString)
175  .def("__repr__", &Vector2::toString)
176  .def(py::self == py::self)
177  .def(py::self != py::self)
178  .def(py::hash(py::self))
179  // N.B. See warning about usage of `py::detail::abs(py::self)` in
180  // `operators.h`.
181  .def("__abs__", [](const Vector2 &v) { return abs(v); });
182 
183  m.attr("Vector") = m.attr("Vector2");
184 
185  // test_operators_notimplemented
186  // #393: need to return NotSupported to ensure correct arithmetic operator behavior
187  py::class_<C1>(m, "C1").def(py::init<>()).def(py::self + py::self);
188 
189  py::class_<C2>(m, "C2")
190  .def(py::init<>())
191  .def(py::self + py::self)
192  .def("__add__", [](const C2 &c2, const C1 &c1) { return c2 + c1; })
193  .def("__radd__", [](const C2 &c2, const C1 &c1) { return c1 + c2; });
194 
195  // test_nested
196  // #328: first member in a class can't be used in operators
197  struct NestABase {
198  int value = -2;
199  };
200  py::class_<NestABase>(m, "NestABase")
201  .def(py::init<>())
202  .def_readwrite("value", &NestABase::value);
203 
204  struct NestA : NestABase {
205  int value = 3;
206  NestA &operator+=(int i) {
207  value += i;
208  return *this;
209  }
210  };
211  py::class_<NestA>(m, "NestA")
212  .def(py::init<>())
213  .def(py::self += int())
214  .def(
215  "as_base",
216  [](NestA &a) -> NestABase & { return (NestABase &) a; },
217  py::return_value_policy::reference_internal);
218  m.def("get_NestA", [](const NestA &a) { return a.value; });
219 
220  struct NestB {
221  NestA a;
222  int value = 4;
223  NestB &operator-=(int i) {
224  value -= i;
225  return *this;
226  }
227  };
228  py::class_<NestB>(m, "NestB")
229  .def(py::init<>())
230  .def(py::self -= int())
231  .def_readwrite("a", &NestB::a);
232  m.def("get_NestB", [](const NestB &b) { return b.value; });
233 
234  struct NestC {
235  NestB b;
236  int value = 5;
237  NestC &operator*=(int i) {
238  value *= i;
239  return *this;
240  }
241  };
242  py::class_<NestC>(m, "NestC")
243  .def(py::init<>())
244  .def(py::self *= int())
245  .def_readwrite("b", &NestC::b);
246  m.def("get_NestC", [](const NestC &c) { return c.value; });
247 
248  // test_overriding_eq_reset_hash
249  // #2191 Overriding __eq__ should set __hash__ to None
250  struct Comparable {
251  int value;
252  bool operator==(const Comparable &rhs) const { return value == rhs.value; }
253  };
254 
255  struct Hashable : Comparable {
256  explicit Hashable(int value) : Comparable{value} {};
257  size_t hash() const { return static_cast<size_t>(value); }
258  };
259 
260  struct Hashable2 : Hashable {
261  using Hashable::Hashable;
262  };
263 
264  py::class_<Comparable>(m, "Comparable").def(py::init<int>()).def(py::self == py::self);
265 
266  py::class_<Hashable>(m, "Hashable")
267  .def(py::init<int>())
268  .def(py::self == py::self)
269  .def("__hash__", &Hashable::hash);
270 
271  // define __hash__ before __eq__
272  py::class_<Hashable2>(m, "Hashable2")
273  .def("__hash__", &Hashable::hash)
274  .def(py::init<int>())
275  .def(py::self == py::self);
276 
277  // define __eq__ but not __hash__
278  py::class_<HashMe>(m, "HashMe").def(py::self == py::self);
279 
280  m.def("get_unhashable_HashMe_set", []() { return std::unordered_set<HashMe>{{"one"}}; });
281 }
Vector2::operator-
friend Vector2 operator-(float f, const Vector2 &v)
Definition: test_operator_overloading.cpp:86
Vector2::operator*=
Vector2 & operator*=(float v)
Definition: test_operator_overloading.cpp:64
Vector2::operator/
friend Vector2 operator/(float f, const Vector2 &v)
Definition: test_operator_overloading.cpp:88
Vector2::Vector2
Vector2(const Vector2 &v)
Definition: test_operator_overloading.cpp:21
c
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
Vector2::operator!=
bool operator!=(const Vector2 &v) const
Definition: test_operator_overloading.cpp:91
b
Scalar * b
Definition: benchVecAdd.cpp:17
Vector2::~Vector2
~Vector2()
Definition: test_operator_overloading.cpp:39
Vector2::Vector2
Vector2(float x, float y)
Definition: test_operator_overloading.cpp:20
stl.h
Vector2::operator+=
Vector2 & operator+=(const Vector2 &v)
Definition: test_operator_overloading.cpp:54
Vector2::operator-
Vector2 operator-() const
Definition: test_operator_overloading.cpp:45
Vector2::operator/
Vector2 operator/(const Vector2 &v) const
Definition: test_operator_overloading.cpp:53
C2
Definition: test_operator_overloading.cpp:98
Eigen::bfloat16_impl::operator*=
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 & operator*=(bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:188
TEST_SUBMODULE
TEST_SUBMODULE(operators, m)
Definition: test_operator_overloading.cpp:150
constructor_stats.h
HashMe::member
std::string member
Definition: test_operator_overloading.cpp:106
Vector2::y
float y
Definition: test_operator_overloading.cpp:94
Vector2::operator+
friend Vector2 operator+(float f, const Vector2 &v)
Definition: test_operator_overloading.cpp:85
operator==
bool operator==(const HashMe &lhs, const HashMe &rhs)
Definition: test_operator_overloading.cpp:109
hash
ssize_t hash(handle obj)
Definition: pytypes.h:934
print_copy_created
void print_copy_created(T *inst, Values &&...values)
Definition: constructor_stats.h:282
Vector2::operator*
friend Vector2 operator*(float f, const Vector2 &v)
Definition: test_operator_overloading.cpp:87
c1
static double c1
Definition: airy.c:54
Vector2::Vector2
Vector2(Vector2 &&v) noexcept
Definition: test_operator_overloading.cpp:22
Vector2::operator*
Vector2 operator*(float value) const
Definition: test_operator_overloading.cpp:50
Vector2::operator==
bool operator==(const Vector2 &v) const
Definition: test_operator_overloading.cpp:90
Vector2::operator=
Vector2 & operator=(Vector2 &&v) noexcept
Definition: test_operator_overloading.cpp:32
abs
std::string abs(const Vector2 &)
Definition: test_operator_overloading.cpp:133
print_copy_assigned
void print_copy_assigned(T *inst, Values &&...values)
Definition: constructor_stats.h:294
C1
Definition: test_operator_overloading.cpp:97
Eigen::bfloat16_impl::operator-=
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 & operator-=(bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:192
Vector2::operator-=
Vector2 & operator-=(const Vector2 &v)
Definition: test_operator_overloading.cpp:59
Vector2
Definition: test_operator_overloading.cpp:18
m
Matrix3f m
Definition: AngleAxis_mimic_euler.cpp:1
HashMe
Definition: test_operator_overloading.cpp:105
size_t
std::size_t size_t
Definition: wrap/pybind11/include/pybind11/detail/common.h:490
Vector2::operator*
Vector2 operator*(const Vector2 &v) const
Definition: test_operator_overloading.cpp:52
tree::f
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
Definition: testExpression.cpp:218
std::hash< Vector2 >::operator()
size_t operator()(const Vector2 &)
Definition: test_operator_overloading.cpp:120
a
ArrayXXi a
Definition: Array_initializer_list_23_cxx11.cpp:1
print_move_created
void print_move_created(T *inst, Values &&...values)
Definition: constructor_stats.h:288
Vector2::toString
std::string toString() const
Definition: test_operator_overloading.cpp:41
pybind11_tests.h
std
Definition: BFloat16.h:88
print_destroyed
void print_destroyed(T *inst, Values &&...values)
Definition: constructor_stats.h:314
Vector2::operator+
Vector2 operator+(float value) const
Definition: test_operator_overloading.cpp:49
c2
static double c2
Definition: airy.c:55
v
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
self
static const self_t self
Definition: operators.h:72
Vector2::operator-
Vector2 operator-(float value) const
Definition: test_operator_overloading.cpp:48
print_move_assigned
void print_move_assigned(T *inst, Values &&...values)
Definition: constructor_stats.h:299
Vector2::operator=
Vector2 & operator=(const Vector2 &v)
Definition: test_operator_overloading.cpp:26
Vector2::operator/=
Vector2 & operator/=(float v)
Definition: test_operator_overloading.cpp:69
Vector2::operator-
Vector2 operator-(const Vector2 &v) const
Definition: test_operator_overloading.cpp:47
Vector2::x
float x
Definition: test_operator_overloading.cpp:94
operator+
int operator+(const C1 &, const C1 &)
Definition: test_operator_overloading.cpp:100
Vector2::operator+
Vector2 operator+(const Vector2 &v) const
Definition: test_operator_overloading.cpp:46
Vector2::operator/
Vector2 operator/(float value) const
Definition: test_operator_overloading.cpp:51
Eigen::bfloat16_impl::operator+=
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 & operator+=(bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:184
std::hash< HashMe >::operator()
std::size_t operator()(const HashMe &selector) const
Definition: test_operator_overloading.cpp:126
operators.h
test_callbacks.value
value
Definition: test_callbacks.py:160
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
Vector2::operator/=
Vector2 & operator/=(const Vector2 &v)
Definition: test_operator_overloading.cpp:79
print_created
void print_created(T *inst, Values &&...values)
Definition: constructor_stats.h:309
PYBIND11_WARNING_DISABLE_CLANG
#define PYBIND11_WARNING_DISABLE_CLANG(name)
Definition: wrap/pybind11/include/pybind11/detail/common.h:61
Vector2::operator*=
Vector2 & operator*=(const Vector2 &v)
Definition: test_operator_overloading.cpp:74


gtsam
Author(s):
autogenerated on Sat Nov 16 2024 04:07:05