• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &>.
21 struct zip_iterator : boost::stl_interfaces::proxy_iterator_interface<
22                       zip_iterator,
23                       std::random_access_iterator_tag,
24                       std::tuple<int, int>,
25                       std::tuple<int &, int &>>
26 {
zip_iteratorzip_iterator27     constexpr zip_iterator() noexcept : it1_(), it2_() {}
zip_iteratorzip_iterator28     constexpr zip_iterator(int * it1, int * it2) noexcept : it1_(it1), it2_(it2)
29     {}
30 
operator *zip_iterator31     constexpr std::tuple<int &, int &> operator*() const noexcept
32     {
33         return std::tuple<int &, int &>{*it1_, *it2_};
34     }
operator +=zip_iterator35     constexpr zip_iterator & operator += (std::ptrdiff_t i) noexcept
36     {
37         it1_ += i;
38         it2_ += i;
39         return *this;
40     }
operator -zip_iterator41     constexpr auto operator-(zip_iterator other) const noexcept
42     {
43         return it1_ - other.it1_;
44     }
45 
46 private:
47     int * it1_;
48     int * it2_;
49 };
50 
51 
52 namespace std {
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.
57     //
58     // Note that this overload does not conflict with any other swap()
59     // overloads, since this one takes rvalue reference parameters.
60     //
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.
swap(zip_iterator::reference && lhs,zip_iterator::reference && rhs)66     void swap(zip_iterator::reference && lhs, zip_iterator::reference && rhs)
67     {
68         using std::swap;
69         swap(std::get<0>(lhs), std::get<0>(rhs));
70         swap(std::get<1>(lhs), std::get<1>(rhs));
71     }
72 }
73 
74 
main()75 int main()
76 {
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}};
79 
80     {
81         std::array<std::tuple<int, int>, 10> const result = {{
82             {2, 1},
83             {0, 1},
84             {1, 1},
85             {5, 1},
86             {3, 1},
87             {6, 1},
88             {8, 1},
89             {4, 1},
90             {9, 1},
91             {7, 1},
92         }};
93 
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()));
97     }
98 
99     {
100         std::array<std::tuple<int, int>, 10> const result = {{
101             {0, 1},
102             {1, 1},
103             {2, 1},
104             {3, 1},
105             {4, 1},
106             {5, 1},
107             {6, 1},
108             {7, 1},
109             {8, 1},
110             {9, 1},
111         }};
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()));
117     }
118 }
119 //]
120