Horizon
transform.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_TRANSFORM_HPP
15 #define RANGES_V3_VIEW_TRANSFORM_HPP
16 
17 #include <iterator>
18 #include <type_traits>
19 #include <utility>
20 
21 #include <meta/meta.hpp>
22 
23 #include <range/v3/range_fwd.hpp>
24 
36 #include <range/v3/utility/static_const.hpp>
38 #include <range/v3/view/all.hpp>
39 #include <range/v3/view/view.hpp>
40 
41 #include <range/v3/detail/prologue.hpp>
42 
43 namespace ranges
44 {
46  namespace detail
47  {
48  constexpr cardinality transform2_cardinality(cardinality c1, cardinality c2)
49  {
50  return c1 >= 0 || c2 >= 0
51  ? (c1 >= 0 && c2 >= 0 ? (c1 < c2 ? c1 : c2) : finite)
52  : c1 == finite || c2 == finite
53  ? finite
54  : c1 == unknown || c2 == unknown ? unknown : infinite;
55  }
56 
57  // clang-format off
60  template(typename Fun, typename Rng)(
61  concept (iter_transform_1_readable_)(Fun, Rng),
62  regular_invocable<Fun &, iterator_t<Rng>> AND
63  regular_invocable<Fun &, copy_tag, iterator_t<Rng>> AND
64  regular_invocable<Fun &, move_tag, iterator_t<Rng>> AND
65  common_reference_with<
66  invoke_result_t<Fun &, iterator_t<Rng>> &&,
67  invoke_result_t<Fun &, copy_tag, iterator_t<Rng>> &> AND
68  common_reference_with<
69  invoke_result_t<Fun &, iterator_t<Rng>> &&,
70  invoke_result_t<Fun &, move_tag, iterator_t<Rng>> &&> AND
71  common_reference_with<
72  invoke_result_t<Fun &, move_tag, iterator_t<Rng>> &&,
73  invoke_result_t<Fun &, copy_tag, iterator_t<Rng>> const &>
74  );
77  template<typename Fun, typename Rng>
78  CPP_concept iter_transform_1_readable =
79  CPP_concept_ref(detail::iter_transform_1_readable_, Fun, Rng);
80 
83  template(typename Fun, typename Rng1, typename Rng2)(
84  concept (iter_transform_2_readable_)(Fun, Rng1, Rng2),
85  regular_invocable<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> AND
86  regular_invocable<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> AND
87  regular_invocable<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> AND
88  common_reference_with<
89  invoke_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> &&,
90  invoke_result_t<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> &> AND
91  common_reference_with<
92  invoke_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> &&,
93  invoke_result_t<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> &&> AND
94  common_reference_with<
95  invoke_result_t<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> &&,
96  invoke_result_t<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> const &>
97  );
100  template<typename Fun, typename Rng1, typename Rng2>
101  CPP_concept iter_transform_2_readable =
102  CPP_concept_ref(detail::iter_transform_2_readable_, Fun, Rng1, Rng2);
103  // clang-format on
104  } // namespace detail
106 
109  template<typename Rng, typename Fun>
111  {
112  private:
113  friend range_access;
114  RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
115  template<bool Const>
116  using use_sentinel_t =
118  single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng>>>>;
119 
120  template<bool IsConst>
121  struct adaptor : adaptor_base
122  {
123  private:
124  friend struct adaptor<!IsConst>;
125  using CRng = meta::const_if_c<IsConst, Rng>;
126  using fun_ref_ = semiregular_box_ref_or_val_t<Fun, IsConst>;
127  RANGES_NO_UNIQUE_ADDRESS fun_ref_ fun_;
128 
129  public:
130  using value_type =
131  detail::decay_t<invoke_result_t<Fun &, copy_tag, iterator_t<CRng>>>;
132  adaptor() = default;
133  adaptor(fun_ref_ fun)
134  : fun_(std::move(fun))
135  {}
136  template(bool Other)(
137  requires IsConst AND CPP_NOT(Other)) //
138  adaptor(adaptor<Other> that)
139  : fun_(std::move(that.fun_))
140  {}
141 
142  // clang-format off
143  auto CPP_auto_fun(read)(iterator_t<CRng> it)(const)
144  (
145  return invoke(fun_, it)
146  )
147  auto CPP_auto_fun(iter_move)(iterator_t<CRng> it)(const)
148  (
149  return invoke(fun_, move_tag{}, it)
150  )
151  // clang-format on
152  };
153 
154  adaptor<false> begin_adaptor()
155  {
156  return {fun_};
157  }
158  template(bool Const = true)(
159  requires Const AND range<meta::const_if_c<Const, Rng>> AND
160  detail::iter_transform_1_readable<Fun const,
161  meta::const_if_c<Const, Rng>>)
162  adaptor<Const> begin_adaptor() const
163  {
164  return {fun_};
165  }
166  meta::if_<use_sentinel_t<false>, adaptor_base, adaptor<false>> end_adaptor()
167  {
168  return {fun_};
169  }
170  template(bool Const = true)(
171  requires Const AND range<meta::const_if_c<Const, Rng>> AND
172  detail::iter_transform_1_readable<Fun const,
173  meta::const_if_c<Const, Rng>>)
174  meta::if_<use_sentinel_t<Const>, adaptor_base, adaptor<Const>> end_adaptor() const
175  {
176  return {fun_};
177  }
178 
179  public:
180  iter_transform_view() = default;
181  iter_transform_view(Rng rng, Fun fun)
182  : iter_transform_view::view_adaptor{std::move(rng)}
183  , fun_(std::move(fun))
184  {}
185  CPP_auto_member
186  constexpr auto CPP_fun(size)()(
187  requires sized_range<Rng>)
188  {
189  return ranges::size(this->base());
190  }
191  CPP_auto_member
192  constexpr auto CPP_fun(size)()(const //
193  requires sized_range<Rng const>)
194  {
195  return ranges::size(this->base());
196  }
197  };
198 
199  template<typename Rng, typename Fun>
200  struct transform_view : iter_transform_view<Rng, indirected<Fun>>
201  {
202  transform_view() = default;
203  transform_view(Rng rng, Fun fun)
205  indirect(std::move(fun))}
206  {}
207  };
208 
209 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
210  template(typename Rng, typename Fun)(
211  requires copy_constructible<Fun>)
212  transform_view(Rng &&, Fun)
214 #endif
215 
216  template<typename Rng1, typename Rng2, typename Fun>
218  : view_facade<iter_transform2_view<Rng1, Rng2, Fun>,
219  detail::transform2_cardinality(range_cardinality<Rng1>::value,
220  range_cardinality<Rng2>::value)>
221  {
222  private:
223  friend range_access;
224  RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
225  Rng1 rng1_;
226  Rng2 rng2_;
227  using difference_type_ =
228  common_type_t<range_difference_t<Rng1>, range_difference_t<Rng2>>;
229 
230  static constexpr cardinality my_cardinality = detail::transform2_cardinality(
232 
233  template<bool>
234  struct cursor;
235 
236  template<bool Const>
237  struct sentinel
238  {
239  private:
240  friend struct cursor<Const>;
241  sentinel_t<meta::const_if_c<Const, Rng1>> end1_;
242  sentinel_t<meta::const_if_c<Const, Rng2>> end2_;
243 
244  public:
245  sentinel() = default;
246  sentinel(meta::const_if_c<Const, iter_transform2_view> * parent,
247  decltype(ranges::end))
248  : end1_(end(parent->rng1_))
249  , end2_(end(parent->rng2_))
250  {}
251  template(bool Other)(
252  requires Const AND CPP_NOT(Other)) //
253  sentinel(sentinel<Other> that)
254  : end1_(std::move(that.end1_))
255  , end2_(std::move(that.end2_))
256  {}
257  };
258 
259  template<bool Const>
260  struct cursor
261  {
262  private:
263  using fun_ref_ = semiregular_box_ref_or_val_t<Fun, Const>;
264  using R1 = meta::const_if_c<Const, Rng1>;
265  using R2 = meta::const_if_c<Const, Rng2>;
266  fun_ref_ fun_;
267  iterator_t<R1> it1_;
268  iterator_t<R2> it2_;
269 
270  public:
271  using difference_type = difference_type_;
272  using single_pass = meta::or_c<(bool)single_pass_iterator_<iterator_t<R1>>,
273  (bool)single_pass_iterator_<iterator_t<R2>>>;
274  using value_type =
275  detail::decay_t<invoke_result_t<meta::const_if_c<Const, Fun> &, copy_tag,
277 
278  cursor() = default;
279  template<typename BeginEndFn>
280  cursor(meta::const_if_c<Const, iter_transform2_view> * parent,
281  BeginEndFn begin_end)
282  : fun_(parent->fun_)
283  , it1_(begin_end(parent->rng1_))
284  , it2_(begin_end(parent->rng2_))
285  {}
286  template(bool Other)(
287  requires Const AND CPP_NOT(Other)) //
288  cursor(cursor<Other> that)
289  : fun_(std::move(that.fun_))
290  , it1_(std::move(that.end1_))
291  , it2_(std::move(that.end2_))
292  {}
293  // clang-format off
294  auto CPP_auto_fun(read)()(const)
295  (
296  return invoke(fun_, it1_, it2_)
297  )
298  // clang-format on
299  void next()
300  {
301  ++it1_;
302  ++it2_;
303  }
304  CPP_member
305  auto equal(cursor const & that) const //
306  -> CPP_ret(bool)(
307  requires forward_range<Rng1> && forward_range<Rng2>)
308  {
309  // By returning true if *any* of the iterators are equal, we allow
310  // transformed ranges to be of different lengths, stopping when the first
311  // one reaches the last.
312  return it1_ == that.it1_ || it2_ == that.it2_;
313  }
314  bool equal(sentinel<Const> const & s) const
315  {
316  // By returning true if *any* of the iterators are equal, we allow
317  // transformed ranges to be of different lengths, stopping when the first
318  // one reaches the last.
319  return it1_ == s.end1_ || it2_ == s.end2_;
320  }
321  CPP_member
322  auto prev() //
323  -> CPP_ret(void)(
324  requires bidirectional_range<R1> && bidirectional_range<R2>)
325  {
326  --it1_;
327  --it2_;
328  }
329  CPP_member
330  auto advance(difference_type n) -> CPP_ret(void)(
331  requires random_access_range<R1> && random_access_range<R2>)
332  {
333  ranges::advance(it1_, n);
334  ranges::advance(it2_, n);
335  }
336  CPP_member
337  auto distance_to(cursor const & that) const //
338  -> CPP_ret(difference_type)(
339  requires sized_sentinel_for<iterator_t<R1>, iterator_t<R1>> &&
340  sized_sentinel_for<iterator_t<R2>, iterator_t<R2>>)
341  {
342  // Return the smallest distance (in magnitude) of any of the iterator
343  // pairs. This is to accommodate zippers of sequences of different length.
344  difference_type d1 = that.it1_ - it1_, d2 = that.it2_ - it2_;
345  return 0 < d1 ? ranges::min(d1, d2) : ranges::max(d1, d2);
346  }
347  // clang-format off
348  auto CPP_auto_fun(move)()(const)
349  (
350  return invoke(fun_, move_tag{}, it1_, it2_)
351  )
352  // clang-format on
353  };
354 
355  template<bool Const>
356  using end_cursor_t = meta::if_c<
357  common_range<meta::const_if_c<Const, Rng1>> &&
358  common_range<meta::const_if_c<Const, Rng2>> &&
359  !single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng1>>> &&
360  !single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng2>>>,
361  cursor<Const>, sentinel<Const>>;
362 
363  cursor<simple_view<Rng1>() && simple_view<Rng2>()> begin_cursor()
364  {
365  return {this, ranges::begin};
366  }
367  end_cursor_t<simple_view<Rng1>() && simple_view<Rng2>()> end_cursor()
368  {
369  return {this, ranges::end};
370  }
371  template(bool Const = true)(
372  requires Const AND range<meta::const_if_c<Const, Rng1>> AND
373  range<meta::const_if_c<Const, Rng2>> AND
374  detail::iter_transform_2_readable< //
375  Fun const, //
376  meta::const_if_c<Const, Rng1>, //
377  meta::const_if_c<Const, Rng2>>)
378  cursor<true> begin_cursor() const
379  {
380  return {this, ranges::begin};
381  }
382  template(bool Const = true)(
383  requires Const AND range<meta::const_if_c<Const, Rng1>> AND
384  range<meta::const_if_c<Const, Rng2>> AND
385  detail::iter_transform_2_readable< //
386  Fun const, //
387  meta::const_if_c<Const, Rng1>, //
388  meta::const_if_c<Const, Rng2>>)
389  end_cursor_t<Const> end_cursor() const
390  {
391  return {this, ranges::end};
392  }
393  template<typename Self>
394  static constexpr auto size_(Self & self)
395  {
396  using size_type = common_type_t<range_size_t<Rng1>, range_size_t<Rng2>>;
397  return ranges::min(static_cast<size_type>(ranges::size(self.rng1_)),
398  static_cast<size_type>(ranges::size(self.rng2_)));
399  }
400 
401  template<bool B>
402  using R1 = meta::invoke<detail::dependent_<B>, Rng1>;
403  template<bool B>
404  using R2 = meta::invoke<detail::dependent_<B>, Rng2>;
405 
406  public:
407  iter_transform2_view() = default;
408  constexpr iter_transform2_view(Rng1 rng1, Rng2 rng2, Fun fun)
409  : fun_(std::move(fun))
410  , rng1_(std::move(rng1))
411  , rng2_(std::move(rng2))
412  {}
413  CPP_member
414  static constexpr auto size() //
415  -> CPP_ret(std::size_t)(
416  requires (my_cardinality >= 0))
417  {
418  return static_cast<std::size_t>(my_cardinality);
419  }
420  template(bool True = true)(
421  requires (my_cardinality < 0) AND sized_range<Rng1 const> AND
422  sized_range<Rng2 const> AND
423  common_with<range_size_t<R1<True>>, range_size_t<R2<True>>>)
424  constexpr auto size() const
425  {
426  return size_(*this);
427  }
428  template(bool True = true)(
429  requires (my_cardinality < 0) AND sized_range<Rng1> AND sized_range<Rng2> AND
430  common_with<range_size_t<R1<True>>, range_size_t<R2<True>>>)
431  constexpr auto size()
432  {
433  return size_(*this);
434  }
435  };
436 
437  template<typename Rng1, typename Rng2, typename Fun>
438  struct transform2_view : iter_transform2_view<Rng1, Rng2, indirected<Fun>>
439  {
440  transform2_view() = default;
441  constexpr transform2_view(Rng1 rng1, Rng2 rng2, Fun fun)
443  std::move(rng2),
444  indirect(std::move(fun))}
445  {}
446  };
447 
448  namespace views
449  {
451  {
452  template(typename Rng, typename Fun)(
453  requires viewable_range<Rng> AND input_range<Rng> AND
454  copy_constructible<Fun> AND
455  detail::iter_transform_1_readable<Fun, Rng>)
456  constexpr iter_transform_view<all_t<Rng>, Fun> //
457  operator()(Rng && rng, Fun fun) const
458  {
459  return {all(static_cast<Rng &&>(rng)), std::move(fun)};
460  }
461 
462  template(typename Rng1, typename Rng2, typename Fun)(
463  requires viewable_range<Rng1> AND input_range<Rng1> AND
464  viewable_range<Rng2> AND input_range<Rng2> AND
465  copy_constructible<Fun> AND
466  common_with<range_difference_t<Rng1>, range_difference_t<Rng1>> AND
467  detail::iter_transform_2_readable<Fun, Rng1, Rng2>)
468  constexpr iter_transform2_view<all_t<Rng1>, all_t<Rng2>, Fun> //
469  operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const
470  {
471  return {all(static_cast<Rng1 &&>(rng1)),
472  all(static_cast<Rng2 &&>(rng2)),
473  std::move(fun)};
474  }
475  };
476 
478  {
479  using iter_transform_base_fn::operator();
480 
481  template<typename Fun>
482  constexpr auto operator()(Fun fun) const
483  {
484  return make_view_closure(
485  bind_back(iter_transform_base_fn{}, std::move(fun)));
486  }
487  };
488 
492 
493  // Don't forget to update views::for_each whenever this set
494  // of concepts changes
495  // clang-format off
498  template(typename Rng, typename Fun)(
499  concept (transformable_range_)(Rng, Fun),
500  regular_invocable<Fun &, range_reference_t<Rng>> AND
501  (!std::is_void<indirect_result_t<Fun &, iterator_t<Rng>>>::value)
502  );
505  template<typename Rng, typename Fun>
506  CPP_concept transformable_range =
507  viewable_range<Rng> && input_range<Rng> &&
508  copy_constructible<Fun> &&
509  CPP_concept_ref(views::transformable_range_, Rng, Fun);
510 
513  template(typename Rng1, typename Rng2, typename Fun)(
514  concept (transformable_ranges_)(Rng1, Rng2, Fun),
515  regular_invocable<Fun &, range_reference_t<Rng1>, range_reference_t<Rng2>> AND
516  (!std::is_void<
517  indirect_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>>>::value)
518  );
521  template<typename Rng1, typename Rng2, typename Fun>
522  CPP_concept transformable_ranges =
523  viewable_range<Rng1> && input_range<Rng1> &&
524  viewable_range<Rng2> && input_range<Rng2> &&
525  copy_constructible<Fun> &&
526  CPP_concept_ref(views::transformable_ranges_, Rng1, Rng2, Fun);
527  // clang-format on
528 
530  {
531  template(typename Rng, typename Fun)(
532  requires transformable_range<Rng, Fun>)
533  constexpr transform_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun)
534  const
535  {
536  return {all(static_cast<Rng &&>(rng)), std::move(fun)};
537  }
538 
539  template(typename Rng1, typename Rng2, typename Fun)(
540  requires transformable_ranges<Rng1, Rng2, Fun>)
541  constexpr transform2_view<all_t<Rng1>, all_t<Rng2>, Fun> //
542  operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const
543  {
544  return {all(static_cast<Rng1 &&>(rng1)),
545  all(static_cast<Rng2 &&>(rng2)),
546  std::move(fun)};
547  }
548  };
549 
582  {
583  using transform_base_fn::operator();
584 
585  template<typename Fun>
586  constexpr auto operator()(Fun fun) const
587  {
588  return make_view_closure(bind_back(transform_base_fn{}, std::move(fun)));
589  }
590  };
591 
595  } // namespace views
596 
597  namespace cpp20
598  {
599  namespace views
600  {
601  using ranges::views::transform;
602  }
603  template(typename Rng, typename F)(
604  requires input_range<Rng> AND copy_constructible<F> AND view_<Rng> AND
605  std::is_object<F>::value AND
606  regular_invocable<F &, iter_reference_t<iterator_t<Rng>>>)
607  using transform_view = ranges::transform_view<Rng, F>;
608  } // namespace cpp20
610 } // namespace ranges
611 
612 #include <range/v3/detail/epilogue.hpp>
613 
614 #include <range/v3/detail/satisfy_boost_range.hpp>
615 RANGES_SATISFY_BOOST_RANGE(::ranges::iter_transform_view)
616 RANGES_SATISFY_BOOST_RANGE(::ranges::transform_view)
617 
618 #endif
CPP_concept regular_invocable
\concept regular_invocable
Definition: concepts.hpp:55
CPP_concept input_range
\concept input_range
Definition: concepts.hpp:103
CPP_concept viewable_range
\concept viewable_range
Definition: concepts.hpp:260
CPP_concept range
\concept range
Definition: concepts.hpp:69
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
std::integral_constant< bool, B > bool_
An integral constant wrapper for bool.
Definition: meta.hpp:168
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
_t< detail::_if_< list< Args... > >> if_
Select one type or another depending on a compile-time Boolean.
Definition: meta.hpp:1247
Tiny meta-programming library.
CPP_concept transformable_ranges
\concept transformable_ranges
Definition: transform.hpp:522
CPP_concept transformable_range
\concept transformable_range
Definition: transform.hpp:506
template(typename Rng1, typename Rng2, typename Fun)(concept(transformable_ranges_)(Rng1
\concept transformable_ranges_
Logically OR together all the Boolean parameters.
Definition: meta.hpp:1432
Definition: adaptor.hpp:110
Definition: range_fwd.hpp:492
Definition: transform.hpp:221
Definition: transform.hpp:111
Definition: range_fwd.hpp:494
Definition: traits.hpp:128
Definition: transform.hpp:439
Definition: transform.hpp:201
Definition: adaptor.hpp:475
A utility for constructing a view from a (derived) type that implements begin and end cursors.
Definition: facade.hpp:66
Definition: transform.hpp:451
Definition: transform.hpp:478
Definition: transform.hpp:530
Definition: transform.hpp:582