Horizon
conversion.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_RANGE_CONVERSION_HPP
15 #define RANGES_V3_RANGE_CONVERSION_HPP
16 
17 #include <vector>
18 
19 #include <meta/meta.hpp>
20 
21 #include <range/v3/range_fwd.hpp>
22 
28 #include <range/v3/utility/static_const.hpp>
29 
30 #include <range/v3/detail/prologue.hpp>
31 
32 namespace ranges
33 {
35  namespace detail
36  {
37  struct to_container
38  {
39  template<typename MetaFn>
40  struct fn;
41 
42  template<typename MetaFn, typename Fn>
43  struct closure;
44 
45  template<typename MetaFn, typename Rng>
46  using container_t = meta::invoke<MetaFn, Rng>;
47 
48  template<typename Rng, typename MetaFn>
49  friend auto operator|(Rng && rng,
50  closure<MetaFn, fn<MetaFn>> (*)(to_container))
51  -> CPP_broken_friend_ret(container_t<MetaFn, Rng>)(
52  requires invocable<fn<MetaFn>, Rng>)
53  {
54  return fn<MetaFn>{}(static_cast<Rng &&>(rng));
55  }
56 
57  template<typename MetaFn, typename Pipeable>
58  friend auto operator|(closure<MetaFn, fn<MetaFn>> (*)(to_container),
59  Pipeable pipe)
60  -> CPP_broken_friend_ret(
61  closure<MetaFn, composed<Pipeable, fn<MetaFn>>>)(
62  requires (is_pipeable_v<Pipeable>))
63  {
64  return closure<MetaFn, composed<Pipeable, fn<MetaFn>>>{
65  compose(static_cast<Pipeable &&>(pipe), fn<MetaFn>{})};
66  }
67  };
68 
69  // A simple, light-weight transform iterator that applies ranges::to
70  // to each element in the range. Used by ranges::to to convert a range
71  // of ranges into a container of containers.
72  template<typename Rng, typename Cont>
73  struct to_container_iterator
74  {
75  private:
76  using I = range_cpp17_iterator_t<Rng>;
77  using ValueType = range_value_t<Cont>;
78  I it_;
79 
80  public:
81  using difference_type = typename std::iterator_traits<I>::difference_type;
82  using value_type = ValueType;
83  using reference = ValueType;
84  using pointer = typename std::iterator_traits<I>::pointer;
85  using iterator_category = typename std::iterator_traits<I>::iterator_category;
86 
87  to_container_iterator() = default;
88  template<typename OtherIt>
89  to_container_iterator(OtherIt it)
90  : it_(std::move(it))
91  {}
92  friend bool operator==(to_container_iterator const & a,
93  to_container_iterator const & b)
94  {
95  return a.it_ == b.it_;
96  }
97  friend bool operator!=(to_container_iterator const & a,
98  to_container_iterator const & b)
99  {
100  return !(a == b);
101  }
102  reference operator*() const
103  {
104  return to_container::fn<meta::id<ValueType>>{}(*it_);
105  }
106  to_container_iterator & operator++()
107  {
108  ++it_;
109  return *this;
110  }
111  to_container_iterator operator++(int)
112  {
113  auto tmp = *this;
114  ++it_;
115  return tmp;
116  }
117  CPP_member
118  auto operator--() //
119  -> CPP_ret(to_container_iterator &)(
120  requires derived_from<iterator_category,
121  std::bidirectional_iterator_tag>)
122  {
123  --it_;
124  return *this;
125  }
126  CPP_member
127  auto operator--(int) //
128  -> CPP_ret(to_container_iterator &)(
129  requires derived_from<iterator_category,
130  std::bidirectional_iterator_tag>)
131  {
132  auto tmp = *this;
133  ++it_;
134  return tmp;
135  }
136  CPP_member
137  auto operator+=(difference_type n) //
138  -> CPP_ret(to_container_iterator &)(
139  requires derived_from<iterator_category,
140  std::random_access_iterator_tag>)
141  {
142  it_ += n;
143  return *this;
144  }
145  CPP_member
146  auto operator-=(difference_type n) //
147  -> CPP_ret(to_container_iterator &)(
148  requires derived_from<iterator_category,
149  std::random_access_iterator_tag>)
150  {
151  it_ -= n;
152  return *this;
153  }
155  friend auto operator+(to_container_iterator i, difference_type n) //
156  -> CPP_broken_friend_ret(to_container_iterator)(
157  requires derived_from<iterator_category,
158  std::random_access_iterator_tag>)
159  {
160  return i += n;
161  }
163  friend auto operator-(to_container_iterator i, difference_type n) //
164  -> CPP_broken_friend_ret(to_container_iterator)(
165  requires derived_from<iterator_category,
166  std::random_access_iterator_tag>)
167  {
168  return i -= n;
169  }
171  friend auto operator-(difference_type n, to_container_iterator i) //
172  -> CPP_broken_friend_ret(to_container_iterator)(
173  requires derived_from<iterator_category,
174  std::random_access_iterator_tag>)
175  {
176  return i -= n;
177  }
179  friend auto operator-(to_container_iterator const & i,
180  to_container_iterator const & j) //
181  -> CPP_broken_friend_ret(difference_type)(
182  requires derived_from<iterator_category,
183  std::random_access_iterator_tag>)
184  {
185  return i.it_ - j.it_;
186  }
187  CPP_member
188  auto operator[](difference_type n) const //
189  -> CPP_ret(reference)(
190  requires derived_from<iterator_category,
191  std::random_access_iterator_tag>)
192  {
193  return *(*this + n);
194  }
195  };
196 
197  template<typename Rng, typename Cont>
198  using to_container_iterator_t =
199  enable_if_t<(bool)range<Rng>, to_container_iterator<Rng, Cont>>;
200 
201  // clang-format off
204  template(typename Rng)(
205  concept (range_and_not_view_)(Rng),
206  range<Rng> AND (!view_<Rng>));
207 
210  template<typename Rng>
211  CPP_concept range_and_not_view =
212  CPP_concept_ref(range_and_not_view_, Rng);
213 
216  template(typename Rng, typename Cont)(
217  concept (convertible_to_cont_impl_)(Rng, Cont),
218  constructible_from<range_value_t<Cont>, range_reference_t<Rng>> AND
219  constructible_from<
220  Cont,
221  range_cpp17_iterator_t<Rng>,
222  range_cpp17_iterator_t<Rng>>
223  );
226  template<typename Rng, typename Cont>
227  CPP_concept convertible_to_cont = //
228  range_and_not_view<Cont> && //
229  move_constructible<Cont> && //
230  CPP_concept_ref(detail::convertible_to_cont_impl_, Rng, Cont);
231 
234  template(typename Rng, typename Cont)(
235  concept (convertible_to_cont_cont_impl_)(Rng, Cont),
236  range_and_not_view<range_value_t<Cont>> AND
237  // Test that each element of the input range can be ranges::to<>
238  // to the output container.
239  invocable<
240  to_container::fn<meta::id<range_value_t<Cont>>>,
241  range_reference_t<Rng>> AND
242  constructible_from<
243  Cont,
244  to_container_iterator_t<Rng, Cont>,
245  to_container_iterator_t<Rng, Cont>>
246  );
249  template<typename Rng, typename Cont>
250  CPP_concept convertible_to_cont_cont = //
251  range<Cont> && //
252  (!view_<Cont>) && //
253  move_constructible<Cont> && //
254  CPP_concept_ref(detail::convertible_to_cont_cont_impl_, Rng, Cont);
255 
258  template<typename C, typename I, typename R>
259  CPP_concept to_container_reserve = //
260  reservable_with_assign<C, I> && //
261  sized_range<R>;
262 
263  template<typename MetaFn, typename Rng>
264  using container_t = meta::invoke<MetaFn, Rng>;
265  // clang-format on
266 
267  struct RANGES_STRUCT_WITH_ADL_BARRIER(to_container_closure_base)
268  {
269  // clang-format off
270  template(typename Rng, typename MetaFn, typename Fn)(
271  requires input_range<Rng> AND
272  convertible_to_cont<Rng, container_t<MetaFn, Rng>>)
273  friend constexpr auto
274  operator|(Rng && rng, to_container::closure<MetaFn, Fn> fn)
275  {
276  return static_cast<Fn &&>(fn)(static_cast<Rng &&>(rng));
277  }
278 
279  template(typename Rng, typename MetaFn, typename Fn)(
280  requires input_range<Rng> AND
281  (!convertible_to_cont<Rng, container_t<MetaFn, Rng>>) AND
282  convertible_to_cont_cont<Rng, container_t<MetaFn, Rng>>)
283  friend constexpr auto
284  operator|(Rng && rng, to_container::closure<MetaFn, Fn> fn)
285  {
286  return static_cast<Fn &&>(fn)(static_cast<Rng &&>(rng));
287  }
288 
289  template<typename MetaFn, typename Fn, typename Pipeable>
290  friend constexpr auto operator|(to_container::closure<MetaFn, Fn> sh,
291  Pipeable pipe)
292  -> CPP_broken_friend_ret(
293  to_container::closure<MetaFn, composed<Pipeable, Fn>>)(
294  requires is_pipeable_v<Pipeable>)
295  {
296  return to_container::closure<MetaFn, composed<Pipeable, Fn>>{
297  compose(static_cast<Pipeable &&>(pipe), static_cast<Fn &&>(sh))};
298  }
299  };
300 
301  template<typename MetaFn, typename Fn>
302  struct to_container::closure
303  : to_container_closure_base
304  , Fn
305  {
306  closure() = default;
307  constexpr explicit closure(Fn fn)
308  : Fn(static_cast<Fn &&>(fn))
309  {}
310  };
311 
312  template<typename MetaFn>
313  struct to_container::fn
314  {
315  private:
316  template<typename Cont, typename I, typename Rng>
317  static Cont impl(Rng && rng, std::false_type)
318  {
319  return Cont(I{ranges::begin(rng)}, I{ranges::end(rng)});
320  }
321  template<typename Cont, typename I, typename Rng>
322  static auto impl(Rng && rng, std::true_type)
323  {
324  Cont c;
325  auto const rng_size = ranges::size(rng);
326  using size_type = decltype(c.max_size());
327  using C = common_type_t<range_size_t<Rng>, size_type>;
328  RANGES_EXPECT(static_cast<C>(rng_size) <= static_cast<C>(c.max_size()));
329  c.reserve(static_cast<size_type>(rng_size));
330  c.assign(I{ranges::begin(rng)}, I{ranges::end(rng)});
331  return c;
332  }
333 
334  public:
335  template(typename Rng)(
336  requires input_range<Rng> AND
337  convertible_to_cont<Rng, container_t<MetaFn, Rng>>)
338  container_t<MetaFn, Rng> operator()(Rng && rng) const
339  {
340  static_assert(!is_infinite<Rng>::value,
341  "Attempt to convert an infinite range to a container.");
342  using cont_t = container_t<MetaFn, Rng>;
343  using iter_t = range_cpp17_iterator_t<Rng>;
344  using use_reserve_t =
345  meta::bool_<(bool)to_container_reserve<cont_t, iter_t, Rng>>;
346  return impl<cont_t, iter_t>(static_cast<Rng &&>(rng), use_reserve_t{});
347  }
348  template(typename Rng)(
349  requires input_range<Rng> AND
350  (!convertible_to_cont<Rng, container_t<MetaFn, Rng>>) AND
351  convertible_to_cont_cont<Rng, container_t<MetaFn, Rng>>)
352  container_t<MetaFn, Rng> operator()(Rng && rng) const
353  {
354  static_assert(!is_infinite<Rng>::value,
355  "Attempt to convert an infinite range to a container.");
356  using cont_t = container_t<MetaFn, Rng>;
357  using iter_t = to_container_iterator<Rng, cont_t>;
358  using use_reserve_t =
359  meta::bool_<(bool)to_container_reserve<cont_t, iter_t, Rng>>;
360  return impl<cont_t, iter_t>(static_cast<Rng &&>(rng), use_reserve_t{});
361  }
362  };
363 
364  template<typename MetaFn, typename Fn>
365  using to_container_closure = to_container::closure<MetaFn, Fn>;
366 
367  template<typename MetaFn>
368  using to_container_fn = to_container_closure<MetaFn, to_container::fn<MetaFn>>;
369 
370  template<template<typename...> class ContT>
371  struct from_range
372  {
373 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
374  // Attempt to use a deduction guide first...
375  template<typename Rng>
376  static auto from_rng_(int) //
377  -> decltype(ContT(range_cpp17_iterator_t<Rng>{},
378  range_cpp17_iterator_t<Rng>{}));
379  // No deduction guide. Fallback to instantiating with the
380  // iterator's value type.
381  template<typename Rng>
382  static auto from_rng_(long) //
383  -> meta::invoke<meta::quote<ContT>, range_value_t<Rng>>;
384 
385  template<typename Rng>
386  using invoke = decltype(from_range::from_rng_<Rng>(0));
387 #else
388  template<typename Rng>
389  using invoke = meta::invoke<meta::quote<ContT>, range_value_t<Rng>>;
390 #endif
391  };
392  } // namespace detail
394 
397 
399  RANGES_INLINE_VARIABLE(detail::to_container_fn<detail::from_range<std::vector>>,
400  to_vector)
401 
402 
403  namespace _to_
404  {
406 
409  template<template<typename...> class ContT>
410  auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {}))
411  -> detail::to_container_fn<detail::from_range<ContT>>
412  {
413  return {};
414  }
415 
417  template(template<typename...> class ContT, typename Rng, typename C = meta::invoke<detail::from_range<ContT>, Rng>)(
418  requires range<Rng> AND
419  detail::convertible_to_cont<Rng, C>)
420  auto to(Rng && rng) -> C
421  {
422  return detail::to_container_fn<detail::from_range<ContT>>{}(
423  static_cast<Rng &&>(rng));
424  }
425 
427  template<typename Cont>
428  auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {}))
429  -> detail::to_container_fn<meta::id<Cont>>
430  {
431  return {};
432  }
433 
435  template(typename Cont, typename Rng)(
436  requires range<Rng> AND detail::convertible_to_cont<Rng, Cont>)
437  auto to(Rng && rng) -> Cont
438  {
439  return detail::to_container_fn<meta::id<Cont>>{}(static_cast<Rng &&>(rng));
440  }
441 
443  template(typename Cont, typename Rng)(
444  requires input_range<Rng> AND
445  (!detail::convertible_to_cont<Rng, Cont>) AND
446  detail::convertible_to_cont_cont<Rng, Cont>)
447  auto to(Rng && rng) -> Cont
448  {
449  return detail::to_container_fn<meta::id<Cont>>{}(static_cast<Rng &&>(rng));
450  }
451 
453  // Slightly odd initializer_list overloads, undocumented for now.
454  template(template<typename...> class ContT, typename T)(
455  requires detail::convertible_to_cont<std::initializer_list<T>, ContT<T>>)
456  auto to(std::initializer_list<T> il) -> ContT<T>
457  {
458  return detail::to_container_fn<detail::from_range<ContT>>{}(il);
459  }
460  template(typename Cont, typename T)(
461  requires detail::convertible_to_cont<std::initializer_list<T>, Cont>)
462  auto to(std::initializer_list<T> il) -> Cont
463  {
464  return detail::to_container_fn<meta::id<Cont>>{}(il);
465  }
467 
469  } // namespace _to_
470  using namespace _to_;
473 
476  namespace _to_
477  {
478  // The old name "ranges::to_" is now deprecated:
479  template<template<typename...> class ContT>
480  RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
481  detail::to_container_fn<detail::from_range<ContT>> to_(detail::to_container = {})
482  {
483  return {};
484  }
485  template(template<typename...> class ContT, typename Rng)(
486  requires range<Rng> AND
487  detail::convertible_to_cont<Rng, ContT<range_value_t<Rng>>>)
488  RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
489  ContT<range_value_t<Rng>> to_(Rng && rng)
490  {
491  return static_cast<Rng &&>(rng) | ranges::to_<ContT>();
492  }
493  template(template<typename...> class ContT, typename T)(
494  requires detail::convertible_to_cont<std::initializer_list<T>, ContT<T>>)
495  RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
496  ContT<T> to_(std::initializer_list<T> il)
497  {
498  return il | ranges::to_<ContT>();
499  }
500  template<typename Cont>
501  RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
502  detail::to_container_fn<meta::id<Cont>> to_(detail::to_container = {})
503  {
504  return {};
505  }
506  template(typename Cont, typename Rng)(
507  requires range<Rng> AND detail::convertible_to_cont<Rng, Cont>)
508  RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
509  Cont to_(Rng && rng)
510  {
511  return static_cast<Rng &&>(rng) | ranges::to_<Cont>();
512  }
513  template(typename Cont, typename T)(
514  requires detail::convertible_to_cont<std::initializer_list<T>, Cont>)
515  RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
516  Cont to_(std::initializer_list<T> list)
517  {
518  return list | ranges::to_<Cont>();
519  }
520  } // namespace _to_
522 
523  template<typename MetaFn, typename Fn>
524  RANGES_INLINE_VAR constexpr bool
525  is_pipeable_v<detail::to_container_closure<MetaFn, Fn>> = true;
526 } // namespace ranges
527 
528 #include <range/v3/detail/epilogue.hpp>
529 
530 #endif
#define CPP_broken_friend_member
INTERNAL ONLY.
Definition: concepts.hpp:447
CPP_concept derived_from
\concept derived_from
Definition: concepts.hpp:904
CPP_concept invocable
\concept invocable
Definition: concepts.hpp:48
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
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
meta::size_t< L::size()> size
An integral constant wrapper that is the size of the meta::list L.
Definition: meta.hpp:1696
Tiny meta-programming library.
Tiny metaprogramming library.
Definition: meta.hpp:116
Point operator*(double s, const Point &a)
Multiply point by scalar.
Definition: shapes.h:250
Point operator-(const Point &a, const Point &b)
Subtract two points_ component-wise.
Definition: shapes.h:244
A trait that always returns its argument T.
Definition: meta.hpp:558