Horizon
zip_with.hpp
Go to the documentation of this file.
1 // 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 
24 #include <range/v3/range_fwd.hpp>
25 
35 #include <range/v3/utility/static_const.hpp>
37 #include <range/v3/view/all.hpp>
38 #include <range/v3/view/empty.hpp>
39 #include <range/v3/view/facade.hpp>
40 
41 #include <range/v3/detail/prologue.hpp>
42 
43 namespace 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  };
57 
58  struct dec_
59  {
60  template<typename T>
61  void operator()(T & t) const
62  {
63  --t;
64  }
65  };
67 
68  struct inc_
69  {
70  template<typename T>
71  void operator()(T & t) const
72  {
73  ++t;
74  }
75  };
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  };
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  };
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<
243  sentinel_for<iterator_t<meta::const_if_c<Const, Rngs>>,
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<
280  sized_sentinel_for<iterator_t<meta::const_if_c<Const, Rngs>>,
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 
416 
417  struct zip_with_fn
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 
442  } // namespace views
444 } // namespace ranges
445 
446 #include <range/v3/detail/epilogue.hpp>
447 
448 #include <range/v3/detail/satisfy_boost_range.hpp>
449 RANGES_SATISFY_BOOST_RANGE(::ranges::iter_zip_with_view)
450 RANGES_SATISFY_BOOST_RANGE(::ranges::zip_with_view)
451 
452 #endif
CPP_concept invocable
\concept invocable
Definition: concepts.hpp:48
decltype(begin(declval(Rng &))) iterator_t
Definition: access.hpp:698
RANGES_INLINE_VARIABLE(detail::to_container_fn< detail::from_range< std::vector >>, to_vector) template< template< typename... > class ContT > auto to(RANGES_HIDDEN_DETAIL(detail
For initializing a container of the specified type with the elements of an Range.
Definition: conversion.hpp:399
_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
std::integral_constant< std::size_t, N > size_t
An integral constant wrapper for std::size_t.
Definition: meta.hpp:163
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
defer< bind_back, Fn, Ts... > bind_back
Definition: meta.hpp:994
meta::size_t< L::size()> size
An integral constant wrapper that is the size of the meta::list L.
Definition: meta.hpp:1696
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
bool_< T::type::value==U::type::value > equal_to
A Boolean integral constant wrapper around the result of comparing T::type::value and U::type::value ...
Definition: meta.hpp:237
fold< pop_front< list< Ts... > >, front< list< Ts... > >, quote< detail::max_ > > max_
An integral constant wrapper around the maximum of Ts::type::value...
Definition: meta.hpp:2205
transform< transpose< ListOfLists >, uncurry< Fn > > zip_with
Given a list of lists of types ListOfLists and an invocable Fn, construct a new list by calling Fn wi...
Definition: meta.hpp:2911
Tiny meta-programming library.
std::integral_constant< decltype(T::type::value+1), T::type::value+1 > inc
An integral constant wrapper around the result of incrementing the wrapped integer T::type::value.
Definition: meta.hpp:185
std::integral_constant< decltype(T::type::value - 1), T::type::value - 1 > dec
An integral constant wrapper around the result of decrementing the wrapped integer T::type::value.
Definition: meta.hpp:190
CPP_concept zippable_with
\concept zippable_with
Definition: zip_with.hpp:152
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