1// Copyright (C) 2019 T. Zachary Laine
2//
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)
6//[ zip_proxy_iterator
7#include <boost/stl_interfaces/iterator_interface.hpp>
8
9#include <algorithm>
10#include <array>
11#include <tuple>
12
13#include <cassert>
14
15
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 &,
20// int &>.
21struct zip_iterator : boost::stl_interfaces::proxy_iterator_interface<
22#if !BOOST_STL_INTERFACES_USE_DEDUCED_THIS
23 zip_iterator,
24#endif
25 std::random_access_iterator_tag,
26 std::tuple<int, int>,
27 std::tuple<int &, int &>>
28{
29 constexpr zip_iterator() noexcept : it1_(), it2_() {}
30 constexpr zip_iterator(int * it1, int * it2) noexcept : it1_(it1), it2_(it2)
31 {}
32
33 constexpr std::tuple<int &, int &> operator*() const noexcept
34 {
35 return std::tuple<int &, int &>{*it1_, *it2_};
36 }
37 constexpr zip_iterator & operator += (std::ptrdiff_t i) noexcept
38 {
39 it1_ += i;
40 it2_ += i;
41 return *this;
42 }
43 constexpr auto operator-(zip_iterator other) const noexcept
44 {
45 return it1_ - other.it1_;
46 }
47
48private:
49 int * it1_;
50 int * it2_;
51};
52
53
54namespace std {
55 // Required for std::sort to work with zip_iterator. Without this
56 // overload, std::sort eventually tries to call std::swap(*it1, *it2),
57 // *it1 and *it2 are rvalues, and std::swap() takes mutable lvalue
58 // references. That makes std::swap(*it1, *it2) ill-formed.
59 //
60 // Note that this overload does not conflict with any other swap()
61 // overloads, since this one takes rvalue reference parameters.
62 //
63 // Also note that this overload has to be in namespace std only because
64 // ADL cannot find it anywhere else. If
65 // zip_iterator::reference/std::tuple's template parameters were not
66 // builtins, this overload could be in whatever namespace those template
67 // parameters were declared in.
68 void swap(zip_iterator::reference && lhs, zip_iterator::reference && rhs)
69 {
70 using std::swap;
71 swap(a&: std::get<0>(t&: lhs), b&: std::get<0>(t&: rhs));
72 swap(a&: std::get<1>(t&: lhs), b&: std::get<1>(t&: rhs));
73 }
74}
75
76
77int main()
78{
79 std::array<int, 10> ints = {._M_elems: {2, 0, 1, 5, 3, 6, 8, 4, 9, 7}};
80 std::array<int, 10> ones = {._M_elems: {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
81
82 {
83 std::array<std::tuple<int, int>, 10> const result = {._M_elems: {
84 {2, 1},
85 {0, 1},
86 {1, 1},
87 {5, 1},
88 {3, 1},
89 {6, 1},
90 {8, 1},
91 {4, 1},
92 {9, 1},
93 {7, 1},
94 }};
95
96 zip_iterator first(ints.data(), ones.data());
97 zip_iterator last(ints.data() + ints.size(), ones.data() + ones.size());
98 assert(std::equal(first, last, result.begin(), result.end()));
99 }
100
101 {
102 std::array<std::tuple<int, int>, 10> const result = {._M_elems: {
103 {0, 1},
104 {1, 1},
105 {2, 1},
106 {3, 1},
107 {4, 1},
108 {5, 1},
109 {6, 1},
110 {7, 1},
111 {8, 1},
112 {9, 1},
113 }};
114 zip_iterator first(ints.data(), ones.data());
115 zip_iterator last(ints.data() + ints.size(), ones.data() + ones.size());
116 assert(!std::equal(first, last, result.begin(), result.end()));
117 std::sort(first: first, last: last);
118 assert(std::equal(first, last, result.begin(), result.end()));
119 }
120}
121//]
122

source code of boost/libs/stl_interfaces/example/zip_proxy_iterator.cpp