123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785 |
- /*
- pybind11/std_bind.h: Binding generators for STL data types
- Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob
- All rights reserved. Use of this source code is governed by a
- BSD-style license that can be found in the LICENSE file.
- */
- #pragma once
- #include "detail/common.h"
- #include "operators.h"
- #include <algorithm>
- #include <sstream>
- PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
- PYBIND11_NAMESPACE_BEGIN(detail)
- /* SFINAE helper class used by 'is_comparable */
- template <typename T>
- struct container_traits {
- template <typename T2>
- static std::true_type
- test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>()) *);
- template <typename T2>
- static std::false_type test_comparable(...);
- template <typename T2>
- static std::true_type test_value(typename T2::value_type *);
- template <typename T2>
- static std::false_type test_value(...);
- template <typename T2>
- static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
- template <typename T2>
- static std::false_type test_pair(...);
- static constexpr const bool is_comparable
- = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
- static constexpr const bool is_pair
- = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
- static constexpr const bool is_vector
- = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
- static constexpr const bool is_element = !is_pair && !is_vector;
- };
- /* Default: is_comparable -> std::false_type */
- template <typename T, typename SFINAE = void>
- struct is_comparable : std::false_type {};
- /* For non-map data structures, check whether operator== can be instantiated */
- template <typename T>
- struct is_comparable<
- T,
- enable_if_t<container_traits<T>::is_element && container_traits<T>::is_comparable>>
- : std::true_type {};
- /* For a vector/map data structure, recursively check the value type
- (which is std::pair for maps) */
- template <typename T>
- struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
- static constexpr const bool value = is_comparable<typename T::value_type>::value;
- };
- /* For pairs, recursively check the two data types */
- template <typename T>
- struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
- static constexpr const bool value = is_comparable<typename T::first_type>::value
- && is_comparable<typename T::second_type>::value;
- };
- /* Fallback functions */
- template <typename, typename, typename... Args>
- void vector_if_copy_constructible(const Args &...) {}
- template <typename, typename, typename... Args>
- void vector_if_equal_operator(const Args &...) {}
- template <typename, typename, typename... Args>
- void vector_if_insertion_operator(const Args &...) {}
- template <typename, typename, typename... Args>
- void vector_modifiers(const Args &...) {}
- template <typename Vector, typename Class_>
- void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
- cl.def(init<const Vector &>(), "Copy constructor");
- }
- template <typename Vector, typename Class_>
- void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
- using T = typename Vector::value_type;
- cl.def(self == self);
- cl.def(self != self);
- cl.def(
- "count",
- [](const Vector &v, const T &x) { return std::count(v.begin(), v.end(), x); },
- arg("x"),
- "Return the number of times ``x`` appears in the list");
- cl.def(
- "remove",
- [](Vector &v, const T &x) {
- auto p = std::find(v.begin(), v.end(), x);
- if (p != v.end()) {
- v.erase(p);
- } else {
- throw value_error();
- }
- },
- arg("x"),
- "Remove the first item from the list whose value is x. "
- "It is an error if there is no such item.");
- cl.def(
- "__contains__",
- [](const Vector &v, const T &x) { return std::find(v.begin(), v.end(), x) != v.end(); },
- arg("x"),
- "Return true the container contains ``x``");
- }
- // Vector modifiers -- requires a copyable vector_type:
- // (Technically, some of these (pop and __delitem__) don't actually require copyability, but it
- // seems silly to allow deletion but not insertion, so include them here too.)
- template <typename Vector, typename Class_>
- void vector_modifiers(
- enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
- using T = typename Vector::value_type;
- using SizeType = typename Vector::size_type;
- using DiffType = typename Vector::difference_type;
- auto wrap_i = [](DiffType i, SizeType n) {
- if (i < 0) {
- i += n;
- }
- if (i < 0 || (SizeType) i >= n) {
- throw index_error();
- }
- return i;
- };
- cl.def(
- "append",
- [](Vector &v, const T &value) { v.push_back(value); },
- arg("x"),
- "Add an item to the end of the list");
- cl.def(init([](const iterable &it) {
- auto v = std::unique_ptr<Vector>(new Vector());
- v->reserve(len_hint(it));
- for (handle h : it) {
- v->push_back(h.cast<T>());
- }
- return v.release();
- }));
- cl.def(
- "clear", [](Vector &v) { v.clear(); }, "Clear the contents");
- cl.def(
- "extend",
- [](Vector &v, const Vector &src) { v.insert(v.end(), src.begin(), src.end()); },
- arg("L"),
- "Extend the list by appending all the items in the given list");
- cl.def(
- "extend",
- [](Vector &v, const iterable &it) {
- const size_t old_size = v.size();
- v.reserve(old_size + len_hint(it));
- try {
- for (handle h : it) {
- v.push_back(h.cast<T>());
- }
- } catch (const cast_error &) {
- v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size),
- v.end());
- try {
- v.shrink_to_fit();
- } catch (const std::exception &) {
- // Do nothing
- }
- throw;
- }
- },
- arg("L"),
- "Extend the list by appending all the items in the given list");
- cl.def(
- "insert",
- [](Vector &v, DiffType i, const T &x) {
- // Can't use wrap_i; i == v.size() is OK
- if (i < 0) {
- i += v.size();
- }
- if (i < 0 || (SizeType) i > v.size()) {
- throw index_error();
- }
- v.insert(v.begin() + i, x);
- },
- arg("i"),
- arg("x"),
- "Insert an item at a given position.");
- cl.def(
- "pop",
- [](Vector &v) {
- if (v.empty()) {
- throw index_error();
- }
- T t = std::move(v.back());
- v.pop_back();
- return t;
- },
- "Remove and return the last item");
- cl.def(
- "pop",
- [wrap_i](Vector &v, DiffType i) {
- i = wrap_i(i, v.size());
- T t = std::move(v[(SizeType) i]);
- v.erase(std::next(v.begin(), i));
- return t;
- },
- arg("i"),
- "Remove and return the item at index ``i``");
- cl.def("__setitem__", [wrap_i](Vector &v, DiffType i, const T &t) {
- i = wrap_i(i, v.size());
- v[(SizeType) i] = t;
- });
- /// Slicing protocol
- cl.def(
- "__getitem__",
- [](const Vector &v, const slice &slice) -> Vector * {
- size_t start = 0, stop = 0, step = 0, slicelength = 0;
- if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
- throw error_already_set();
- }
- auto *seq = new Vector();
- seq->reserve((size_t) slicelength);
- for (size_t i = 0; i < slicelength; ++i) {
- seq->push_back(v[start]);
- start += step;
- }
- return seq;
- },
- arg("s"),
- "Retrieve list elements using a slice object");
- cl.def(
- "__setitem__",
- [](Vector &v, const slice &slice, const Vector &value) {
- size_t start = 0, stop = 0, step = 0, slicelength = 0;
- if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
- throw error_already_set();
- }
- if (slicelength != value.size()) {
- throw std::runtime_error(
- "Left and right hand size of slice assignment have different sizes!");
- }
- for (size_t i = 0; i < slicelength; ++i) {
- v[start] = value[i];
- start += step;
- }
- },
- "Assign list elements using a slice object");
- cl.def(
- "__delitem__",
- [wrap_i](Vector &v, DiffType i) {
- i = wrap_i(i, v.size());
- v.erase(v.begin() + i);
- },
- "Delete the list elements at index ``i``");
- cl.def(
- "__delitem__",
- [](Vector &v, const slice &slice) {
- size_t start = 0, stop = 0, step = 0, slicelength = 0;
- if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
- throw error_already_set();
- }
- if (step == 1 && false) {
- v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
- } else {
- for (size_t i = 0; i < slicelength; ++i) {
- v.erase(v.begin() + DiffType(start));
- start += step - 1;
- }
- }
- },
- "Delete list elements using a slice object");
- }
- // If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
- // we have to access by copying; otherwise we return by reference.
- template <typename Vector>
- using vector_needs_copy
- = negation<std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]),
- typename Vector::value_type &>>;
- // The usual case: access and iterate by reference
- template <typename Vector, typename Class_>
- void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) {
- using T = typename Vector::value_type;
- using SizeType = typename Vector::size_type;
- using DiffType = typename Vector::difference_type;
- using ItType = typename Vector::iterator;
- auto wrap_i = [](DiffType i, SizeType n) {
- if (i < 0) {
- i += n;
- }
- if (i < 0 || (SizeType) i >= n) {
- throw index_error();
- }
- return i;
- };
- cl.def(
- "__getitem__",
- [wrap_i](Vector &v, DiffType i) -> T & {
- i = wrap_i(i, v.size());
- return v[(SizeType) i];
- },
- return_value_policy::reference_internal // ref + keepalive
- );
- cl.def(
- "__iter__",
- [](Vector &v) {
- return make_iterator<return_value_policy::reference_internal, ItType, ItType, T &>(
- v.begin(), v.end());
- },
- keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
- );
- }
- // The case for special objects, like std::vector<bool>, that have to be returned-by-copy:
- template <typename Vector, typename Class_>
- void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) {
- using T = typename Vector::value_type;
- using SizeType = typename Vector::size_type;
- using DiffType = typename Vector::difference_type;
- using ItType = typename Vector::iterator;
- cl.def("__getitem__", [](const Vector &v, DiffType i) -> T {
- if (i < 0 && (i += v.size()) < 0) {
- throw index_error();
- }
- if ((SizeType) i >= v.size()) {
- throw index_error();
- }
- return v[(SizeType) i];
- });
- cl.def(
- "__iter__",
- [](Vector &v) {
- return make_iterator<return_value_policy::copy, ItType, ItType, T>(v.begin(), v.end());
- },
- keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
- );
- }
- template <typename Vector, typename Class_>
- auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
- -> decltype(std::declval<std::ostream &>() << std::declval<typename Vector::value_type>(),
- void()) {
- using size_type = typename Vector::size_type;
- cl.def(
- "__repr__",
- [name](Vector &v) {
- std::ostringstream s;
- s << name << '[';
- for (size_type i = 0; i < v.size(); ++i) {
- s << v[i];
- if (i != v.size() - 1) {
- s << ", ";
- }
- }
- s << ']';
- return s.str();
- },
- "Return the canonical string representation of this list.");
- }
- // Provide the buffer interface for vectors if we have data() and we have a format for it
- // 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
- template <typename Vector, typename = void>
- struct vector_has_data_and_format : std::false_type {};
- template <typename Vector>
- 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 {};
- // [workaround(intel)] Separate function required here
- // Workaround as the Intel compiler does not compile the enable_if_t part below
- // (tested with icc (ICC) 2021.1 Beta 20200827)
- template <typename... Args>
- constexpr bool args_any_are_buffer() {
- return detail::any_of<std::is_same<Args, buffer_protocol>...>::value;
- }
- // [workaround(intel)] Separate function required here
- // [workaround(msvc)] Can't use constexpr bool in return type
- // Add the buffer interface to a vector
- template <typename Vector, typename Class_, typename... Args>
- void vector_buffer_impl(Class_ &cl, std::true_type) {
- using T = typename Vector::value_type;
- static_assert(vector_has_data_and_format<Vector>::value,
- "There is not an appropriate format descriptor for this vector");
- // 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
- format_descriptor<T>::format();
- cl.def_buffer([](Vector &v) -> buffer_info {
- return buffer_info(v.data(),
- static_cast<ssize_t>(sizeof(T)),
- format_descriptor<T>::format(),
- 1,
- {v.size()},
- {sizeof(T)});
- });
- cl.def(init([](const buffer &buf) {
- auto info = buf.request();
- if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) {
- throw type_error("Only valid 1D buffers can be copied to a vector");
- }
- if (!detail::compare_buffer_info<T>::compare(info)
- || (ssize_t) sizeof(T) != info.itemsize) {
- throw type_error("Format mismatch (Python: " + info.format
- + " C++: " + format_descriptor<T>::format() + ")");
- }
- T *p = static_cast<T *>(info.ptr);
- ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
- T *end = p + info.shape[0] * step;
- if (step == 1) {
- return Vector(p, end);
- }
- Vector vec;
- vec.reserve((size_t) info.shape[0]);
- for (; p != end; p += step) {
- vec.push_back(*p);
- }
- return vec;
- }));
- return;
- }
- template <typename Vector, typename Class_, typename... Args>
- void vector_buffer_impl(Class_ &, std::false_type) {}
- template <typename Vector, typename Class_, typename... Args>
- void vector_buffer(Class_ &cl) {
- vector_buffer_impl<Vector, Class_, Args...>(
- cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
- }
- PYBIND11_NAMESPACE_END(detail)
- //
- // std::vector
- //
- template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
- class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args &&...args) {
- using Class_ = class_<Vector, holder_type>;
- // If the value_type is unregistered (e.g. a converting type) or is itself registered
- // module-local then make the vector binding module-local as well:
- using vtype = typename Vector::value_type;
- auto *vtype_info = detail::get_type_info(typeid(vtype));
- bool local = !vtype_info || vtype_info->module_local;
- Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
- // Declare the buffer interface if a buffer_protocol() is passed in
- detail::vector_buffer<Vector, Class_, Args...>(cl);
- cl.def(init<>());
- // Register copy constructor (if possible)
- detail::vector_if_copy_constructible<Vector, Class_>(cl);
- // Register comparison-related operators and functions (if possible)
- detail::vector_if_equal_operator<Vector, Class_>(cl);
- // Register stream insertion operator (if possible)
- detail::vector_if_insertion_operator<Vector, Class_>(cl, name);
- // Modifiers require copyable vector value type
- detail::vector_modifiers<Vector, Class_>(cl);
- // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
- detail::vector_accessor<Vector, Class_>(cl);
- cl.def(
- "__bool__",
- [](const Vector &v) -> bool { return !v.empty(); },
- "Check whether the list is nonempty");
- cl.def("__len__", &Vector::size);
- #if 0
- // C++ style functions deprecated, leaving it here as an example
- cl.def(init<size_type>());
- cl.def("resize",
- (void (Vector::*) (size_type count)) & Vector::resize,
- "changes the number of elements stored");
- cl.def("erase",
- [](Vector &v, SizeType i) {
- if (i >= v.size())
- throw index_error();
- v.erase(v.begin() + i);
- }, "erases element at index ``i``");
- cl.def("empty", &Vector::empty, "checks whether the container is empty");
- cl.def("size", &Vector::size, "returns the number of elements");
- cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end");
- cl.def("pop_back", &Vector::pop_back, "removes the last element");
- cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements");
- cl.def("reserve", &Vector::reserve, "reserves storage");
- cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage");
- cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory");
- cl.def("clear", &Vector::clear, "clears the contents");
- cl.def("swap", &Vector::swap, "swaps the contents");
- cl.def("front", [](Vector &v) {
- if (v.size()) return v.front();
- else throw index_error();
- }, "access the first element");
- cl.def("back", [](Vector &v) {
- if (v.size()) return v.back();
- else throw index_error();
- }, "access the last element ");
- #endif
- return cl;
- }
- //
- // std::map, std::unordered_map
- //
- PYBIND11_NAMESPACE_BEGIN(detail)
- /* Fallback functions */
- template <typename, typename, typename... Args>
- void map_if_insertion_operator(const Args &...) {}
- template <typename, typename, typename... Args>
- void map_assignment(const Args &...) {}
- // Map assignment when copy-assignable: just copy the value
- template <typename Map, typename Class_>
- void map_assignment(
- enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
- using KeyType = typename Map::key_type;
- using MappedType = typename Map::mapped_type;
- cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
- auto it = m.find(k);
- if (it != m.end()) {
- it->second = v;
- } else {
- m.emplace(k, v);
- }
- });
- }
- // Not copy-assignable, but still copy-constructible: we can update the value by erasing and
- // reinserting
- template <typename Map, typename Class_>
- void map_assignment(enable_if_t<!is_copy_assignable<typename Map::mapped_type>::value
- && is_copy_constructible<typename Map::mapped_type>::value,
- Class_> &cl) {
- using KeyType = typename Map::key_type;
- using MappedType = typename Map::mapped_type;
- cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
- // We can't use m[k] = v; because value type might not be default constructable
- auto r = m.emplace(k, v);
- if (!r.second) {
- // value type is not copy assignable so the only way to insert it is to erase it
- // first...
- m.erase(r.first);
- m.emplace(k, v);
- }
- });
- }
- template <typename Map, typename Class_>
- auto map_if_insertion_operator(Class_ &cl, std::string const &name)
- -> decltype(std::declval<std::ostream &>() << std::declval<typename Map::key_type>()
- << std::declval<typename Map::mapped_type>(),
- void()) {
- cl.def(
- "__repr__",
- [name](Map &m) {
- std::ostringstream s;
- s << name << '{';
- bool f = false;
- for (auto const &kv : m) {
- if (f) {
- s << ", ";
- }
- s << kv.first << ": " << kv.second;
- f = true;
- }
- s << '}';
- return s.str();
- },
- "Return the canonical string representation of this map.");
- }
- template <typename Map>
- struct keys_view {
- Map ↦
- };
- template <typename Map>
- struct values_view {
- Map ↦
- };
- template <typename Map>
- struct items_view {
- Map ↦
- };
- PYBIND11_NAMESPACE_END(detail)
- template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
- class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
- using KeyType = typename Map::key_type;
- using MappedType = typename Map::mapped_type;
- using KeysView = detail::keys_view<Map>;
- using ValuesView = detail::values_view<Map>;
- using ItemsView = detail::items_view<Map>;
- using Class_ = class_<Map, holder_type>;
- // If either type is a non-module-local bound type then make the map binding non-local as well;
- // otherwise (e.g. both types are either module-local or converting) the map will be
- // module-local.
- auto *tinfo = detail::get_type_info(typeid(MappedType));
- bool local = !tinfo || tinfo->module_local;
- if (local) {
- tinfo = detail::get_type_info(typeid(KeyType));
- local = !tinfo || tinfo->module_local;
- }
- Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
- class_<KeysView> keys_view(
- scope, ("KeysView[" + name + "]").c_str(), pybind11::module_local(local));
- class_<ValuesView> values_view(
- scope, ("ValuesView[" + name + "]").c_str(), pybind11::module_local(local));
- class_<ItemsView> items_view(
- scope, ("ItemsView[" + name + "]").c_str(), pybind11::module_local(local));
- cl.def(init<>());
- // Register stream insertion operator (if possible)
- detail::map_if_insertion_operator<Map, Class_>(cl, name);
- cl.def(
- "__bool__",
- [](const Map &m) -> bool { return !m.empty(); },
- "Check whether the map is nonempty");
- cl.def(
- "__iter__",
- [](Map &m) { return make_key_iterator(m.begin(), m.end()); },
- keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
- );
- cl.def(
- "keys",
- [](Map &m) { return KeysView{m}; },
- keep_alive<0, 1>() /* Essential: keep map alive while view exists */
- );
- cl.def(
- "values",
- [](Map &m) { return ValuesView{m}; },
- keep_alive<0, 1>() /* Essential: keep map alive while view exists */
- );
- cl.def(
- "items",
- [](Map &m) { return ItemsView{m}; },
- keep_alive<0, 1>() /* Essential: keep map alive while view exists */
- );
- cl.def(
- "__getitem__",
- [](Map &m, const KeyType &k) -> MappedType & {
- auto it = m.find(k);
- if (it == m.end()) {
- throw key_error();
- }
- return it->second;
- },
- return_value_policy::reference_internal // ref + keepalive
- );
- cl.def("__contains__", [](Map &m, const KeyType &k) -> bool {
- auto it = m.find(k);
- if (it == m.end()) {
- return false;
- }
- return true;
- });
- // Fallback for when the object is not of the key type
- cl.def("__contains__", [](Map &, const object &) -> bool { return false; });
- // Assignment provided only if the type is copyable
- detail::map_assignment<Map, Class_>(cl);
- cl.def("__delitem__", [](Map &m, const KeyType &k) {
- auto it = m.find(k);
- if (it == m.end()) {
- throw key_error();
- }
- m.erase(it);
- });
- cl.def("__len__", &Map::size);
- keys_view.def("__len__", [](KeysView &view) { return view.map.size(); });
- keys_view.def(
- "__iter__",
- [](KeysView &view) { return make_key_iterator(view.map.begin(), view.map.end()); },
- keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
- );
- keys_view.def("__contains__", [](KeysView &view, const KeyType &k) -> bool {
- auto it = view.map.find(k);
- if (it == view.map.end()) {
- return false;
- }
- return true;
- });
- // Fallback for when the object is not of the key type
- keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; });
- values_view.def("__len__", [](ValuesView &view) { return view.map.size(); });
- values_view.def(
- "__iter__",
- [](ValuesView &view) { return make_value_iterator(view.map.begin(), view.map.end()); },
- keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
- );
- items_view.def("__len__", [](ItemsView &view) { return view.map.size(); });
- items_view.def(
- "__iter__",
- [](ItemsView &view) { return make_iterator(view.map.begin(), view.map.end()); },
- keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
- );
- return cl;
- }
- PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|