1 /// \file
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_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 
23 #include <range/v3/action/concepts.hpp>
24 #include <range/v3/functional/pipeable.hpp>
25 #include <range/v3/iterator/common_iterator.hpp>
26 #include <range/v3/range/concepts.hpp>
27 #include <range/v3/range/traits.hpp>
28 #include <range/v3/utility/static_const.hpp>
29 
30 #include <range/v3/detail/prologue.hpp>
31 
32 namespace ranges
33 {
34     /// \cond
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>
operator |(Rng && rng,closure<MetaFn,fn<MetaFn>> (*)(to_container))49             friend auto operator|(Rng && rng,
50                                   closure<MetaFn, fn<MetaFn>> (*)(to_container))
51                 -> CPP_broken_friend_ret(container_t<MetaFn, Rng>)(
52                     /// \pre
53                     requires invocable<fn<MetaFn>, Rng>)
54             {
55                 return fn<MetaFn>{}(static_cast<Rng &&>(rng));
56             }
57 
58             template<typename MetaFn, typename Pipeable>
operator |(closure<MetaFn,fn<MetaFn>> (*)(to_container),Pipeable pipe)59             friend auto operator|(closure<MetaFn, fn<MetaFn>> (*)(to_container),
60                                   Pipeable pipe)
61                 -> CPP_broken_friend_ret(
62                     closure<MetaFn, composed<Pipeable, fn<MetaFn>>>)(
63                     /// \pre
64                     requires (is_pipeable_v<Pipeable>))
65             {
66                 return closure<MetaFn, composed<Pipeable, fn<MetaFn>>>{
67                     compose(static_cast<Pipeable &&>(pipe), fn<MetaFn>{})};
68             }
69         };
70 
71         // A simple, light-weight transform iterator that applies ranges::to
72         // to each element in the range. Used by ranges::to to convert a range
73         // of ranges into a container of containers.
74         template<typename Rng, typename Cont>
75         struct to_container_iterator
76         {
77         private:
78             using I = range_cpp17_iterator_t<Rng>;
79             using ValueType = range_value_t<Cont>;
80             I it_;
81 
82         public:
83             using difference_type = typename std::iterator_traits<I>::difference_type;
84             using value_type = ValueType;
85             using reference = ValueType;
86             using pointer = typename std::iterator_traits<I>::pointer;
87             using iterator_category = typename std::iterator_traits<I>::iterator_category;
88 
89             to_container_iterator() = default;
90             template<typename OtherIt>
to_container_iteratorranges::detail::to_container_iterator91             to_container_iterator(OtherIt it)
92               : it_(std::move(it))
93             {}
operator ==(to_container_iterator const & a,to_container_iterator const & b)94             friend bool operator==(to_container_iterator const & a,
95                                    to_container_iterator const & b)
96             {
97                 return a.it_ == b.it_;
98             }
operator !=(to_container_iterator const & a,to_container_iterator const & b)99             friend bool operator!=(to_container_iterator const & a,
100                                    to_container_iterator const & b)
101             {
102                 return !(a == b);
103             }
operator *ranges::detail::to_container_iterator104             reference operator*() const
105             {
106                 return to_container::fn<meta::id<ValueType>>{}(*it_);
107             }
operator ++ranges::detail::to_container_iterator108             to_container_iterator & operator++()
109             {
110                 ++it_;
111                 return *this;
112             }
operator ++ranges::detail::to_container_iterator113             to_container_iterator operator++(int)
114             {
115                 auto tmp = *this;
116                 ++it_;
117                 return tmp;
118             }
119             CPP_member
operator --ranges::detail::to_container_iterator120             auto operator--() //
121                 -> CPP_ret(to_container_iterator &)(
122                     /// \pre
123                     requires derived_from<iterator_category,
124                                           std::bidirectional_iterator_tag>)
125             {
126                 --it_;
127                 return *this;
128             }
129             CPP_member
operator --ranges::detail::to_container_iterator130             auto operator--(int) //
131                 -> CPP_ret(to_container_iterator &)(
132                     /// \pre
133                     requires derived_from<iterator_category,
134                                           std::bidirectional_iterator_tag>)
135             {
136                 auto tmp = *this;
137                 ++it_;
138                 return tmp;
139             }
140             CPP_member
operator +=ranges::detail::to_container_iterator141             auto operator+=(difference_type n) //
142                 -> CPP_ret(to_container_iterator &)(
143                     /// \pre
144                     requires derived_from<iterator_category,
145                                           std::random_access_iterator_tag>)
146             {
147                 it_ += n;
148                 return *this;
149             }
150             CPP_member
operator -=ranges::detail::to_container_iterator151             auto operator-=(difference_type n) //
152                 -> CPP_ret(to_container_iterator &)(
153                     /// \pre
154                     requires derived_from<iterator_category,
155                                           std::random_access_iterator_tag>)
156             {
157                 it_ -= n;
158                 return *this;
159             }
160             CPP_broken_friend_member
operator +(to_container_iterator i,difference_type n)161             friend auto operator+(to_container_iterator i, difference_type n) //
162                 -> CPP_broken_friend_ret(to_container_iterator)(
163                     /// \pre
164                     requires derived_from<iterator_category,
165                                           std::random_access_iterator_tag>)
166             {
167                 return i += n;
168             }
169             CPP_broken_friend_member
operator -(to_container_iterator i,difference_type n)170             friend auto operator-(to_container_iterator i, difference_type n) //
171                 -> CPP_broken_friend_ret(to_container_iterator)(
172                     /// \pre
173                     requires derived_from<iterator_category,
174                                           std::random_access_iterator_tag>)
175             {
176                 return i -= n;
177             }
178             CPP_broken_friend_member
operator -(difference_type n,to_container_iterator i)179             friend auto operator-(difference_type n, to_container_iterator i) //
180                 -> CPP_broken_friend_ret(to_container_iterator)(
181                     /// \pre
182                     requires derived_from<iterator_category,
183                                           std::random_access_iterator_tag>)
184             {
185                 return i -= n;
186             }
187             CPP_broken_friend_member
operator -(to_container_iterator const & i,to_container_iterator const & j)188             friend auto operator-(to_container_iterator const & i,
189                                   to_container_iterator const & j) //
190                 -> CPP_broken_friend_ret(difference_type)(
191                     /// \pre
192                     requires derived_from<iterator_category,
193                                           std::random_access_iterator_tag>)
194             {
195                 return i.it_ - j.it_;
196             }
197             CPP_member
operator []ranges::detail::to_container_iterator198             auto operator[](difference_type n) const //
199                 -> CPP_ret(reference)(
200                     /// \pre
201                     requires derived_from<iterator_category,
202                                           std::random_access_iterator_tag>)
203             {
204                 return *(*this + n);
205             }
206         };
207 
208         template<typename Rng, typename Cont>
209         using to_container_iterator_t =
210             enable_if_t<(bool)range<Rng>, to_container_iterator<Rng, Cont>>;
211 
212         // clang-format off
213         template(typename Rng)(
214         concept (range_and_not_view_)(Rng),
215             range<Rng> AND (!view_<Rng>));
216 
217         template<typename Rng>
218         CPP_concept range_and_not_view =
219             CPP_concept_ref(range_and_not_view_, Rng);
220 
221         template(typename Rng, typename Cont)(
222         concept (convertible_to_cont_impl_)(Rng, Cont),
223             constructible_from<range_value_t<Cont>, range_reference_t<Rng>> AND
224             constructible_from<
225                 Cont,
226                 range_cpp17_iterator_t<Rng>,
227                 range_cpp17_iterator_t<Rng>>
228         );
229         template<typename Rng, typename Cont>
230         CPP_concept convertible_to_cont = //
231             range_and_not_view<Cont> && //
232             move_constructible<Cont> && //
233             CPP_concept_ref(detail::convertible_to_cont_impl_, Rng, Cont);
234 
235         template(typename Rng, typename Cont)(
236         concept (convertible_to_cont_cont_impl_)(Rng, Cont),
237             range_and_not_view<range_value_t<Cont>> AND
238             // Test that each element of the input range can be ranges::to<>
239             // to the output container.
240             invocable<
241                 to_container::fn<meta::id<range_value_t<Cont>>>,
242                 range_reference_t<Rng>> AND
243             constructible_from<
244                 Cont,
245                 to_container_iterator_t<Rng, Cont>,
246                 to_container_iterator_t<Rng, Cont>>
247         );
248         template<typename Rng, typename Cont>
249         CPP_concept convertible_to_cont_cont = //
250             range<Cont> && //
251             (!view_<Cont>) && //
252             move_constructible<Cont> && //
253             CPP_concept_ref(detail::convertible_to_cont_cont_impl_, Rng, Cont);
254 
255         template<typename C, typename I, typename R>
256         CPP_concept to_container_reserve = //
257             reservable_with_assign<C, I> && //
258             sized_range<R>;
259 
260         template<typename MetaFn, typename Rng>
261         using container_t = meta::invoke<MetaFn, Rng>;
262         // clang-format on
263 
RANGES_STRUCT_WITH_ADL_BARRIER(to_container_closure_base)264         struct RANGES_STRUCT_WITH_ADL_BARRIER(to_container_closure_base)
265         {
266             // clang-format off
267             template(typename Rng, typename MetaFn, typename Fn)(
268                 /// \pre
269                 requires input_range<Rng> AND
270                     convertible_to_cont<Rng, container_t<MetaFn, Rng>>)
271             friend constexpr auto
272             operator|(Rng && rng, to_container::closure<MetaFn, Fn> fn)
273             {
274                 return static_cast<Fn &&>(fn)(static_cast<Rng &&>(rng));
275             }
276 
277             template(typename Rng, typename MetaFn, typename Fn)(
278                 /// \pre
279                 requires input_range<Rng> AND
280                     (!convertible_to_cont<Rng, container_t<MetaFn, Rng>>) AND
281                     convertible_to_cont_cont<Rng, container_t<MetaFn, Rng>>)
282             friend constexpr auto
283             operator|(Rng && rng, to_container::closure<MetaFn, Fn> fn)
284             {
285                 return static_cast<Fn &&>(fn)(static_cast<Rng &&>(rng));
286             }
287 
288             template<typename MetaFn, typename Fn, typename Pipeable>
289             friend constexpr auto operator|(to_container::closure<MetaFn, Fn> sh,
290                                             Pipeable pipe)
291                 -> CPP_broken_friend_ret(
292                     to_container::closure<MetaFn, composed<Pipeable, Fn>>)(
293                     /// \pre
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;
closureranges::detail::to_container::closure307             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>
implranges::detail::to_container::fn317             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>
implranges::detail::to_container::fn322             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                 /// \pre
337                 requires input_range<Rng> AND
338                     convertible_to_cont<Rng, container_t<MetaFn, Rng>>)
operator ()ranges::detail::to_container::fn339             container_t<MetaFn, Rng> operator()(Rng && rng) const
340             {
341                 static_assert(!is_infinite<Rng>::value,
342                               "Attempt to convert an infinite range to a container.");
343                 using cont_t = container_t<MetaFn, Rng>;
344                 using iter_t = range_cpp17_iterator_t<Rng>;
345                 using use_reserve_t =
346                     meta::bool_<(bool)to_container_reserve<cont_t, iter_t, Rng>>;
347                 return impl<cont_t, iter_t>(static_cast<Rng &&>(rng), use_reserve_t{});
348             }
349             template(typename Rng)(
350                 /// \pre
351                 requires input_range<Rng> AND
352                     (!convertible_to_cont<Rng, container_t<MetaFn, Rng>>) AND
353                     convertible_to_cont_cont<Rng, container_t<MetaFn, Rng>>)
operator ()ranges::detail::to_container::fn354             container_t<MetaFn, Rng> operator()(Rng && rng) const
355             {
356                 static_assert(!is_infinite<Rng>::value,
357                               "Attempt to convert an infinite range to a container.");
358                 using cont_t = container_t<MetaFn, Rng>;
359                 using iter_t = to_container_iterator<Rng, cont_t>;
360                 using use_reserve_t =
361                     meta::bool_<(bool)to_container_reserve<cont_t, iter_t, Rng>>;
362                 return impl<cont_t, iter_t>(static_cast<Rng &&>(rng), use_reserve_t{});
363             }
364         };
365 
366         template<typename MetaFn, typename Fn>
367         using to_container_closure = to_container::closure<MetaFn, Fn>;
368 
369         template<typename MetaFn>
370         using to_container_fn = to_container_closure<MetaFn, to_container::fn<MetaFn>>;
371 
372         template<template<typename...> class ContT>
373         struct from_range
374         {
375 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
376             // Attempt to use a deduction guide first...
377             template<typename Rng>
378             static auto from_rng_(int) //
379                 -> decltype(ContT(range_cpp17_iterator_t<Rng>{},
380                                   range_cpp17_iterator_t<Rng>{}));
381             // No deduction guide. Fallback to instantiating with the
382             // iterator's value type.
383             template<typename Rng>
384             static auto from_rng_(long) //
385                 -> meta::invoke<meta::quote<ContT>, range_value_t<Rng>>;
386 
387             template<typename Rng>
388             using invoke = decltype(from_range::from_rng_<Rng>(0));
389 #else
390             template<typename Rng>
391             using invoke = meta::invoke<meta::quote<ContT>, range_value_t<Rng>>;
392 #endif
393         };
394     } // namespace detail
395     /// \endcond
396 
397     /// \addtogroup group-range
398     /// @{
399 
400     /// \ingroup group-range
401     RANGES_INLINE_VARIABLE(detail::to_container_fn<detail::from_range<std::vector>>,
402                            to_vector)
403 
404     /// \cond
405     namespace _to_
406     {
407         /// \endcond
408 
409         /// \brief For initializing a container of the specified type with the elements of
410         /// an Range
411         template<template<typename...> class ContT>
to(RANGES_HIDDEN_DETAIL (detail::to_container={}))412         auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {}))
413             -> detail::to_container_fn<detail::from_range<ContT>>
414         {
415             return {};
416         }
417 
418         /// \overload
419         template(template<typename...> class ContT, typename Rng)(
420             /// \pre
421             requires range<Rng> AND
422                 detail::convertible_to_cont<Rng, ContT<range_value_t<Rng>>>)
to(Rng && rng)423         auto to(Rng && rng) -> ContT<range_value_t<Rng>>
424         {
425             return detail::to_container_fn<detail::from_range<ContT>>{}(
426                 static_cast<Rng &&>(rng));
427         }
428 
429         /// \overload
430         template<typename Cont>
to(RANGES_HIDDEN_DETAIL (detail::to_container={}))431         auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {}))
432             -> detail::to_container_fn<meta::id<Cont>>
433         {
434             return {};
435         }
436 
437         /// \overload
438         template(typename Cont, typename Rng)(
439             /// \pre
440             requires range<Rng> AND detail::convertible_to_cont<Rng, Cont>)
to(Rng && rng)441         auto to(Rng && rng) -> Cont
442         {
443             return detail::to_container_fn<meta::id<Cont>>{}(static_cast<Rng &&>(rng));
444         }
445 
446         /// \cond
447         // Slightly odd initializer_list overloads, undocumented for now.
448         template(template<typename...> class ContT, typename T)(
449             /// \pre
450             requires detail::convertible_to_cont<std::initializer_list<T>, ContT<T>>)
451         auto to(std::initializer_list<T> il) -> ContT<T>
452         {
453             return detail::to_container_fn<detail::from_range<ContT>>{}(il);
454         }
455         template(typename Cont, typename T)(
456             /// \pre
457             requires detail::convertible_to_cont<std::initializer_list<T>, Cont>)
458         auto to(std::initializer_list<T> il) -> Cont
459         {
460             return detail::to_container_fn<meta::id<Cont>>{}(il);
461         }
462         /// \endcond
463 
464         /// \cond
465     } // namespace _to_
466     using namespace _to_;
467     /// \endcond
468     /// @}
469 
470     ////////////////////////////////////////////////////////////////////////////
471     /// \cond
472     namespace _to_
473     {
474         // The old name "ranges::to_" is now deprecated:
475         template<template<typename...> class ContT>
476         RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
477         detail::to_container_fn<detail::from_range<ContT>> to_(detail::to_container = {})
478         {
479             return {};
480         }
481         template(template<typename...> class ContT, typename Rng)(
482             /// \pre
483             requires range<Rng> AND
484                 detail::convertible_to_cont<Rng, ContT<range_value_t<Rng>>>)
485         RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
486         ContT<range_value_t<Rng>> to_(Rng && rng)
487         {
488             return static_cast<Rng &&>(rng) | ranges::to_<ContT>();
489         }
490         template(template<typename...> class ContT, typename T)(
491             /// \pre
492             requires detail::convertible_to_cont<std::initializer_list<T>, ContT<T>>)
493         RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
494         ContT<T> to_(std::initializer_list<T> il)
495         {
496             return il | ranges::to_<ContT>();
497         }
498         template<typename Cont>
499         RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
500         detail::to_container_fn<meta::id<Cont>> to_(detail::to_container = {})
501         {
502             return {};
503         }
504         template(typename Cont, typename Rng)(
505             /// \pre
506             requires range<Rng> AND detail::convertible_to_cont<Rng, Cont>)
507         RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
508         Cont to_(Rng && rng)
509         {
510             return static_cast<Rng &&>(rng) | ranges::to_<Cont>();
511         }
512         template(typename Cont, typename T)(
513             /// \pre
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_
521     /// \endcond
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
531