stl_bind.h revision 11986:c12e4625ab56
1/* 2 pybind11/std_bind.h: Binding generators for STL data types 3 4 Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob 5 6 All rights reserved. Use of this source code is governed by a 7 BSD-style license that can be found in the LICENSE file. 8*/ 9 10#pragma once 11 12#include "common.h" 13#include "operators.h" 14 15#include <algorithm> 16#include <sstream> 17 18NAMESPACE_BEGIN(pybind11) 19NAMESPACE_BEGIN(detail) 20 21/* SFINAE helper class used by 'is_comparable */ 22template <typename T> struct container_traits { 23 template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*); 24 template <typename T2> static std::false_type test_comparable(...); 25 template <typename T2> static std::true_type test_value(typename T2::value_type *); 26 template <typename T2> static std::false_type test_value(...); 27 template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *); 28 template <typename T2> static std::false_type test_pair(...); 29 30 static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value; 31 static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value; 32 static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value; 33 static constexpr const bool is_element = !is_pair && !is_vector; 34}; 35 36/* Default: is_comparable -> std::false_type */ 37template <typename T, typename SFINAE = void> 38struct is_comparable : std::false_type { }; 39 40/* For non-map data structures, check whether operator== can be instantiated */ 41template <typename T> 42struct is_comparable< 43 T, enable_if_t<container_traits<T>::is_element && 44 container_traits<T>::is_comparable>> 45 : std::true_type { }; 46 47/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */ 48template <typename T> 49struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> { 50 static constexpr const bool value = 51 is_comparable<typename T::value_type>::value; 52}; 53 54/* For pairs, recursively check the two data types */ 55template <typename T> 56struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> { 57 static constexpr const bool value = 58 is_comparable<typename T::first_type>::value && 59 is_comparable<typename T::second_type>::value; 60}; 61 62/* Fallback functions */ 63template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { } 64template <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { } 65template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { } 66template <typename, typename, typename... Args> void vector_modifiers(const Args &...) { } 67 68template<typename Vector, typename Class_> 69void vector_if_copy_constructible(enable_if_t< 70 std::is_copy_constructible<Vector>::value && 71 std::is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) { 72 73 cl.def(pybind11::init<const Vector &>(), "Copy constructor"); 74} 75 76template<typename Vector, typename Class_> 77void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) { 78 using T = typename Vector::value_type; 79 80 cl.def(self == self); 81 cl.def(self != self); 82 83 cl.def("count", 84 [](const Vector &v, const T &x) { 85 return std::count(v.begin(), v.end(), x); 86 }, 87 arg("x"), 88 "Return the number of times ``x`` appears in the list" 89 ); 90 91 cl.def("remove", [](Vector &v, const T &x) { 92 auto p = std::find(v.begin(), v.end(), x); 93 if (p != v.end()) 94 v.erase(p); 95 else 96 throw pybind11::value_error(); 97 }, 98 arg("x"), 99 "Remove the first item from the list whose value is x. " 100 "It is an error if there is no such item." 101 ); 102 103 cl.def("__contains__", 104 [](const Vector &v, const T &x) { 105 return std::find(v.begin(), v.end(), x) != v.end(); 106 }, 107 arg("x"), 108 "Return true the container contains ``x``" 109 ); 110} 111 112// Vector modifiers -- requires a copyable vector_type: 113// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems 114// silly to allow deletion but not insertion, so include them here too.) 115template <typename Vector, typename Class_> 116void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) { 117 using T = typename Vector::value_type; 118 using SizeType = typename Vector::size_type; 119 using DiffType = typename Vector::difference_type; 120 121 cl.def("append", 122 [](Vector &v, const T &value) { v.push_back(value); }, 123 arg("x"), 124 "Add an item to the end of the list"); 125 126 cl.def("__init__", [](Vector &v, iterable it) { 127 new (&v) Vector(); 128 try { 129 v.reserve(len(it)); 130 for (handle h : it) 131 v.push_back(h.cast<T>()); 132 } catch (...) { 133 v.~Vector(); 134 throw; 135 } 136 }); 137 138 cl.def("extend", 139 [](Vector &v, const Vector &src) { 140 v.reserve(v.size() + src.size()); 141 v.insert(v.end(), src.begin(), src.end()); 142 }, 143 arg("L"), 144 "Extend the list by appending all the items in the given list" 145 ); 146 147 cl.def("insert", 148 [](Vector &v, SizeType i, const T &x) { 149 v.insert(v.begin() + (DiffType) i, x); 150 }, 151 arg("i") , arg("x"), 152 "Insert an item at a given position." 153 ); 154 155 cl.def("pop", 156 [](Vector &v) { 157 if (v.empty()) 158 throw pybind11::index_error(); 159 T t = v.back(); 160 v.pop_back(); 161 return t; 162 }, 163 "Remove and return the last item" 164 ); 165 166 cl.def("pop", 167 [](Vector &v, SizeType i) { 168 if (i >= v.size()) 169 throw pybind11::index_error(); 170 T t = v[i]; 171 v.erase(v.begin() + (DiffType) i); 172 return t; 173 }, 174 arg("i"), 175 "Remove and return the item at index ``i``" 176 ); 177 178 cl.def("__setitem__", 179 [](Vector &v, SizeType i, const T &t) { 180 if (i >= v.size()) 181 throw pybind11::index_error(); 182 v[i] = t; 183 } 184 ); 185 186 /// Slicing protocol 187 cl.def("__getitem__", 188 [](const Vector &v, slice slice) -> Vector * { 189 size_t start, stop, step, slicelength; 190 191 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 192 throw pybind11::error_already_set(); 193 194 Vector *seq = new Vector(); 195 seq->reserve((size_t) slicelength); 196 197 for (size_t i=0; i<slicelength; ++i) { 198 seq->push_back(v[start]); 199 start += step; 200 } 201 return seq; 202 }, 203 arg("s"), 204 "Retrieve list elements using a slice object" 205 ); 206 207 cl.def("__setitem__", 208 [](Vector &v, slice slice, const Vector &value) { 209 size_t start, stop, step, slicelength; 210 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 211 throw pybind11::error_already_set(); 212 213 if (slicelength != value.size()) 214 throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); 215 216 for (size_t i=0; i<slicelength; ++i) { 217 v[start] = value[i]; 218 start += step; 219 } 220 }, 221 "Assign list elements using a slice object" 222 ); 223 224 cl.def("__delitem__", 225 [](Vector &v, SizeType i) { 226 if (i >= v.size()) 227 throw pybind11::index_error(); 228 v.erase(v.begin() + DiffType(i)); 229 }, 230 "Delete the list elements at index ``i``" 231 ); 232 233 cl.def("__delitem__", 234 [](Vector &v, slice slice) { 235 size_t start, stop, step, slicelength; 236 237 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 238 throw pybind11::error_already_set(); 239 240 if (step == 1 && false) { 241 v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength)); 242 } else { 243 for (size_t i = 0; i < slicelength; ++i) { 244 v.erase(v.begin() + DiffType(start)); 245 start += step - 1; 246 } 247 } 248 }, 249 "Delete list elements using a slice object" 250 ); 251 252} 253 254// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>), 255// we have to access by copying; otherwise we return by reference. 256template <typename Vector> using vector_needs_copy = bool_constant< 257 !std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>::value>; 258 259// The usual case: access and iterate by reference 260template <typename Vector, typename Class_> 261void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) { 262 using T = typename Vector::value_type; 263 using SizeType = typename Vector::size_type; 264 using ItType = typename Vector::iterator; 265 266 cl.def("__getitem__", 267 [](Vector &v, SizeType i) -> T & { 268 if (i >= v.size()) 269 throw pybind11::index_error(); 270 return v[i]; 271 }, 272 return_value_policy::reference_internal // ref + keepalive 273 ); 274 275 cl.def("__iter__", 276 [](Vector &v) { 277 return pybind11::make_iterator< 278 return_value_policy::reference_internal, ItType, ItType, T&>( 279 v.begin(), v.end()); 280 }, 281 keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 282 ); 283} 284 285// The case for special objects, like std::vector<bool>, that have to be returned-by-copy: 286template <typename Vector, typename Class_> 287void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) { 288 using T = typename Vector::value_type; 289 using SizeType = typename Vector::size_type; 290 using ItType = typename Vector::iterator; 291 cl.def("__getitem__", 292 [](const Vector &v, SizeType i) -> T { 293 if (i >= v.size()) 294 throw pybind11::index_error(); 295 return v[i]; 296 } 297 ); 298 299 cl.def("__iter__", 300 [](Vector &v) { 301 return pybind11::make_iterator< 302 return_value_policy::copy, ItType, ItType, T>( 303 v.begin(), v.end()); 304 }, 305 keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 306 ); 307} 308 309template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name) 310 -> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) { 311 using size_type = typename Vector::size_type; 312 313 cl.def("__repr__", 314 [name](Vector &v) { 315 std::ostringstream s; 316 s << name << '['; 317 for (size_type i=0; i < v.size(); ++i) { 318 s << v[i]; 319 if (i != v.size() - 1) 320 s << ", "; 321 } 322 s << ']'; 323 return s.str(); 324 }, 325 "Return the canonical string representation of this list." 326 ); 327} 328 329NAMESPACE_END(detail) 330 331// 332// std::vector 333// 334template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args> 335pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) { 336 using Class_ = pybind11::class_<Vector, holder_type>; 337 338 Class_ cl(m, name.c_str(), std::forward<Args>(args)...); 339 340 cl.def(pybind11::init<>()); 341 342 // Register copy constructor (if possible) 343 detail::vector_if_copy_constructible<Vector, Class_>(cl); 344 345 // Register comparison-related operators and functions (if possible) 346 detail::vector_if_equal_operator<Vector, Class_>(cl); 347 348 // Register stream insertion operator (if possible) 349 detail::vector_if_insertion_operator<Vector, Class_>(cl, name); 350 351 // Modifiers require copyable vector value type 352 detail::vector_modifiers<Vector, Class_>(cl); 353 354 // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive 355 detail::vector_accessor<Vector, Class_>(cl); 356 357 cl.def("__bool__", 358 [](const Vector &v) -> bool { 359 return !v.empty(); 360 }, 361 "Check whether the list is nonempty" 362 ); 363 364 cl.def("__len__", &Vector::size); 365 366 367 368 369#if 0 370 // C++ style functions deprecated, leaving it here as an example 371 cl.def(pybind11::init<size_type>()); 372 373 cl.def("resize", 374 (void (Vector::*) (size_type count)) & Vector::resize, 375 "changes the number of elements stored"); 376 377 cl.def("erase", 378 [](Vector &v, SizeType i) { 379 if (i >= v.size()) 380 throw pybind11::index_error(); 381 v.erase(v.begin() + i); 382 }, "erases element at index ``i``"); 383 384 cl.def("empty", &Vector::empty, "checks whether the container is empty"); 385 cl.def("size", &Vector::size, "returns the number of elements"); 386 cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); 387 cl.def("pop_back", &Vector::pop_back, "removes the last element"); 388 389 cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); 390 cl.def("reserve", &Vector::reserve, "reserves storage"); 391 cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); 392 cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); 393 394 cl.def("clear", &Vector::clear, "clears the contents"); 395 cl.def("swap", &Vector::swap, "swaps the contents"); 396 397 cl.def("front", [](Vector &v) { 398 if (v.size()) return v.front(); 399 else throw pybind11::index_error(); 400 }, "access the first element"); 401 402 cl.def("back", [](Vector &v) { 403 if (v.size()) return v.back(); 404 else throw pybind11::index_error(); 405 }, "access the last element "); 406 407#endif 408 409 return cl; 410} 411 412 413 414// 415// std::map, std::unordered_map 416// 417 418NAMESPACE_BEGIN(detail) 419 420/* Fallback functions */ 421template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { } 422template <typename, typename, typename... Args> void map_assignment(const Args &...) { } 423 424// Map assignment when copy-assignable: just copy the value 425template <typename Map, typename Class_> 426void map_assignment(enable_if_t<std::is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) { 427 using KeyType = typename Map::key_type; 428 using MappedType = typename Map::mapped_type; 429 430 cl.def("__setitem__", 431 [](Map &m, const KeyType &k, const MappedType &v) { 432 auto it = m.find(k); 433 if (it != m.end()) it->second = v; 434 else m.emplace(k, v); 435 } 436 ); 437} 438 439// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting 440template<typename Map, typename Class_> 441void map_assignment(enable_if_t< 442 !std::is_copy_assignable<typename Map::mapped_type>::value && 443 std::is_copy_constructible<typename Map::mapped_type>::value, 444 Class_> &cl) { 445 using KeyType = typename Map::key_type; 446 using MappedType = typename Map::mapped_type; 447 448 cl.def("__setitem__", 449 [](Map &m, const KeyType &k, const MappedType &v) { 450 // We can't use m[k] = v; because value type might not be default constructable 451 auto r = m.emplace(k, v); 452 if (!r.second) { 453 // value type is not copy assignable so the only way to insert it is to erase it first... 454 m.erase(r.first); 455 m.emplace(k, v); 456 } 457 } 458 ); 459} 460 461 462template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name) 463-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) { 464 465 cl.def("__repr__", 466 [name](Map &m) { 467 std::ostringstream s; 468 s << name << '{'; 469 bool f = false; 470 for (auto const &kv : m) { 471 if (f) 472 s << ", "; 473 s << kv.first << ": " << kv.second; 474 f = true; 475 } 476 s << '}'; 477 return s.str(); 478 }, 479 "Return the canonical string representation of this map." 480 ); 481} 482 483 484NAMESPACE_END(detail) 485 486template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args> 487pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) { 488 using KeyType = typename Map::key_type; 489 using MappedType = typename Map::mapped_type; 490 using Class_ = pybind11::class_<Map, holder_type>; 491 492 Class_ cl(m, name.c_str(), std::forward<Args>(args)...); 493 494 cl.def(pybind11::init<>()); 495 496 // Register stream insertion operator (if possible) 497 detail::map_if_insertion_operator<Map, Class_>(cl, name); 498 499 cl.def("__bool__", 500 [](const Map &m) -> bool { return !m.empty(); }, 501 "Check whether the map is nonempty" 502 ); 503 504 cl.def("__iter__", 505 [](Map &m) { return pybind11::make_key_iterator(m.begin(), m.end()); }, 506 pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 507 ); 508 509 cl.def("items", 510 [](Map &m) { return pybind11::make_iterator(m.begin(), m.end()); }, 511 pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 512 ); 513 514 cl.def("__getitem__", 515 [](Map &m, const KeyType &k) -> MappedType & { 516 auto it = m.find(k); 517 if (it == m.end()) 518 throw pybind11::key_error(); 519 return it->second; 520 }, 521 return_value_policy::reference_internal // ref + keepalive 522 ); 523 524 // Assignment provided only if the type is copyable 525 detail::map_assignment<Map, Class_>(cl); 526 527 cl.def("__delitem__", 528 [](Map &m, const KeyType &k) { 529 auto it = m.find(k); 530 if (it == m.end()) 531 throw pybind11::key_error(); 532 return m.erase(it); 533 } 534 ); 535 536 cl.def("__len__", &Map::size); 537 538 return cl; 539} 540 541NAMESPACE_END(pybind11) 542