Skip to content

Commit 2fa3fcf

Browse files
committed
Revert "Add make_value_iterator (#3271)"
This reverts commit ee0c5ee.
1 parent 1dc9a23 commit 2fa3fcf

File tree

4 files changed

+32
-176
lines changed

4 files changed

+32
-176
lines changed

docs/reference.rst

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,6 @@ Convenience functions converting to Python types
6363
.. doxygenfunction:: make_key_iterator(Iterator, Sentinel, Extra &&...)
6464
.. doxygenfunction:: make_key_iterator(Type &, Extra&&...)
6565

66-
.. doxygenfunction:: make_value_iterator(Iterator, Sentinel, Extra &&...)
67-
.. doxygenfunction:: make_value_iterator(Type &, Extra&&...)
68-
6966
.. _extras:
7067

7168
Passing extra arguments to ``def`` or ``class_``

include/pybind11/pybind11.h

Lines changed: 32 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,52 +1955,25 @@ inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_t
19551955
return res;
19561956
}
19571957

1958-
/* There are a large number of apparently unused template arguments because
1959-
* each combination requires a separate py::class_ registration.
1960-
*/
1961-
template <typename Access, return_value_policy Policy, typename Iterator, typename Sentinel, typename ValueType, typename... Extra>
1958+
template <typename Iterator, typename Sentinel, bool KeyIterator, return_value_policy Policy>
19621959
struct iterator_state {
19631960
Iterator it;
19641961
Sentinel end;
19651962
bool first_or_done;
19661963
};
19671964

1968-
// Note: these helpers take the iterator by non-const reference because some
1969-
// iterators in the wild can't be dereferenced when const.
1970-
template <typename Iterator>
1971-
struct iterator_access {
1972-
using result_type = decltype((*std::declval<Iterator>()));
1973-
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
1974-
result_type operator()(Iterator &it) const {
1975-
return *it;
1976-
}
1977-
};
1978-
1979-
template <typename Iterator>
1980-
struct iterator_key_access {
1981-
using result_type = decltype(((*std::declval<Iterator>()).first));
1982-
result_type operator()(Iterator &it) const {
1983-
return (*it).first;
1984-
}
1985-
};
1986-
1987-
template <typename Iterator>
1988-
struct iterator_value_access {
1989-
using result_type = decltype(((*std::declval<Iterator>()).second));
1990-
result_type operator()(Iterator &it) const {
1991-
return (*it).second;
1992-
}
1993-
};
1965+
PYBIND11_NAMESPACE_END(detail)
19941966

1995-
template <typename Access,
1996-
return_value_policy Policy,
1967+
/// Makes a python iterator from a first and past-the-end C++ InputIterator.
1968+
template <return_value_policy Policy = return_value_policy::reference_internal,
19971969
typename Iterator,
19981970
typename Sentinel,
1999-
typename ValueType,
1971+
#ifndef DOXYGEN_SHOULD_SKIP_THIS // Issue in breathe 4.26.1
1972+
typename ValueType = decltype(*std::declval<Iterator>()),
1973+
#endif
20001974
typename... Extra>
2001-
iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&... extra) {
2002-
using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;
2003-
// TODO: state captures only the types of Extra, not the values
1975+
iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
1976+
using state = detail::iterator_state<Iterator, Sentinel, false, Policy>;
20041977

20051978
if (!detail::get_type_info(typeid(state), false)) {
20061979
class_<state>(handle(), "iterator", pybind11::module_local())
@@ -2014,63 +1987,43 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&... extra) {
20141987
s.first_or_done = true;
20151988
throw stop_iteration();
20161989
}
2017-
return Access()(s.it);
1990+
return *s.it;
20181991
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
20191992
}, std::forward<Extra>(extra)..., Policy);
20201993
}
20211994

20221995
return cast(state{first, last, true});
20231996
}
20241997

