1 // Copyright (C) 2019 T. Zachary Laine
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 #include <boost/stl_interfaces/iterator_interface.hpp>
16 // This is a zip iterator, meaning that it iterates over a notional sequence
17 // of pairs that is formed from two actual sequences of scalars. To make this
18 // iterator writable, it needs to have a reference type that is not actually a
19 // reference -- the reference type is a pair of references, std::tuple<int &,
21 struct zip_iterator
: boost::stl_interfaces::proxy_iterator_interface
<
23 std::random_access_iterator_tag
,
25 std::tuple
<int &, int &>>
27 constexpr zip_iterator() noexcept
: it1_(), it2_() {}
28 constexpr zip_iterator(int * it1
, int * it2
) noexcept
: it1_(it1
), it2_(it2
)
31 constexpr std::tuple
<int &, int &> operator*() const noexcept
33 return std::tuple
<int &, int &>{*it1_
, *it2_
};
35 constexpr zip_iterator
& operator += (std::ptrdiff_t i
) noexcept
41 constexpr auto operator-(zip_iterator other
) const noexcept
43 return it1_
- other
.it1_
;
53 // Required for std::sort to work with zip_iterator. Without this
54 // overload, std::sort eventually tries to call std::swap(*it1, *it2),
55 // *it1 and *it2 are rvalues, and std::swap() takes mutable lvalue
56 // references. That makes std::swap(*it1, *it2) ill-formed.
58 // Note that this overload does not conflict with any other swap()
59 // overloads, since this one takes rvalue reference parameters.
61 // Also note that this overload has to be in namespace std only because
62 // ADL cannot find it anywhere else. If
63 // zip_iterator::reference/std::tuple's template parameters were not
64 // builtins, this overload could be in whatever namespace those template
65 // parameters were declared in.
66 void swap(zip_iterator::reference
&& lhs
, zip_iterator::reference
&& rhs
)
69 swap(std::get
<0>(lhs
), std::get
<0>(rhs
));
70 swap(std::get
<1>(lhs
), std::get
<1>(rhs
));
77 std::array
<int, 10> ints
= {{2, 0, 1, 5, 3, 6, 8, 4, 9, 7}};
78 std::array
<int, 10> ones
= {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
81 std::array
<std::tuple
<int, int>, 10> const result
= {{
94 zip_iterator
first(ints
.data(), ones
.data());
95 zip_iterator
last(ints
.data() + ints
.size(), ones
.data() + ones
.size());
96 assert(std::equal(first
, last
, result
.begin(), result
.end()));
100 std::array
<std::tuple
<int, int>, 10> const result
= {{
112 zip_iterator
first(ints
.data(), ones
.data());
113 zip_iterator
last(ints
.data() + ints
.size(), ones
.data() + ones
.size());
114 assert(!std::equal(first
, last
, result
.begin(), result
.end()));
115 std::sort(first
, last
);
116 assert(std::equal(first
, last
, result
.begin(), result
.end()));