Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:06:18

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