2025-
PYBIND11_NAMESPACE_END(detail)
2026-
2027-
/// Makes a python iterator from a first and past-the-end C++ InputIterator.
2028-
template <return_value_policy Policy = return_value_policy::reference_internal,
2029-
typename Iterator,
2030-
typename Sentinel,
2031-
typename ValueType = typename detail::iterator_access<Iterator>::result_type,
2032-
typename... Extra>
2033-
iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
2034-
return detail::make_iterator_impl<
2035-
detail::iterator_access<Iterator>,
2036-
Policy,
2037-
Iterator,
2038-
Sentinel,
2039-
ValueType,
2040-
Extra...>(first, last, std::forward<Extra>(extra)...);
2041-
}
2042-
2043-
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
1998+
/// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a
20441999
/// first and past-the-end InputIterator.
20452000
template <return_value_policy Policy = return_value_policy::reference_internal,
20462001
typename Iterator,
20472002
typename Sentinel,
2048-
typename KeyType = typename detail::iterator_key_access<Iterator>::result_type,
2003+
#ifndef DOXYGEN_SHOULD_SKIP_THIS // Issue in breathe 4.26.1
2004+
typename KeyType = decltype((*std::declval<Iterator>()).first),
2005+
#endif
20492006
typename... Extra>
20502007
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
2051-
return detail::make_iterator_impl<
2052-
detail::iterator_key_access<Iterator>,
2053-
Policy,
2054-
Iterator,
2055-
Sentinel,
2056-
KeyType,
2057-
Extra...>(first, last, std::forward<Extra>(extra)...);
2058-
}
2008+
using state = detail::iterator_state<Iterator, Sentinel, true, Policy>;
20592009

2060-
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
2061-
/// first and past-the-end InputIterator.
2062-
template <return_value_policy Policy = return_value_policy::reference_internal,
2063-
typename Iterator,
2064-
typename Sentinel,
2065-
typename ValueType = typename detail::iterator_value_access<Iterator>::result_type,
2066-
typename... Extra>
2067-
iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
2068-
return detail::make_iterator_impl<
2069-
detail::iterator_value_access<Iterator>,
2070-
Policy, Iterator,
2071-
Sentinel,
2072-
ValueType,
2073-
Extra...>(first, last, std::forward<Extra>(extra)...);
2010+
if (!detail::get_type_info(typeid(state), false)) {
2011+
class_<state>(handle(), "iterator", pybind11::module_local())
2012+
.def("__iter__", [](state &s) -> state& { return s; })
2013+
.def("__next__", [](state &s) -> detail::remove_cv_t<KeyType> {
2014+
if (!s.first_or_done)
2015+
++s.it;
2016+
else
2017+
s.first_or_done = false;
2018+
if (s.it == s.end) {
2019+
s.first_or_done = true;
2020+
throw stop_iteration();
2021+
}
2022+
return (*s.it).first;
2023+
}, std::forward<Extra>(extra)..., Policy);
2024+
}
2025+
2026+
return cast(state{first, last, true});
20742027
}
20752028

20762029
/// Makes an iterator over values of an stl container or other container supporting
@@ -2087,13 +2040,6 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
20872040
return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...);
20882041
}
20892042

