stl_bind.h revision 14299:2fbea9df56d2
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 "detail/common.h" 13#include "operators.h" 14 15#include <algorithm> 16#include <sstream> 17 18NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 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<is_copy_constructible<Vector>::value, Class_> &cl) { 70 cl.def(init<const Vector &>(), "Copy constructor"); 71} 72 73template<typename Vector, typename Class_> 74void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) { 75 using T = typename Vector::value_type; 76 77 cl.def(self == self); 78 cl.def(self != self); 79 80 cl.def("count", 81 [](const Vector &v, const T &x) { 82 return std::count(v.begin(), v.end(), x); 83 }, 84 arg("x"), 85 "Return the number of times ``x`` appears in the list" 86 ); 87 88 cl.def("remove", [](Vector &v, const T &x) { 89 auto p = std::find(v.begin(), v.end(), x); 90 if (p != v.end()) 91 v.erase(p); 92 else 93 throw value_error(); 94 }, 95 arg("x"), 96 "Remove the first item from the list whose value is x. " 97 "It is an error if there is no such item." 98 ); 99 100 cl.def("__contains__", 101 [](const Vector &v, const T &x) { 102 return std::find(v.begin(), v.end(), x) != v.end(); 103 }, 104 arg("x"), 105 "Return true the container contains ``x``" 106 ); 107} 108 109// Vector modifiers -- requires a copyable vector_type: 110// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems 111// silly to allow deletion but not insertion, so include them here too.) 112template <typename Vector, typename Class_> 113void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) { 114 using T = typename Vector::value_type; 115 using SizeType = typename Vector::size_type; 116 using DiffType = typename Vector::difference_type; 117 118 auto wrap_i = [](DiffType i, SizeType n) { 119 if (i < 0) 120 i += n; 121 if (i < 0 || (SizeType)i >= n) 122 throw index_error(); 123 return i; 124 }; 125 126 cl.def("append", 127 [](Vector &v, const T &value) { v.push_back(value); }, 128 arg("x"), 129 "Add an item to the end of the list"); 130 131 cl.def(init([](iterable it) { 132 auto v = std::unique_ptr<Vector>(new Vector()); 133 v->reserve(len_hint(it)); 134 for (handle h : it) 135 v->push_back(h.cast<T>()); 136 return v.release(); 137 })); 138 139 cl.def("extend", 140 [](Vector &v, const Vector &src) { 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("extend", 148 [](Vector &v, iterable it) { 149 const size_t old_size = v.size(); 150 v.reserve(old_size + len_hint(it)); 151 try { 152 for (handle h : it) { 153 v.push_back(h.cast<T>()); 154 } 155 } catch (const cast_error &) { 156 v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), v.end()); 157 try { 158 v.shrink_to_fit(); 159 } catch (const std::exception &) { 160 // Do nothing 161 } 162 throw; 163 } 164 }, 165 arg("L"), 166 "Extend the list by appending all the items in the given list" 167 ); 168 169 cl.def("insert", 170 [](Vector &v, DiffType i, const T &x) { 171 // Can't use wrap_i; i == v.size() is OK 172 if (i < 0) 173 i += v.size(); 174 if (i < 0 || (SizeType)i > v.size()) 175 throw index_error(); 176 v.insert(v.begin() + i, x); 177 }, 178 arg("i") , arg("x"), 179 "Insert an item at a given position." 180 ); 181 182 cl.def("pop", 183 [](Vector &v) { 184 if (v.empty()) 185 throw index_error(); 186 T t = v.back(); 187 v.pop_back(); 188 return t; 189 }, 190 "Remove and return the last item" 191 ); 192 193 cl.def("pop", 194 [wrap_i](Vector &v, DiffType i) { 195 i = wrap_i(i, v.size()); 196 T t = v[(SizeType) i]; 197 v.erase(v.begin() + i); 198 return t; 199 }, 200 arg("i"), 201 "Remove and return the item at index ``i``" 202 ); 203 204 cl.def("__setitem__", 205 [wrap_i](Vector &v, DiffType i, const T &t) { 206 i = wrap_i(i, v.size()); 207 v[(SizeType)i] = t; 208 } 209 ); 210 211 /// Slicing protocol 212 cl.def("__getitem__", 213 [](const Vector &v, slice slice) -> Vector * { 214 size_t start, stop, step, slicelength; 215 216 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 217 throw error_already_set(); 218 219 Vector *seq = new Vector(); 220 seq->reserve((size_t) slicelength); 221 222 for (size_t i=0; i<slicelength; ++i) { 223 seq->push_back(v[start]); 224 start += step; 225 } 226 return seq; 227 }, 228 arg("s"), 229 "Retrieve list elements using a slice object" 230 ); 231 232 cl.def("__setitem__", 233 [](Vector &v, slice slice, const Vector &value) { 234 size_t start, stop, step, slicelength; 235 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 236 throw error_already_set(); 237 238 if (slicelength != value.size()) 239 throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); 240 241 for (size_t i=0; i<slicelength; ++i) { 242 v[start] = value[i]; 243 start += step; 244 } 245 }, 246 "Assign list elements using a slice object" 247 ); 248 249 cl.def("__delitem__", 250 [wrap_i](Vector &v, DiffType i) { 251 i = wrap_i(i, v.size()); 252 v.erase(v.begin() + i); 253 }, 254 "Delete the list elements at index ``i``" 255 ); 256 257 cl.def("__delitem__", 258 [](Vector &v, slice slice) { 259 size_t start, stop, step, slicelength; 260 261 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 262 throw error_already_set(); 263 264 if (step == 1 && false) { 265 v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength)); 266 } else { 267 for (size_t i = 0; i < slicelength; ++i) { 268 v.erase(v.begin() + DiffType(start)); 269 start += step - 1; 270 } 271 } 272 }, 273 "Delete list elements using a slice object" 274 ); 275 276} 277 278// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>), 279// we have to access by copying; otherwise we return by reference. 280template <typename Vector> using vector_needs_copy = negation< 281 std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>; 282 283// The usual case: access and iterate by reference 284template <typename Vector, typename Class_> 285void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) { 286 using T = typename Vector::value_type; 287 using SizeType = typename Vector::size_type; 288 using DiffType = typename Vector::difference_type; 289 using ItType = typename Vector::iterator; 290 291 auto wrap_i = [](DiffType i, SizeType n) { 292 if (i < 0) 293 i += n; 294 if (i < 0 || (SizeType)i >= n) 295 throw index_error(); 296 return i; 297 }; 298 299 cl.def("__getitem__", 300 [wrap_i](Vector &v, DiffType i) -> T & { 301 i = wrap_i(i, v.size()); 302 return v[(SizeType)i]; 303 }, 304 return_value_policy::reference_internal // ref + keepalive 305 ); 306 307 cl.def("__iter__", 308 [](Vector &v) { 309 return make_iterator< 310 return_value_policy::reference_internal, ItType, ItType, T&>( 311 v.begin(), v.end()); 312 }, 313 keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 314 ); 315} 316 317// The case for special objects, like std::vector<bool>, that have to be returned-by-copy: 318template <typename Vector, typename Class_> 319void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) { 320 using T = typename Vector::value_type; 321 using SizeType = typename Vector::size_type; 322 using DiffType = typename Vector::difference_type; 323 using ItType = typename Vector::iterator; 324 cl.def("__getitem__", 325 [](const Vector &v, DiffType i) -> T { 326 if (i < 0 && (i += v.size()) < 0) 327 throw index_error(); 328 if ((SizeType)i >= v.size()) 329 throw index_error(); 330 return v[(SizeType)i]; 331 } 332 ); 333 334 cl.def("__iter__", 335 [](Vector &v) { 336 return make_iterator< 337 return_value_policy::copy, ItType, ItType, T>( 338 v.begin(), v.end()); 339 }, 340 keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 341 ); 342} 343 344template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name) 345 -> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) { 346 using size_type = typename Vector::size_type; 347 348 cl.def("__repr__", 349 [name](Vector &v) { 350 std::ostringstream s; 351 s << name << '['; 352 for (size_type i=0; i < v.size(); ++i) { 353 s << v[i]; 354 if (i != v.size() - 1) 355 s << ", "; 356 } 357 s << ']'; 358 return s.str(); 359 }, 360 "Return the canonical string representation of this list." 361 ); 362} 363 364// Provide the buffer interface for vectors if we have data() and we have a format for it 365// 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 366template <typename Vector, typename = void> 367struct vector_has_data_and_format : std::false_type {}; 368template <typename Vector> 369struct 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 {}; 370 371// Add the buffer interface to a vector 372template <typename Vector, typename Class_, typename... Args> 373enable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value> 374vector_buffer(Class_& cl) { 375 using T = typename Vector::value_type; 376 377 static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector"); 378 379 // 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 380 format_descriptor<T>::format(); 381 382 cl.def_buffer([](Vector& v) -> buffer_info { 383 return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)}); 384 }); 385 386 cl.def(init([](buffer buf) { 387 auto info = buf.request(); 388 if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) 389 throw type_error("Only valid 1D buffers can be copied to a vector"); 390 if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize) 391 throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")"); 392 393 auto vec = std::unique_ptr<Vector>(new Vector()); 394 vec->reserve((size_t) info.shape[0]); 395 T *p = static_cast<T*>(info.ptr); 396 ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T)); 397 T *end = p + info.shape[0] * step; 398 for (; p != end; p += step) 399 vec->push_back(*p); 400 return vec.release(); 401 })); 402 403 return; 404} 405 406template <typename Vector, typename Class_, typename... Args> 407enable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {} 408 409NAMESPACE_END(detail) 410 411// 412// std::vector 413// 414template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args> 415class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) { 416 using Class_ = class_<Vector, holder_type>; 417 418 // If the value_type is unregistered (e.g. a converting type) or is itself registered 419 // module-local then make the vector binding module-local as well: 420 using vtype = typename Vector::value_type; 421 auto vtype_info = detail::get_type_info(typeid(vtype)); 422 bool local = !vtype_info || vtype_info->module_local; 423 424 Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...); 425 426 // Declare the buffer interface if a buffer_protocol() is passed in 427 detail::vector_buffer<Vector, Class_, Args...>(cl); 428 429 cl.def(init<>()); 430 431 // Register copy constructor (if possible) 432 detail::vector_if_copy_constructible<Vector, Class_>(cl); 433 434 // Register comparison-related operators and functions (if possible) 435 detail::vector_if_equal_operator<Vector, Class_>(cl); 436 437 // Register stream insertion operator (if possible) 438 detail::vector_if_insertion_operator<Vector, Class_>(cl, name); 439 440 // Modifiers require copyable vector value type 441 detail::vector_modifiers<Vector, Class_>(cl); 442 443 // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive 444 detail::vector_accessor<Vector, Class_>(cl); 445 446 cl.def("__bool__", 447 [](const Vector &v) -> bool { 448 return !v.empty(); 449 }, 450 "Check whether the list is nonempty" 451 ); 452 453 cl.def("__len__", &Vector::size); 454 455 456 457 458#if 0 459 // C++ style functions deprecated, leaving it here as an example 460 cl.def(init<size_type>()); 461 462 cl.def("resize", 463 (void (Vector::*) (size_type count)) & Vector::resize, 464 "changes the number of elements stored"); 465 466 cl.def("erase", 467 [](Vector &v, SizeType i) { 468 if (i >= v.size()) 469 throw index_error(); 470 v.erase(v.begin() + i); 471 }, "erases element at index ``i``"); 472 473 cl.def("empty", &Vector::empty, "checks whether the container is empty"); 474 cl.def("size", &Vector::size, "returns the number of elements"); 475 cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); 476 cl.def("pop_back", &Vector::pop_back, "removes the last element"); 477 478 cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); 479 cl.def("reserve", &Vector::reserve, "reserves storage"); 480 cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); 481 cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); 482 483 cl.def("clear", &Vector::clear, "clears the contents"); 484 cl.def("swap", &Vector::swap, "swaps the contents"); 485 486 cl.def("front", [](Vector &v) { 487 if (v.size()) return v.front(); 488 else throw index_error(); 489 }, "access the first element"); 490 491 cl.def("back", [](Vector &v) { 492 if (v.size()) return v.back(); 493 else throw index_error(); 494 }, "access the last element "); 495 496#endif 497 498 return cl; 499} 500 501 502 503// 504// std::map, std::unordered_map 505// 506 507NAMESPACE_BEGIN(detail) 508 509/* Fallback functions */ 510template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { } 511template <typename, typename, typename... Args> void map_assignment(const Args &...) { } 512 513// Map assignment when copy-assignable: just copy the value 514template <typename Map, typename Class_> 515void map_assignment(enable_if_t<std::is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) { 516 using KeyType = typename Map::key_type; 517 using MappedType = typename Map::mapped_type; 518 519 cl.def("__setitem__", 520 [](Map &m, const KeyType &k, const MappedType &v) { 521 auto it = m.find(k); 522 if (it != m.end()) it->second = v; 523 else m.emplace(k, v); 524 } 525 ); 526} 527 528// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting 529template<typename Map, typename Class_> 530void map_assignment(enable_if_t< 531 !std::is_copy_assignable<typename Map::mapped_type>::value && 532 is_copy_constructible<typename Map::mapped_type>::value, 533 Class_> &cl) { 534 using KeyType = typename Map::key_type; 535 using MappedType = typename Map::mapped_type; 536 537 cl.def("__setitem__", 538 [](Map &m, const KeyType &k, const MappedType &v) { 539 // We can't use m[k] = v; because value type might not be default constructable 540 auto r = m.emplace(k, v); 541 if (!r.second) { 542 // value type is not copy assignable so the only way to insert it is to erase it first... 543 m.erase(r.first); 544 m.emplace(k, v); 545 } 546 } 547 ); 548} 549 550 551template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name) 552-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) { 553 554 cl.def("__repr__", 555 [name](Map &m) { 556 std::ostringstream s; 557 s << name << '{'; 558 bool f = false; 559 for (auto const &kv : m) { 560 if (f) 561 s << ", "; 562 s << kv.first << ": " << kv.second; 563 f = true; 564 } 565 s << '}'; 566 return s.str(); 567 }, 568 "Return the canonical string representation of this map." 569 ); 570} 571 572 573NAMESPACE_END(detail) 574 575template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args> 576class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) { 577 using KeyType = typename Map::key_type; 578 using MappedType = typename Map::mapped_type; 579 using Class_ = class_<Map, holder_type>; 580 581 // If either type is a non-module-local bound type then make the map binding non-local as well; 582 // otherwise (e.g. both types are either module-local or converting) the map will be 583 // module-local. 584 auto tinfo = detail::get_type_info(typeid(MappedType)); 585 bool local = !tinfo || tinfo->module_local; 586 if (local) { 587 tinfo = detail::get_type_info(typeid(KeyType)); 588 local = !tinfo || tinfo->module_local; 589 } 590 591 Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...); 592 593 cl.def(init<>()); 594 595 // Register stream insertion operator (if possible) 596 detail::map_if_insertion_operator<Map, Class_>(cl, name); 597 598 cl.def("__bool__", 599 [](const Map &m) -> bool { return !m.empty(); }, 600 "Check whether the map is nonempty" 601 ); 602 603 cl.def("__iter__", 604 [](Map &m) { return make_key_iterator(m.begin(), m.end()); }, 605 keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 606 ); 607 608 cl.def("items", 609 [](Map &m) { return make_iterator(m.begin(), m.end()); }, 610 keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 611 ); 612 613 cl.def("__getitem__", 614 [](Map &m, const KeyType &k) -> MappedType & { 615 auto it = m.find(k); 616 if (it == m.end()) 617 throw key_error(); 618 return it->second; 619 }, 620 return_value_policy::reference_internal // ref + keepalive 621 ); 622 623 cl.def("__contains__", 624 [](Map &m, const KeyType &k) -> bool { 625 auto it = m.find(k); 626 if (it == m.end()) 627 return false; 628 return true; 629 } 630 ); 631 632 // Assignment provided only if the type is copyable 633 detail::map_assignment<Map, Class_>(cl); 634 635 cl.def("__delitem__", 636 [](Map &m, const KeyType &k) { 637 auto it = m.find(k); 638 if (it == m.end()) 639 throw key_error(); 640 m.erase(it); 641 } 642 ); 643 644 cl.def("__len__", &Map::size); 645 646 return cl; 647} 648 649NAMESPACE_END(PYBIND11_NAMESPACE) 650