Horizon
Loading...
Searching...
No Matches
conversion.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_RANGE_CONVERSION_HPP
15#define RANGES_V3_RANGE_CONVERSION_HPP
16
17#include <vector>
18
19#include <meta/meta.hpp>
20
22
28#include <range/v3/utility/static_const.hpp>
29
30#include <range/v3/detail/prologue.hpp>
31
32namespace 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
The input_range concept.
The range concept.
#define CPP_broken_friend_member
INTERNAL ONLY.
Definition concepts.hpp:447
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
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