Horizon
Loading...
Searching...
No Matches
transform.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_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
24
36#include <range/v3/utility/static_const.hpp>
38#include <range/v3/view/all.hpp>
40
41#include <range/v3/detail/prologue.hpp>
42
43namespace 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)(
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)(
325 {
326 --it1_;
327 --it2_;
328 }
329 CPP_member
330 auto advance(difference_type n) -> CPP_ret(void)(
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)(
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<
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
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)(
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)(
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
491 RANGES_INLINE_VARIABLE(iter_transform_fn, iter_transform)
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 =
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 =
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)(
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)(
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
594 RANGES_INLINE_VARIABLE(transform_fn, transform)
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>
615RANGES_SATISFY_BOOST_RANGE(::ranges::iter_transform_view)
616RANGES_SATISFY_BOOST_RANGE(::ranges::transform_view)
617
618#endif
The bidirectional_range concept.
The common_range concept.
The forward_range concept.
The input_range concept.
The random_access_range concept.
The range concept.
The regular_invocable concept.
The sized_range concept.
The sized_sentinel_for concept.
The viewable_range concept.
The transformable_range_ concept.
The transformable_range concept.
The transformable_ranges_ concept.
The transformable_ranges concept.
decltype(begin(declval(Rng &))) iterator_t
Definition access.hpp:698
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
_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.
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