111986Sandreas.sandberg@arm.com/* 211986Sandreas.sandberg@arm.com pybind11/std_bind.h: Binding generators for STL data types 311986Sandreas.sandberg@arm.com 411986Sandreas.sandberg@arm.com Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob 511986Sandreas.sandberg@arm.com 611986Sandreas.sandberg@arm.com All rights reserved. Use of this source code is governed by a 711986Sandreas.sandberg@arm.com BSD-style license that can be found in the LICENSE file. 811986Sandreas.sandberg@arm.com*/ 911986Sandreas.sandberg@arm.com 1011986Sandreas.sandberg@arm.com#pragma once 1111986Sandreas.sandberg@arm.com 1212391Sjason@lowepower.com#include "detail/common.h" 1311986Sandreas.sandberg@arm.com#include "operators.h" 1411986Sandreas.sandberg@arm.com 1511986Sandreas.sandberg@arm.com#include <algorithm> 1611986Sandreas.sandberg@arm.com#include <sstream> 1711986Sandreas.sandberg@arm.com 1812391Sjason@lowepower.comNAMESPACE_BEGIN(PYBIND11_NAMESPACE) 1911986Sandreas.sandberg@arm.comNAMESPACE_BEGIN(detail) 2011986Sandreas.sandberg@arm.com 2111986Sandreas.sandberg@arm.com/* SFINAE helper class used by 'is_comparable */ 2211986Sandreas.sandberg@arm.comtemplate <typename T> struct container_traits { 2311986Sandreas.sandberg@arm.com template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*); 2411986Sandreas.sandberg@arm.com template <typename T2> static std::false_type test_comparable(...); 2511986Sandreas.sandberg@arm.com template <typename T2> static std::true_type test_value(typename T2::value_type *); 2611986Sandreas.sandberg@arm.com template <typename T2> static std::false_type test_value(...); 2711986Sandreas.sandberg@arm.com template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *); 2811986Sandreas.sandberg@arm.com template <typename T2> static std::false_type test_pair(...); 2911986Sandreas.sandberg@arm.com 3011986Sandreas.sandberg@arm.com static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value; 3111986Sandreas.sandberg@arm.com static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value; 3211986Sandreas.sandberg@arm.com static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value; 3311986Sandreas.sandberg@arm.com static constexpr const bool is_element = !is_pair && !is_vector; 3411986Sandreas.sandberg@arm.com}; 3511986Sandreas.sandberg@arm.com 3611986Sandreas.sandberg@arm.com/* Default: is_comparable -> std::false_type */ 3711986Sandreas.sandberg@arm.comtemplate <typename T, typename SFINAE = void> 3811986Sandreas.sandberg@arm.comstruct is_comparable : std::false_type { }; 3911986Sandreas.sandberg@arm.com 4011986Sandreas.sandberg@arm.com/* For non-map data structures, check whether operator== can be instantiated */ 4111986Sandreas.sandberg@arm.comtemplate <typename T> 4211986Sandreas.sandberg@arm.comstruct is_comparable< 4311986Sandreas.sandberg@arm.com T, enable_if_t<container_traits<T>::is_element && 4411986Sandreas.sandberg@arm.com container_traits<T>::is_comparable>> 4511986Sandreas.sandberg@arm.com : std::true_type { }; 4611986Sandreas.sandberg@arm.com 4711986Sandreas.sandberg@arm.com/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */ 4811986Sandreas.sandberg@arm.comtemplate <typename T> 4911986Sandreas.sandberg@arm.comstruct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> { 5011986Sandreas.sandberg@arm.com static constexpr const bool value = 5111986Sandreas.sandberg@arm.com is_comparable<typename T::value_type>::value; 5211986Sandreas.sandberg@arm.com}; 5311986Sandreas.sandberg@arm.com 5411986Sandreas.sandberg@arm.com/* For pairs, recursively check the two data types */ 5511986Sandreas.sandberg@arm.comtemplate <typename T> 5611986Sandreas.sandberg@arm.comstruct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> { 5711986Sandreas.sandberg@arm.com static constexpr const bool value = 5811986Sandreas.sandberg@arm.com is_comparable<typename T::first_type>::value && 5911986Sandreas.sandberg@arm.com is_comparable<typename T::second_type>::value; 6011986Sandreas.sandberg@arm.com}; 6111986Sandreas.sandberg@arm.com 6211986Sandreas.sandberg@arm.com/* Fallback functions */ 6311986Sandreas.sandberg@arm.comtemplate <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { } 6411986Sandreas.sandberg@arm.comtemplate <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { } 6511986Sandreas.sandberg@arm.comtemplate <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { } 6611986Sandreas.sandberg@arm.comtemplate <typename, typename, typename... Args> void vector_modifiers(const Args &...) { } 6711986Sandreas.sandberg@arm.com 6811986Sandreas.sandberg@arm.comtemplate<typename Vector, typename Class_> 6912391Sjason@lowepower.comvoid vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) { 7012037Sandreas.sandberg@arm.com cl.def(init<const Vector &>(), "Copy constructor"); 7111986Sandreas.sandberg@arm.com} 7211986Sandreas.sandberg@arm.com 7311986Sandreas.sandberg@arm.comtemplate<typename Vector, typename Class_> 7411986Sandreas.sandberg@arm.comvoid vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) { 7511986Sandreas.sandberg@arm.com using T = typename Vector::value_type; 7611986Sandreas.sandberg@arm.com 7711986Sandreas.sandberg@arm.com cl.def(self == self); 7811986Sandreas.sandberg@arm.com cl.def(self != self); 7911986Sandreas.sandberg@arm.com 8011986Sandreas.sandberg@arm.com cl.def("count", 8111986Sandreas.sandberg@arm.com [](const Vector &v, const T &x) { 8211986Sandreas.sandberg@arm.com return std::count(v.begin(), v.end(), x); 8311986Sandreas.sandberg@arm.com }, 8411986Sandreas.sandberg@arm.com arg("x"), 8511986Sandreas.sandberg@arm.com "Return the number of times ``x`` appears in the list" 8611986Sandreas.sandberg@arm.com ); 8711986Sandreas.sandberg@arm.com 8811986Sandreas.sandberg@arm.com cl.def("remove", [](Vector &v, const T &x) { 8911986Sandreas.sandberg@arm.com auto p = std::find(v.begin(), v.end(), x); 9011986Sandreas.sandberg@arm.com if (p != v.end()) 9111986Sandreas.sandberg@arm.com v.erase(p); 9211986Sandreas.sandberg@arm.com else 9312037Sandreas.sandberg@arm.com throw value_error(); 9411986Sandreas.sandberg@arm.com }, 9511986Sandreas.sandberg@arm.com arg("x"), 9611986Sandreas.sandberg@arm.com "Remove the first item from the list whose value is x. " 9711986Sandreas.sandberg@arm.com "It is an error if there is no such item." 9811986Sandreas.sandberg@arm.com ); 9911986Sandreas.sandberg@arm.com 10011986Sandreas.sandberg@arm.com cl.def("__contains__", 10111986Sandreas.sandberg@arm.com [](const Vector &v, const T &x) { 10211986Sandreas.sandberg@arm.com return std::find(v.begin(), v.end(), x) != v.end(); 10311986Sandreas.sandberg@arm.com }, 10411986Sandreas.sandberg@arm.com arg("x"), 10511986Sandreas.sandberg@arm.com "Return true the container contains ``x``" 10611986Sandreas.sandberg@arm.com ); 10711986Sandreas.sandberg@arm.com} 10811986Sandreas.sandberg@arm.com 10911986Sandreas.sandberg@arm.com// Vector modifiers -- requires a copyable vector_type: 11011986Sandreas.sandberg@arm.com// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems 11111986Sandreas.sandberg@arm.com// silly to allow deletion but not insertion, so include them here too.) 11211986Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_> 11312391Sjason@lowepower.comvoid vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) { 11411986Sandreas.sandberg@arm.com using T = typename Vector::value_type; 11511986Sandreas.sandberg@arm.com using SizeType = typename Vector::size_type; 11611986Sandreas.sandberg@arm.com using DiffType = typename Vector::difference_type; 11711986Sandreas.sandberg@arm.com 11814299Sbbruce@ucdavis.edu auto wrap_i = [](DiffType i, SizeType n) { 11914299Sbbruce@ucdavis.edu if (i < 0) 12014299Sbbruce@ucdavis.edu i += n; 12114299Sbbruce@ucdavis.edu if (i < 0 || (SizeType)i >= n) 12214299Sbbruce@ucdavis.edu throw index_error(); 12314299Sbbruce@ucdavis.edu return i; 12414299Sbbruce@ucdavis.edu }; 12514299Sbbruce@ucdavis.edu 12611986Sandreas.sandberg@arm.com cl.def("append", 12711986Sandreas.sandberg@arm.com [](Vector &v, const T &value) { v.push_back(value); }, 12811986Sandreas.sandberg@arm.com arg("x"), 12911986Sandreas.sandberg@arm.com "Add an item to the end of the list"); 13011986Sandreas.sandberg@arm.com 13112391Sjason@lowepower.com cl.def(init([](iterable it) { 13212391Sjason@lowepower.com auto v = std::unique_ptr<Vector>(new Vector()); 13314299Sbbruce@ucdavis.edu v->reserve(len_hint(it)); 13412391Sjason@lowepower.com for (handle h : it) 13512391Sjason@lowepower.com v->push_back(h.cast<T>()); 13612391Sjason@lowepower.com return v.release(); 13712391Sjason@lowepower.com })); 13811986Sandreas.sandberg@arm.com 13911986Sandreas.sandberg@arm.com cl.def("extend", 14011986Sandreas.sandberg@arm.com [](Vector &v, const Vector &src) { 14111986Sandreas.sandberg@arm.com v.insert(v.end(), src.begin(), src.end()); 14211986Sandreas.sandberg@arm.com }, 14311986Sandreas.sandberg@arm.com arg("L"), 14411986Sandreas.sandberg@arm.com "Extend the list by appending all the items in the given list" 14511986Sandreas.sandberg@arm.com ); 14611986Sandreas.sandberg@arm.com 14714299Sbbruce@ucdavis.edu cl.def("extend", 14814299Sbbruce@ucdavis.edu [](Vector &v, iterable it) { 14914299Sbbruce@ucdavis.edu const size_t old_size = v.size(); 15014299Sbbruce@ucdavis.edu v.reserve(old_size + len_hint(it)); 15114299Sbbruce@ucdavis.edu try { 15214299Sbbruce@ucdavis.edu for (handle h : it) { 15314299Sbbruce@ucdavis.edu v.push_back(h.cast<T>()); 15414299Sbbruce@ucdavis.edu } 15514299Sbbruce@ucdavis.edu } catch (const cast_error &) { 15614299Sbbruce@ucdavis.edu v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), v.end()); 15714299Sbbruce@ucdavis.edu try { 15814299Sbbruce@ucdavis.edu v.shrink_to_fit(); 15914299Sbbruce@ucdavis.edu } catch (const std::exception &) { 16014299Sbbruce@ucdavis.edu // Do nothing 16114299Sbbruce@ucdavis.edu } 16214299Sbbruce@ucdavis.edu throw; 16314299Sbbruce@ucdavis.edu } 16414299Sbbruce@ucdavis.edu }, 16514299Sbbruce@ucdavis.edu arg("L"), 16614299Sbbruce@ucdavis.edu "Extend the list by appending all the items in the given list" 16714299Sbbruce@ucdavis.edu ); 16814299Sbbruce@ucdavis.edu 16911986Sandreas.sandberg@arm.com cl.def("insert", 17014299Sbbruce@ucdavis.edu [](Vector &v, DiffType i, const T &x) { 17114299Sbbruce@ucdavis.edu // Can't use wrap_i; i == v.size() is OK 17214299Sbbruce@ucdavis.edu if (i < 0) 17314299Sbbruce@ucdavis.edu i += v.size(); 17414299Sbbruce@ucdavis.edu if (i < 0 || (SizeType)i > v.size()) 17512391Sjason@lowepower.com throw index_error(); 17614299Sbbruce@ucdavis.edu v.insert(v.begin() + i, x); 17711986Sandreas.sandberg@arm.com }, 17811986Sandreas.sandberg@arm.com arg("i") , arg("x"), 17911986Sandreas.sandberg@arm.com "Insert an item at a given position." 18011986Sandreas.sandberg@arm.com ); 18111986Sandreas.sandberg@arm.com 18211986Sandreas.sandberg@arm.com cl.def("pop", 18311986Sandreas.sandberg@arm.com [](Vector &v) { 18411986Sandreas.sandberg@arm.com if (v.empty()) 18512037Sandreas.sandberg@arm.com throw index_error(); 18611986Sandreas.sandberg@arm.com T t = v.back(); 18711986Sandreas.sandberg@arm.com v.pop_back(); 18811986Sandreas.sandberg@arm.com return t; 18911986Sandreas.sandberg@arm.com }, 19011986Sandreas.sandberg@arm.com "Remove and return the last item" 19111986Sandreas.sandberg@arm.com ); 19211986Sandreas.sandberg@arm.com 19311986Sandreas.sandberg@arm.com cl.def("pop", 19414299Sbbruce@ucdavis.edu [wrap_i](Vector &v, DiffType i) { 19514299Sbbruce@ucdavis.edu i = wrap_i(i, v.size()); 19614299Sbbruce@ucdavis.edu T t = v[(SizeType) i]; 19714299Sbbruce@ucdavis.edu v.erase(v.begin() + i); 19811986Sandreas.sandberg@arm.com return t; 19911986Sandreas.sandberg@arm.com }, 20011986Sandreas.sandberg@arm.com arg("i"), 20111986Sandreas.sandberg@arm.com "Remove and return the item at index ``i``" 20211986Sandreas.sandberg@arm.com ); 20311986Sandreas.sandberg@arm.com 20411986Sandreas.sandberg@arm.com cl.def("__setitem__", 20514299Sbbruce@ucdavis.edu [wrap_i](Vector &v, DiffType i, const T &t) { 20614299Sbbruce@ucdavis.edu i = wrap_i(i, v.size()); 20714299Sbbruce@ucdavis.edu v[(SizeType)i] = t; 20811986Sandreas.sandberg@arm.com } 20911986Sandreas.sandberg@arm.com ); 21011986Sandreas.sandberg@arm.com 21111986Sandreas.sandberg@arm.com /// Slicing protocol 21211986Sandreas.sandberg@arm.com cl.def("__getitem__", 21311986Sandreas.sandberg@arm.com [](const Vector &v, slice slice) -> Vector * { 21411986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 21511986Sandreas.sandberg@arm.com 21611986Sandreas.sandberg@arm.com if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 21712037Sandreas.sandberg@arm.com throw error_already_set(); 21811986Sandreas.sandberg@arm.com 21911986Sandreas.sandberg@arm.com Vector *seq = new Vector(); 22011986Sandreas.sandberg@arm.com seq->reserve((size_t) slicelength); 22111986Sandreas.sandberg@arm.com 22211986Sandreas.sandberg@arm.com for (size_t i=0; i<slicelength; ++i) { 22311986Sandreas.sandberg@arm.com seq->push_back(v[start]); 22411986Sandreas.sandberg@arm.com start += step; 22511986Sandreas.sandberg@arm.com } 22611986Sandreas.sandberg@arm.com return seq; 22711986Sandreas.sandberg@arm.com }, 22811986Sandreas.sandberg@arm.com arg("s"), 22911986Sandreas.sandberg@arm.com "Retrieve list elements using a slice object" 23011986Sandreas.sandberg@arm.com ); 23111986Sandreas.sandberg@arm.com 23211986Sandreas.sandberg@arm.com cl.def("__setitem__", 23311986Sandreas.sandberg@arm.com [](Vector &v, slice slice, const Vector &value) { 23411986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 23511986Sandreas.sandberg@arm.com if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 23612037Sandreas.sandberg@arm.com throw error_already_set(); 23711986Sandreas.sandberg@arm.com 23811986Sandreas.sandberg@arm.com if (slicelength != value.size()) 23911986Sandreas.sandberg@arm.com throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); 24011986Sandreas.sandberg@arm.com 24111986Sandreas.sandberg@arm.com for (size_t i=0; i<slicelength; ++i) { 24211986Sandreas.sandberg@arm.com v[start] = value[i]; 24311986Sandreas.sandberg@arm.com start += step; 24411986Sandreas.sandberg@arm.com } 24511986Sandreas.sandberg@arm.com }, 24611986Sandreas.sandberg@arm.com "Assign list elements using a slice object" 24711986Sandreas.sandberg@arm.com ); 24811986Sandreas.sandberg@arm.com 24911986Sandreas.sandberg@arm.com cl.def("__delitem__", 25014299Sbbruce@ucdavis.edu [wrap_i](Vector &v, DiffType i) { 25114299Sbbruce@ucdavis.edu i = wrap_i(i, v.size()); 25214299Sbbruce@ucdavis.edu v.erase(v.begin() + i); 25311986Sandreas.sandberg@arm.com }, 25411986Sandreas.sandberg@arm.com "Delete the list elements at index ``i``" 25511986Sandreas.sandberg@arm.com ); 25611986Sandreas.sandberg@arm.com 25711986Sandreas.sandberg@arm.com cl.def("__delitem__", 25811986Sandreas.sandberg@arm.com [](Vector &v, slice slice) { 25911986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 26011986Sandreas.sandberg@arm.com 26111986Sandreas.sandberg@arm.com if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 26212037Sandreas.sandberg@arm.com throw error_already_set(); 26311986Sandreas.sandberg@arm.com 26411986Sandreas.sandberg@arm.com if (step == 1 && false) { 26511986Sandreas.sandberg@arm.com v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength)); 26611986Sandreas.sandberg@arm.com } else { 26711986Sandreas.sandberg@arm.com for (size_t i = 0; i < slicelength; ++i) { 26811986Sandreas.sandberg@arm.com v.erase(v.begin() + DiffType(start)); 26911986Sandreas.sandberg@arm.com start += step - 1; 27011986Sandreas.sandberg@arm.com } 27111986Sandreas.sandberg@arm.com } 27211986Sandreas.sandberg@arm.com }, 27311986Sandreas.sandberg@arm.com "Delete list elements using a slice object" 27411986Sandreas.sandberg@arm.com ); 27511986Sandreas.sandberg@arm.com 27611986Sandreas.sandberg@arm.com} 27711986Sandreas.sandberg@arm.com 27811986Sandreas.sandberg@arm.com// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>), 27911986Sandreas.sandberg@arm.com// we have to access by copying; otherwise we return by reference. 28012037Sandreas.sandberg@arm.comtemplate <typename Vector> using vector_needs_copy = negation< 28112037Sandreas.sandberg@arm.com std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>; 28211986Sandreas.sandberg@arm.com 28311986Sandreas.sandberg@arm.com// The usual case: access and iterate by reference 28411986Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_> 28511986Sandreas.sandberg@arm.comvoid vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) { 28611986Sandreas.sandberg@arm.com using T = typename Vector::value_type; 28711986Sandreas.sandberg@arm.com using SizeType = typename Vector::size_type; 28814299Sbbruce@ucdavis.edu using DiffType = typename Vector::difference_type; 28911986Sandreas.sandberg@arm.com using ItType = typename Vector::iterator; 29011986Sandreas.sandberg@arm.com 29114299Sbbruce@ucdavis.edu auto wrap_i = [](DiffType i, SizeType n) { 29214299Sbbruce@ucdavis.edu if (i < 0) 29314299Sbbruce@ucdavis.edu i += n; 29414299Sbbruce@ucdavis.edu if (i < 0 || (SizeType)i >= n) 29514299Sbbruce@ucdavis.edu throw index_error(); 29614299Sbbruce@ucdavis.edu return i; 29714299Sbbruce@ucdavis.edu }; 29814299Sbbruce@ucdavis.edu 29911986Sandreas.sandberg@arm.com cl.def("__getitem__", 30014299Sbbruce@ucdavis.edu [wrap_i](Vector &v, DiffType i) -> T & { 30114299Sbbruce@ucdavis.edu i = wrap_i(i, v.size()); 30214299Sbbruce@ucdavis.edu return v[(SizeType)i]; 30311986Sandreas.sandberg@arm.com }, 30411986Sandreas.sandberg@arm.com return_value_policy::reference_internal // ref + keepalive 30511986Sandreas.sandberg@arm.com ); 30611986Sandreas.sandberg@arm.com 30711986Sandreas.sandberg@arm.com cl.def("__iter__", 30811986Sandreas.sandberg@arm.com [](Vector &v) { 30912037Sandreas.sandberg@arm.com return make_iterator< 31011986Sandreas.sandberg@arm.com return_value_policy::reference_internal, ItType, ItType, T&>( 31111986Sandreas.sandberg@arm.com v.begin(), v.end()); 31211986Sandreas.sandberg@arm.com }, 31311986Sandreas.sandberg@arm.com keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 31411986Sandreas.sandberg@arm.com ); 31511986Sandreas.sandberg@arm.com} 31611986Sandreas.sandberg@arm.com 31711986Sandreas.sandberg@arm.com// The case for special objects, like std::vector<bool>, that have to be returned-by-copy: 31811986Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_> 31911986Sandreas.sandberg@arm.comvoid vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) { 32011986Sandreas.sandberg@arm.com using T = typename Vector::value_type; 32111986Sandreas.sandberg@arm.com using SizeType = typename Vector::size_type; 32214299Sbbruce@ucdavis.edu using DiffType = typename Vector::difference_type; 32311986Sandreas.sandberg@arm.com using ItType = typename Vector::iterator; 32411986Sandreas.sandberg@arm.com cl.def("__getitem__", 32514299Sbbruce@ucdavis.edu [](const Vector &v, DiffType i) -> T { 32614299Sbbruce@ucdavis.edu if (i < 0 && (i += v.size()) < 0) 32712037Sandreas.sandberg@arm.com throw index_error(); 32814299Sbbruce@ucdavis.edu if ((SizeType)i >= v.size()) 32914299Sbbruce@ucdavis.edu throw index_error(); 33014299Sbbruce@ucdavis.edu return v[(SizeType)i]; 33111986Sandreas.sandberg@arm.com } 33211986Sandreas.sandberg@arm.com ); 33311986Sandreas.sandberg@arm.com 33411986Sandreas.sandberg@arm.com cl.def("__iter__", 33511986Sandreas.sandberg@arm.com [](Vector &v) { 33612037Sandreas.sandberg@arm.com return make_iterator< 33711986Sandreas.sandberg@arm.com return_value_policy::copy, ItType, ItType, T>( 33811986Sandreas.sandberg@arm.com v.begin(), v.end()); 33911986Sandreas.sandberg@arm.com }, 34011986Sandreas.sandberg@arm.com keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 34111986Sandreas.sandberg@arm.com ); 34211986Sandreas.sandberg@arm.com} 34311986Sandreas.sandberg@arm.com 34411986Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name) 34511986Sandreas.sandberg@arm.com -> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) { 34611986Sandreas.sandberg@arm.com using size_type = typename Vector::size_type; 34711986Sandreas.sandberg@arm.com 34811986Sandreas.sandberg@arm.com cl.def("__repr__", 34911986Sandreas.sandberg@arm.com [name](Vector &v) { 35011986Sandreas.sandberg@arm.com std::ostringstream s; 35111986Sandreas.sandberg@arm.com s << name << '['; 35211986Sandreas.sandberg@arm.com for (size_type i=0; i < v.size(); ++i) { 35311986Sandreas.sandberg@arm.com s << v[i]; 35411986Sandreas.sandberg@arm.com if (i != v.size() - 1) 35511986Sandreas.sandberg@arm.com s << ", "; 35611986Sandreas.sandberg@arm.com } 35711986Sandreas.sandberg@arm.com s << ']'; 35811986Sandreas.sandberg@arm.com return s.str(); 35911986Sandreas.sandberg@arm.com }, 36011986Sandreas.sandberg@arm.com "Return the canonical string representation of this list." 36111986Sandreas.sandberg@arm.com ); 36211986Sandreas.sandberg@arm.com} 36311986Sandreas.sandberg@arm.com 36412037Sandreas.sandberg@arm.com// Provide the buffer interface for vectors if we have data() and we have a format for it 36512037Sandreas.sandberg@arm.com// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer 36612037Sandreas.sandberg@arm.comtemplate <typename Vector, typename = void> 36712037Sandreas.sandberg@arm.comstruct vector_has_data_and_format : std::false_type {}; 36812037Sandreas.sandberg@arm.comtemplate <typename Vector> 36912037Sandreas.sandberg@arm.comstruct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {}; 37012037Sandreas.sandberg@arm.com 37112037Sandreas.sandberg@arm.com// Add the buffer interface to a vector 37212037Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_, typename... Args> 37312037Sandreas.sandberg@arm.comenable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value> 37412037Sandreas.sandberg@arm.comvector_buffer(Class_& cl) { 37512037Sandreas.sandberg@arm.com using T = typename Vector::value_type; 37612037Sandreas.sandberg@arm.com 37712037Sandreas.sandberg@arm.com static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector"); 37812037Sandreas.sandberg@arm.com 37912037Sandreas.sandberg@arm.com // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here 38012037Sandreas.sandberg@arm.com format_descriptor<T>::format(); 38112037Sandreas.sandberg@arm.com 38212037Sandreas.sandberg@arm.com cl.def_buffer([](Vector& v) -> buffer_info { 38312391Sjason@lowepower.com return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)}); 38412037Sandreas.sandberg@arm.com }); 38512037Sandreas.sandberg@arm.com 38612391Sjason@lowepower.com cl.def(init([](buffer buf) { 38712037Sandreas.sandberg@arm.com auto info = buf.request(); 38812391Sjason@lowepower.com if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) 38912037Sandreas.sandberg@arm.com throw type_error("Only valid 1D buffers can be copied to a vector"); 39012391Sjason@lowepower.com if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize) 39112037Sandreas.sandberg@arm.com throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")"); 39212391Sjason@lowepower.com 39312391Sjason@lowepower.com auto vec = std::unique_ptr<Vector>(new Vector()); 39412391Sjason@lowepower.com vec->reserve((size_t) info.shape[0]); 39512037Sandreas.sandberg@arm.com T *p = static_cast<T*>(info.ptr); 39612391Sjason@lowepower.com ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T)); 39712037Sandreas.sandberg@arm.com T *end = p + info.shape[0] * step; 39812391Sjason@lowepower.com for (; p != end; p += step) 39912391Sjason@lowepower.com vec->push_back(*p); 40012391Sjason@lowepower.com return vec.release(); 40112391Sjason@lowepower.com })); 40212037Sandreas.sandberg@arm.com 40312037Sandreas.sandberg@arm.com return; 40412037Sandreas.sandberg@arm.com} 40512037Sandreas.sandberg@arm.com 40612037Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_, typename... Args> 40712037Sandreas.sandberg@arm.comenable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {} 40812037Sandreas.sandberg@arm.com 40911986Sandreas.sandberg@arm.comNAMESPACE_END(detail) 41011986Sandreas.sandberg@arm.com 41111986Sandreas.sandberg@arm.com// 41211986Sandreas.sandberg@arm.com// std::vector 41311986Sandreas.sandberg@arm.com// 41411986Sandreas.sandberg@arm.comtemplate <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args> 41512391Sjason@lowepower.comclass_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) { 41612037Sandreas.sandberg@arm.com using Class_ = class_<Vector, holder_type>; 41711986Sandreas.sandberg@arm.com 41812391Sjason@lowepower.com // If the value_type is unregistered (e.g. a converting type) or is itself registered 41912391Sjason@lowepower.com // module-local then make the vector binding module-local as well: 42012391Sjason@lowepower.com using vtype = typename Vector::value_type; 42112391Sjason@lowepower.com auto vtype_info = detail::get_type_info(typeid(vtype)); 42212391Sjason@lowepower.com bool local = !vtype_info || vtype_info->module_local; 42312391Sjason@lowepower.com 42412391Sjason@lowepower.com Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...); 42511986Sandreas.sandberg@arm.com 42612037Sandreas.sandberg@arm.com // Declare the buffer interface if a buffer_protocol() is passed in 42712037Sandreas.sandberg@arm.com detail::vector_buffer<Vector, Class_, Args...>(cl); 42812037Sandreas.sandberg@arm.com 42912037Sandreas.sandberg@arm.com cl.def(init<>()); 43011986Sandreas.sandberg@arm.com 43111986Sandreas.sandberg@arm.com // Register copy constructor (if possible) 43211986Sandreas.sandberg@arm.com detail::vector_if_copy_constructible<Vector, Class_>(cl); 43311986Sandreas.sandberg@arm.com 43411986Sandreas.sandberg@arm.com // Register comparison-related operators and functions (if possible) 43511986Sandreas.sandberg@arm.com detail::vector_if_equal_operator<Vector, Class_>(cl); 43611986Sandreas.sandberg@arm.com 43711986Sandreas.sandberg@arm.com // Register stream insertion operator (if possible) 43811986Sandreas.sandberg@arm.com detail::vector_if_insertion_operator<Vector, Class_>(cl, name); 43911986Sandreas.sandberg@arm.com 44011986Sandreas.sandberg@arm.com // Modifiers require copyable vector value type 44111986Sandreas.sandberg@arm.com detail::vector_modifiers<Vector, Class_>(cl); 44211986Sandreas.sandberg@arm.com 44311986Sandreas.sandberg@arm.com // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive 44411986Sandreas.sandberg@arm.com detail::vector_accessor<Vector, Class_>(cl); 44511986Sandreas.sandberg@arm.com 44611986Sandreas.sandberg@arm.com cl.def("__bool__", 44711986Sandreas.sandberg@arm.com [](const Vector &v) -> bool { 44811986Sandreas.sandberg@arm.com return !v.empty(); 44911986Sandreas.sandberg@arm.com }, 45011986Sandreas.sandberg@arm.com "Check whether the list is nonempty" 45111986Sandreas.sandberg@arm.com ); 45211986Sandreas.sandberg@arm.com 45311986Sandreas.sandberg@arm.com cl.def("__len__", &Vector::size); 45411986Sandreas.sandberg@arm.com 45511986Sandreas.sandberg@arm.com 45611986Sandreas.sandberg@arm.com 45711986Sandreas.sandberg@arm.com 45811986Sandreas.sandberg@arm.com#if 0 45911986Sandreas.sandberg@arm.com // C++ style functions deprecated, leaving it here as an example 46012037Sandreas.sandberg@arm.com cl.def(init<size_type>()); 46111986Sandreas.sandberg@arm.com 46211986Sandreas.sandberg@arm.com cl.def("resize", 46311986Sandreas.sandberg@arm.com (void (Vector::*) (size_type count)) & Vector::resize, 46411986Sandreas.sandberg@arm.com "changes the number of elements stored"); 46511986Sandreas.sandberg@arm.com 46611986Sandreas.sandberg@arm.com cl.def("erase", 46711986Sandreas.sandberg@arm.com [](Vector &v, SizeType i) { 46811986Sandreas.sandberg@arm.com if (i >= v.size()) 46912037Sandreas.sandberg@arm.com throw index_error(); 47011986Sandreas.sandberg@arm.com v.erase(v.begin() + i); 47111986Sandreas.sandberg@arm.com }, "erases element at index ``i``"); 47211986Sandreas.sandberg@arm.com 47311986Sandreas.sandberg@arm.com cl.def("empty", &Vector::empty, "checks whether the container is empty"); 47411986Sandreas.sandberg@arm.com cl.def("size", &Vector::size, "returns the number of elements"); 47511986Sandreas.sandberg@arm.com cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); 47611986Sandreas.sandberg@arm.com cl.def("pop_back", &Vector::pop_back, "removes the last element"); 47711986Sandreas.sandberg@arm.com 47811986Sandreas.sandberg@arm.com cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); 47911986Sandreas.sandberg@arm.com cl.def("reserve", &Vector::reserve, "reserves storage"); 48011986Sandreas.sandberg@arm.com cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); 48111986Sandreas.sandberg@arm.com cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); 48211986Sandreas.sandberg@arm.com 48311986Sandreas.sandberg@arm.com cl.def("clear", &Vector::clear, "clears the contents"); 48411986Sandreas.sandberg@arm.com cl.def("swap", &Vector::swap, "swaps the contents"); 48511986Sandreas.sandberg@arm.com 48611986Sandreas.sandberg@arm.com cl.def("front", [](Vector &v) { 48711986Sandreas.sandberg@arm.com if (v.size()) return v.front(); 48812037Sandreas.sandberg@arm.com else throw index_error(); 48911986Sandreas.sandberg@arm.com }, "access the first element"); 49011986Sandreas.sandberg@arm.com 49111986Sandreas.sandberg@arm.com cl.def("back", [](Vector &v) { 49211986Sandreas.sandberg@arm.com if (v.size()) return v.back(); 49312037Sandreas.sandberg@arm.com else throw index_error(); 49411986Sandreas.sandberg@arm.com }, "access the last element "); 49511986Sandreas.sandberg@arm.com 49611986Sandreas.sandberg@arm.com#endif 49711986Sandreas.sandberg@arm.com 49811986Sandreas.sandberg@arm.com return cl; 49911986Sandreas.sandberg@arm.com} 50011986Sandreas.sandberg@arm.com 50111986Sandreas.sandberg@arm.com 50211986Sandreas.sandberg@arm.com 50311986Sandreas.sandberg@arm.com// 50411986Sandreas.sandberg@arm.com// std::map, std::unordered_map 50511986Sandreas.sandberg@arm.com// 50611986Sandreas.sandberg@arm.com 50711986Sandreas.sandberg@arm.comNAMESPACE_BEGIN(detail) 50811986Sandreas.sandberg@arm.com 50911986Sandreas.sandberg@arm.com/* Fallback functions */ 51011986Sandreas.sandberg@arm.comtemplate <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { } 51111986Sandreas.sandberg@arm.comtemplate <typename, typename, typename... Args> void map_assignment(const Args &...) { } 51211986Sandreas.sandberg@arm.com 51311986Sandreas.sandberg@arm.com// Map assignment when copy-assignable: just copy the value 51411986Sandreas.sandberg@arm.comtemplate <typename Map, typename Class_> 51511986Sandreas.sandberg@arm.comvoid map_assignment(enable_if_t<std::is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) { 51611986Sandreas.sandberg@arm.com using KeyType = typename Map::key_type; 51711986Sandreas.sandberg@arm.com using MappedType = typename Map::mapped_type; 51811986Sandreas.sandberg@arm.com 51911986Sandreas.sandberg@arm.com cl.def("__setitem__", 52011986Sandreas.sandberg@arm.com [](Map &m, const KeyType &k, const MappedType &v) { 52111986Sandreas.sandberg@arm.com auto it = m.find(k); 52211986Sandreas.sandberg@arm.com if (it != m.end()) it->second = v; 52311986Sandreas.sandberg@arm.com else m.emplace(k, v); 52411986Sandreas.sandberg@arm.com } 52511986Sandreas.sandberg@arm.com ); 52611986Sandreas.sandberg@arm.com} 52711986Sandreas.sandberg@arm.com 52811986Sandreas.sandberg@arm.com// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting 52911986Sandreas.sandberg@arm.comtemplate<typename Map, typename Class_> 53011986Sandreas.sandberg@arm.comvoid map_assignment(enable_if_t< 53111986Sandreas.sandberg@arm.com !std::is_copy_assignable<typename Map::mapped_type>::value && 53212391Sjason@lowepower.com is_copy_constructible<typename Map::mapped_type>::value, 53311986Sandreas.sandberg@arm.com Class_> &cl) { 53411986Sandreas.sandberg@arm.com using KeyType = typename Map::key_type; 53511986Sandreas.sandberg@arm.com using MappedType = typename Map::mapped_type; 53611986Sandreas.sandberg@arm.com 53711986Sandreas.sandberg@arm.com cl.def("__setitem__", 53811986Sandreas.sandberg@arm.com [](Map &m, const KeyType &k, const MappedType &v) { 53911986Sandreas.sandberg@arm.com // We can't use m[k] = v; because value type might not be default constructable 54011986Sandreas.sandberg@arm.com auto r = m.emplace(k, v); 54111986Sandreas.sandberg@arm.com if (!r.second) { 54211986Sandreas.sandberg@arm.com // value type is not copy assignable so the only way to insert it is to erase it first... 54311986Sandreas.sandberg@arm.com m.erase(r.first); 54411986Sandreas.sandberg@arm.com m.emplace(k, v); 54511986Sandreas.sandberg@arm.com } 54611986Sandreas.sandberg@arm.com } 54711986Sandreas.sandberg@arm.com ); 54811986Sandreas.sandberg@arm.com} 54911986Sandreas.sandberg@arm.com 55011986Sandreas.sandberg@arm.com 55111986Sandreas.sandberg@arm.comtemplate <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name) 55211986Sandreas.sandberg@arm.com-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) { 55311986Sandreas.sandberg@arm.com 55411986Sandreas.sandberg@arm.com cl.def("__repr__", 55511986Sandreas.sandberg@arm.com [name](Map &m) { 55611986Sandreas.sandberg@arm.com std::ostringstream s; 55711986Sandreas.sandberg@arm.com s << name << '{'; 55811986Sandreas.sandberg@arm.com bool f = false; 55911986Sandreas.sandberg@arm.com for (auto const &kv : m) { 56011986Sandreas.sandberg@arm.com if (f) 56111986Sandreas.sandberg@arm.com s << ", "; 56211986Sandreas.sandberg@arm.com s << kv.first << ": " << kv.second; 56311986Sandreas.sandberg@arm.com f = true; 56411986Sandreas.sandberg@arm.com } 56511986Sandreas.sandberg@arm.com s << '}'; 56611986Sandreas.sandberg@arm.com return s.str(); 56711986Sandreas.sandberg@arm.com }, 56811986Sandreas.sandberg@arm.com "Return the canonical string representation of this map." 56911986Sandreas.sandberg@arm.com ); 57011986Sandreas.sandberg@arm.com} 57111986Sandreas.sandberg@arm.com 57211986Sandreas.sandberg@arm.com 57311986Sandreas.sandberg@arm.comNAMESPACE_END(detail) 57411986Sandreas.sandberg@arm.com 57511986Sandreas.sandberg@arm.comtemplate <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args> 57612391Sjason@lowepower.comclass_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) { 57711986Sandreas.sandberg@arm.com using KeyType = typename Map::key_type; 57811986Sandreas.sandberg@arm.com using MappedType = typename Map::mapped_type; 57912037Sandreas.sandberg@arm.com using Class_ = class_<Map, holder_type>; 58011986Sandreas.sandberg@arm.com 58112391Sjason@lowepower.com // If either type is a non-module-local bound type then make the map binding non-local as well; 58212391Sjason@lowepower.com // otherwise (e.g. both types are either module-local or converting) the map will be 58312391Sjason@lowepower.com // module-local. 58412391Sjason@lowepower.com auto tinfo = detail::get_type_info(typeid(MappedType)); 58512391Sjason@lowepower.com bool local = !tinfo || tinfo->module_local; 58612391Sjason@lowepower.com if (local) { 58712391Sjason@lowepower.com tinfo = detail::get_type_info(typeid(KeyType)); 58812391Sjason@lowepower.com local = !tinfo || tinfo->module_local; 58912391Sjason@lowepower.com } 59012391Sjason@lowepower.com 59112391Sjason@lowepower.com Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...); 59211986Sandreas.sandberg@arm.com 59312037Sandreas.sandberg@arm.com cl.def(init<>()); 59411986Sandreas.sandberg@arm.com 59511986Sandreas.sandberg@arm.com // Register stream insertion operator (if possible) 59611986Sandreas.sandberg@arm.com detail::map_if_insertion_operator<Map, Class_>(cl, name); 59711986Sandreas.sandberg@arm.com 59811986Sandreas.sandberg@arm.com cl.def("__bool__", 59911986Sandreas.sandberg@arm.com [](const Map &m) -> bool { return !m.empty(); }, 60011986Sandreas.sandberg@arm.com "Check whether the map is nonempty" 60111986Sandreas.sandberg@arm.com ); 60211986Sandreas.sandberg@arm.com 60311986Sandreas.sandberg@arm.com cl.def("__iter__", 60412037Sandreas.sandberg@arm.com [](Map &m) { return make_key_iterator(m.begin(), m.end()); }, 60512037Sandreas.sandberg@arm.com keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 60611986Sandreas.sandberg@arm.com ); 60711986Sandreas.sandberg@arm.com 60811986Sandreas.sandberg@arm.com cl.def("items", 60912037Sandreas.sandberg@arm.com [](Map &m) { return make_iterator(m.begin(), m.end()); }, 61012037Sandreas.sandberg@arm.com keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 61111986Sandreas.sandberg@arm.com ); 61211986Sandreas.sandberg@arm.com 61311986Sandreas.sandberg@arm.com cl.def("__getitem__", 61411986Sandreas.sandberg@arm.com [](Map &m, const KeyType &k) -> MappedType & { 61511986Sandreas.sandberg@arm.com auto it = m.find(k); 61611986Sandreas.sandberg@arm.com if (it == m.end()) 61712037Sandreas.sandberg@arm.com throw key_error(); 61811986Sandreas.sandberg@arm.com return it->second; 61911986Sandreas.sandberg@arm.com }, 62011986Sandreas.sandberg@arm.com return_value_policy::reference_internal // ref + keepalive 62111986Sandreas.sandberg@arm.com ); 62211986Sandreas.sandberg@arm.com 62314299Sbbruce@ucdavis.edu cl.def("__contains__", 62414299Sbbruce@ucdavis.edu [](Map &m, const KeyType &k) -> bool { 62514299Sbbruce@ucdavis.edu auto it = m.find(k); 62614299Sbbruce@ucdavis.edu if (it == m.end()) 62714299Sbbruce@ucdavis.edu return false; 62814299Sbbruce@ucdavis.edu return true; 62914299Sbbruce@ucdavis.edu } 63014299Sbbruce@ucdavis.edu ); 63114299Sbbruce@ucdavis.edu 63211986Sandreas.sandberg@arm.com // Assignment provided only if the type is copyable 63311986Sandreas.sandberg@arm.com detail::map_assignment<Map, Class_>(cl); 63411986Sandreas.sandberg@arm.com 63511986Sandreas.sandberg@arm.com cl.def("__delitem__", 63611986Sandreas.sandberg@arm.com [](Map &m, const KeyType &k) { 63711986Sandreas.sandberg@arm.com auto it = m.find(k); 63811986Sandreas.sandberg@arm.com if (it == m.end()) 63912037Sandreas.sandberg@arm.com throw key_error(); 64014299Sbbruce@ucdavis.edu m.erase(it); 64111986Sandreas.sandberg@arm.com } 64211986Sandreas.sandberg@arm.com ); 64311986Sandreas.sandberg@arm.com 64411986Sandreas.sandberg@arm.com cl.def("__len__", &Map::size); 64511986Sandreas.sandberg@arm.com 64611986Sandreas.sandberg@arm.com return cl; 64711986Sandreas.sandberg@arm.com} 64811986Sandreas.sandberg@arm.com 64912391Sjason@lowepower.comNAMESPACE_END(PYBIND11_NAMESPACE) 650