2090-
/// Makes an iterator over the values (`.second`) of a stl map-like container supporting
2091-
/// `std::begin()`/`std::end()`
2092-
template <return_value_policy Policy = return_value_policy::reference_internal,
2093-
typename Type, typename... Extra> iterator make_value_iterator(Type &value, Extra&&... extra) {
2094-
return make_value_iterator<Policy>(std::begin(value), std::end(value), extra...);
2095-
}
2096-
20972043
template <typename InputType, typename OutputType> void implicitly_convertible() {
20982044
struct set_flag {
20992045
bool &flag;

tests/test_sequences_and_iterators.cpp

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
#include <algorithm>
1717
#include <utility>
18-
#include <vector>
1918

2019
#ifdef PYBIND11_HAS_OPTIONAL
2120
#include <optional>
@@ -38,29 +37,6 @@ bool operator==(const NonZeroIterator<std::pair<A, B>>& it, const NonZeroSentine
3837
return !(*it).first || !(*it).second;
3938
}
4039

41-
class NonCopyableInt {
42-
public:
43-
explicit NonCopyableInt(int value) : value_(value) {}
44-
NonCopyableInt(const NonCopyableInt &) = delete;
45-
NonCopyableInt(NonCopyableInt &&other) noexcept : value_(other.value_) {
46-
other.value_ = -1; // detect when an unwanted move occurs
47-
}
48-
NonCopyableInt &operator=(const NonCopyableInt &) = delete;
49-
NonCopyableInt &operator=(NonCopyableInt &&other) noexcept {
50-
value_ = other.value_;
51-
other.value_ = -1; // detect when an unwanted move occurs
52-
return *this;
53-
}
54-
int get() const { return value_; }
55-
void set(int value) { value_ = value; }
56-
~NonCopyableInt() = default;
57-
private:
58-
int value_;
59-
};
60-
using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
61-
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
62-
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
63-
6440
template <typename PythonType>
6541
py::list test_random_access_iterator(PythonType x) {
6642
if (x.size() < 5)
@@ -312,10 +288,6 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
312288
.def(
313289
"items",
314290
[](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); },
315-
py::keep_alive<0, 1>())
316-
.def(
317-
"values",
318-
[](const StringMap &map) { return py::make_value_iterator(map.begin(), map.end()); },
319291
py::keep_alive<0, 1>());
320292

321293
// test_generalized_iterators
@@ -334,38 +306,8 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
334306
.def("nonzero_keys", [](const IntPairs& s) {
335307
return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
336308
}, py::keep_alive<0, 1>())
337-
.def("nonzero_values", [](const IntPairs& s) {
338-
return py::make_value_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
339-
}, py::keep_alive<0, 1>())
340309
;
341310

342-
// test_iterater_referencing
343-
py::class_<NonCopyableInt>(m, "NonCopyableInt")
344-
.def(py::init<int>())
345-
.def("set", &NonCopyableInt::set)
346-
.def("__int__", &NonCopyableInt::get)
347-
;
348-
py::class_<std::vector<NonCopyableInt>>(m, "VectorNonCopyableInt")
349-
.def(py::init<>())
350-
.def("append", [](std::vector<NonCopyableInt> &vec, int value) {
351-
vec.emplace_back(value);
352-
})
353-
.def("__iter__", [](std::vector<NonCopyableInt> &vec) {
354-
return py::make_iterator(vec.begin(), vec.end());
355-
})
356-
;
357-
py::class_<std::vector<NonCopyableIntPair>>(m, "VectorNonCopyableIntPair")
358-
.def(py::init<>())
359-
.def("append", [](std::vector<NonCopyableIntPair> &vec, const std::pair<int, int> &value) {
360-
vec.emplace_back(NonCopyableInt(value.first), NonCopyableInt(value.second));
361-
})
362-
.def("keys", [](std::vector<NonCopyableIntPair> &vec) {
363-
return py::make_key_iterator(vec.begin(), vec.end());
364-
})
365-
.def("values", [](std::vector<NonCopyableIntPair> &vec) {
366-
return py::make_value_iterator(vec.begin(), vec.end());
367-
})
368-
;
369311

370312
#if 0
371313
// Obsolete: special data structure for exposing custom iterator types to python

tests/test_sequences_and_iterators.py

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ def test_generalized_iterators():
3636
assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1]
3737
assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == []
3838

39-
assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_values()) == [2, 4]
40-
assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_values()) == [2]
41-
assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_values()) == []
42-
4339
# __next__ must continue to raise StopIteration
4440
it = m.IntPairs([(0, 0)]).nonzero()
4541
for _ in range(3):
@@ -52,30 +48,6 @@ def test_generalized_iterators():
5248
next(it)
5349

5450

55-
def test_iterator_referencing():
56-
"""Test that iterators reference rather than copy their referents."""
57-
vec = m.VectorNonCopyableInt()
58-
vec.append(3)
59-
vec.append(5)
60-
assert [int(x) for x in vec] == [3, 5]
61-
# Increment everything to make sure the referents can be mutated
62-
for x in vec:
63-
x.set(int(x) + 1)
64-
assert [int(x) for x in vec] == [4, 6]
65-
66-
vec = m.VectorNonCopyableIntPair()
67-
vec.append([3, 4])
68-
vec.append([5, 7])
69-
assert [int(x) for x in vec.keys()] == [3, 5]
70-
assert [int(x) for x in vec.values()] == [4, 7]
71-
for x in vec.keys():
72-
x.set(int(x) + 1)
73-
for x in vec.values():
74-
x.set(int(x) + 10)
75-
assert [int(x) for x in vec.keys()] == [4, 6]
76-
assert [int(x) for x in vec.values()] == [14, 17]
77-
78-
7951
def test_sliceable():
8052
sliceable = m.Sliceable(100)
8153
assert sliceable[::] == (0, 100, 1)
@@ -179,7 +151,6 @@ def test_map_iterator():
179151
assert sm[k] == expected[k]
180152
for k, v in sm.items():
181153
assert v == expected[k]
182-
assert list(sm.values()) == [expected[k] for k in sm]
183154

184155
it = iter(m.StringMap({}))
185156
for _ in range(3): # __next__ must continue to raise StopIteration

0 commit comments

Comments
 (0)