File indexing completed on 2025-01-18 10:17:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <pybind11/operators.h>
0012 #include <pybind11/stl.h>
0013
0014 #include "constructor_stats.h"
0015 #include "pybind11_tests.h"
0016
0017 #include <algorithm>
0018 #include <utility>
0019 #include <vector>
0020
0021 #ifdef PYBIND11_HAS_OPTIONAL
0022 # include <optional>
0023 #endif
0024
0025 template <typename T>
0026 class NonZeroIterator {
0027 const T *ptr_;
0028
0029 public:
0030 explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {}
0031 const T &operator*() const { return *ptr_; }
0032 NonZeroIterator &operator++() {
0033 ++ptr_;
0034 return *this;
0035 }
0036 };
0037
0038 class NonZeroSentinel {};
0039
0040 template <typename A, typename B>
0041 bool operator==(const NonZeroIterator<std::pair<A, B>> &it, const NonZeroSentinel &) {
0042 return !(*it).first || !(*it).second;
0043 }
0044
0045
0046 template <typename T>
0047 class NonRefIterator {
0048 const T *ptr_;
0049
0050 public:
0051 explicit NonRefIterator(const T *ptr) : ptr_(ptr) {}
0052 T operator*() const { return T(*ptr_); }
0053 NonRefIterator &operator++() {
0054 ++ptr_;
0055 return *this;
0056 }
0057 bool operator==(const NonRefIterator &other) const { return ptr_ == other.ptr_; }
0058 };
0059
0060 class NonCopyableInt {
0061 public:
0062 explicit NonCopyableInt(int value) : value_(value) {}
0063 NonCopyableInt(const NonCopyableInt &) = delete;
0064 NonCopyableInt(NonCopyableInt &&other) noexcept : value_(other.value_) {
0065 other.value_ = -1;
0066 }
0067 NonCopyableInt &operator=(const NonCopyableInt &) = delete;
0068 NonCopyableInt &operator=(NonCopyableInt &&other) noexcept {
0069 value_ = other.value_;
0070 other.value_ = -1;
0071 return *this;
0072 }
0073 int get() const { return value_; }
0074 void set(int value) { value_ = value; }
0075 ~NonCopyableInt() = default;
0076
0077 private:
0078 int value_;
0079 };
0080 using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
0081 PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
0082 PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
0083
0084 template <typename PythonType>
0085 py::list test_random_access_iterator(PythonType x) {
0086 if (x.size() < 5) {
0087 throw py::value_error("Please provide at least 5 elements for testing.");
0088 }
0089
0090 auto checks = py::list();
0091 auto assert_equal = [&checks](py::handle a, py::handle b) {
0092 auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ);
0093 if (result == -1) {
0094 throw py::error_already_set();
0095 }
0096 checks.append(result != 0);
0097 };
0098
0099 auto it = x.begin();
0100 assert_equal(x[0], *it);
0101 assert_equal(x[0], it[0]);
0102 assert_equal(x[1], it[1]);
0103
0104 assert_equal(x[1], *(++it));
0105 assert_equal(x[1], *(it++));
0106 assert_equal(x[2], *it);
0107 assert_equal(x[3], *(it += 1));
0108 assert_equal(x[2], *(--it));
0109 assert_equal(x[2], *(it--));
0110 assert_equal(x[1], *it);
0111 assert_equal(x[0], *(it -= 1));
0112
0113 assert_equal(it->attr("real"), x[0].attr("real"));
0114 assert_equal((it + 1)->attr("real"), x[1].attr("real"));
0115
0116 assert_equal(x[1], *(it + 1));
0117 assert_equal(x[1], *(1 + it));
0118 it += 3;
0119 assert_equal(x[1], *(it - 2));
0120
0121 checks.append(static_cast<std::size_t>(x.end() - x.begin()) == x.size());
0122 checks.append((x.begin() + static_cast<std::ptrdiff_t>(x.size())) == x.end());
0123 checks.append(x.begin() < x.end());
0124
0125 return checks;
0126 }
0127
0128 TEST_SUBMODULE(sequences_and_iterators, m) {
0129
0130 class Sliceable {
0131 public:
0132 explicit Sliceable(int n) : size(n) {}
0133 int start, stop, step;
0134 int size;
0135 };
0136 py::class_<Sliceable>(m, "Sliceable")
0137 .def(py::init<int>())
0138 .def("__getitem__", [](const Sliceable &s, const py::slice &slice) {
0139 py::ssize_t start = 0, stop = 0, step = 0, slicelength = 0;
0140 if (!slice.compute(s.size, &start, &stop, &step, &slicelength)) {
0141 throw py::error_already_set();
0142 }
0143 int istart = static_cast<int>(start);
0144 int istop = static_cast<int>(stop);
0145 int istep = static_cast<int>(step);
0146 return std::make_tuple(istart, istop, istep);
0147 });
0148
0149 m.def("make_forward_slice_size_t", []() { return py::slice(0, -1, 1); });
0150 m.def("make_reversed_slice_object",
0151 []() { return py::slice(py::none(), py::none(), py::int_(-1)); });
0152 #ifdef PYBIND11_HAS_OPTIONAL
0153 m.attr("has_optional") = true;
0154 m.def("make_reversed_slice_size_t_optional_verbose",
0155 []() { return py::slice(std::nullopt, std::nullopt, -1); });
0156
0157
0158 m.def("make_reversed_slice_size_t_optional", []() { return py::slice({}, {}, -1); });
0159 #else
0160 m.attr("has_optional") = false;
0161 #endif
0162
0163
0164 class Sequence {
0165 public:
0166 explicit Sequence(size_t size) : m_size(size) {
0167 print_created(this, "of size", m_size);
0168
0169 m_data = new float[size];
0170 memset(m_data, 0, sizeof(float) * size);
0171 }
0172 explicit Sequence(const std::vector<float> &value) : m_size(value.size()) {
0173 print_created(this, "of size", m_size, "from std::vector");
0174
0175 m_data = new float[m_size];
0176 memcpy(m_data, &value[0], sizeof(float) * m_size);
0177 }
0178 Sequence(const Sequence &s) : m_size(s.m_size) {
0179 print_copy_created(this);
0180
0181 m_data = new float[m_size];
0182 memcpy(m_data, s.m_data, sizeof(float) * m_size);
0183 }
0184 Sequence(Sequence &&s) noexcept : m_size(s.m_size), m_data(s.m_data) {
0185 print_move_created(this);
0186 s.m_size = 0;
0187 s.m_data = nullptr;
0188 }
0189
0190 ~Sequence() {
0191 print_destroyed(this);
0192 delete[] m_data;
0193 }
0194
0195 Sequence &operator=(const Sequence &s) {
0196 if (&s != this) {
0197 delete[] m_data;
0198 m_size = s.m_size;
0199 m_data = new float[m_size];
0200 memcpy(m_data, s.m_data, sizeof(float) * m_size);
0201 }
0202 print_copy_assigned(this);
0203 return *this;
0204 }
0205
0206 Sequence &operator=(Sequence &&s) noexcept {
0207 if (&s != this) {
0208 delete[] m_data;
0209 m_size = s.m_size;
0210 m_data = s.m_data;
0211 s.m_size = 0;
0212 s.m_data = nullptr;
0213 }
0214 print_move_assigned(this);
0215 return *this;
0216 }
0217
0218 bool operator==(const Sequence &s) const {
0219 if (m_size != s.size()) {
0220 return false;
0221 }
0222 for (size_t i = 0; i < m_size; ++i) {
0223 if (m_data[i] != s[i]) {
0224 return false;
0225 }
0226 }
0227 return true;
0228 }
0229 bool operator!=(const Sequence &s) const { return !operator==(s); }
0230
0231 float operator[](size_t index) const { return m_data[index]; }
0232 float &operator[](size_t index) { return m_data[index]; }
0233
0234 bool contains(float v) const {
0235 for (size_t i = 0; i < m_size; ++i) {
0236 if (v == m_data[i]) {
0237 return true;
0238 }
0239 }
0240 return false;
0241 }
0242
0243 Sequence reversed() const {
0244 Sequence result(m_size);
0245 for (size_t i = 0; i < m_size; ++i) {
0246 result[m_size - i - 1] = m_data[i];
0247 }
0248 return result;
0249 }
0250
0251 size_t size() const { return m_size; }
0252
0253 const float *begin() const { return m_data; }
0254 const float *end() const { return m_data + m_size; }
0255
0256 private:
0257 size_t m_size;
0258 float *m_data;
0259 };
0260 py::class_<Sequence>(m, "Sequence")
0261 .def(py::init<size_t>())
0262 .def(py::init<const std::vector<float> &>())
0263
0264 .def("__getitem__",
0265 [](const Sequence &s, size_t i) {
0266 if (i >= s.size()) {
0267 throw py::index_error();
0268 }
0269 return s[i];
0270 })
0271 .def("__setitem__",
0272 [](Sequence &s, size_t i, float v) {
0273 if (i >= s.size()) {
0274 throw py::index_error();
0275 }
0276 s[i] = v;
0277 })
0278 .def("__len__", &Sequence::size)
0279
0280 .def(
0281 "__iter__",
0282 [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); },
0283 py::keep_alive<0, 1>() )
0284 .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); })
0285 .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
0286
0287 .def("__getitem__",
0288 [](const Sequence &s, const py::slice &slice) -> Sequence * {
0289 size_t start = 0, stop = 0, step = 0, slicelength = 0;
0290 if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) {
0291 throw py::error_already_set();
0292 }
0293 auto *seq = new Sequence(slicelength);
0294 for (size_t i = 0; i < slicelength; ++i) {
0295 (*seq)[i] = s[start];
0296 start += step;
0297 }
0298 return seq;
0299 })
0300 .def("__setitem__",
0301 [](Sequence &s, const py::slice &slice, const Sequence &value) {
0302 size_t start = 0, stop = 0, step = 0, slicelength = 0;
0303 if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) {
0304 throw py::error_already_set();
0305 }
0306 if (slicelength != value.size()) {
0307 throw std::runtime_error(
0308 "Left and right hand size of slice assignment have different sizes!");
0309 }
0310 for (size_t i = 0; i < slicelength; ++i) {
0311 s[start] = value[i];
0312 start += step;
0313 }
0314 })
0315
0316 .def(py::self == py::self)
0317 .def(py::self != py::self)
0318
0319 ;
0320
0321
0322
0323
0324 class StringMap {
0325 public:
0326 StringMap() = default;
0327 explicit StringMap(std::unordered_map<std::string, std::string> init)
0328 : map(std::move(init)) {}
0329
0330 void set(const std::string &key, std::string val) { map[key] = std::move(val); }
0331 std::string get(const std::string &key) const { return map.at(key); }
0332 size_t size() const { return map.size(); }
0333
0334 private:
0335 std::unordered_map<std::string, std::string> map;
0336
0337 public:
0338 decltype(map.cbegin()) begin() const { return map.cbegin(); }
0339 decltype(map.cend()) end() const { return map.cend(); }
0340 };
0341 py::class_<StringMap>(m, "StringMap")
0342 .def(py::init<>())
0343 .def(py::init<std::unordered_map<std::string, std::string>>())
0344 .def("__getitem__",
0345 [](const StringMap &map, const std::string &key) {
0346 try {
0347 return map.get(key);
0348 } catch (const std::out_of_range &) {
0349 throw py::key_error("key '" + key + "' does not exist");
0350 }
0351 })
0352 .def("__setitem__", &StringMap::set)
0353 .def("__len__", &StringMap::size)
0354 .def(
0355 "__iter__",
0356 [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); },
0357 py::keep_alive<0, 1>())
0358 .def(
0359 "items",
0360 [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); },
0361 py::keep_alive<0, 1>())
0362 .def(
0363 "values",
0364 [](const StringMap &map) { return py::make_value_iterator(map.begin(), map.end()); },
0365 py::keep_alive<0, 1>());
0366
0367
0368 class IntPairs {
0369 public:
0370 explicit IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {}
0371 const std::pair<int, int> *begin() const { return data_.data(); }
0372
0373 const std::pair<int, int> *end() const { return data_.data() + data_.size(); }
0374
0375 private:
0376 std::vector<std::pair<int, int>> data_;
0377 };
0378 py::class_<IntPairs>(m, "IntPairs")
0379 .def(py::init<std::vector<std::pair<int, int>>>())
0380 .def(
0381 "nonzero",
0382 [](const IntPairs &s) {
0383 return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()),
0384 NonZeroSentinel());
0385 },
0386 py::keep_alive<0, 1>())
0387 .def(
0388 "nonzero_keys",
0389 [](const IntPairs &s) {
0390 return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()),
0391 NonZeroSentinel());
0392 },
0393 py::keep_alive<0, 1>())
0394 .def(
0395 "nonzero_values",
0396 [](const IntPairs &s) {
0397 return py::make_value_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()),
0398 NonZeroSentinel());
0399 },
0400 py::keep_alive<0, 1>())
0401
0402
0403 .def(
0404 "nonref",
0405 [](const IntPairs &s) {
0406 return py::make_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
0407 NonRefIterator<std::pair<int, int>>(s.end()));
0408 },
0409 py::keep_alive<0, 1>())
0410 .def(
0411 "nonref_keys",
0412 [](const IntPairs &s) {
0413 return py::make_key_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
0414 NonRefIterator<std::pair<int, int>>(s.end()));
0415 },
0416 py::keep_alive<0, 1>())
0417 .def(
0418 "nonref_values",
0419 [](const IntPairs &s) {
0420 return py::make_value_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
0421 NonRefIterator<std::pair<int, int>>(s.end()));
0422 },
0423 py::keep_alive<0, 1>())
0424
0425
0426 .def(
0427 "simple_iterator",
0428 [](IntPairs &self) { return py::make_iterator(self); },
0429 py::keep_alive<0, 1>())
0430 .def(
0431 "simple_keys",
0432 [](IntPairs &self) { return py::make_key_iterator(self); },
0433 py::keep_alive<0, 1>())
0434 .def(
0435 "simple_values",
0436 [](IntPairs &self) { return py::make_value_iterator(self); },
0437 py::keep_alive<0, 1>())
0438
0439
0440
0441
0442 .def(
0443 "_make_iterator_extras",
0444 [](IntPairs &self) { return py::make_iterator(self, py::call_guard<int>()); },
0445 py::keep_alive<0, 1>())
0446 .def(
0447 "_make_key_extras",
0448 [](IntPairs &self) { return py::make_key_iterator(self, py::call_guard<int>()); },
0449 py::keep_alive<0, 1>())
0450 .def(
0451 "_make_value_extras",
0452 [](IntPairs &self) { return py::make_value_iterator(self, py::call_guard<int>()); },
0453 py::keep_alive<0, 1>());
0454
0455
0456 py::class_<NonCopyableInt>(m, "NonCopyableInt")
0457 .def(py::init<int>())
0458 .def("set", &NonCopyableInt::set)
0459 .def("__int__", &NonCopyableInt::get);
0460 py::class_<std::vector<NonCopyableInt>>(m, "VectorNonCopyableInt")
0461 .def(py::init<>())
0462 .def("append",
0463 [](std::vector<NonCopyableInt> &vec, int value) { vec.emplace_back(value); })
0464 .def("__iter__", [](std::vector<NonCopyableInt> &vec) {
0465 return py::make_iterator(vec.begin(), vec.end());
0466 });
0467 py::class_<std::vector<NonCopyableIntPair>>(m, "VectorNonCopyableIntPair")
0468 .def(py::init<>())
0469 .def("append",
0470 [](std::vector<NonCopyableIntPair> &vec, const std::pair<int, int> &value) {
0471 vec.emplace_back(NonCopyableInt(value.first), NonCopyableInt(value.second));
0472 })
0473 .def("keys",
0474 [](std::vector<NonCopyableIntPair> &vec) {
0475 return py::make_key_iterator(vec.begin(), vec.end());
0476 })
0477 .def("values", [](std::vector<NonCopyableIntPair> &vec) {
0478 return py::make_value_iterator(vec.begin(), vec.end());
0479 });
0480
0481 #if 0
0482
0483
0484
0485
0486 struct PySequenceIterator {
0487 PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { }
0488
0489 float next() {
0490 if (index == seq.size())
0491 throw py::stop_iteration();
0492 return seq[index++];
0493 }
0494
0495 const Sequence &seq;
0496 py::object ref;
0497 size_t index = 0;
0498 };
0499
0500 py::class_<PySequenceIterator>(seq, "Iterator")
0501 .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; })
0502 .def("__next__", &PySequenceIterator::next);
0503
0504 On the actual Sequence object, the iterator would be constructed as follows:
0505 .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); })
0506 #endif
0507
0508
0509 m.def("object_to_list", [](const py::object &o) {
0510 auto l = py::list();
0511 for (auto item : o) {
0512 l.append(item);
0513 }
0514 return l;
0515 });
0516
0517 m.def("iterator_to_list", [](py::iterator it) {
0518 auto l = py::list();
0519 while (it != py::iterator::sentinel()) {
0520 l.append(*it);
0521 ++it;
0522 }
0523 return l;
0524 });
0525
0526
0527 m.def("sequence_length", [](const py::sequence &seq) { return seq.size(); });
0528
0529
0530 m.def("count_none", [](const py::object &o) {
0531 return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); });
0532 });
0533
0534 m.def("find_none", [](const py::object &o) {
0535 auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); });
0536 return it->is_none();
0537 });
0538
0539 m.def("count_nonzeros", [](const py::dict &d) {
0540 return std::count_if(d.begin(), d.end(), [](std::pair<py::handle, py::handle> p) {
0541 return p.second.cast<int>() != 0;
0542 });
0543 });
0544
0545 m.def("tuple_iterator", &test_random_access_iterator<py::tuple>);
0546 m.def("list_iterator", &test_random_access_iterator<py::list>);
0547 m.def("sequence_iterator", &test_random_access_iterator<py::sequence>);
0548
0549
0550
0551 m.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
0552 return py::make_iterator(std::begin(s), std::end(s));
0553 });
0554
0555
0556
0557 static std::vector<int> list = {1, 2, 3};
0558 m.def("make_iterator_1",
0559 []() { return py::make_iterator<py::return_value_policy::copy>(list); });
0560 m.def("make_iterator_2",
0561 []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
0562
0563
0564
0565 class CArrayHolder {
0566 public:
0567 CArrayHolder(double x, double y, double z) {
0568 values[0] = x;
0569 values[1] = y;
0570 values[2] = z;
0571 };
0572 double values[3];
0573 };
0574
0575 py::class_<CArrayHolder>(m, "CArrayHolder")
0576 .def(py::init<double, double, double>())
0577 .def(
0578 "__iter__",
0579 [](const CArrayHolder &v) { return py::make_iterator(v.values, v.values + 3); },
0580 py::keep_alive<0, 1>());
0581 }