mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-13 09:46:10 +00:00
Added pybind11::make_key_iterator for map iteration
This allows exposing a dict-like interface to python code, allowing
iteration over keys via:
for k in custommapping:
...
while still allowing iteration over pairs, so that you can also
implement 'dict.items()' functionality which returns a pair iterator,
allowing:
for k, v in custommapping.items():
...
example-sequences-and-iterators is updated with a custom class providing
both types of iteration.
This commit is contained in:
@@ -55,6 +55,7 @@ PYBIND11_NOINLINE inline internals &get_internals() {
|
||||
if (p) std::rethrow_exception(p);
|
||||
} catch (const error_already_set &) { return;
|
||||
} catch (const index_error &e) { PyErr_SetString(PyExc_IndexError, e.what()); return;
|
||||
} catch (const key_error &e) { PyErr_SetString(PyExc_KeyError, e.what()); return;
|
||||
} catch (const value_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||
} catch (const stop_iteration &e) { PyErr_SetString(PyExc_StopIteration, e.what()); return;
|
||||
} catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return;
|
||||
|
||||
@@ -314,6 +314,7 @@ NAMESPACE_END(detail)
|
||||
class error_already_set : public std::runtime_error { public: error_already_set() : std::runtime_error(detail::error_string()) {} };
|
||||
PYBIND11_RUNTIME_EXCEPTION(stop_iteration)
|
||||
PYBIND11_RUNTIME_EXCEPTION(index_error)
|
||||
PYBIND11_RUNTIME_EXCEPTION(key_error)
|
||||
PYBIND11_RUNTIME_EXCEPTION(value_error)
|
||||
PYBIND11_RUNTIME_EXCEPTION(cast_error) /// Thrown when pybind11::cast or handle::call fail due to a type casting error
|
||||
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error) /// Used internally
|
||||
|
||||
@@ -1117,7 +1117,7 @@ PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, handle arg
|
||||
keep_alive_impl(nurse, patient);
|
||||
}
|
||||
|
||||
template <typename Iterator> struct iterator_state {
|
||||
template <typename Iterator, bool KeyIterator = false> struct iterator_state {
|
||||
Iterator it, end;
|
||||
bool first;
|
||||
};
|
||||
@@ -1148,11 +1148,37 @@ iterator make_iterator(Iterator first, Iterator last, Extra &&... extra) {
|
||||
|
||||
return (iterator) cast(state { first, last, true });
|
||||
}
|
||||
template <typename Iterator,
|
||||
typename KeyType = decltype(std::declval<Iterator>()->first),
|
||||
typename... Extra>
|
||||
iterator make_key_iterator(Iterator first, Iterator last, Extra &&... extra) {
|
||||
typedef detail::iterator_state<Iterator, true> state;
|
||||
|
||||
if (!detail::get_type_info(typeid(state))) {
|
||||
class_<state>(handle(), "")
|
||||
.def("__iter__", [](state &s) -> state& { return s; })
|
||||
.def("__next__", [](state &s) -> KeyType {
|
||||
if (!s.first)
|
||||
++s.it;
|
||||
else
|
||||
s.first = false;
|
||||
if (s.it == s.end)
|
||||
throw stop_iteration();
|
||||
return s.it->first;
|
||||
}, return_value_policy::reference_internal, std::forward<Extra>(extra)...);
|
||||
}
|
||||
|
||||
return (iterator) cast(state { first, last, true });
|
||||
}
|
||||
|
||||
template <typename Type, typename... Extra> iterator make_iterator(Type &value, Extra&&... extra) {
|
||||
return make_iterator(std::begin(value), std::end(value), extra...);
|
||||
}
|
||||
|
||||
template <typename Type, typename... Extra> iterator make_key_iterator(Type &value, Extra&&... extra) {
|
||||
return make_key_iterator(std::begin(value), std::end(value), extra...);
|
||||
}
|
||||
|
||||
template <typename InputType, typename OutputType> void implicitly_convertible() {
|
||||
auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
|
||||
if (!detail::type_caster<InputType>().load(obj, false))
|
||||
|
||||
Reference in New Issue
Block a user