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