1 #ifndef _STL_EXT_ZIP_HPP_
2 #define _STL_EXT_ZIP_HPP_
3
4 #include <tuple>
5 #include <vector>
6
7 #include "type_traits.hpp"
8
9 namespace stl_ext
10 {
11
12 namespace detail
13 {
14
15 template <size_t I, typename... Args>
16 struct min_size_helper
17 {
operator ()stl_ext::detail::min_size_helper18 size_t operator()(const std::tuple<Args...>& v)
19 {
20 return std::min(std::get<I-1>(v).size(), min_size_helper<I-1, Args...>()(v));
21 }
22 };
23
24 template <typename... Args>
25 struct min_size_helper<1, Args...>
26 {
operator ()stl_ext::detail::min_size_helper27 size_t operator()(const std::tuple<Args...>& v)
28 {
29 return std::get<0>(v).size();
30 }
31 };
32
33 template <typename... Args>
34 struct min_size_helper<0, Args...>
35 {
operator ()stl_ext::detail::min_size_helper36 size_t operator()(const std::tuple<Args...>& v)
37 {
38 return 0;
39 }
40 };
41
42 template <typename... Args>
min_size(const std::tuple<Args...> & v)43 size_t min_size(const std::tuple<Args...>& v)
44 {
45 return min_size_helper<sizeof...(Args), Args...>()(v);
46 }
47
48 template <size_t I, typename... Args>
49 struct cbegin_helper
50 {
operator ()stl_ext::detail::cbegin_helper51 void operator()(std::tuple<typename decay_t<Args>::const_iterator...>& i,
52 const std::tuple<Args...>& v)
53 {
54 std::get<I-1>(i) = std::get<I-1>(v).begin();
55 cbegin_helper<I-1, Args...>()(i, v);
56 }
57 };
58
59 template <typename... Args>
60 struct cbegin_helper<1, Args...>
61 {
operator ()stl_ext::detail::cbegin_helper62 void operator()(std::tuple<typename decay_t<Args>::const_iterator...>& i,
63 const std::tuple<Args...>& v)
64 {
65 std::get<0>(i) = std::get<0>(v).begin();
66 }
67 };
68
69 template <typename... Args>
70 struct cbegin_helper<0, Args...>
71 {
operator ()stl_ext::detail::cbegin_helper72 void operator()(std::tuple<typename decay_t<Args>::const_iterator...>& i,
73 const std::tuple<Args...>& v) {}
74 };
75
76 template <typename... Args>
cbegin(const std::tuple<Args...> & v)77 std::tuple<typename decay_t<Args>::const_iterator...> cbegin(const std::tuple<Args...>& v)
78 {
79 std::tuple<typename decay_t<Args>::const_iterator...> i;
80 cbegin_helper<sizeof...(Args), Args...>()(i, v);
81 return i;
82 }
83
84 template <size_t I, typename... Args>
85 struct increment_helper
86 {
operator ()stl_ext::detail::increment_helper87 void operator()(std::tuple<Args...>& i)
88 {
89 ++std::get<I-1>(i);
90 increment_helper<I-1, Args...>()(i);
91 }
92 };
93
94 template <typename... Args>
95 struct increment_helper<1, Args...>
96 {
operator ()stl_ext::detail::increment_helper97 void operator()(std::tuple<Args...>& i)
98 {
99 ++std::get<0>(i);
100 }
101 };
102
103 template <typename... Args>
104 struct increment_helper<0, Args...>
105 {
operator ()stl_ext::detail::increment_helper106 void operator()(std::tuple<Args...>& i) {}
107 };
108
109 template <typename... Args>
increment(std::tuple<Args...> & i)110 void increment(std::tuple<Args...>& i)
111 {
112 increment_helper<sizeof...(Args), Args...>()(i);
113 }
114
115 template <size_t I, typename... Args>
116 struct not_end_helper
117 {
operator ()stl_ext::detail::not_end_helper118 bool operator()(const std::tuple<typename decay_t<Args>::const_iterator...>& i,
119 const std::tuple<Args...>& v)
120 {
121 return std::get<I-1>(i) != std::get<I-1>(v).end() &&
122 not_end_helper<I-1, Args...>()(i, v);
123 }
124 };
125
126 template <typename... Args>
127 struct not_end_helper<1, Args...>
128 {
operator ()stl_ext::detail::not_end_helper129 bool operator()(const std::tuple<typename decay_t<Args>::const_iterator...>& i,
130 const std::tuple<Args...>& v)
131 {
132 return std::get<0>(i) != std::get<0>(v).end();
133 }
134 };
135
136 template <typename... Args>
137 struct not_end_helper<0, Args...>
138 {
operator ()stl_ext::detail::not_end_helper139 bool operator()(const std::tuple<typename decay_t<Args>::const_iterator...>& i,
140 const std::tuple<Args...>& v)
141 {
142 return false;
143 }
144 };
145
146 template <typename... Args>
not_end(const std::tuple<typename decay_t<Args>::const_iterator...> & i,const std::tuple<Args...> & v)147 bool not_end(const std::tuple<typename decay_t<Args>::const_iterator...>& i,
148 const std::tuple<Args...>& v)
149 {
150 return not_end_helper<sizeof...(Args), Args...>()(i, v);
151 }
152
153 template <size_t I, typename... Args>
154 struct reserve_helper
155 {
operator ()stl_ext::detail::reserve_helper156 void operator()(std::tuple<Args...>& t, size_t n)
157 {
158 std::get<I-1>(t).reserve(n);
159 reserve_helper<I-1, Args...>()(t, n);
160 }
161 };
162
163 template <typename... Args>
164 struct reserve_helper<1, Args...>
165 {
operator ()stl_ext::detail::reserve_helper166 void operator()(std::tuple<Args...>& t, size_t n)
167 {
168 std::get<0>(t).reserve(n);
169 }
170 };
171
172 template <typename... Args>
173 struct reserve_helper<0, Args...>
174 {
operator ()stl_ext::detail::reserve_helper175 void operator()(std::tuple<Args...>& t, size_t n) {}
176 };
177
178 template <typename... Args>
reserve(std::tuple<Args...> & t,size_t n)179 void reserve(std::tuple<Args...>& t, size_t n)
180 {
181 reserve_helper<sizeof...(Args), Args...>()(t, n);
182 }
183
184 template <size_t I, typename... Args>
185 struct emplace_back_helper
186 {
operator ()stl_ext::detail::emplace_back_helper187 void operator()(std::tuple<Args...>& t, const std::tuple<typename Args::value_type...>& v)
188 {
189 std::get<I-1>(t).emplace_back(std::get<I-1>(v));
190 emplace_back_helper<I-1, Args...>()(t, v);
191 }
192
operator ()stl_ext::detail::emplace_back_helper193 void operator()(std::tuple<Args...>& t, std::tuple<typename Args::value_type...>&& v)
194 {
195 std::get<I-1>(t).emplace_back(std::move(std::get<I-1>(v)));
196 emplace_back_helper<I-1, Args...>()(t, v);
197 }
198 };
199
200 template <typename... Args>
201 struct emplace_back_helper<1, Args...>
202 {
operator ()stl_ext::detail::emplace_back_helper203 void operator()(std::tuple<Args...>& t, const std::tuple<typename Args::value_type...>& v)
204 {
205 std::get<0>(t).emplace_back(std::get<0>(v));
206 }
207
operator ()stl_ext::detail::emplace_back_helper208 void operator()(std::tuple<Args...>& t, std::tuple<typename Args::value_type...>&& v)
209 {
210 std::get<0>(t).emplace_back(std::move(std::get<0>(v)));
211 }
212 };
213
214 template <typename... Args>
215 struct emplace_back_helper<0, Args...>
216 {
operator ()stl_ext::detail::emplace_back_helper217 void operator()(std::tuple<Args...>& t, const std::tuple<typename Args::value_type...>& v) {}
218
operator ()stl_ext::detail::emplace_back_helper219 void operator()(std::tuple<Args...>& t, std::tuple<typename Args::value_type...>&& v) {}
220 };
221
222 template <typename... Args>
emplace_back(std::tuple<Args...> & t,const std::tuple<typename Args::value_type...> & v)223 void emplace_back(std::tuple<Args...>& t, const std::tuple<typename Args::value_type...>& v)
224 {
225 emplace_back_helper<sizeof...(Args), Args...>()(t, v);
226 }
227
228 template <typename... Args>
emplace_back(std::tuple<Args...> & t,std::tuple<typename Args::value_type...> && v)229 void emplace_back(std::tuple<Args...>& t, std::tuple<typename Args::value_type...>&& v)
230 {
231 emplace_back_helper<sizeof...(Args), Args...>()(t, std::move(v));
232 }
233
234 template <typename T, T... S> struct integer_sequence {};
235
236 template <typename T, typename U, typename V> struct concat_sequences;
237 template <typename T, T... S, T... R>
238 struct concat_sequences<T, integer_sequence<T, S...>, integer_sequence<T, R...>>
239 {
240 typedef integer_sequence<T, S..., (R+sizeof...(S))...> type;
241 };
242
243 template <size_t N> struct static_range_helper;
244
245 template <> struct static_range_helper<0>
246 {
247 typedef integer_sequence<size_t> type;
248 };
249
250 template <> struct static_range_helper<1>
251 {
252 typedef integer_sequence<size_t,0> type;
253 };
254
255 template <size_t N> struct static_range_helper
256 {
257 typedef typename concat_sequences<size_t, typename static_range_helper<(N+1)/2>::type,
258 typename static_range_helper<N/2>::type>::type type;
259 };
260
261 template <size_t N>
262 using static_range = typename static_range_helper<N>::type;
263
264 template <typename... Args>
265 struct call_helper
266 {
267 template <typename Func, size_t... S>
call_helperstl_ext::detail::call_helper268 call_helper(Func func, std::tuple<Args...>& args, integer_sequence<size_t, S...> seq)
269 {
270 func(std::get<S>(args)...);
271 }
272
273 template <typename Func, size_t... S>
call_helperstl_ext::detail::call_helper274 call_helper(Func func, const std::tuple<Args...>& args, integer_sequence<size_t, S...> seq)
275 {
276 func(std::get<S>(args)...);
277 }
278
279 template <typename Func, size_t... S>
call_helperstl_ext::detail::call_helper280 call_helper(Func func, std::tuple<Args...>&& args, integer_sequence<size_t, S...> seq)
281 {
282 func(std::get<S>(std::move(args))...);
283 }
284 };
285
286 }
287
288 template <typename Func, typename... Args>
call(Func func,std::tuple<Args...> & args)289 void call(Func func, std::tuple<Args...>& args)
290 {
291 detail::call_helper<Args...>(func, args, detail::static_range<sizeof...(Args)>{});
292 }
293
294 template <typename Func, typename... Args>
call(Func func,const std::tuple<Args...> & args)295 void call(Func func, const std::tuple<Args...>& args)
296 {
297 detail::call_helper<Args...>(func, args, detail::static_range<sizeof...(Args)>{});
298 }
299
300 template <typename Func, typename... Args>
call(Func func,std::tuple<Args...> && args)301 void call(Func func, std::tuple<Args...>&& args)
302 {
303 detail::call_helper<Args...>(func, std::move(args), detail::static_range<sizeof...(Args)>{});
304 }
305
306 template <typename... Args>
zip(const std::tuple<Args...> & v)307 std::vector<std::tuple<typename decay_t<Args>::value_type...>> zip(const std::tuple<Args...>& v)
308 {
309 //TODO move elements when possible
310
311 std::vector<std::tuple<typename decay_t<Args>::value_type...>> t;
312 t.reserve(detail::min_size(v));
313
314 auto i = detail::cbegin(v);
315 for (;detail::not_end(i,v);detail::increment(i))
316 {
317 call([&t](typename decay_t<Args>::const_iterator... args) {t.emplace_back(*args...); }, i);
318 }
319
320 return t;
321 }
322
323 template <typename Arg, typename... Args>
324 std::vector<std::tuple<typename decay_t<Arg>::value_type, typename decay_t<Args>::value_type...>>
zip(Arg && v,Args &&...v_)325 zip(Arg&& v, Args&&... v_)
326 {
327 return zip(forward_as_tuple(std::forward<Arg>(v), std::forward<Args>(v_)...));
328 }
329
330 template <typename... Args>
unzip(const std::vector<std::tuple<Args...>> & v)331 std::tuple<std::vector<Args>...> unzip(const std::vector<std::tuple<Args...>>& v)
332 {
333 std::tuple<std::vector<Args>...> t;
334 detail::reserve(t, v.size());
335
336 for (auto i = v.begin();i != v.end();++i)
337 {
338 detail::emplace_back(t, *i);
339 }
340
341 return t;
342 }
343
344 template <typename... Args>
unzip(std::vector<std::tuple<Args...>> && v)345 std::tuple<std::vector<Args>...> unzip(std::vector<std::tuple<Args...>>&& v)
346 {
347 std::tuple<std::vector<Args>...> t;
348 detail::reserve(t, v.size());
349
350 for (auto i = v.begin();i != v.end();++i)
351 {
352 detail::emplace_back(t, move(*i));
353 }
354
355 return t;
356 }
357
358 }
359
360 #endif
361