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 &map;
0602 };
0603 
0604 template<typename Map>
0605 struct values_view
0606 {
0607     Map &map;
0608 };
0609 
0610 template<typename Map>
0611 struct items_view
0612 {
0613     Map &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)