File indexing completed on 2025-02-16 05:12:19
0001 /* 0002 pybind11/std_bind.h: Binding generators for STL data types 0003 0004 Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob 0005 0006 All rights reserved. Use of this source code is governed by a 0007 BSD-style license that can be found in the LICENSE file. 0008 */ 0009 0010 #pragma once 0011 0012 #include "detail/common.h" 0013 #include "operators.h" 0014 0015 #include <algorithm> 0016 #include <sstream> 0017 0018 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 0019 PYBIND11_NAMESPACE_BEGIN(detail) 0020 0021 /* SFINAE helper class used by 'is_comparable */ 0022 template <typename T> struct container_traits { 0023 template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*); 0024 template <typename T2> static std::false_type test_comparable(...); 0025 template <typename T2> static std::true_type test_value(typename T2::value_type *); 0026 template <typename T2> static std::false_type test_value(...); 0027 template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *); 0028 template <typename T2> static std::false_type test_pair(...); 0029 0030 static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value; 0031 static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value; 0032 static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value; 0033 static constexpr const bool is_element = !is_pair && !is_vector; 0034 }; 0035 0036 /* Default: is_comparable -> std::false_type */ 0037 template <typename T, typename SFINAE = void> 0038 struct is_comparable : std::false_type { }; 0039 0040 /* For non-map data structures, check whether operator== can be instantiated */ 0041 template <typename T> 0042 struct is_comparable< 0043 T, enable_if_t<container_traits<T>::is_element && 0044 container_traits<T>::is_comparable>> 0045 : std::true_type { }; 0046 0047 /* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */ 0048 template <typename T> 0049 struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> { 0050 static constexpr const bool value = 0051 is_comparable<typename T::value_type>::value; 0052 }; 0053 0054 /* For pairs, recursively check the two data types */ 0055 template <typename T> 0056 struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> { 0057 static constexpr const bool value = 0058 is_comparable<typename T::first_type>::value && 0059 is_comparable<typename T::second_type>::value; 0060 }; 0061 0062 /* Fallback functions */ 0063 template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { } 0064 template <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { } 0065 template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { } 0066 template <typename, typename, typename... Args> void vector_modifiers(const Args &...) { } 0067 0068 template<typename Vector, typename Class_> 0069 void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) { 0070 cl.def(init<const Vector &>(), "Copy constructor"); 0071 } 0072 0073 template<typename Vector, typename Class_> 0074 void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) { 0075 using T = typename Vector::value_type; 0076 0077 cl.def(self == self); 0078 cl.def(self != self); 0079 0080 cl.def("count", 0081 [](const Vector &v, const T &x) { 0082 return std::count(v.begin(), v.end(), x); 0083 }, 0084 arg("x"), 0085 "Return the number of times ``x`` appears in the list" 0086 ); 0087 0088 cl.def("remove", [](Vector &v, const T &x) { 0089 auto p = std::find(v.begin(), v.end(), x); 0090 if (p != v.end()) 0091 v.erase(p); 0092 else 0093 throw value_error(); 0094 }, 0095 arg("x"), 0096 "Remove the first item from the list whose value is x. " 0097 "It is an error if there is no such item." 0098 ); 0099 0100 cl.def("__contains__", 0101 [](const Vector &v, const T &x) { 0102 return std::find(v.begin(), v.end(), x) != v.end(); 0103 }, 0104 arg("x"), 0105 "Return true the container contains ``x``" 0106 ); 0107 } 0108 0109 // Vector modifiers -- requires a copyable vector_type: 0110 // (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems 0111 // silly to allow deletion but not insertion, so include them here too.) 0112 template <typename Vector, typename Class_> 0113 void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) { 0114 using T = typename Vector::value_type; 0115 using SizeType = typename Vector::size_type; 0116 using DiffType = typename Vector::difference_type; 0117 0118 auto wrap_i = [](DiffType i, SizeType n) { 0119 if (i < 0) 0120 i += n; 0121 if (i < 0 || (SizeType)i >= n) 0122 throw index_error(); 0123 return i; 0124 }; 0125 0126 cl.def("append", 0127 [](Vector &v, const T &value) { v.push_back(value); }, 0128 arg("x"), 0129 "Add an item to the end of the list"); 0130 0131 cl.def(init([](const iterable &it) { 0132 auto v = std::unique_ptr<Vector>(new Vector()); 0133 v->reserve(len_hint(it)); 0134 for (handle h : it) 0135 v->push_back(h.cast<T>()); 0136 return v.release(); 0137 })); 0138 0139 cl.def("clear", 0140 [](Vector &v) { 0141 v.clear(); 0142 }, 0143 "Clear the contents" 0144 ); 0145 0146 cl.def("extend", 0147 [](Vector &v, const Vector &src) { 0148 v.insert(v.end(), src.begin(), src.end()); 0149 }, 0150 arg("L"), 0151 "Extend the list by appending all the items in the given list" 0152 ); 0153 0154 cl.def( 0155 "extend", 0156 [](Vector &v, const iterable &it) { 0157 const size_t old_size = v.size(); 0158 v.reserve(old_size + len_hint(it)); 0159 try { 0160 for (handle h : it) { 0161 v.push_back(h.cast<T>()); 0162 } 0163 } catch (const cast_error &) { 0164 v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), 0165 v.end()); 0166 try { 0167 v.shrink_to_fit(); 0168 } catch (const std::exception &) { 0169 // Do nothing 0170 } 0171 throw; 0172 } 0173 }, 0174 arg("L"), 0175 "Extend the list by appending all the items in the given list"); 0176 0177 cl.def("insert", 0178 [](Vector &v, DiffType i, const T &x) { 0179 // Can't use wrap_i; i == v.size() is OK 0180 if (i < 0) 0181 i += v.size(); 0182 if (i < 0 || (SizeType)i > v.size()) 0183 throw index_error(); 0184 v.insert(v.begin() + i, x); 0185 }, 0186 arg("i") , arg("x"), 0187 "Insert an item at a given position." 0188 ); 0189 0190 cl.def("pop", 0191 [](Vector &v) { 0192 if (v.empty()) 0193 throw index_error(); 0194 T t = std::move(v.back()); 0195 v.pop_back(); 0196 return t; 0197 }, 0198 "Remove and return the last item" 0199 ); 0200 0201 cl.def("pop", 0202 [wrap_i](Vector &v, DiffType i) { 0203 i = wrap_i(i, v.size()); 0204 T t = std::move(v[(SizeType) i]); 0205 v.erase(std::next(v.begin(), i)); 0206 return t; 0207 }, 0208 arg("i"), 0209 "Remove and return the item at index ``i``" 0210 ); 0211 0212 cl.def("__setitem__", 0213 [wrap_i](Vector &v, DiffType i, const T &t) { 0214 i = wrap_i(i, v.size()); 0215 v[(SizeType)i] = t; 0216 } 0217 ); 0218 0219 /// Slicing protocol 0220 cl.def( 0221 "__getitem__", 0222 [](const Vector &v, slice slice) -> Vector * { 0223 size_t start = 0, stop = 0, step = 0, slicelength = 0; 0224 0225 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 0226 throw error_already_set(); 0227 0228 auto *seq = new Vector(); 0229 seq->reserve((size_t) slicelength); 0230 0231 for (size_t i=0; i<slicelength; ++i) { 0232 seq->push_back(v[start]); 0233 start += step; 0234 } 0235 return seq; 0236 }, 0237 arg("s"), 0238 "Retrieve list elements using a slice object"); 0239 0240 cl.def( 0241 "__setitem__", 0242 [](Vector &v, slice slice, const Vector &value) { 0243 size_t start = 0, stop = 0, step = 0, slicelength = 0; 0244 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 0245 throw error_already_set(); 0246 0247 if (slicelength != value.size()) 0248 throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); 0249 0250 for (size_t i=0; i<slicelength; ++i) { 0251 v[start] = value[i]; 0252 start += step; 0253 } 0254 }, 0255 "Assign list elements using a slice object"); 0256 0257 cl.def("__delitem__", 0258 [wrap_i](Vector &v, DiffType i) { 0259 i = wrap_i(i, v.size()); 0260 v.erase(v.begin() + i); 0261 }, 0262 "Delete the list elements at index ``i``" 0263 ); 0264 0265 cl.def( 0266 "__delitem__", 0267 [](Vector &v, slice slice) { 0268 size_t start = 0, stop = 0, step = 0, slicelength = 0; 0269 0270 if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) 0271 throw error_already_set(); 0272 0273 if (step == 1 && false) { 0274 v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength)); 0275 } else { 0276 for (size_t i = 0; i < slicelength; ++i) { 0277 v.erase(v.begin() + DiffType(start)); 0278 start += step - 1; 0279 } 0280 } 0281 }, 0282 "Delete list elements using a slice object"); 0283 } 0284 0285 // If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>), 0286 // we have to access by copying; otherwise we return by reference. 0287 template <typename Vector> using vector_needs_copy = negation< 0288 std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>; 0289 0290 // The usual case: access and iterate by reference 0291 template <typename Vector, typename Class_> 0292 void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) { 0293 using T = typename Vector::value_type; 0294 using SizeType = typename Vector::size_type; 0295 using DiffType = typename Vector::difference_type; 0296 using ItType = typename Vector::iterator; 0297 0298 auto wrap_i = [](DiffType i, SizeType n) { 0299 if (i < 0) 0300 i += n; 0301 if (i < 0 || (SizeType)i >= n) 0302 throw index_error(); 0303 return i; 0304 }; 0305 0306 cl.def("__getitem__", 0307 [wrap_i](Vector &v, DiffType i) -> T & { 0308 i = wrap_i(i, v.size()); 0309 return v[(SizeType)i]; 0310 }, 0311 return_value_policy::reference_internal // ref + keepalive 0312 ); 0313 0314 cl.def("__iter__", 0315 [](Vector &v) { 0316 return make_iterator< 0317 return_value_policy::reference_internal, ItType, ItType, T&>( 0318 v.begin(), v.end()); 0319 }, 0320 keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 0321 ); 0322 } 0323 0324 // The case for special objects, like std::vector<bool>, that have to be returned-by-copy: 0325 template <typename Vector, typename Class_> 0326 void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) { 0327 using T = typename Vector::value_type; 0328 using SizeType = typename Vector::size_type; 0329 using DiffType = typename Vector::difference_type; 0330 using ItType = typename Vector::iterator; 0331 cl.def("__getitem__", 0332 [](const Vector &v, DiffType i) -> T { 0333 if (i < 0 && (i += v.size()) < 0) 0334 throw index_error(); 0335 if ((SizeType)i >= v.size()) 0336 throw index_error(); 0337 return v[(SizeType)i]; 0338 } 0339 ); 0340 0341 cl.def("__iter__", 0342 [](Vector &v) { 0343 return make_iterator< 0344 return_value_policy::copy, ItType, ItType, T>( 0345 v.begin(), v.end()); 0346 }, 0347 keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ 0348 ); 0349 } 0350 0351 template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name) 0352 -> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) { 0353 using size_type = typename Vector::size_type; 0354 0355 cl.def("__repr__", 0356 [name](Vector &v) { 0357 std::ostringstream s; 0358 s << name << '['; 0359 for (size_type i=0; i < v.size(); ++i) { 0360 s << v[i]; 0361 if (i != v.size() - 1) 0362 s << ", "; 0363 } 0364 s << ']'; 0365 return s.str(); 0366 }, 0367 "Return the canonical string representation of this list." 0368 ); 0369 } 0370 0371 // Provide the buffer interface for vectors if we have data() and we have a format for it 0372 // 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 0373 template <typename Vector, typename = void> 0374 struct vector_has_data_and_format : std::false_type {}; 0375 template <typename Vector> 0376 struct 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 {}; 0377 0378 // [workaround(intel)] Separate function required here 0379 // Workaround as the Intel compiler does not compile the enable_if_t part below 0380 // (tested with icc (ICC) 2021.1 Beta 20200827) 0381 template <typename... Args> 0382 constexpr bool args_any_are_buffer() { 0383 return detail::any_of<std::is_same<Args, buffer_protocol>...>::value; 0384 } 0385 0386 // [workaround(intel)] Separate function required here 0387 // [workaround(msvc)] Can't use constexpr bool in return type 0388 0389 // Add the buffer interface to a vector 0390 template <typename Vector, typename Class_, typename... Args> 0391 void vector_buffer_impl(Class_& cl, std::true_type) { 0392 using T = typename Vector::value_type; 0393 0394 static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector"); 0395 0396 // 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 0397 format_descriptor<T>::format(); 0398 0399 cl.def_buffer([](Vector& v) -> buffer_info { 0400 return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)}); 0401 }); 0402 0403 cl.def(init([](const buffer &buf) { 0404 auto info = buf.request(); 0405 if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) 0406 throw type_error("Only valid 1D buffers can be copied to a vector"); 0407 if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize) 0408 throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")"); 0409 0410 T *p = static_cast<T*>(info.ptr); 0411 ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T)); 0412 T *end = p + info.shape[0] * step; 0413 if (step == 1) { 0414 return Vector(p, end); 0415 } 0416 Vector vec; 0417 vec.reserve((size_t) info.shape[0]); 0418 for (; p != end; p += step) 0419 vec.push_back(*p); 0420 return vec; 0421 0422 })); 0423 0424 return; 0425 } 0426 0427 template <typename Vector, typename Class_, typename... Args> 0428 void vector_buffer_impl(Class_&, std::false_type) {} 0429 0430 template <typename Vector, typename Class_, typename... Args> 0431 void vector_buffer(Class_& cl) { 0432 vector_buffer_impl<Vector, Class_, Args...>(cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{}); 0433 } 0434 0435 PYBIND11_NAMESPACE_END(detail) 0436 0437 // 0438 // std::vector 0439 // 0440 template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args> 0441 class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) { 0442 using Class_ = class_<Vector, holder_type>; 0443 0444 // If the value_type is unregistered (e.g. a converting type) or is itself registered 0445 // module-local then make the vector binding module-local as well: 0446 using vtype = typename Vector::value_type; 0447 auto vtype_info = detail::get_type_info(typeid(vtype)); 0448 bool local = !vtype_info || vtype_info->module_local; 0449 0450 Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...); 0451 0452 // Declare the buffer interface if a buffer_protocol() is passed in 0453 detail::vector_buffer<Vector, Class_, Args...>(cl); 0454 0455 cl.def(init<>()); 0456 0457 // Register copy constructor (if possible) 0458 detail::vector_if_copy_constructible<Vector, Class_>(cl); 0459 0460 // Register comparison-related operators and functions (if possible) 0461 detail::vector_if_equal_operator<Vector, Class_>(cl); 0462 0463 // Register stream insertion operator (if possible) 0464 detail::vector_if_insertion_operator<Vector, Class_>(cl, name); 0465 0466 // Modifiers require copyable vector value type 0467 detail::vector_modifiers<Vector, Class_>(cl); 0468 0469 // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive 0470 detail::vector_accessor<Vector, Class_>(cl); 0471 0472 cl.def("__bool__", 0473 [](const Vector &v) -> bool { 0474 return !v.empty(); 0475 }, 0476 "Check whether the list is nonempty" 0477 ); 0478 0479 cl.def("__len__", &Vector::size); 0480 0481 0482 0483 0484 #if 0 0485 // C++ style functions deprecated, leaving it here as an example 0486 cl.def(init<size_type>()); 0487 0488 cl.def("resize", 0489 (void (Vector::*) (size_type count)) & Vector::resize, 0490 "changes the number of elements stored"); 0491 0492 cl.def("erase", 0493 [](Vector &v, SizeType i) { 0494 if (i >= v.size()) 0495 throw index_error(); 0496 v.erase(v.begin() + i); 0497 }, "erases element at index ``i``"); 0498 0499 cl.def("empty", &Vector::empty, "checks whether the container is empty"); 0500 cl.def("size", &Vector::size, "returns the number of elements"); 0501 cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); 0502 cl.def("pop_back", &Vector::pop_back, "removes the last element"); 0503 0504 cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); 0505 cl.def("reserve", &Vector::reserve, "reserves storage"); 0506 cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); 0507 cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); 0508 0509 cl.def("clear", &Vector::clear, "clears the contents"); 0510 cl.def("swap", &Vector::swap, "swaps the contents"); 0511 0512 cl.def("front", [](Vector &v) { 0513 if (v.size()) return v.front(); 0514 else throw index_error(); 0515 }, "access the first element"); 0516 0517 cl.def("back", [](Vector &v) { 0518 if (v.size()) return v.back(); 0519 else throw index_error(); 0520 }, "access the last element "); 0521 0522 #endif 0523 0524 return cl; 0525 } 0526 0527 0528 0529 // 0530 // std::map, std::unordered_map 0531 // 0532 0533 PYBIND11_NAMESPACE_BEGIN(detail) 0534 0535 /* Fallback functions */ 0536 template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { } 0537 template <typename, typename, typename... Args> void map_assignment(const Args &...) { } 0538 0539 // Map assignment when copy-assignable: just copy the value 0540 template <typename Map, typename Class_> 0541 void map_assignment(enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) { 0542 using KeyType = typename Map::key_type; 0543 using MappedType = typename Map::mapped_type; 0544 0545 cl.def("__setitem__", 0546 [](Map &m, const KeyType &k, const MappedType &v) { 0547 auto it = m.find(k); 0548 if (it != m.end()) it->second = v; 0549 else m.emplace(k, v); 0550 } 0551 ); 0552 } 0553 0554 // Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting 0555 template<typename Map, typename Class_> 0556 void map_assignment(enable_if_t< 0557 !is_copy_assignable<typename Map::mapped_type>::value && 0558 is_copy_constructible<typename Map::mapped_type>::value, 0559 Class_> &cl) { 0560 using KeyType = typename Map::key_type; 0561 using MappedType = typename Map::mapped_type; 0562 0563 cl.def("__setitem__", 0564 [](Map &m, const KeyType &k, const MappedType &v) { 0565 // We can't use m[k] = v; because value type might not be default constructable 0566 auto r = m.emplace(k, v); 0567 if (!r.second) { 0568 // value type is not copy assignable so the only way to insert it is to erase it first... 0569 m.erase(r.first); 0570 m.emplace(k, v); 0571 } 0572 } 0573 ); 0574 } 0575 0576 0577 template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name) 0578 -> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) { 0579 0580 cl.def("__repr__", 0581 [name](Map &m) { 0582 std::ostringstream s; 0583 s << name << '{'; 0584 bool f = false; 0585 for (auto const &kv : m) { 0586 if (f) 0587 s << ", "; 0588 s << kv.first << ": " << kv.second; 0589 f = true; 0590 } 0591 s << '}'; 0592 return s.str(); 0593 }, 0594 "Return the canonical string representation of this map." 0595 ); 0596 } 0597 0598 template<typename Map> 0599 struct keys_view 0600 { 0601 Map ↦ 0602 }; 0603 0604 template<typename Map> 0605 struct values_view 0606 { 0607 Map ↦ 0608 }; 0609 0610 template<typename Map> 0611 struct items_view 0612 { 0613 Map ↦ 0614 }; 0615 0616 PYBIND11_NAMESPACE_END(detail) 0617 0618 template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args> 0619 class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) { 0620 using KeyType = typename Map::key_type; 0621 using MappedType = typename Map::mapped_type; 0622 using KeysView = detail::keys_view<Map>; 0623 using ValuesView = detail::values_view<Map>; 0624 using ItemsView = detail::items_view<Map>; 0625 using Class_ = class_<Map, holder_type>; 0626 0627 // If either type is a non-module-local bound type then make the map binding non-local as well; 0628 // otherwise (e.g. both types are either module-local or converting) the map will be 0629 // module-local. 0630 auto tinfo = detail::get_type_info(typeid(MappedType)); 0631 bool local = !tinfo || tinfo->module_local; 0632 if (local) { 0633 tinfo = detail::get_type_info(typeid(KeyType)); 0634 local = !tinfo || tinfo->module_local; 0635 } 0636 0637 Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...); 0638 class_<KeysView> keys_view( 0639 scope, ("KeysView[" + name + "]").c_str(), pybind11::module_local(local)); 0640 class_<ValuesView> values_view( 0641 scope, ("ValuesView[" + name + "]").c_str(), pybind11::module_local(local)); 0642 class_<ItemsView> items_view( 0643 scope, ("ItemsView[" + name + "]").c_str(), pybind11::module_local(local)); 0644 0645 cl.def(init<>()); 0646 0647 // Register stream insertion operator (if possible) 0648 detail::map_if_insertion_operator<Map, Class_>(cl, name); 0649 0650 cl.def("__bool__", 0651 [](const Map &m) -> bool { return !m.empty(); }, 0652 "Check whether the map is nonempty" 0653 ); 0654 0655 cl.def("__iter__", 0656 [](Map &m) { return make_key_iterator(m.begin(), m.end()); }, 0657 keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */ 0658 ); 0659 0660 cl.def("keys", 0661 [](Map &m) { return KeysView{m}; }, 0662 keep_alive<0, 1>() /* Essential: keep map alive while view exists */ 0663 ); 0664 0665 cl.def("values", 0666 [](Map &m) { return ValuesView{m}; }, 0667 keep_alive<0, 1>() /* Essential: keep map alive while view exists */ 0668 ); 0669 0670 cl.def("items", 0671 [](Map &m) { return ItemsView{m}; }, 0672 keep_alive<0, 1>() /* Essential: keep map alive while view exists */ 0673 ); 0674 0675 cl.def("__getitem__", 0676 [](Map &m, const KeyType &k) -> MappedType & { 0677 auto it = m.find(k); 0678 if (it == m.end()) 0679 throw key_error(); 0680 return it->second; 0681 }, 0682 return_value_policy::reference_internal // ref + keepalive 0683 ); 0684 0685 cl.def("__contains__", 0686 [](Map &m, const KeyType &k) -> bool { 0687 auto it = m.find(k); 0688 if (it == m.end()) 0689 return false; 0690 return true; 0691 } 0692 ); 0693 // Fallback for when the object is not of the key type 0694 cl.def("__contains__", [](Map &, const object &) -> bool { return false; }); 0695 0696 // Assignment provided only if the type is copyable 0697 detail::map_assignment<Map, Class_>(cl); 0698 0699 cl.def("__delitem__", 0700 [](Map &m, const KeyType &k) { 0701 auto it = m.find(k); 0702 if (it == m.end()) 0703 throw key_error(); 0704 m.erase(it); 0705 } 0706 ); 0707 0708 cl.def("__len__", &Map::size); 0709 0710 keys_view.def("__len__", [](KeysView &view) { return view.map.size(); }); 0711 keys_view.def("__iter__", 0712 [](KeysView &view) { 0713 return make_key_iterator(view.map.begin(), view.map.end()); 0714 }, 0715 keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */ 0716 ); 0717 keys_view.def("__contains__", 0718 [](KeysView &view, const KeyType &k) -> bool { 0719 auto it = view.map.find(k); 0720 if (it == view.map.end()) 0721 return false; 0722 return true; 0723 } 0724 ); 0725 // Fallback for when the object is not of the key type 0726 keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; }); 0727 0728 values_view.def("__len__", [](ValuesView &view) { return view.map.size(); }); 0729 values_view.def("__iter__", 0730 [](ValuesView &view) { 0731 return make_value_iterator(view.map.begin(), view.map.end()); 0732 }, 0733 keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */ 0734 ); 0735 0736 items_view.def("__len__", [](ItemsView &view) { return view.map.size(); }); 0737 items_view.def("__iter__", 0738 [](ItemsView &view) { 0739 return make_iterator(view.map.begin(), view.map.end()); 0740 }, 0741 keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */ 0742 ); 0743 0744 return cl; 0745 } 0746 0747 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)