stl_bind.h revision 11986
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 1211986Sandreas.sandberg@arm.com#include "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 1811986Sandreas.sandberg@arm.comNAMESPACE_BEGIN(pybind11) 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_> 6911986Sandreas.sandberg@arm.comvoid vector_if_copy_constructible(enable_if_t< 7011986Sandreas.sandberg@arm.com std::is_copy_constructible<Vector>::value && 7111986Sandreas.sandberg@arm.com std::is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) { 7211986Sandreas.sandberg@arm.com 7311986Sandreas.sandberg@arm.com cl.def(pybind11::init<const Vector &>(), "Copy constructor"); 7411986Sandreas.sandberg@arm.com} 7511986Sandreas.sandberg@arm.com 7611986Sandreas.sandberg@arm.comtemplate<typename Vector, typename Class_> 7711986Sandreas.sandberg@arm.comvoid vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) { 7811986Sandreas.sandberg@arm.com using T = typename Vector::value_type; 7911986Sandreas.sandberg@arm.com 8011986Sandreas.sandberg@arm.com cl.def(self == self); 8111986Sandreas.sandberg@arm.com cl.def(self != self); 8211986Sandreas.sandberg@arm.com 8311986Sandreas.sandberg@arm.com cl.def("count", 8411986Sandreas.sandberg@arm.com [](const Vector &v, const T &x) { 8511986Sandreas.sandberg@arm.com return std::count(v.begin(), v.end(), x); 8611986Sandreas.sandberg@arm.com }, 8711986Sandreas.sandberg@arm.com arg("x"), 8811986Sandreas.sandberg@arm.com "Return the number of times ``x`` appears in the list" 8911986Sandreas.sandberg@arm.com ); 9011986Sandreas.sandberg@arm.com 9111986Sandreas.sandberg@arm.com cl.def("remove", [](Vector &v, const T &x) { 9211986Sandreas.sandberg@arm.com auto p = std::find(v.begin(), v.end(), x); 9311986Sandreas.sandberg@arm.com if (p != v.end()) 9411986Sandreas.sandberg@arm.com v.erase(p); 9511986Sandreas.sandberg@arm.com else 9611986Sandreas.sandberg@arm.com throw pybind11::value_error(); 9711986Sandreas.sandberg@arm.com }, 9811986Sandreas.sandberg@arm.com arg("x"), 9911986Sandreas.sandberg@arm.com "Remove the first item from the list whose value is x. " 10011986Sandreas.sandberg@arm.com "It is an error if there is no such item." 10111986Sandreas.sandberg@arm.com ); 10211986Sandreas.sandberg@arm.com 10311986Sandreas.sandberg@arm.com cl.def("__contains__", 10411986Sandreas.sandberg@arm.com [](const Vector &v, const T &x) { 10511986Sandreas.sandberg@arm.com return std::find(v.begin(), v.end(), x) != v.end(); 10611986Sandreas.sandberg@arm.com }, 10711986Sandreas.sandberg@arm.com arg("x"), 10811986Sandreas.sandberg@arm.com "Return true the container contains ``x``" 10911986Sandreas.sandberg@arm.com ); 11011986Sandreas.sandberg@arm.com} 11111986Sandreas.sandberg@arm.com 11211986Sandreas.sandberg@arm.com// Vector modifiers -- requires a copyable vector_type: 11311986Sandreas.sandberg@arm.com// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems 11411986Sandreas.sandberg@arm.com// silly to allow deletion but not insertion, so include them here too.) 11511986Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_> 11611986Sandreas.sandberg@arm.comvoid vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) { 11711986Sandreas.sandberg@arm.com using T = typename Vector::value_type; 11811986Sandreas.sandberg@arm.com using SizeType = typename Vector::size_type; 11911986Sandreas.sandberg@arm.com using DiffType = typename Vector::difference_type; 12011986Sandreas.sandberg@arm.com 12111986Sandreas.sandberg@arm.com cl.def("append", 12211986Sandreas.sandberg@arm.com [](Vector &v, const T &value) { v.push_back(value); }, 12311986Sandreas.sandberg@arm.com arg("x"), 12411986Sandreas.sandberg@arm.com "Add an item to the end of the list"); 12511986Sandreas.sandberg@arm.com 12611986Sandreas.sandberg@arm.com cl.def("__init__", [](Vector &v, iterable it) { 12711986Sandreas.sandberg@arm.com new (&v) Vector(); 12811986Sandreas.sandberg@arm.com try { 12911986Sandreas.sandberg@arm.com v.reserve(len(it)); 13011986Sandreas.sandberg@arm.com for (handle h : it) 13111986Sandreas.sandberg@arm.com v.push_back(h.cast<T>()); 13211986Sandreas.sandberg@arm.com } catch (...) { 13311986Sandreas.sandberg@arm.com v.~Vector(); 13411986Sandreas.sandberg@arm.com throw; 13511986Sandreas.sandberg@arm.com } 13611986Sandreas.sandberg@arm.com }); 13711986Sandreas.sandberg@arm.com 13811986Sandreas.sandberg@arm.com cl.def("extend", 13911986Sandreas.sandberg@arm.com [](Vector &v, const Vector &src) { 14011986Sandreas.sandberg@arm.com v.reserve(v.size() + src.size()); 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 14711986Sandreas.sandberg@arm.com cl.def("insert", 14811986Sandreas.sandberg@arm.com [](Vector &v, SizeType i, const T &x) { 14911986Sandreas.sandberg@arm.com v.insert(v.begin() + (DiffType) i, x); 15011986Sandreas.sandberg@arm.com }, 15111986Sandreas.sandberg@arm.com arg("i") , arg("x"), 15211986Sandreas.sandberg@arm.com "Insert an item at a given position." 15311986Sandreas.sandberg@arm.com ); 15411986Sandreas.sandberg@arm.com 15511986Sandreas.sandberg@arm.com cl.def("pop", 15611986Sandreas.sandberg@arm.com [](Vector &v) { 15711986Sandreas.sandberg@arm.com if (v.empty()) 15811986Sandreas.sandberg@arm.com throw pybind11::index_error(); 15911986Sandreas.sandberg@arm.com T t = v.back(); 16011986Sandreas.sandberg@arm.com v.pop_back(); 16111986Sandreas.sandberg@arm.com return t; 16211986Sandreas.sandberg@arm.com }, 16311986Sandreas.sandberg@arm.com "Remove and return the last item" 16411986Sandreas.sandberg@arm.com ); 16511986Sandreas.sandberg@arm.com 16611986Sandreas.sandberg@arm.com cl.def("pop", 16711986Sandreas.sandberg@arm.com [](Vector &v, SizeType i) { 16811986Sandreas.sandberg@arm.com if (i >= v.size()) 16911986Sandreas.sandberg@arm.com throw pybind11::index_error(); 17011986Sandreas.sandberg@arm.com T t = v[i]; 17111986Sandreas.sandberg@arm.com v.erase(v.begin() + (DiffType) i); 17211986Sandreas.sandberg@arm.com return t; 17311986Sandreas.sandberg@arm.com }, 17411986Sandreas.sandberg@arm.com arg("i"), 17511986Sandreas.sandberg@arm.com "Remove and return the item at index ``i``" 17611986Sandreas.sandberg@arm.com ); 17711986Sandreas.sandberg@arm.com 17811986Sandreas.sandberg@arm.com cl.def("__setitem__", 17911986Sandreas.sandberg@arm.com [](Vector &v, SizeType i, const T &t) { 18011986Sandreas.sandberg@arm.com if (i >= v.size()) 18111986Sandreas.sandberg@arm.com throw pybind11::index_error(); 18211986Sandreas.sandberg@arm.com v[i] = t; 18311986Sandreas.sandberg@arm.com } 18411986Sandreas.sandberg@arm.com ); 18511986Sandreas.sandberg@arm.com 18611986Sandreas.sandberg@arm.com /// Slicing protocol 18711986Sandreas.sandberg@arm.com cl.def("__getitem__", 18811986Sandreas.sandberg@arm.com [](const Vector &v, slice slice) -> Vector * { 18911986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 19011986Sandreas.sandberg@arm.com 19111986Sandreas.sandberg@arm.com if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 19211986Sandreas.sandberg@arm.com throw pybind11::error_already_set(); 19311986Sandreas.sandberg@arm.com 19411986Sandreas.sandberg@arm.com Vector *seq = new Vector(); 19511986Sandreas.sandberg@arm.com seq->reserve((size_t) slicelength); 19611986Sandreas.sandberg@arm.com 19711986Sandreas.sandberg@arm.com for (size_t i=0; i<slicelength; ++i) { 19811986Sandreas.sandberg@arm.com seq->push_back(v[start]); 19911986Sandreas.sandberg@arm.com start += step; 20011986Sandreas.sandberg@arm.com } 20111986Sandreas.sandberg@arm.com return seq; 20211986Sandreas.sandberg@arm.com }, 20311986Sandreas.sandberg@arm.com arg("s"), 20411986Sandreas.sandberg@arm.com "Retrieve list elements using a slice object" 20511986Sandreas.sandberg@arm.com ); 20611986Sandreas.sandberg@arm.com 20711986Sandreas.sandberg@arm.com cl.def("__setitem__", 20811986Sandreas.sandberg@arm.com [](Vector &v, slice slice, const Vector &value) { 20911986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 21011986Sandreas.sandberg@arm.com if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 21111986Sandreas.sandberg@arm.com throw pybind11::error_already_set(); 21211986Sandreas.sandberg@arm.com 21311986Sandreas.sandberg@arm.com if (slicelength != value.size()) 21411986Sandreas.sandberg@arm.com throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); 21511986Sandreas.sandberg@arm.com 21611986Sandreas.sandberg@arm.com for (size_t i=0; i<slicelength; ++i) { 21711986Sandreas.sandberg@arm.com v[start] = value[i]; 21811986Sandreas.sandberg@arm.com start += step; 21911986Sandreas.sandberg@arm.com } 22011986Sandreas.sandberg@arm.com }, 22111986Sandreas.sandberg@arm.com "Assign list elements using a slice object" 22211986Sandreas.sandberg@arm.com ); 22311986Sandreas.sandberg@arm.com 22411986Sandreas.sandberg@arm.com cl.def("__delitem__", 22511986Sandreas.sandberg@arm.com [](Vector &v, SizeType i) { 22611986Sandreas.sandberg@arm.com if (i >= v.size()) 22711986Sandreas.sandberg@arm.com throw pybind11::index_error(); 22811986Sandreas.sandberg@arm.com v.erase(v.begin() + DiffType(i)); 22911986Sandreas.sandberg@arm.com }, 23011986Sandreas.sandberg@arm.com "Delete the list elements at index ``i``" 23111986Sandreas.sandberg@arm.com ); 23211986Sandreas.sandberg@arm.com 23311986Sandreas.sandberg@arm.com cl.def("__delitem__", 23411986Sandreas.sandberg@arm.com [](Vector &v, slice slice) { 23511986Sandreas.sandberg@arm.com size_t start, stop, step, slicelength; 23611986Sandreas.sandberg@arm.com 23711986Sandreas.sandberg@arm.com if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 23811986Sandreas.sandberg@arm.com throw pybind11::error_already_set(); 23911986Sandreas.sandberg@arm.com 24011986Sandreas.sandberg@arm.com if (step == 1 && false) { 24111986Sandreas.sandberg@arm.com v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength)); 24211986Sandreas.sandberg@arm.com } else { 24311986Sandreas.sandberg@arm.com for (size_t i = 0; i < slicelength; ++i) { 24411986Sandreas.sandberg@arm.com v.erase(v.begin() + DiffType(start)); 24511986Sandreas.sandberg@arm.com start += step - 1; 24611986Sandreas.sandberg@arm.com } 24711986Sandreas.sandberg@arm.com } 24811986Sandreas.sandberg@arm.com }, 24911986Sandreas.sandberg@arm.com "Delete list elements using a slice object" 25011986Sandreas.sandberg@arm.com ); 25111986Sandreas.sandberg@arm.com 25211986Sandreas.sandberg@arm.com} 25311986Sandreas.sandberg@arm.com 25411986Sandreas.sandberg@arm.com// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>), 25511986Sandreas.sandberg@arm.com// we have to access by copying; otherwise we return by reference. 25611986Sandreas.sandberg@arm.comtemplate <typename Vector> using vector_needs_copy = bool_constant< 25711986Sandreas.sandberg@arm.com !std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>::value>; 25811986Sandreas.sandberg@arm.com 25911986Sandreas.sandberg@arm.com// The usual case: access and iterate by reference 26011986Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_> 26111986Sandreas.sandberg@arm.comvoid vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) { 26211986Sandreas.sandberg@arm.com using T = typename Vector::value_type; 26311986Sandreas.sandberg@arm.com using SizeType = typename Vector::size_type; 26411986Sandreas.sandberg@arm.com using ItType = typename Vector::iterator; 26511986Sandreas.sandberg@arm.com 26611986Sandreas.sandberg@arm.com cl.def("__getitem__", 26711986Sandreas.sandberg@arm.com [](Vector &v, SizeType i) -> T & { 26811986Sandreas.sandberg@arm.com if (i >= v.size()) 26911986Sandreas.sandberg@arm.com throw pybind11::index_error(); 27011986Sandreas.sandberg@arm.com return v[i]; 27111986Sandreas.sandberg@arm.com }, 27211986Sandreas.sandberg@arm.com return_value_policy::reference_internal // ref + keepalive 27311986Sandreas.sandberg@arm.com ); 27411986Sandreas.sandberg@arm.com 27511986Sandreas.sandberg@arm.com cl.def("__iter__", 27611986Sandreas.sandberg@arm.com [](Vector &v) { 27711986Sandreas.sandberg@arm.com return pybind11::make_iterator< 27811986Sandreas.sandberg@arm.com return_value_policy::reference_internal, ItType, ItType, T&>( 27911986Sandreas.sandberg@arm.com v.begin(), v.end()); 28011986Sandreas.sandberg@arm.com }, 28111986Sandreas.sandberg@arm.com keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 28211986Sandreas.sandberg@arm.com ); 28311986Sandreas.sandberg@arm.com} 28411986Sandreas.sandberg@arm.com 28511986Sandreas.sandberg@arm.com// The case for special objects, like std::vector<bool>, that have to be returned-by-copy: 28611986Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_> 28711986Sandreas.sandberg@arm.comvoid vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) { 28811986Sandreas.sandberg@arm.com using T = typename Vector::value_type; 28911986Sandreas.sandberg@arm.com using SizeType = typename Vector::size_type; 29011986Sandreas.sandberg@arm.com using ItType = typename Vector::iterator; 29111986Sandreas.sandberg@arm.com cl.def("__getitem__", 29211986Sandreas.sandberg@arm.com [](const Vector &v, SizeType i) -> T { 29311986Sandreas.sandberg@arm.com if (i >= v.size()) 29411986Sandreas.sandberg@arm.com throw pybind11::index_error(); 29511986Sandreas.sandberg@arm.com return v[i]; 29611986Sandreas.sandberg@arm.com } 29711986Sandreas.sandberg@arm.com ); 29811986Sandreas.sandberg@arm.com 29911986Sandreas.sandberg@arm.com cl.def("__iter__", 30011986Sandreas.sandberg@arm.com [](Vector &v) { 30111986Sandreas.sandberg@arm.com return pybind11::make_iterator< 30211986Sandreas.sandberg@arm.com return_value_policy::copy, ItType, ItType, T>( 30311986Sandreas.sandberg@arm.com v.begin(), v.end()); 30411986Sandreas.sandberg@arm.com }, 30511986Sandreas.sandberg@arm.com keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 30611986Sandreas.sandberg@arm.com ); 30711986Sandreas.sandberg@arm.com} 30811986Sandreas.sandberg@arm.com 30911986Sandreas.sandberg@arm.comtemplate <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name) 31011986Sandreas.sandberg@arm.com -> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) { 31111986Sandreas.sandberg@arm.com using size_type = typename Vector::size_type; 31211986Sandreas.sandberg@arm.com 31311986Sandreas.sandberg@arm.com cl.def("__repr__", 31411986Sandreas.sandberg@arm.com [name](Vector &v) { 31511986Sandreas.sandberg@arm.com std::ostringstream s; 31611986Sandreas.sandberg@arm.com s << name << '['; 31711986Sandreas.sandberg@arm.com for (size_type i=0; i < v.size(); ++i) { 31811986Sandreas.sandberg@arm.com s << v[i]; 31911986Sandreas.sandberg@arm.com if (i != v.size() - 1) 32011986Sandreas.sandberg@arm.com s << ", "; 32111986Sandreas.sandberg@arm.com } 32211986Sandreas.sandberg@arm.com s << ']'; 32311986Sandreas.sandberg@arm.com return s.str(); 32411986Sandreas.sandberg@arm.com }, 32511986Sandreas.sandberg@arm.com "Return the canonical string representation of this list." 32611986Sandreas.sandberg@arm.com ); 32711986Sandreas.sandberg@arm.com} 32811986Sandreas.sandberg@arm.com 32911986Sandreas.sandberg@arm.comNAMESPACE_END(detail) 33011986Sandreas.sandberg@arm.com 33111986Sandreas.sandberg@arm.com// 33211986Sandreas.sandberg@arm.com// std::vector 33311986Sandreas.sandberg@arm.com// 33411986Sandreas.sandberg@arm.comtemplate <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args> 33511986Sandreas.sandberg@arm.compybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) { 33611986Sandreas.sandberg@arm.com using Class_ = pybind11::class_<Vector, holder_type>; 33711986Sandreas.sandberg@arm.com 33811986Sandreas.sandberg@arm.com Class_ cl(m, name.c_str(), std::forward<Args>(args)...); 33911986Sandreas.sandberg@arm.com 34011986Sandreas.sandberg@arm.com cl.def(pybind11::init<>()); 34111986Sandreas.sandberg@arm.com 34211986Sandreas.sandberg@arm.com // Register copy constructor (if possible) 34311986Sandreas.sandberg@arm.com detail::vector_if_copy_constructible<Vector, Class_>(cl); 34411986Sandreas.sandberg@arm.com 34511986Sandreas.sandberg@arm.com // Register comparison-related operators and functions (if possible) 34611986Sandreas.sandberg@arm.com detail::vector_if_equal_operator<Vector, Class_>(cl); 34711986Sandreas.sandberg@arm.com 34811986Sandreas.sandberg@arm.com // Register stream insertion operator (if possible) 34911986Sandreas.sandberg@arm.com detail::vector_if_insertion_operator<Vector, Class_>(cl, name); 35011986Sandreas.sandberg@arm.com 35111986Sandreas.sandberg@arm.com // Modifiers require copyable vector value type 35211986Sandreas.sandberg@arm.com detail::vector_modifiers<Vector, Class_>(cl); 35311986Sandreas.sandberg@arm.com 35411986Sandreas.sandberg@arm.com // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive 35511986Sandreas.sandberg@arm.com detail::vector_accessor<Vector, Class_>(cl); 35611986Sandreas.sandberg@arm.com 35711986Sandreas.sandberg@arm.com cl.def("__bool__", 35811986Sandreas.sandberg@arm.com [](const Vector &v) -> bool { 35911986Sandreas.sandberg@arm.com return !v.empty(); 36011986Sandreas.sandberg@arm.com }, 36111986Sandreas.sandberg@arm.com "Check whether the list is nonempty" 36211986Sandreas.sandberg@arm.com ); 36311986Sandreas.sandberg@arm.com 36411986Sandreas.sandberg@arm.com cl.def("__len__", &Vector::size); 36511986Sandreas.sandberg@arm.com 36611986Sandreas.sandberg@arm.com 36711986Sandreas.sandberg@arm.com 36811986Sandreas.sandberg@arm.com 36911986Sandreas.sandberg@arm.com#if 0 37011986Sandreas.sandberg@arm.com // C++ style functions deprecated, leaving it here as an example 37111986Sandreas.sandberg@arm.com cl.def(pybind11::init<size_type>()); 37211986Sandreas.sandberg@arm.com 37311986Sandreas.sandberg@arm.com cl.def("resize", 37411986Sandreas.sandberg@arm.com (void (Vector::*) (size_type count)) & Vector::resize, 37511986Sandreas.sandberg@arm.com "changes the number of elements stored"); 37611986Sandreas.sandberg@arm.com 37711986Sandreas.sandberg@arm.com cl.def("erase", 37811986Sandreas.sandberg@arm.com [](Vector &v, SizeType i) { 37911986Sandreas.sandberg@arm.com if (i >= v.size()) 38011986Sandreas.sandberg@arm.com throw pybind11::index_error(); 38111986Sandreas.sandberg@arm.com v.erase(v.begin() + i); 38211986Sandreas.sandberg@arm.com }, "erases element at index ``i``"); 38311986Sandreas.sandberg@arm.com 38411986Sandreas.sandberg@arm.com cl.def("empty", &Vector::empty, "checks whether the container is empty"); 38511986Sandreas.sandberg@arm.com cl.def("size", &Vector::size, "returns the number of elements"); 38611986Sandreas.sandberg@arm.com cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); 38711986Sandreas.sandberg@arm.com cl.def("pop_back", &Vector::pop_back, "removes the last element"); 38811986Sandreas.sandberg@arm.com 38911986Sandreas.sandberg@arm.com cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); 39011986Sandreas.sandberg@arm.com cl.def("reserve", &Vector::reserve, "reserves storage"); 39111986Sandreas.sandberg@arm.com cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); 39211986Sandreas.sandberg@arm.com cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); 39311986Sandreas.sandberg@arm.com 39411986Sandreas.sandberg@arm.com cl.def("clear", &Vector::clear, "clears the contents"); 39511986Sandreas.sandberg@arm.com cl.def("swap", &Vector::swap, "swaps the contents"); 39611986Sandreas.sandberg@arm.com 39711986Sandreas.sandberg@arm.com cl.def("front", [](Vector &v) { 39811986Sandreas.sandberg@arm.com if (v.size()) return v.front(); 39911986Sandreas.sandberg@arm.com else throw pybind11::index_error(); 40011986Sandreas.sandberg@arm.com }, "access the first element"); 40111986Sandreas.sandberg@arm.com 40211986Sandreas.sandberg@arm.com cl.def("back", [](Vector &v) { 40311986Sandreas.sandberg@arm.com if (v.size()) return v.back(); 40411986Sandreas.sandberg@arm.com else throw pybind11::index_error(); 40511986Sandreas.sandberg@arm.com }, "access the last element "); 40611986Sandreas.sandberg@arm.com 40711986Sandreas.sandberg@arm.com#endif 40811986Sandreas.sandberg@arm.com 40911986Sandreas.sandberg@arm.com return cl; 41011986Sandreas.sandberg@arm.com} 41111986Sandreas.sandberg@arm.com 41211986Sandreas.sandberg@arm.com 41311986Sandreas.sandberg@arm.com 41411986Sandreas.sandberg@arm.com// 41511986Sandreas.sandberg@arm.com// std::map, std::unordered_map 41611986Sandreas.sandberg@arm.com// 41711986Sandreas.sandberg@arm.com 41811986Sandreas.sandberg@arm.comNAMESPACE_BEGIN(detail) 41911986Sandreas.sandberg@arm.com 42011986Sandreas.sandberg@arm.com/* Fallback functions */ 42111986Sandreas.sandberg@arm.comtemplate <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { } 42211986Sandreas.sandberg@arm.comtemplate <typename, typename, typename... Args> void map_assignment(const Args &...) { } 42311986Sandreas.sandberg@arm.com 42411986Sandreas.sandberg@arm.com// Map assignment when copy-assignable: just copy the value 42511986Sandreas.sandberg@arm.comtemplate <typename Map, typename Class_> 42611986Sandreas.sandberg@arm.comvoid map_assignment(enable_if_t<std::is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) { 42711986Sandreas.sandberg@arm.com using KeyType = typename Map::key_type; 42811986Sandreas.sandberg@arm.com using MappedType = typename Map::mapped_type; 42911986Sandreas.sandberg@arm.com 43011986Sandreas.sandberg@arm.com cl.def("__setitem__", 43111986Sandreas.sandberg@arm.com [](Map &m, const KeyType &k, const MappedType &v) { 43211986Sandreas.sandberg@arm.com auto it = m.find(k); 43311986Sandreas.sandberg@arm.com if (it != m.end()) it->second = v; 43411986Sandreas.sandberg@arm.com else m.emplace(k, v); 43511986Sandreas.sandberg@arm.com } 43611986Sandreas.sandberg@arm.com ); 43711986Sandreas.sandberg@arm.com} 43811986Sandreas.sandberg@arm.com 43911986Sandreas.sandberg@arm.com// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting 44011986Sandreas.sandberg@arm.comtemplate<typename Map, typename Class_> 44111986Sandreas.sandberg@arm.comvoid map_assignment(enable_if_t< 44211986Sandreas.sandberg@arm.com !std::is_copy_assignable<typename Map::mapped_type>::value && 44311986Sandreas.sandberg@arm.com std::is_copy_constructible<typename Map::mapped_type>::value, 44411986Sandreas.sandberg@arm.com Class_> &cl) { 44511986Sandreas.sandberg@arm.com using KeyType = typename Map::key_type; 44611986Sandreas.sandberg@arm.com using MappedType = typename Map::mapped_type; 44711986Sandreas.sandberg@arm.com 44811986Sandreas.sandberg@arm.com cl.def("__setitem__", 44911986Sandreas.sandberg@arm.com [](Map &m, const KeyType &k, const MappedType &v) { 45011986Sandreas.sandberg@arm.com // We can't use m[k] = v; because value type might not be default constructable 45111986Sandreas.sandberg@arm.com auto r = m.emplace(k, v); 45211986Sandreas.sandberg@arm.com if (!r.second) { 45311986Sandreas.sandberg@arm.com // value type is not copy assignable so the only way to insert it is to erase it first... 45411986Sandreas.sandberg@arm.com m.erase(r.first); 45511986Sandreas.sandberg@arm.com m.emplace(k, v); 45611986Sandreas.sandberg@arm.com } 45711986Sandreas.sandberg@arm.com } 45811986Sandreas.sandberg@arm.com ); 45911986Sandreas.sandberg@arm.com} 46011986Sandreas.sandberg@arm.com 46111986Sandreas.sandberg@arm.com 46211986Sandreas.sandberg@arm.comtemplate <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name) 46311986Sandreas.sandberg@arm.com-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) { 46411986Sandreas.sandberg@arm.com 46511986Sandreas.sandberg@arm.com cl.def("__repr__", 46611986Sandreas.sandberg@arm.com [name](Map &m) { 46711986Sandreas.sandberg@arm.com std::ostringstream s; 46811986Sandreas.sandberg@arm.com s << name << '{'; 46911986Sandreas.sandberg@arm.com bool f = false; 47011986Sandreas.sandberg@arm.com for (auto const &kv : m) { 47111986Sandreas.sandberg@arm.com if (f) 47211986Sandreas.sandberg@arm.com s << ", "; 47311986Sandreas.sandberg@arm.com s << kv.first << ": " << kv.second; 47411986Sandreas.sandberg@arm.com f = true; 47511986Sandreas.sandberg@arm.com } 47611986Sandreas.sandberg@arm.com s << '}'; 47711986Sandreas.sandberg@arm.com return s.str(); 47811986Sandreas.sandberg@arm.com }, 47911986Sandreas.sandberg@arm.com "Return the canonical string representation of this map." 48011986Sandreas.sandberg@arm.com ); 48111986Sandreas.sandberg@arm.com} 48211986Sandreas.sandberg@arm.com 48311986Sandreas.sandberg@arm.com 48411986Sandreas.sandberg@arm.comNAMESPACE_END(detail) 48511986Sandreas.sandberg@arm.com 48611986Sandreas.sandberg@arm.comtemplate <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args> 48711986Sandreas.sandberg@arm.compybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) { 48811986Sandreas.sandberg@arm.com using KeyType = typename Map::key_type; 48911986Sandreas.sandberg@arm.com using MappedType = typename Map::mapped_type; 49011986Sandreas.sandberg@arm.com using Class_ = pybind11::class_<Map, holder_type>; 49111986Sandreas.sandberg@arm.com 49211986Sandreas.sandberg@arm.com Class_ cl(m, name.c_str(), std::forward<Args>(args)...); 49311986Sandreas.sandberg@arm.com 49411986Sandreas.sandberg@arm.com cl.def(pybind11::init<>()); 49511986Sandreas.sandberg@arm.com 49611986Sandreas.sandberg@arm.com // Register stream insertion operator (if possible) 49711986Sandreas.sandberg@arm.com detail::map_if_insertion_operator<Map, Class_>(cl, name); 49811986Sandreas.sandberg@arm.com 49911986Sandreas.sandberg@arm.com cl.def("__bool__", 50011986Sandreas.sandberg@arm.com [](const Map &m) -> bool { return !m.empty(); }, 50111986Sandreas.sandberg@arm.com "Check whether the map is nonempty" 50211986Sandreas.sandberg@arm.com ); 50311986Sandreas.sandberg@arm.com 50411986Sandreas.sandberg@arm.com cl.def("__iter__", 50511986Sandreas.sandberg@arm.com [](Map &m) { return pybind11::make_key_iterator(m.begin(), m.end()); }, 50611986Sandreas.sandberg@arm.com pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 50711986Sandreas.sandberg@arm.com ); 50811986Sandreas.sandberg@arm.com 50911986Sandreas.sandberg@arm.com cl.def("items", 51011986Sandreas.sandberg@arm.com [](Map &m) { return pybind11::make_iterator(m.begin(), m.end()); }, 51111986Sandreas.sandberg@arm.com pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 51211986Sandreas.sandberg@arm.com ); 51311986Sandreas.sandberg@arm.com 51411986Sandreas.sandberg@arm.com cl.def("__getitem__", 51511986Sandreas.sandberg@arm.com [](Map &m, const KeyType &k) -> MappedType & { 51611986Sandreas.sandberg@arm.com auto it = m.find(k); 51711986Sandreas.sandberg@arm.com if (it == m.end()) 51811986Sandreas.sandberg@arm.com throw pybind11::key_error(); 51911986Sandreas.sandberg@arm.com return it->second; 52011986Sandreas.sandberg@arm.com }, 52111986Sandreas.sandberg@arm.com return_value_policy::reference_internal // ref + keepalive 52211986Sandreas.sandberg@arm.com ); 52311986Sandreas.sandberg@arm.com 52411986Sandreas.sandberg@arm.com // Assignment provided only if the type is copyable 52511986Sandreas.sandberg@arm.com detail::map_assignment<Map, Class_>(cl); 52611986Sandreas.sandberg@arm.com 52711986Sandreas.sandberg@arm.com cl.def("__delitem__", 52811986Sandreas.sandberg@arm.com [](Map &m, const KeyType &k) { 52911986Sandreas.sandberg@arm.com auto it = m.find(k); 53011986Sandreas.sandberg@arm.com if (it == m.end()) 53111986Sandreas.sandberg@arm.com throw pybind11::key_error(); 53211986Sandreas.sandberg@arm.com return m.erase(it); 53311986Sandreas.sandberg@arm.com } 53411986Sandreas.sandberg@arm.com ); 53511986Sandreas.sandberg@arm.com 53611986Sandreas.sandberg@arm.com cl.def("__len__", &Map::size); 53711986Sandreas.sandberg@arm.com 53811986Sandreas.sandberg@arm.com return cl; 53911986Sandreas.sandberg@arm.com} 54011986Sandreas.sandberg@arm.com 54111986Sandreas.sandberg@arm.comNAMESPACE_END(pybind11) 542