Horizon
Loading...
Searching...
No Matches
zip_with.hpp
Go to the documentation of this file.
1
2// Range v3 library
3//
4// Copyright Eric Niebler 2013-present
5//
6// Use, modification and distribution is subject to the
7// Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10//
11// Project home: https://github.com/ericniebler/range-v3
12//
13
14#ifndef RANGES_V3_VIEW_ZIP_WITH_HPP
15#define RANGES_V3_VIEW_ZIP_WITH_HPP
16
17#include <limits>
18#include <tuple>
19#include <type_traits>
20#include <utility>
21
22#include <meta/meta.hpp>
23
25
35#include <range/v3/utility/static_const.hpp>
37#include <range/v3/view/all.hpp>
40
41#include <range/v3/detail/prologue.hpp>
42
43namespace ranges
44{
46 namespace detail
47 {
48 struct equal_to_
49 {
50 template<typename T, typename U>
51 bool operator()(T const & t, U const & u) const
52 {
53 return static_cast<bool>(t == u);
54 }
55 };
56 RANGES_INLINE_VARIABLE(equal_to_, equal_to)
57
58 struct dec_
59 {
60 template<typename T>
61 void operator()(T & t) const
62 {
63 --t;
64 }
65 };
66 RANGES_INLINE_VARIABLE(dec_, dec)
67
68 struct inc_
69 {
70 template<typename T>
71 void operator()(T & t) const
72 {
73 ++t;
74 }
75 };
76 RANGES_INLINE_VARIABLE(inc_, inc)
77
78 struct _advance_
79 {
80 template(typename I, typename Diff)(
81 requires input_or_output_iterator<I> AND integer_like_<Diff>)
82 void operator()(I & i, Diff n) const
83 {
84 advance(i, static_cast<iter_difference_t<I>>(n));
85 }
86 };
87 RANGES_INLINE_VARIABLE(_advance_, advance_)
88
89 struct distance_to_
90 {
91 template<typename T>
92 constexpr auto operator()(T const & t, T const & u) const -> decltype(u - t)
93 {
94 return u - t;
95 }
96 };
97 RANGES_INLINE_VARIABLE(distance_to_, distance_to)
98
99 struct _min_
100 {
101 template<typename T, typename U>
102 constexpr auto operator()(T const & t, U const & u) const
103 -> decltype(true ? t : u)
104 {
105 return u < t ? u : t;
106 }
107 };
108 RANGES_INLINE_VARIABLE(_min_, min_)
109
110 struct _max_
111 {
112 template<typename T, typename U>
113 constexpr auto operator()(T const & t, U const & u) const
114 -> decltype(true ? u : t)
115 {
116 return u < t ? t : u;
117 }
118 };
119 RANGES_INLINE_VARIABLE(_max_, max_)
120
121 template<typename State, typename Value>
122 using zip_cardinality = std::integral_constant<
123 cardinality,
124 State::value >= 0 && Value::value >= 0
125 ? min_(State::value, Value::value)
126 : State::value >=0 && Value::value == infinite
127 ? State::value
128 : State::value == infinite && Value::value >= 0
129 ? Value::value
130 : State::value == finite || Value::value == finite
131 ? finite
132 : State::value == unknown || Value::value == unknown
133 ? unknown
134 : infinite>;
135 } // namespace detail
137
138 namespace views
139 {
140 // clang-format off
143 template(typename Fun, typename... Rngs)(
144 concept (zippable_with_)(Fun, Rngs...),
145 invocable<Fun&, iterator_t<Rngs>...> AND
146 invocable<Fun&, copy_tag, iterator_t<Rngs>...> AND
147 invocable<Fun&, move_tag, iterator_t<Rngs>...>
148 );
151 template<typename Fun, typename ...Rngs>
152 CPP_concept zippable_with =
153 and_v<input_range<Rngs>...> &&
154 copy_constructible<Fun> &&
155 CPP_concept_ref(views::zippable_with_, Fun, Rngs...);
156 // clang-format on
157 } // namespace views
158
161 template<typename Fun, typename... Rngs>
163 : view_facade<iter_zip_with_view<Fun, Rngs...>,
164 meta::fold<meta::list<range_cardinality<Rngs>...>,
165 std::integral_constant<cardinality, cardinality::infinite>,
166 meta::quote<detail::zip_cardinality>>::value>
167 {
168 private:
169 CPP_assert(sizeof...(Rngs) != 0);
170 friend range_access;
171
172 semiregular_box_t<Fun> fun_;
173 std::tuple<Rngs...> rngs_;
174 using difference_type_ = common_type_t<range_difference_t<Rngs>...>;
175
176 template<bool Const>
177 struct cursor;
178
179 template<bool Const>
180 struct sentinel
181 {
182 private:
183 friend struct cursor<Const>;
184 friend struct sentinel<!Const>;
185 std::tuple<sentinel_t<meta::const_if_c<Const, Rngs>>...> ends_;
186
187 public:
188 sentinel() = default;
189 sentinel(detail::ignore_t,
190 std::tuple<sentinel_t<meta::const_if_c<Const, Rngs>>...> ends)
191 : ends_(std::move(ends))
192 {}
193 template(bool Other)(
194 requires Const AND CPP_NOT(Other)) //
195 sentinel(sentinel<Other> that)
196 : ends_(std::move(that.ends_))
197 {}
198 };
199
200 template<bool Const>
201 struct cursor
202 {
203 private:
204 friend struct cursor<!Const>;
205 using fun_ref_ = semiregular_box_ref_or_val_t<Fun, Const>;
206 fun_ref_ fun_;
207 std::tuple<iterator_t<meta::const_if_c<Const, Rngs>>...> its_;
208
209 public:
210 using difference_type =
211 common_type_t<range_difference_t<meta::const_if_c<Const, Rngs>>...>;
212 using single_pass = meta::or_c<(
213 bool)single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rngs>>>...>;
214 using value_type = detail::decay_t<invoke_result_t<
216
217 cursor() = default;
218 cursor(fun_ref_ fun,
219 std::tuple<iterator_t<meta::const_if_c<Const, Rngs>>...> its)
220 : fun_(std::move(fun))
221 , its_(std::move(its))
222 {}
223 template(bool Other)(
224 requires Const AND CPP_NOT(Other)) //
225 cursor(cursor<Other> that)
226 : fun_(std::move(that.fun_))
227 , its_(std::move(that.its_))
228 {}
229 // clang-format off
230 auto CPP_auto_fun(read)()(const)
231 (
232 return tuple_apply(fun_, its_)
233 )
234 // clang-format on
235 void next()
236 {
237 tuple_for_each(its_, detail::inc);
238 }
239 CPP_member
240 auto equal(cursor const & that) const //
241 -> CPP_ret(bool)(
242 requires and_v<
245 {
246 // By returning true if *any* of the iterators are equal, we allow
247 // zipped ranges to be of different lengths, stopping when the first
248 // one reaches the last.
249 return tuple_foldl(tuple_transform(its_, that.its_, detail::equal_to),
250 false,
251 [](bool a, bool b) { return a || b; });
252 }
253 bool equal(sentinel<Const> const & s) const
254 {
255 // By returning true if *any* of the iterators are equal, we allow
256 // zipped ranges to be of different lengths, stopping when the first
257 // one reaches the last.
258 return tuple_foldl(tuple_transform(its_, s.ends_, detail::equal_to),
259 false,
260 [](bool a, bool b) { return a || b; });
261 }
262 CPP_member
263 auto prev() //
264 -> CPP_ret(void)(
265 requires and_v<bidirectional_range<meta::const_if_c<Const, Rngs>>...>)
266 {
267 tuple_for_each(its_, detail::dec);
268 }
269 CPP_member
270 auto advance(difference_type n) //
271 -> CPP_ret(void)(
272 requires and_v<random_access_range<meta::const_if_c<Const, Rngs>>...>)
273 {
274 tuple_for_each(its_, bind_back(detail::advance_, n));
275 }
276 CPP_member
277 auto distance_to(cursor const & that) const //
278 -> CPP_ret(difference_type)(
279 requires and_v<
282 {
283 // Return the smallest distance (in magnitude) of any of the iterator
284 // pairs. This is to accommodate zippers of sequences of different length.
285 if(0 < std::get<0>(that.its_) - std::get<0>(its_))
286 return tuple_foldl(
287 tuple_transform(its_, that.its_, detail::distance_to),
288 (std::numeric_limits<difference_type>::max)(),
289 detail::min_);
290 else
291 return tuple_foldl(
292 tuple_transform(its_, that.its_, detail::distance_to),
293 (std::numeric_limits<difference_type>::min)(),
294 detail::max_);
295 }
296 // clang-format off
297 template<std::size_t... Is>
298 auto CPP_auto_fun(move_)(meta::index_sequence<Is...>)(const)
299 (
300 return invoke(fun_, move_tag{}, std::get<Is>(its_)...)
301 )
302 // clang-format on
303 auto move() const noexcept(noexcept(std::declval<cursor const &>().move_(
304 meta::make_index_sequence<sizeof...(Rngs)>{})))
305 -> decltype(std::declval<cursor const &>().move_(
306 meta::make_index_sequence<sizeof...(Rngs)>{}))
307 {
308 return move_(meta::make_index_sequence<sizeof...(Rngs)>{});
309 }
310 };
311
312 template<bool Const>
313 using end_cursor_t =
314 meta::if_c<concepts::and_v<(bool)common_range<Rngs>...,
315 !(bool)single_pass_iterator_<iterator_t<Rngs>>...>,
316 cursor<Const>, sentinel<Const>>;
317
318 cursor<false> begin_cursor()
319 {
320 return {fun_, tuple_transform(rngs_, ranges::begin)};
321 }
322 end_cursor_t<false> end_cursor()
323 {
324 return {fun_, tuple_transform(rngs_, ranges::end)};
325 }
326 template(bool Const = true)(
327 requires Const AND and_v<range<Rngs const>...> AND
328 views::zippable_with<Fun, meta::if_c<Const, Rngs const>...>)
329 cursor<Const> begin_cursor() const
330 {
331 return {fun_, tuple_transform(rngs_, ranges::begin)};
332 }
333 template(bool Const = true)(
334 requires Const AND and_v<range<Rngs const>...> AND
335 views::zippable_with<Fun, meta::if_c<Const, Rngs const>...>)
336 end_cursor_t<Const> end_cursor() const
337 {
338 return {fun_, tuple_transform(rngs_, ranges::end)};
339 }
340
341 public:
342 iter_zip_with_view() = default;
343 explicit iter_zip_with_view(Rngs... rngs)
344 : fun_(Fun{})
345 , rngs_{std::move(rngs)...}
346 {}
347 explicit iter_zip_with_view(Fun fun, Rngs... rngs)
348 : fun_(std::move(fun))
349 , rngs_{std::move(rngs)...}
350 {}
351 CPP_auto_member
352 constexpr auto CPP_fun(size)()(const //
353 requires and_v<sized_range<Rngs const>...>)
354 {
355 using size_type = common_type_t<range_size_t<Rngs const>...>;
357 ? size_type{(
359 : tuple_foldl(tuple_transform(rngs_,
360 [](auto && r) -> size_type {
361 return ranges::size(r);
362 }),
363 (std::numeric_limits<size_type>::max)(),
364 detail::min_);
365 }
366 };
367
368 template<typename Fun, typename... Rngs>
369 struct zip_with_view : iter_zip_with_view<indirected<Fun>, Rngs...>
370 {
371 CPP_assert(sizeof...(Rngs) != 0);
372
373 zip_with_view() = default;
374 explicit zip_with_view(Rngs... rngs)
375 : iter_zip_with_view<indirected<Fun>, Rngs...>{{Fun{}}, std::move(rngs)...}
376 {}
377 explicit zip_with_view(Fun fun, Rngs... rngs)
378 : iter_zip_with_view<indirected<Fun>, Rngs...>{{std::move(fun)},
379 std::move(rngs)...}
380 {}
381 };
382
383#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
384 template(typename Fun, typename... Rng)(
385 requires copy_constructible<Fun>)
386 zip_with_view(Fun, Rng &&...)
388#endif
389
390 namespace views
391 {
393 {
394 template(typename... Rngs, typename Fun)(
395 requires and_v<viewable_range<Rngs>...> AND
396 zippable_with<Fun, Rngs...> AND (sizeof...(Rngs) != 0)) //
397 iter_zip_with_view<Fun, all_t<Rngs>...> //
398 operator()(Fun fun, Rngs &&... rngs) const
399 {
401 std::move(fun), all(static_cast<Rngs &&>(rngs))...};
402 }
403
404 template(typename Fun)(
405 requires zippable_with<Fun>) //
407 operator()(Fun) const noexcept
408 {
409 return {};
410 }
411 };
412
415 RANGES_INLINE_VARIABLE(iter_zip_with_fn, iter_zip_with)
416
418 {
419 template(typename... Rngs, typename Fun)(
420 requires and_v<viewable_range<Rngs>...> AND
421 and_v<input_range<Rngs>...> AND copy_constructible<Fun> AND
422 invocable<Fun &, range_reference_t<Rngs>...> AND
423 (sizeof...(Rngs) != 0)) //
424 zip_with_view<Fun, all_t<Rngs>...> operator()(Fun fun, Rngs &&... rngs) const
425 {
427 std::move(fun), all(static_cast<Rngs &&>(rngs))...};
428 }
429
430 template(typename Fun)(
431 requires copy_constructible<Fun> AND invocable<Fun &>) //
433 operator()(Fun) const noexcept
434 {
435 return {};
436 }
437 };
438
441 RANGES_INLINE_VARIABLE(zip_with_fn, zip_with)
442 } // namespace views
444} // namespace ranges
445
446#include <range/v3/detail/epilogue.hpp>
447
448#include <range/v3/detail/satisfy_boost_range.hpp>
449RANGES_SATISFY_BOOST_RANGE(::ranges::iter_zip_with_view)
450RANGES_SATISFY_BOOST_RANGE(::ranges::zip_with_view)
451
452#endif
The common_range concept.
The input_range concept.
The invocable concept.
The range concept.
The sentinel_for concept.
The sized_range concept.
The sized_sentinel_for concept.
The viewable_range concept.
The zippable_with concept.
decltype(begin(declval(Rng &))) iterator_t
Definition access.hpp:698
_t< detail::make_indices_< N, index_sequence< 0 >, detail::strategy_(1, N)> > make_index_sequence
Generate index_sequence containing integer constants [0,1,2,...,N-1].
Definition meta.hpp:473
fold< pop_front< list< Ts... > >, front< list< Ts... > >, quote< detail::min_ > > min_
An integral constant wrapper around the minimum of Ts::type::value...
Definition meta.hpp:2197
Tiny meta-programming library.
A container for a sequence of compile-time integer constants.
Definition meta.hpp:434
Logically OR together all the Boolean parameters.
Definition meta.hpp:1432
Definition range_fwd.hpp:492
Definition empty.hpp:29
Definition zip_with.hpp:167
Definition range_fwd.hpp:494
Definition traits.hpp:128
A utility for constructing a view from a (derived) type that implements begin and end cursors.
Definition facade.hpp:66
Definition zip_with.hpp:393
Definition zip_with.hpp:418
Definition zip_with.hpp:370