test_sequences_and_iterators.cpp revision 14299
111986Sandreas.sandberg@arm.com/* 211986Sandreas.sandberg@arm.com tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators, 311986Sandreas.sandberg@arm.com etc. 411986Sandreas.sandberg@arm.com 511986Sandreas.sandberg@arm.com Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> 611986Sandreas.sandberg@arm.com 711986Sandreas.sandberg@arm.com All rights reserved. Use of this source code is governed by a 811986Sandreas.sandberg@arm.com BSD-style license that can be found in the LICENSE file. 911986Sandreas.sandberg@arm.com*/ 1011986Sandreas.sandberg@arm.com 1111986Sandreas.sandberg@arm.com#include "pybind11_tests.h" 1211986Sandreas.sandberg@arm.com#include "constructor_stats.h" 1311986Sandreas.sandberg@arm.com#include <pybind11/operators.h> 1411986Sandreas.sandberg@arm.com#include <pybind11/stl.h> 1511986Sandreas.sandberg@arm.com 1611986Sandreas.sandberg@arm.comtemplate<typename T> 1711986Sandreas.sandberg@arm.comclass NonZeroIterator { 1811986Sandreas.sandberg@arm.com const T* ptr_; 1911986Sandreas.sandberg@arm.compublic: 2011986Sandreas.sandberg@arm.com NonZeroIterator(const T* ptr) : ptr_(ptr) {} 2111986Sandreas.sandberg@arm.com const T& operator*() const { return *ptr_; } 2211986Sandreas.sandberg@arm.com NonZeroIterator& operator++() { ++ptr_; return *this; } 2311986Sandreas.sandberg@arm.com}; 2411986Sandreas.sandberg@arm.com 2511986Sandreas.sandberg@arm.comclass NonZeroSentinel {}; 2611986Sandreas.sandberg@arm.com 2711986Sandreas.sandberg@arm.comtemplate<typename A, typename B> 2811986Sandreas.sandberg@arm.combool operator==(const NonZeroIterator<std::pair<A, B>>& it, const NonZeroSentinel&) { 2911986Sandreas.sandberg@arm.com return !(*it).first || !(*it).second; 3011986Sandreas.sandberg@arm.com} 3111986Sandreas.sandberg@arm.com 3212037Sandreas.sandberg@arm.comtemplate <typename PythonType> 3312037Sandreas.sandberg@arm.compy::list test_random_access_iterator(PythonType x) { 3412037Sandreas.sandberg@arm.com if (x.size() < 5) 3512037Sandreas.sandberg@arm.com throw py::value_error("Please provide at least 5 elements for testing."); 3612037Sandreas.sandberg@arm.com 3712037Sandreas.sandberg@arm.com auto checks = py::list(); 3812037Sandreas.sandberg@arm.com auto assert_equal = [&checks](py::handle a, py::handle b) { 3912037Sandreas.sandberg@arm.com auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ); 4012037Sandreas.sandberg@arm.com if (result == -1) { throw py::error_already_set(); } 4112037Sandreas.sandberg@arm.com checks.append(result != 0); 4212037Sandreas.sandberg@arm.com }; 4312037Sandreas.sandberg@arm.com 4412037Sandreas.sandberg@arm.com auto it = x.begin(); 4512037Sandreas.sandberg@arm.com assert_equal(x[0], *it); 4612037Sandreas.sandberg@arm.com assert_equal(x[0], it[0]); 4712037Sandreas.sandberg@arm.com assert_equal(x[1], it[1]); 4812037Sandreas.sandberg@arm.com 4912037Sandreas.sandberg@arm.com assert_equal(x[1], *(++it)); 5012037Sandreas.sandberg@arm.com assert_equal(x[1], *(it++)); 5112037Sandreas.sandberg@arm.com assert_equal(x[2], *it); 5212037Sandreas.sandberg@arm.com assert_equal(x[3], *(it += 1)); 5312037Sandreas.sandberg@arm.com assert_equal(x[2], *(--it)); 5412037Sandreas.sandberg@arm.com assert_equal(x[2], *(it--)); 5512037Sandreas.sandberg@arm.com assert_equal(x[1], *it); 5612037Sandreas.sandberg@arm.com assert_equal(x[0], *(it -= 1)); 5712037Sandreas.sandberg@arm.com 5812037Sandreas.sandberg@arm.com assert_equal(it->attr("real"), x[0].attr("real")); 5912037Sandreas.sandberg@arm.com assert_equal((it + 1)->attr("real"), x[1].attr("real")); 6012037Sandreas.sandberg@arm.com 6112037Sandreas.sandberg@arm.com assert_equal(x[1], *(it + 1)); 6212037Sandreas.sandberg@arm.com assert_equal(x[1], *(1 + it)); 6312037Sandreas.sandberg@arm.com it += 3; 6412037Sandreas.sandberg@arm.com assert_equal(x[1], *(it - 2)); 6512037Sandreas.sandberg@arm.com 6612037Sandreas.sandberg@arm.com checks.append(static_cast<std::size_t>(x.end() - x.begin()) == x.size()); 6712037Sandreas.sandberg@arm.com checks.append((x.begin() + static_cast<std::ptrdiff_t>(x.size())) == x.end()); 6812037Sandreas.sandberg@arm.com checks.append(x.begin() < x.end()); 6912037Sandreas.sandberg@arm.com 7012037Sandreas.sandberg@arm.com return checks; 7112037Sandreas.sandberg@arm.com} 7212037Sandreas.sandberg@arm.com 7312391Sjason@lowepower.comTEST_SUBMODULE(sequences_and_iterators, m) { 7414299Sbbruce@ucdavis.edu // test_sliceable 7514299Sbbruce@ucdavis.edu class Sliceable{ 7614299Sbbruce@ucdavis.edu public: 7714299Sbbruce@ucdavis.edu Sliceable(int n): size(n) {} 7814299Sbbruce@ucdavis.edu int start,stop,step; 7914299Sbbruce@ucdavis.edu int size; 8014299Sbbruce@ucdavis.edu }; 8114299Sbbruce@ucdavis.edu py::class_<Sliceable>(m,"Sliceable") 8214299Sbbruce@ucdavis.edu .def(py::init<int>()) 8314299Sbbruce@ucdavis.edu .def("__getitem__",[](const Sliceable &s, py::slice slice) { 8414299Sbbruce@ucdavis.edu ssize_t start, stop, step, slicelength; 8514299Sbbruce@ucdavis.edu if (!slice.compute(s.size, &start, &stop, &step, &slicelength)) 8614299Sbbruce@ucdavis.edu throw py::error_already_set(); 8714299Sbbruce@ucdavis.edu int istart = static_cast<int>(start); 8814299Sbbruce@ucdavis.edu int istop = static_cast<int>(stop); 8914299Sbbruce@ucdavis.edu int istep = static_cast<int>(step); 9014299Sbbruce@ucdavis.edu return std::make_tuple(istart,istop,istep); 9114299Sbbruce@ucdavis.edu }) 9214299Sbbruce@ucdavis.edu ; 9311986Sandreas.sandberg@arm.com 9412391Sjason@lowepower.com // test_sequence 9512391Sjason@lowepower.com class Sequence { 9612391Sjason@lowepower.com public: 9712391Sjason@lowepower.com Sequence(size_t size) : m_size(size) { 9812391Sjason@lowepower.com print_created(this, "of size", m_size); 9912391Sjason@lowepower.com m_data = new float[size]; 10012391Sjason@lowepower.com memset(m_data, 0, sizeof(float) * size); 10112391Sjason@lowepower.com } 10212391Sjason@lowepower.com Sequence(const std::vector<float> &value) : m_size(value.size()) { 10312391Sjason@lowepower.com print_created(this, "of size", m_size, "from std::vector"); 10412391Sjason@lowepower.com m_data = new float[m_size]; 10512391Sjason@lowepower.com memcpy(m_data, &value[0], sizeof(float) * m_size); 10612391Sjason@lowepower.com } 10712391Sjason@lowepower.com Sequence(const Sequence &s) : m_size(s.m_size) { 10812391Sjason@lowepower.com print_copy_created(this); 10912391Sjason@lowepower.com m_data = new float[m_size]; 11012391Sjason@lowepower.com memcpy(m_data, s.m_data, sizeof(float)*m_size); 11112391Sjason@lowepower.com } 11212391Sjason@lowepower.com Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) { 11312391Sjason@lowepower.com print_move_created(this); 11412391Sjason@lowepower.com s.m_size = 0; 11512391Sjason@lowepower.com s.m_data = nullptr; 11612391Sjason@lowepower.com } 11711986Sandreas.sandberg@arm.com 11812391Sjason@lowepower.com ~Sequence() { print_destroyed(this); delete[] m_data; } 11912391Sjason@lowepower.com 12012391Sjason@lowepower.com Sequence &operator=(const Sequence &s) { 12112391Sjason@lowepower.com if (&s != this) { 12212391Sjason@lowepower.com delete[] m_data; 12312391Sjason@lowepower.com m_size = s.m_size; 12412391Sjason@lowepower.com m_data = new float[m_size]; 12512391Sjason@lowepower.com memcpy(m_data, s.m_data, sizeof(float)*m_size); 12612391Sjason@lowepower.com } 12712391Sjason@lowepower.com print_copy_assigned(this); 12812391Sjason@lowepower.com return *this; 12912391Sjason@lowepower.com } 13012391Sjason@lowepower.com 13112391Sjason@lowepower.com Sequence &operator=(Sequence &&s) { 13212391Sjason@lowepower.com if (&s != this) { 13312391Sjason@lowepower.com delete[] m_data; 13412391Sjason@lowepower.com m_size = s.m_size; 13512391Sjason@lowepower.com m_data = s.m_data; 13612391Sjason@lowepower.com s.m_size = 0; 13712391Sjason@lowepower.com s.m_data = nullptr; 13812391Sjason@lowepower.com } 13912391Sjason@lowepower.com print_move_assigned(this); 14012391Sjason@lowepower.com return *this; 14112391Sjason@lowepower.com } 14212391Sjason@lowepower.com 14312391Sjason@lowepower.com bool operator==(const Sequence &s) const { 14412391Sjason@lowepower.com if (m_size != s.size()) return false; 14512391Sjason@lowepower.com for (size_t i = 0; i < m_size; ++i) 14612391Sjason@lowepower.com if (m_data[i] != s[i]) 14712391Sjason@lowepower.com return false; 14812391Sjason@lowepower.com return true; 14912391Sjason@lowepower.com } 15012391Sjason@lowepower.com bool operator!=(const Sequence &s) const { return !operator==(s); } 15112391Sjason@lowepower.com 15212391Sjason@lowepower.com float operator[](size_t index) const { return m_data[index]; } 15312391Sjason@lowepower.com float &operator[](size_t index) { return m_data[index]; } 15412391Sjason@lowepower.com 15512391Sjason@lowepower.com bool contains(float v) const { 15612391Sjason@lowepower.com for (size_t i = 0; i < m_size; ++i) 15712391Sjason@lowepower.com if (v == m_data[i]) 15812391Sjason@lowepower.com return true; 15912391Sjason@lowepower.com return false; 16012391Sjason@lowepower.com } 16112391Sjason@lowepower.com 16212391Sjason@lowepower.com Sequence reversed() const { 16312391Sjason@lowepower.com Sequence result(m_size); 16412391Sjason@lowepower.com for (size_t i = 0; i < m_size; ++i) 16512391Sjason@lowepower.com result[m_size - i - 1] = m_data[i]; 16612391Sjason@lowepower.com return result; 16712391Sjason@lowepower.com } 16812391Sjason@lowepower.com 16912391Sjason@lowepower.com size_t size() const { return m_size; } 17012391Sjason@lowepower.com 17112391Sjason@lowepower.com const float *begin() const { return m_data; } 17212391Sjason@lowepower.com const float *end() const { return m_data+m_size; } 17312391Sjason@lowepower.com 17412391Sjason@lowepower.com private: 17512391Sjason@lowepower.com size_t m_size; 17612391Sjason@lowepower.com float *m_data; 17712391Sjason@lowepower.com }; 17812391Sjason@lowepower.com py::class_<Sequence>(m, "Sequence") 17912391Sjason@lowepower.com .def(py::init<size_t>()) 18012391Sjason@lowepower.com .def(py::init<const std::vector<float>&>()) 18112391Sjason@lowepower.com /// Bare bones interface 18212391Sjason@lowepower.com .def("__getitem__", [](const Sequence &s, size_t i) { 18312391Sjason@lowepower.com if (i >= s.size()) throw py::index_error(); 18411986Sandreas.sandberg@arm.com return s[i]; 18511986Sandreas.sandberg@arm.com }) 18612391Sjason@lowepower.com .def("__setitem__", [](Sequence &s, size_t i, float v) { 18712391Sjason@lowepower.com if (i >= s.size()) throw py::index_error(); 18811986Sandreas.sandberg@arm.com s[i] = v; 18911986Sandreas.sandberg@arm.com }) 19012391Sjason@lowepower.com .def("__len__", &Sequence::size) 19112391Sjason@lowepower.com /// Optional sequence protocol operations 19212391Sjason@lowepower.com .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, 19312391Sjason@lowepower.com py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) 19412391Sjason@lowepower.com .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); }) 19512391Sjason@lowepower.com .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) 19612391Sjason@lowepower.com /// Slicing protocol (optional) 19712391Sjason@lowepower.com .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* { 19811986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 19911986Sandreas.sandberg@arm.com if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) 20011986Sandreas.sandberg@arm.com throw py::error_already_set(); 20111986Sandreas.sandberg@arm.com Sequence *seq = new Sequence(slicelength); 20212391Sjason@lowepower.com for (size_t i = 0; i < slicelength; ++i) { 20311986Sandreas.sandberg@arm.com (*seq)[i] = s[start]; start += step; 20411986Sandreas.sandberg@arm.com } 20511986Sandreas.sandberg@arm.com return seq; 20611986Sandreas.sandberg@arm.com }) 20712391Sjason@lowepower.com .def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) { 20811986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 20911986Sandreas.sandberg@arm.com if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) 21011986Sandreas.sandberg@arm.com throw py::error_already_set(); 21111986Sandreas.sandberg@arm.com if (slicelength != value.size()) 21211986Sandreas.sandberg@arm.com throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); 21312391Sjason@lowepower.com for (size_t i = 0; i < slicelength; ++i) { 21411986Sandreas.sandberg@arm.com s[start] = value[i]; start += step; 21511986Sandreas.sandberg@arm.com } 21611986Sandreas.sandberg@arm.com }) 21712391Sjason@lowepower.com /// Comparisons 21812391Sjason@lowepower.com .def(py::self == py::self) 21912391Sjason@lowepower.com .def(py::self != py::self) 22012391Sjason@lowepower.com // Could also define py::self + py::self for concatenation, etc. 22112391Sjason@lowepower.com ; 22211986Sandreas.sandberg@arm.com 22312391Sjason@lowepower.com // test_map_iterator 22412391Sjason@lowepower.com // Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic 22512391Sjason@lowepower.com // map-like functionality. 22612391Sjason@lowepower.com class StringMap { 22712391Sjason@lowepower.com public: 22812391Sjason@lowepower.com StringMap() = default; 22912391Sjason@lowepower.com StringMap(std::unordered_map<std::string, std::string> init) 23012391Sjason@lowepower.com : map(std::move(init)) {} 23111986Sandreas.sandberg@arm.com 23212391Sjason@lowepower.com void set(std::string key, std::string val) { map[key] = val; } 23312391Sjason@lowepower.com std::string get(std::string key) const { return map.at(key); } 23412391Sjason@lowepower.com size_t size() const { return map.size(); } 23512391Sjason@lowepower.com private: 23612391Sjason@lowepower.com std::unordered_map<std::string, std::string> map; 23712391Sjason@lowepower.com public: 23812391Sjason@lowepower.com decltype(map.cbegin()) begin() const { return map.cbegin(); } 23912391Sjason@lowepower.com decltype(map.cend()) end() const { return map.cend(); } 24012391Sjason@lowepower.com }; 24112391Sjason@lowepower.com py::class_<StringMap>(m, "StringMap") 24212391Sjason@lowepower.com .def(py::init<>()) 24311986Sandreas.sandberg@arm.com .def(py::init<std::unordered_map<std::string, std::string>>()) 24411986Sandreas.sandberg@arm.com .def("__getitem__", [](const StringMap &map, std::string key) { 24511986Sandreas.sandberg@arm.com try { return map.get(key); } 24611986Sandreas.sandberg@arm.com catch (const std::out_of_range&) { 24711986Sandreas.sandberg@arm.com throw py::key_error("key '" + key + "' does not exist"); 24811986Sandreas.sandberg@arm.com } 24912391Sjason@lowepower.com }) 25011986Sandreas.sandberg@arm.com .def("__setitem__", &StringMap::set) 25111986Sandreas.sandberg@arm.com .def("__len__", &StringMap::size) 25211986Sandreas.sandberg@arm.com .def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); }, 25311986Sandreas.sandberg@arm.com py::keep_alive<0, 1>()) 25411986Sandreas.sandberg@arm.com .def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); }, 25511986Sandreas.sandberg@arm.com py::keep_alive<0, 1>()) 25611986Sandreas.sandberg@arm.com ; 25711986Sandreas.sandberg@arm.com 25812391Sjason@lowepower.com // test_generalized_iterators 25912391Sjason@lowepower.com class IntPairs { 26012391Sjason@lowepower.com public: 26112391Sjason@lowepower.com IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {} 26212391Sjason@lowepower.com const std::pair<int, int>* begin() const { return data_.data(); } 26312391Sjason@lowepower.com private: 26412391Sjason@lowepower.com std::vector<std::pair<int, int>> data_; 26512391Sjason@lowepower.com }; 26611986Sandreas.sandberg@arm.com py::class_<IntPairs>(m, "IntPairs") 26711986Sandreas.sandberg@arm.com .def(py::init<std::vector<std::pair<int, int>>>()) 26811986Sandreas.sandberg@arm.com .def("nonzero", [](const IntPairs& s) { 26911986Sandreas.sandberg@arm.com return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel()); 27012391Sjason@lowepower.com }, py::keep_alive<0, 1>()) 27111986Sandreas.sandberg@arm.com .def("nonzero_keys", [](const IntPairs& s) { 27211986Sandreas.sandberg@arm.com return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel()); 27312391Sjason@lowepower.com }, py::keep_alive<0, 1>()) 27412391Sjason@lowepower.com ; 27511986Sandreas.sandberg@arm.com 27611986Sandreas.sandberg@arm.com 27711986Sandreas.sandberg@arm.com#if 0 27811986Sandreas.sandberg@arm.com // Obsolete: special data structure for exposing custom iterator types to python 27911986Sandreas.sandberg@arm.com // kept here for illustrative purposes because there might be some use cases which 28011986Sandreas.sandberg@arm.com // are not covered by the much simpler py::make_iterator 28111986Sandreas.sandberg@arm.com 28211986Sandreas.sandberg@arm.com struct PySequenceIterator { 28311986Sandreas.sandberg@arm.com PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { } 28411986Sandreas.sandberg@arm.com 28511986Sandreas.sandberg@arm.com float next() { 28611986Sandreas.sandberg@arm.com if (index == seq.size()) 28711986Sandreas.sandberg@arm.com throw py::stop_iteration(); 28811986Sandreas.sandberg@arm.com return seq[index++]; 28911986Sandreas.sandberg@arm.com } 29011986Sandreas.sandberg@arm.com 29111986Sandreas.sandberg@arm.com const Sequence &seq; 29211986Sandreas.sandberg@arm.com py::object ref; // keep a reference 29311986Sandreas.sandberg@arm.com size_t index = 0; 29411986Sandreas.sandberg@arm.com }; 29511986Sandreas.sandberg@arm.com 29611986Sandreas.sandberg@arm.com py::class_<PySequenceIterator>(seq, "Iterator") 29711986Sandreas.sandberg@arm.com .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; }) 29811986Sandreas.sandberg@arm.com .def("__next__", &PySequenceIterator::next); 29911986Sandreas.sandberg@arm.com 30011986Sandreas.sandberg@arm.com On the actual Sequence object, the iterator would be constructed as follows: 30111986Sandreas.sandberg@arm.com .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); }) 30211986Sandreas.sandberg@arm.com#endif 30312037Sandreas.sandberg@arm.com 30412391Sjason@lowepower.com // test_python_iterator_in_cpp 30512037Sandreas.sandberg@arm.com m.def("object_to_list", [](py::object o) { 30612037Sandreas.sandberg@arm.com auto l = py::list(); 30712037Sandreas.sandberg@arm.com for (auto item : o) { 30812037Sandreas.sandberg@arm.com l.append(item); 30912037Sandreas.sandberg@arm.com } 31012037Sandreas.sandberg@arm.com return l; 31112037Sandreas.sandberg@arm.com }); 31212037Sandreas.sandberg@arm.com 31312037Sandreas.sandberg@arm.com m.def("iterator_to_list", [](py::iterator it) { 31412037Sandreas.sandberg@arm.com auto l = py::list(); 31512037Sandreas.sandberg@arm.com while (it != py::iterator::sentinel()) { 31612037Sandreas.sandberg@arm.com l.append(*it); 31712037Sandreas.sandberg@arm.com ++it; 31812037Sandreas.sandberg@arm.com } 31912037Sandreas.sandberg@arm.com return l; 32012037Sandreas.sandberg@arm.com }); 32112037Sandreas.sandberg@arm.com 32212037Sandreas.sandberg@arm.com // Make sure that py::iterator works with std algorithms 32312037Sandreas.sandberg@arm.com m.def("count_none", [](py::object o) { 32412037Sandreas.sandberg@arm.com return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); 32512037Sandreas.sandberg@arm.com }); 32612037Sandreas.sandberg@arm.com 32712037Sandreas.sandberg@arm.com m.def("find_none", [](py::object o) { 32812037Sandreas.sandberg@arm.com auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); 32912037Sandreas.sandberg@arm.com return it->is_none(); 33012037Sandreas.sandberg@arm.com }); 33112037Sandreas.sandberg@arm.com 33212037Sandreas.sandberg@arm.com m.def("count_nonzeros", [](py::dict d) { 33312037Sandreas.sandberg@arm.com return std::count_if(d.begin(), d.end(), [](std::pair<py::handle, py::handle> p) { 33412037Sandreas.sandberg@arm.com return p.second.cast<int>() != 0; 33512037Sandreas.sandberg@arm.com }); 33612037Sandreas.sandberg@arm.com }); 33712037Sandreas.sandberg@arm.com 33812391Sjason@lowepower.com m.def("tuple_iterator", &test_random_access_iterator<py::tuple>); 33912391Sjason@lowepower.com m.def("list_iterator", &test_random_access_iterator<py::list>); 34012391Sjason@lowepower.com m.def("sequence_iterator", &test_random_access_iterator<py::sequence>); 34112391Sjason@lowepower.com 34212391Sjason@lowepower.com // test_iterator_passthrough 34312391Sjason@lowepower.com // #181: iterator passthrough did not compile 34412391Sjason@lowepower.com m.def("iterator_passthrough", [](py::iterator s) -> py::iterator { 34512391Sjason@lowepower.com return py::make_iterator(std::begin(s), std::end(s)); 34612391Sjason@lowepower.com }); 34712391Sjason@lowepower.com 34812391Sjason@lowepower.com // test_iterator_rvp 34912391Sjason@lowepower.com // #388: Can't make iterators via make_iterator() with different r/v policies 35012391Sjason@lowepower.com static std::vector<int> list = { 1, 2, 3 }; 35112391Sjason@lowepower.com m.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); }); 35212391Sjason@lowepower.com m.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); }); 35312391Sjason@lowepower.com} 354