Skip to content

Commit

Permalink
feature: Support move-only iterators in py::make_*iterator (#4834)
Browse files Browse the repository at this point in the history
* feature: Support move-only iterators in `py::make_*iterator`

* fix: Missing static assertion message

* fixup: Missing `explicit` in single argument constructors

* fix: Simplify tests: make existing iterator move-only

* fix: Missing `noexcept`
  • Loading branch information
sizmailov authored Sep 7, 2023
1 parent 4a2f7e4 commit c836059
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
14 changes: 10 additions & 4 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -2434,7 +2434,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
Policy);
}

return cast(state{first, last, true});
return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true});
}

PYBIND11_NAMESPACE_END(detail)
Expand All @@ -2451,7 +2451,9 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
Iterator,
Sentinel,
ValueType,
Extra...>(first, last, std::forward<Extra>(extra)...);
Extra...>(std::forward<Iterator>(first),
std::forward<Sentinel>(last),
std::forward<Extra>(extra)...);
}

/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
Expand All @@ -2467,7 +2469,9 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
Iterator,
Sentinel,
KeyType,
Extra...>(first, last, std::forward<Extra>(extra)...);
Extra...>(std::forward<Iterator>(first),
std::forward<Sentinel>(last),
std::forward<Extra>(extra)...);
}

/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
Expand All @@ -2483,7 +2487,9 @@ iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
Iterator,
Sentinel,
ValueType,
Extra...>(first, last, std::forward<Extra>(extra)...);
Extra...>(std::forward<Iterator>(first),
std::forward<Sentinel>(last),
std::forward<Extra>(extra)...);
}

/// Makes an iterator over values of an stl container or other container supporting
Expand Down
19 changes: 19 additions & 0 deletions tests/test_sequences_and_iterators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ class NonZeroIterator {

public:
explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {}

// Make the iterator non-copyable and movable
NonZeroIterator(const NonZeroIterator &) = delete;
NonZeroIterator(NonZeroIterator &&) noexcept = default;
NonZeroIterator &operator=(const NonZeroIterator &) = delete;
NonZeroIterator &operator=(NonZeroIterator &&) noexcept = default;

const T &operator*() const { return *ptr_; }
NonZeroIterator &operator++() {
++ptr_;
Expand Down Expand Up @@ -78,6 +85,7 @@ class NonCopyableInt {
int value_;
};
using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;

PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);

Expand Down Expand Up @@ -375,6 +383,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
private:
std::vector<std::pair<int, int>> data_;
};

{
// #4383 : Make sure `py::make_*iterator` functions work with move-only iterators
using iterator_t = NonZeroIterator<std::pair<int, int>>;

static_assert(std::is_move_assignable<iterator_t>::value, "");
static_assert(std::is_move_constructible<iterator_t>::value, "");
static_assert(!std::is_copy_assignable<iterator_t>::value, "");
static_assert(!std::is_copy_constructible<iterator_t>::value, "");
}

py::class_<IntPairs>(m, "IntPairs")
.def(py::init<std::vector<std::pair<int, int>>>())
.def(
Expand Down

0 comments on commit c836059

Please sign in to comment.