Zen C++ Libraries
Zero-dependency re-usable components for C++
Loading...
Searching...
No Matches
zip_iterator.hpp
Go to the documentation of this file.
1
3
4#ifndef ZEN_ZIP_ITERATOR_HPP
5#define ZEN_ZIP_ITERATOR_HPP
6
7#include <algorithm>
8#include <boost/hana/fwd/fold.hpp>
9#include <boost/hana/fwd/index_if.hpp>
10#include <boost/hana/fwd/tuple.hpp>
11#include <boost/hana/fwd/type.hpp>
12#include <cstddef>
13#include <iterator>
14#include <tuple>
15#include <utility>
16
17#include "zen/config.hpp"
18#include "zen/hana.hpp"
19#include "zen/algorithm.hpp"
20
21ZEN_NAMESPACE_START
22
23template<typename IterT>
24using iterator_category_t = std::iterator_traits<IterT>::iterator_category;
25
26template<typename T>
28
29template<typename ...Ts>
30struct to_hana_tuple_t<std::tuple<Ts...>> {
31 static constexpr auto value = hana::make_tuple(hana::type_c<Ts>...);
32};
33
34constexpr auto _iterator_categories = to_hana_tuple_t<std::tuple<
35 std::input_iterator_tag
36, std::forward_iterator_tag
37, std::bidirectional_iterator_tag
38, std::random_access_iterator_tag
39, std::contiguous_iterator_tag
40>>::value;
41
42// template<typename T>
43// struct common_iterator_category : meta::fold1<
44// meta::bind<
45// meta::min_by_t<
46// meta::index_t<tags, meta::_1>,
47// meta::map_t<T, meta::bind<iterator_category_t<meta::_1>>>,
48// std::contiguous_iterator_tag
49// >
50// >,
51// T
52// > {};
53
54// template<typename T>
55// using common_iterator_category_t = common_iterator_category<T>::type;
56//
57
58template<typename T>
59constexpr auto _iterator_category_tag_index(T element) {
60 return hana::index_if(
61 _iterator_categories,
62 [&](const auto& x) { return hana::equal(x, element); }
63 ).value();
64}
65
66template<typename T, typename Fn, typename I>
67constexpr auto min_by(T&& seq, Fn&& get, I&& init) {
68 return hana::fold(
69 seq,
70 init,
71 [&](auto a, auto b) {
72 return hana::if_(
73 hana::less(get(a), get(b)),
74 a,
75 b
76 );
77 }
78 );
79}
80
82template<typename T>
83class zip_iterator {
84
85 T iterators;
86
87public:
88
89 using value_type = decltype(
90 +hana::unpack(
91 hana::transform(
93 [](auto t) {
94 using It = typename decltype(t)::type;
95 return hana::type_c<std::iter_value_t<It>>;
96 }
97 ),
98 hana::template_<std::tuple>
99 )
100 )::type;
101
107 using reference = value_type;
108
109 using pointer = value_type*;
110
111 using difference_type = std::ptrdiff_t;
112
113 using iterator_category = decltype(
114 +min_by(
115 hana::transform(
117 [](auto el) { return hana::type_c<iterator_category_t<typename decltype(+el)::type>>; }
118 ),
119 [](auto el) {
120 return _iterator_category_tag_index(el);
121 },
122 hana::type_c<std::random_access_iterator_tag>
123 )
124 )::type;
125
126 // using iterator_category = std::random_access_iterator_tag;
127 // using iterator_category = common_iterator_category<T>;
128
129 zip_iterator(T iterators):
130 iterators(iterators) {}
131
132 zip_iterator(const zip_iterator& other):
133 iterators(other.iterators) {}
134
135 zip_iterator(zip_iterator&& other):
136 iterators(std::move(other.iterators)) {}
137
138 zip_iterator& operator=(zip_iterator&& other) {
139 iterators = std::move(other.iterators);
140 return *this;
141 }
142
143 zip_iterator copy() {
144 return { iterators };
145 }
146
147 bool operator==(const zip_iterator& other) const {
148 return std::get<0>(iterators) == std::get<0>(other.iterators);
149 }
150
151 bool operator!=(const zip_iterator& other) const {
152 return std::get<0>(iterators) != std::get<0>(other.iterators);
153 }
154
155 zip_iterator& operator++() {
156 std::apply([](auto& ...args) { ((++args),...); }, iterators);
157 return *this;
158 }
159
160 zip_iterator operator++(int) {
161 return map(iterators, [&] (auto& iter) { return iter++; });
162 }
163
164 void operator--() {
165 std::apply([&](auto& ...args) { ((--args),...); }, iterators);
166 }
167
168 zip_iterator operator+(std::ptrdiff_t offset) {
169 return cmap(iterators, [&] (auto& iter) { return iter + offset; });
170 }
171
172 zip_iterator operator-(std::ptrdiff_t offset) {
173 return cmap(iterators, [&] (auto& iter) { return iter - offset; });
174 }
175
176 zip_iterator& operator=(const zip_iterator& other) {
177 iterators = other.iterators;
178 return *this;
179 }
180
181 reference operator*() {
182 return cmap(iterators, [] (const auto& iter) { return *iter; });
183 }
184
185};
186
187template<std::input_iterator...Ts>
188auto zip(Ts...args) {
189 return zip_iterator<std::tuple<Ts...>>(std::tuple<Ts...>(std::forward<Ts>(args)...));
190}
191
192ZEN_NAMESPACE_END
193
194namespace std {
195
196 template <typename T>
197 struct iterator_traits<zen::zip_iterator<T>>
198 {
199 using difference_type = ZEN_NAMESPACE::zip_iterator<T>::difference_type;
200 using value_type = ZEN_NAMESPACE::zip_iterator<T>::value_type;
201 using pointer = ZEN_NAMESPACE::zip_iterator<T>::pointer;
202 using reference = ZEN_NAMESPACE::zip_iterator<T>::reference;
203 using iterator_category = ZEN_NAMESPACE::zip_iterator<T>::iterator_category;
204 };
205
206}
207
208#endif // #ifndef ZEN_ZIP_ITERATOR_HPP
Definition value.hpp:34
An iterator that merges multiple other iterators.
Definition zip_iterator.hpp:83
value_type reference
Definition zip_iterator.hpp:107
Definition concepts.hpp:45
auto zip(Ts &&...args)
Definition iterator_range.hpp:136
Definition zip_iterator.hpp:27