test_sequences_and_iterators.cpp revision 12037
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.comclass Sequence { 1711986Sandreas.sandberg@arm.compublic: 1811986Sandreas.sandberg@arm.com Sequence(size_t size) : m_size(size) { 1911986Sandreas.sandberg@arm.com print_created(this, "of size", m_size); 2011986Sandreas.sandberg@arm.com m_data = new float[size]; 2111986Sandreas.sandberg@arm.com memset(m_data, 0, sizeof(float) * size); 2211986Sandreas.sandberg@arm.com } 2311986Sandreas.sandberg@arm.com 2411986Sandreas.sandberg@arm.com Sequence(const std::vector<float> &value) : m_size(value.size()) { 2511986Sandreas.sandberg@arm.com print_created(this, "of size", m_size, "from std::vector"); 2611986Sandreas.sandberg@arm.com m_data = new float[m_size]; 2711986Sandreas.sandberg@arm.com memcpy(m_data, &value[0], sizeof(float) * m_size); 2811986Sandreas.sandberg@arm.com } 2911986Sandreas.sandberg@arm.com 3011986Sandreas.sandberg@arm.com Sequence(const Sequence &s) : m_size(s.m_size) { 3111986Sandreas.sandberg@arm.com print_copy_created(this); 3211986Sandreas.sandberg@arm.com m_data = new float[m_size]; 3311986Sandreas.sandberg@arm.com memcpy(m_data, s.m_data, sizeof(float)*m_size); 3411986Sandreas.sandberg@arm.com } 3511986Sandreas.sandberg@arm.com 3611986Sandreas.sandberg@arm.com Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) { 3711986Sandreas.sandberg@arm.com print_move_created(this); 3811986Sandreas.sandberg@arm.com s.m_size = 0; 3911986Sandreas.sandberg@arm.com s.m_data = nullptr; 4011986Sandreas.sandberg@arm.com } 4111986Sandreas.sandberg@arm.com 4211986Sandreas.sandberg@arm.com ~Sequence() { 4311986Sandreas.sandberg@arm.com print_destroyed(this); 4411986Sandreas.sandberg@arm.com delete[] m_data; 4511986Sandreas.sandberg@arm.com } 4611986Sandreas.sandberg@arm.com 4711986Sandreas.sandberg@arm.com Sequence &operator=(const Sequence &s) { 4811986Sandreas.sandberg@arm.com if (&s != this) { 4911986Sandreas.sandberg@arm.com delete[] m_data; 5011986Sandreas.sandberg@arm.com m_size = s.m_size; 5111986Sandreas.sandberg@arm.com m_data = new float[m_size]; 5211986Sandreas.sandberg@arm.com memcpy(m_data, s.m_data, sizeof(float)*m_size); 5311986Sandreas.sandberg@arm.com } 5411986Sandreas.sandberg@arm.com 5511986Sandreas.sandberg@arm.com print_copy_assigned(this); 5611986Sandreas.sandberg@arm.com 5711986Sandreas.sandberg@arm.com return *this; 5811986Sandreas.sandberg@arm.com } 5911986Sandreas.sandberg@arm.com 6011986Sandreas.sandberg@arm.com Sequence &operator=(Sequence &&s) { 6111986Sandreas.sandberg@arm.com if (&s != this) { 6211986Sandreas.sandberg@arm.com delete[] m_data; 6311986Sandreas.sandberg@arm.com m_size = s.m_size; 6411986Sandreas.sandberg@arm.com m_data = s.m_data; 6511986Sandreas.sandberg@arm.com s.m_size = 0; 6611986Sandreas.sandberg@arm.com s.m_data = nullptr; 6711986Sandreas.sandberg@arm.com } 6811986Sandreas.sandberg@arm.com 6911986Sandreas.sandberg@arm.com print_move_assigned(this); 7011986Sandreas.sandberg@arm.com 7111986Sandreas.sandberg@arm.com return *this; 7211986Sandreas.sandberg@arm.com } 7311986Sandreas.sandberg@arm.com 7411986Sandreas.sandberg@arm.com bool operator==(const Sequence &s) const { 7511986Sandreas.sandberg@arm.com if (m_size != s.size()) 7611986Sandreas.sandberg@arm.com return false; 7711986Sandreas.sandberg@arm.com for (size_t i=0; i<m_size; ++i) 7811986Sandreas.sandberg@arm.com if (m_data[i] != s[i]) 7911986Sandreas.sandberg@arm.com return false; 8011986Sandreas.sandberg@arm.com return true; 8111986Sandreas.sandberg@arm.com } 8211986Sandreas.sandberg@arm.com 8311986Sandreas.sandberg@arm.com bool operator!=(const Sequence &s) const { 8411986Sandreas.sandberg@arm.com return !operator==(s); 8511986Sandreas.sandberg@arm.com } 8611986Sandreas.sandberg@arm.com 8711986Sandreas.sandberg@arm.com float operator[](size_t index) const { 8811986Sandreas.sandberg@arm.com return m_data[index]; 8911986Sandreas.sandberg@arm.com } 9011986Sandreas.sandberg@arm.com 9111986Sandreas.sandberg@arm.com float &operator[](size_t index) { 9211986Sandreas.sandberg@arm.com return m_data[index]; 9311986Sandreas.sandberg@arm.com } 9411986Sandreas.sandberg@arm.com 9511986Sandreas.sandberg@arm.com bool contains(float v) const { 9611986Sandreas.sandberg@arm.com for (size_t i=0; i<m_size; ++i) 9711986Sandreas.sandberg@arm.com if (v == m_data[i]) 9811986Sandreas.sandberg@arm.com return true; 9911986Sandreas.sandberg@arm.com return false; 10011986Sandreas.sandberg@arm.com } 10111986Sandreas.sandberg@arm.com 10211986Sandreas.sandberg@arm.com Sequence reversed() const { 10311986Sandreas.sandberg@arm.com Sequence result(m_size); 10411986Sandreas.sandberg@arm.com for (size_t i=0; i<m_size; ++i) 10511986Sandreas.sandberg@arm.com result[m_size-i-1] = m_data[i]; 10611986Sandreas.sandberg@arm.com return result; 10711986Sandreas.sandberg@arm.com } 10811986Sandreas.sandberg@arm.com 10911986Sandreas.sandberg@arm.com size_t size() const { return m_size; } 11011986Sandreas.sandberg@arm.com 11111986Sandreas.sandberg@arm.com const float *begin() const { return m_data; } 11211986Sandreas.sandberg@arm.com const float *end() const { return m_data+m_size; } 11311986Sandreas.sandberg@arm.com 11411986Sandreas.sandberg@arm.comprivate: 11511986Sandreas.sandberg@arm.com size_t m_size; 11611986Sandreas.sandberg@arm.com float *m_data; 11711986Sandreas.sandberg@arm.com}; 11811986Sandreas.sandberg@arm.com 11911986Sandreas.sandberg@arm.comclass IntPairs { 12011986Sandreas.sandberg@arm.compublic: 12111986Sandreas.sandberg@arm.com IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {} 12211986Sandreas.sandberg@arm.com const std::pair<int, int>* begin() const { return data_.data(); } 12311986Sandreas.sandberg@arm.com 12411986Sandreas.sandberg@arm.comprivate: 12511986Sandreas.sandberg@arm.com std::vector<std::pair<int, int>> data_; 12611986Sandreas.sandberg@arm.com}; 12711986Sandreas.sandberg@arm.com 12811986Sandreas.sandberg@arm.com// Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic 12911986Sandreas.sandberg@arm.com// map-like functionality. 13011986Sandreas.sandberg@arm.comclass StringMap { 13111986Sandreas.sandberg@arm.compublic: 13211986Sandreas.sandberg@arm.com StringMap() = default; 13311986Sandreas.sandberg@arm.com StringMap(std::unordered_map<std::string, std::string> init) 13411986Sandreas.sandberg@arm.com : map(std::move(init)) {} 13511986Sandreas.sandberg@arm.com 13611986Sandreas.sandberg@arm.com void set(std::string key, std::string val) { 13711986Sandreas.sandberg@arm.com map[key] = val; 13811986Sandreas.sandberg@arm.com } 13911986Sandreas.sandberg@arm.com 14011986Sandreas.sandberg@arm.com std::string get(std::string key) const { 14111986Sandreas.sandberg@arm.com return map.at(key); 14211986Sandreas.sandberg@arm.com } 14311986Sandreas.sandberg@arm.com 14411986Sandreas.sandberg@arm.com size_t size() const { 14511986Sandreas.sandberg@arm.com return map.size(); 14611986Sandreas.sandberg@arm.com } 14711986Sandreas.sandberg@arm.com 14811986Sandreas.sandberg@arm.comprivate: 14911986Sandreas.sandberg@arm.com std::unordered_map<std::string, std::string> map; 15011986Sandreas.sandberg@arm.com 15111986Sandreas.sandberg@arm.compublic: 15211986Sandreas.sandberg@arm.com decltype(map.cbegin()) begin() const { return map.cbegin(); } 15311986Sandreas.sandberg@arm.com decltype(map.cend()) end() const { return map.cend(); } 15411986Sandreas.sandberg@arm.com}; 15511986Sandreas.sandberg@arm.com 15611986Sandreas.sandberg@arm.comtemplate<typename T> 15711986Sandreas.sandberg@arm.comclass NonZeroIterator { 15811986Sandreas.sandberg@arm.com const T* ptr_; 15911986Sandreas.sandberg@arm.compublic: 16011986Sandreas.sandberg@arm.com NonZeroIterator(const T* ptr) : ptr_(ptr) {} 16111986Sandreas.sandberg@arm.com const T& operator*() const { return *ptr_; } 16211986Sandreas.sandberg@arm.com NonZeroIterator& operator++() { ++ptr_; return *this; } 16311986Sandreas.sandberg@arm.com}; 16411986Sandreas.sandberg@arm.com 16511986Sandreas.sandberg@arm.comclass NonZeroSentinel {}; 16611986Sandreas.sandberg@arm.com 16711986Sandreas.sandberg@arm.comtemplate<typename A, typename B> 16811986Sandreas.sandberg@arm.combool operator==(const NonZeroIterator<std::pair<A, B>>& it, const NonZeroSentinel&) { 16911986Sandreas.sandberg@arm.com return !(*it).first || !(*it).second; 17011986Sandreas.sandberg@arm.com} 17111986Sandreas.sandberg@arm.com 17212037Sandreas.sandberg@arm.comtemplate <typename PythonType> 17312037Sandreas.sandberg@arm.compy::list test_random_access_iterator(PythonType x) { 17412037Sandreas.sandberg@arm.com if (x.size() < 5) 17512037Sandreas.sandberg@arm.com throw py::value_error("Please provide at least 5 elements for testing."); 17612037Sandreas.sandberg@arm.com 17712037Sandreas.sandberg@arm.com auto checks = py::list(); 17812037Sandreas.sandberg@arm.com auto assert_equal = [&checks](py::handle a, py::handle b) { 17912037Sandreas.sandberg@arm.com auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ); 18012037Sandreas.sandberg@arm.com if (result == -1) { throw py::error_already_set(); } 18112037Sandreas.sandberg@arm.com checks.append(result != 0); 18212037Sandreas.sandberg@arm.com }; 18312037Sandreas.sandberg@arm.com 18412037Sandreas.sandberg@arm.com auto it = x.begin(); 18512037Sandreas.sandberg@arm.com assert_equal(x[0], *it); 18612037Sandreas.sandberg@arm.com assert_equal(x[0], it[0]); 18712037Sandreas.sandberg@arm.com assert_equal(x[1], it[1]); 18812037Sandreas.sandberg@arm.com 18912037Sandreas.sandberg@arm.com assert_equal(x[1], *(++it)); 19012037Sandreas.sandberg@arm.com assert_equal(x[1], *(it++)); 19112037Sandreas.sandberg@arm.com assert_equal(x[2], *it); 19212037Sandreas.sandberg@arm.com assert_equal(x[3], *(it += 1)); 19312037Sandreas.sandberg@arm.com assert_equal(x[2], *(--it)); 19412037Sandreas.sandberg@arm.com assert_equal(x[2], *(it--)); 19512037Sandreas.sandberg@arm.com assert_equal(x[1], *it); 19612037Sandreas.sandberg@arm.com assert_equal(x[0], *(it -= 1)); 19712037Sandreas.sandberg@arm.com 19812037Sandreas.sandberg@arm.com assert_equal(it->attr("real"), x[0].attr("real")); 19912037Sandreas.sandberg@arm.com assert_equal((it + 1)->attr("real"), x[1].attr("real")); 20012037Sandreas.sandberg@arm.com 20112037Sandreas.sandberg@arm.com assert_equal(x[1], *(it + 1)); 20212037Sandreas.sandberg@arm.com assert_equal(x[1], *(1 + it)); 20312037Sandreas.sandberg@arm.com it += 3; 20412037Sandreas.sandberg@arm.com assert_equal(x[1], *(it - 2)); 20512037Sandreas.sandberg@arm.com 20612037Sandreas.sandberg@arm.com checks.append(static_cast<std::size_t>(x.end() - x.begin()) == x.size()); 20712037Sandreas.sandberg@arm.com checks.append((x.begin() + static_cast<std::ptrdiff_t>(x.size())) == x.end()); 20812037Sandreas.sandberg@arm.com checks.append(x.begin() < x.end()); 20912037Sandreas.sandberg@arm.com 21012037Sandreas.sandberg@arm.com return checks; 21112037Sandreas.sandberg@arm.com} 21212037Sandreas.sandberg@arm.com 21312037Sandreas.sandberg@arm.comtest_initializer sequences_and_iterators([](py::module &pm) { 21412037Sandreas.sandberg@arm.com auto m = pm.def_submodule("sequences_and_iterators"); 21511986Sandreas.sandberg@arm.com 21611986Sandreas.sandberg@arm.com py::class_<Sequence> seq(m, "Sequence"); 21711986Sandreas.sandberg@arm.com 21811986Sandreas.sandberg@arm.com seq.def(py::init<size_t>()) 21911986Sandreas.sandberg@arm.com .def(py::init<const std::vector<float>&>()) 22011986Sandreas.sandberg@arm.com /// Bare bones interface 22111986Sandreas.sandberg@arm.com .def("__getitem__", [](const Sequence &s, size_t i) { 22211986Sandreas.sandberg@arm.com if (i >= s.size()) 22311986Sandreas.sandberg@arm.com throw py::index_error(); 22411986Sandreas.sandberg@arm.com return s[i]; 22511986Sandreas.sandberg@arm.com }) 22611986Sandreas.sandberg@arm.com .def("__setitem__", [](Sequence &s, size_t i, float v) { 22711986Sandreas.sandberg@arm.com if (i >= s.size()) 22811986Sandreas.sandberg@arm.com throw py::index_error(); 22911986Sandreas.sandberg@arm.com s[i] = v; 23011986Sandreas.sandberg@arm.com }) 23111986Sandreas.sandberg@arm.com .def("__len__", &Sequence::size) 23211986Sandreas.sandberg@arm.com /// Optional sequence protocol operations 23311986Sandreas.sandberg@arm.com .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, 23411986Sandreas.sandberg@arm.com py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) 23511986Sandreas.sandberg@arm.com .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); }) 23611986Sandreas.sandberg@arm.com .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) 23711986Sandreas.sandberg@arm.com /// Slicing protocol (optional) 23811986Sandreas.sandberg@arm.com .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* { 23911986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 24011986Sandreas.sandberg@arm.com if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) 24111986Sandreas.sandberg@arm.com throw py::error_already_set(); 24211986Sandreas.sandberg@arm.com Sequence *seq = new Sequence(slicelength); 24311986Sandreas.sandberg@arm.com for (size_t i=0; i<slicelength; ++i) { 24411986Sandreas.sandberg@arm.com (*seq)[i] = s[start]; start += step; 24511986Sandreas.sandberg@arm.com } 24611986Sandreas.sandberg@arm.com return seq; 24711986Sandreas.sandberg@arm.com }) 24811986Sandreas.sandberg@arm.com .def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) { 24911986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 25011986Sandreas.sandberg@arm.com if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) 25111986Sandreas.sandberg@arm.com throw py::error_already_set(); 25211986Sandreas.sandberg@arm.com if (slicelength != value.size()) 25311986Sandreas.sandberg@arm.com throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); 25411986Sandreas.sandberg@arm.com for (size_t i=0; i<slicelength; ++i) { 25511986Sandreas.sandberg@arm.com s[start] = value[i]; start += step; 25611986Sandreas.sandberg@arm.com } 25711986Sandreas.sandberg@arm.com }) 25811986Sandreas.sandberg@arm.com /// Comparisons 25911986Sandreas.sandberg@arm.com .def(py::self == py::self) 26011986Sandreas.sandberg@arm.com .def(py::self != py::self); 26111986Sandreas.sandberg@arm.com // Could also define py::self + py::self for concatenation, etc. 26211986Sandreas.sandberg@arm.com 26311986Sandreas.sandberg@arm.com py::class_<StringMap> map(m, "StringMap"); 26411986Sandreas.sandberg@arm.com 26511986Sandreas.sandberg@arm.com map .def(py::init<>()) 26611986Sandreas.sandberg@arm.com .def(py::init<std::unordered_map<std::string, std::string>>()) 26711986Sandreas.sandberg@arm.com .def("__getitem__", [](const StringMap &map, std::string key) { 26811986Sandreas.sandberg@arm.com try { return map.get(key); } 26911986Sandreas.sandberg@arm.com catch (const std::out_of_range&) { 27011986Sandreas.sandberg@arm.com throw py::key_error("key '" + key + "' does not exist"); 27111986Sandreas.sandberg@arm.com } 27211986Sandreas.sandberg@arm.com }) 27311986Sandreas.sandberg@arm.com .def("__setitem__", &StringMap::set) 27411986Sandreas.sandberg@arm.com .def("__len__", &StringMap::size) 27511986Sandreas.sandberg@arm.com .def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); }, 27611986Sandreas.sandberg@arm.com py::keep_alive<0, 1>()) 27711986Sandreas.sandberg@arm.com .def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); }, 27811986Sandreas.sandberg@arm.com py::keep_alive<0, 1>()) 27911986Sandreas.sandberg@arm.com ; 28011986Sandreas.sandberg@arm.com 28111986Sandreas.sandberg@arm.com py::class_<IntPairs>(m, "IntPairs") 28211986Sandreas.sandberg@arm.com .def(py::init<std::vector<std::pair<int, int>>>()) 28311986Sandreas.sandberg@arm.com .def("nonzero", [](const IntPairs& s) { 28411986Sandreas.sandberg@arm.com return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel()); 28511986Sandreas.sandberg@arm.com }, py::keep_alive<0, 1>()) 28611986Sandreas.sandberg@arm.com .def("nonzero_keys", [](const IntPairs& s) { 28711986Sandreas.sandberg@arm.com return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel()); 28811986Sandreas.sandberg@arm.com }, py::keep_alive<0, 1>()); 28911986Sandreas.sandberg@arm.com 29011986Sandreas.sandberg@arm.com 29111986Sandreas.sandberg@arm.com#if 0 29211986Sandreas.sandberg@arm.com // Obsolete: special data structure for exposing custom iterator types to python 29311986Sandreas.sandberg@arm.com // kept here for illustrative purposes because there might be some use cases which 29411986Sandreas.sandberg@arm.com // are not covered by the much simpler py::make_iterator 29511986Sandreas.sandberg@arm.com 29611986Sandreas.sandberg@arm.com struct PySequenceIterator { 29711986Sandreas.sandberg@arm.com PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { } 29811986Sandreas.sandberg@arm.com 29911986Sandreas.sandberg@arm.com float next() { 30011986Sandreas.sandberg@arm.com if (index == seq.size()) 30111986Sandreas.sandberg@arm.com throw py::stop_iteration(); 30211986Sandreas.sandberg@arm.com return seq[index++]; 30311986Sandreas.sandberg@arm.com } 30411986Sandreas.sandberg@arm.com 30511986Sandreas.sandberg@arm.com const Sequence &seq; 30611986Sandreas.sandberg@arm.com py::object ref; // keep a reference 30711986Sandreas.sandberg@arm.com size_t index = 0; 30811986Sandreas.sandberg@arm.com }; 30911986Sandreas.sandberg@arm.com 31011986Sandreas.sandberg@arm.com py::class_<PySequenceIterator>(seq, "Iterator") 31111986Sandreas.sandberg@arm.com .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; }) 31211986Sandreas.sandberg@arm.com .def("__next__", &PySequenceIterator::next); 31311986Sandreas.sandberg@arm.com 31411986Sandreas.sandberg@arm.com On the actual Sequence object, the iterator would be constructed as follows: 31511986Sandreas.sandberg@arm.com .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); }) 31611986Sandreas.sandberg@arm.com#endif 31712037Sandreas.sandberg@arm.com 31812037Sandreas.sandberg@arm.com m.def("object_to_list", [](py::object o) { 31912037Sandreas.sandberg@arm.com auto l = py::list(); 32012037Sandreas.sandberg@arm.com for (auto item : o) { 32112037Sandreas.sandberg@arm.com l.append(item); 32212037Sandreas.sandberg@arm.com } 32312037Sandreas.sandberg@arm.com return l; 32412037Sandreas.sandberg@arm.com }); 32512037Sandreas.sandberg@arm.com 32612037Sandreas.sandberg@arm.com m.def("iterator_to_list", [](py::iterator it) { 32712037Sandreas.sandberg@arm.com auto l = py::list(); 32812037Sandreas.sandberg@arm.com while (it != py::iterator::sentinel()) { 32912037Sandreas.sandberg@arm.com l.append(*it); 33012037Sandreas.sandberg@arm.com ++it; 33112037Sandreas.sandberg@arm.com } 33212037Sandreas.sandberg@arm.com return l; 33312037Sandreas.sandberg@arm.com }); 33412037Sandreas.sandberg@arm.com 33512037Sandreas.sandberg@arm.com // Make sure that py::iterator works with std algorithms 33612037Sandreas.sandberg@arm.com m.def("count_none", [](py::object o) { 33712037Sandreas.sandberg@arm.com return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); 33812037Sandreas.sandberg@arm.com }); 33912037Sandreas.sandberg@arm.com 34012037Sandreas.sandberg@arm.com m.def("find_none", [](py::object o) { 34112037Sandreas.sandberg@arm.com auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); 34212037Sandreas.sandberg@arm.com return it->is_none(); 34312037Sandreas.sandberg@arm.com }); 34412037Sandreas.sandberg@arm.com 34512037Sandreas.sandberg@arm.com m.def("count_nonzeros", [](py::dict d) { 34612037Sandreas.sandberg@arm.com return std::count_if(d.begin(), d.end(), [](std::pair<py::handle, py::handle> p) { 34712037Sandreas.sandberg@arm.com return p.second.cast<int>() != 0; 34812037Sandreas.sandberg@arm.com }); 34912037Sandreas.sandberg@arm.com }); 35012037Sandreas.sandberg@arm.com 35112037Sandreas.sandberg@arm.com m.def("tuple_iterator", [](py::tuple x) { return test_random_access_iterator(x); }); 35212037Sandreas.sandberg@arm.com m.def("list_iterator", [](py::list x) { return test_random_access_iterator(x); }); 35312037Sandreas.sandberg@arm.com m.def("sequence_iterator", [](py::sequence x) { return test_random_access_iterator(x); }); 35411986Sandreas.sandberg@arm.com}); 355