xref: /freebsd/contrib/llvm-project/libcxx/include/__ranges/transform_view.h (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___RANGES_TRANSFORM_VIEW_H
10 #define _LIBCPP___RANGES_TRANSFORM_VIEW_H
11 
12 #include <__compare/three_way_comparable.h>
13 #include <__concepts/constructible.h>
14 #include <__concepts/convertible_to.h>
15 #include <__concepts/copyable.h>
16 #include <__concepts/derived_from.h>
17 #include <__concepts/equality_comparable.h>
18 #include <__concepts/invocable.h>
19 #include <__config>
20 #include <__functional/bind_back.h>
21 #include <__functional/invoke.h>
22 #include <__iterator/concepts.h>
23 #include <__iterator/iterator_traits.h>
24 #include <__memory/addressof.h>
25 #include <__ranges/access.h>
26 #include <__ranges/all.h>
27 #include <__ranges/concepts.h>
28 #include <__ranges/copyable_box.h>
29 #include <__ranges/empty.h>
30 #include <__ranges/range_adaptor.h>
31 #include <__ranges/size.h>
32 #include <__ranges/view_interface.h>
33 #include <__utility/forward.h>
34 #include <__utility/in_place.h>
35 #include <__utility/move.h>
36 #include <type_traits>
37 
38 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
39 #  pragma GCC system_header
40 #endif
41 
42 _LIBCPP_BEGIN_NAMESPACE_STD
43 
44 #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
45 
46 namespace ranges {
47 
48 template<class _Fn, class _View>
49 concept __regular_invocable_with_range_ref =
50   regular_invocable<_Fn, range_reference_t<_View>>;
51 
52 template<class _View, class _Fn>
53 concept __transform_view_constraints =
54   view<_View> && is_object_v<_Fn> &&
55   regular_invocable<_Fn&, range_reference_t<_View>> &&
56   __can_reference<invoke_result_t<_Fn&, range_reference_t<_View>>>;
57 
58 template<input_range _View, copy_constructible _Fn>
59   requires __transform_view_constraints<_View, _Fn>
60 class transform_view : public view_interface<transform_view<_View, _Fn>> {
61   template<bool> class __iterator;
62   template<bool> class __sentinel;
63 
64   _LIBCPP_NO_UNIQUE_ADDRESS __copyable_box<_Fn> __func_;
65   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
66 
67 public:
68   _LIBCPP_HIDE_FROM_ABI
69   transform_view()
70     requires default_initializable<_View> && default_initializable<_Fn> = default;
71 
72   _LIBCPP_HIDE_FROM_ABI
73   constexpr transform_view(_View __base, _Fn __func)
74     : __func_(std::in_place, std::move(__func)), __base_(std::move(__base)) {}
75 
76   _LIBCPP_HIDE_FROM_ABI
77   constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
78   _LIBCPP_HIDE_FROM_ABI
79   constexpr _View base() && { return std::move(__base_); }
80 
81   _LIBCPP_HIDE_FROM_ABI
82   constexpr __iterator<false> begin() {
83     return __iterator<false>{*this, ranges::begin(__base_)};
84   }
85   _LIBCPP_HIDE_FROM_ABI
86   constexpr __iterator<true> begin() const
87     requires range<const _View> &&
88              __regular_invocable_with_range_ref<const _Fn&, const _View>
89   {
90     return __iterator<true>(*this, ranges::begin(__base_));
91   }
92 
93   _LIBCPP_HIDE_FROM_ABI
94   constexpr __sentinel<false> end() {
95     return __sentinel<false>(ranges::end(__base_));
96   }
97   _LIBCPP_HIDE_FROM_ABI
98   constexpr __iterator<false> end()
99     requires common_range<_View>
100   {
101     return __iterator<false>(*this, ranges::end(__base_));
102   }
103   _LIBCPP_HIDE_FROM_ABI
104   constexpr __sentinel<true> end() const
105     requires range<const _View> &&
106              __regular_invocable_with_range_ref<const _Fn&, const _View>
107   {
108     return __sentinel<true>(ranges::end(__base_));
109   }
110   _LIBCPP_HIDE_FROM_ABI
111   constexpr __iterator<true> end() const
112     requires common_range<const _View> &&
113              __regular_invocable_with_range_ref<const _Fn&, const _View>
114   {
115     return __iterator<true>(*this, ranges::end(__base_));
116   }
117 
118   _LIBCPP_HIDE_FROM_ABI
119   constexpr auto size() requires sized_range<_View> { return ranges::size(__base_); }
120   _LIBCPP_HIDE_FROM_ABI
121   constexpr auto size() const requires sized_range<const _View> { return ranges::size(__base_); }
122 };
123 
124 template<class _Range, class _Fn>
125 transform_view(_Range&&, _Fn) -> transform_view<views::all_t<_Range>, _Fn>;
126 
127 template<class _View>
128 struct __transform_view_iterator_concept { using type = input_iterator_tag; };
129 
130 template<random_access_range _View>
131 struct __transform_view_iterator_concept<_View> { using type = random_access_iterator_tag; };
132 
133 template<bidirectional_range _View>
134 struct __transform_view_iterator_concept<_View> { using type = bidirectional_iterator_tag; };
135 
136 template<forward_range _View>
137 struct __transform_view_iterator_concept<_View> { using type = forward_iterator_tag; };
138 
139 template<class, class>
140 struct __transform_view_iterator_category_base {};
141 
142 template<forward_range _View, class _Fn>
143 struct __transform_view_iterator_category_base<_View, _Fn> {
144   using _Cat = typename iterator_traits<iterator_t<_View>>::iterator_category;
145 
146   using iterator_category = conditional_t<
147     is_lvalue_reference_v<invoke_result_t<_Fn&, range_reference_t<_View>>>,
148     conditional_t<
149       derived_from<_Cat, contiguous_iterator_tag>,
150       random_access_iterator_tag,
151       _Cat
152     >,
153     input_iterator_tag
154   >;
155 };
156 
157 template<input_range _View, copy_constructible _Fn>
158   requires __transform_view_constraints<_View, _Fn>
159 template<bool _Const>
160 class transform_view<_View, _Fn>::__iterator
161   : public __transform_view_iterator_category_base<_View, _Fn> {
162 
163   using _Parent = __maybe_const<_Const, transform_view>;
164   using _Base = __maybe_const<_Const, _View>;
165 
166   _Parent *__parent_ = nullptr;
167 
168   template<bool>
169   friend class transform_view<_View, _Fn>::__iterator;
170 
171   template<bool>
172   friend class transform_view<_View, _Fn>::__sentinel;
173 
174 public:
175   iterator_t<_Base> __current_ = iterator_t<_Base>();
176 
177   using iterator_concept = typename __transform_view_iterator_concept<_View>::type;
178   using value_type = remove_cvref_t<invoke_result_t<_Fn&, range_reference_t<_Base>>>;
179   using difference_type = range_difference_t<_Base>;
180 
181   _LIBCPP_HIDE_FROM_ABI
182   __iterator() requires default_initializable<iterator_t<_Base>> = default;
183 
184   _LIBCPP_HIDE_FROM_ABI
185   constexpr __iterator(_Parent& __parent, iterator_t<_Base> __current)
186     : __parent_(std::addressof(__parent)), __current_(std::move(__current)) {}
187 
188   // Note: `__i` should always be `__iterator<false>`, but directly using
189   // `__iterator<false>` is ill-formed when `_Const` is false
190   // (see http://wg21.link/class.copy.ctor#5).
191   _LIBCPP_HIDE_FROM_ABI
192   constexpr __iterator(__iterator<!_Const> __i)
193     requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
194     : __parent_(__i.__parent_), __current_(std::move(__i.__current_)) {}
195 
196   _LIBCPP_HIDE_FROM_ABI
197   constexpr const iterator_t<_Base>& base() const& noexcept {
198     return __current_;
199   }
200 
201   _LIBCPP_HIDE_FROM_ABI
202   constexpr iterator_t<_Base> base() && {
203     return std::move(__current_);
204   }
205 
206   _LIBCPP_HIDE_FROM_ABI
207   constexpr decltype(auto) operator*() const
208     noexcept(noexcept(std::invoke(*__parent_->__func_, *__current_)))
209   {
210     return std::invoke(*__parent_->__func_, *__current_);
211   }
212 
213   _LIBCPP_HIDE_FROM_ABI
214   constexpr __iterator& operator++() {
215     ++__current_;
216     return *this;
217   }
218 
219   _LIBCPP_HIDE_FROM_ABI
220   constexpr void operator++(int) { ++__current_; }
221 
222   _LIBCPP_HIDE_FROM_ABI
223   constexpr __iterator operator++(int)
224     requires forward_range<_Base>
225   {
226     auto __tmp = *this;
227     ++*this;
228     return __tmp;
229   }
230 
231   _LIBCPP_HIDE_FROM_ABI
232   constexpr __iterator& operator--()
233     requires bidirectional_range<_Base>
234   {
235     --__current_;
236     return *this;
237   }
238 
239   _LIBCPP_HIDE_FROM_ABI
240   constexpr __iterator operator--(int)
241     requires bidirectional_range<_Base>
242   {
243     auto __tmp = *this;
244     --*this;
245     return __tmp;
246   }
247 
248   _LIBCPP_HIDE_FROM_ABI
249   constexpr __iterator& operator+=(difference_type __n)
250     requires random_access_range<_Base>
251   {
252     __current_ += __n;
253     return *this;
254   }
255 
256   _LIBCPP_HIDE_FROM_ABI
257   constexpr __iterator& operator-=(difference_type __n)
258     requires random_access_range<_Base>
259   {
260     __current_ -= __n;
261     return *this;
262   }
263 
264   _LIBCPP_HIDE_FROM_ABI
265   constexpr decltype(auto) operator[](difference_type __n) const
266     noexcept(noexcept(std::invoke(*__parent_->__func_, __current_[__n])))
267     requires random_access_range<_Base>
268   {
269     return std::invoke(*__parent_->__func_, __current_[__n]);
270   }
271 
272   _LIBCPP_HIDE_FROM_ABI
273   friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
274     requires equality_comparable<iterator_t<_Base>>
275   {
276     return __x.__current_ == __y.__current_;
277   }
278 
279   _LIBCPP_HIDE_FROM_ABI
280   friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
281     requires random_access_range<_Base>
282   {
283     return __x.__current_ < __y.__current_;
284   }
285 
286   _LIBCPP_HIDE_FROM_ABI
287   friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
288     requires random_access_range<_Base>
289   {
290     return __x.__current_ > __y.__current_;
291   }
292 
293   _LIBCPP_HIDE_FROM_ABI
294   friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
295     requires random_access_range<_Base>
296   {
297     return __x.__current_ <= __y.__current_;
298   }
299 
300   _LIBCPP_HIDE_FROM_ABI
301   friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
302     requires random_access_range<_Base>
303   {
304     return __x.__current_ >= __y.__current_;
305   }
306 
307   _LIBCPP_HIDE_FROM_ABI
308   friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
309     requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
310   {
311     return __x.__current_ <=> __y.__current_;
312   }
313 
314   _LIBCPP_HIDE_FROM_ABI
315   friend constexpr __iterator operator+(__iterator __i, difference_type __n)
316     requires random_access_range<_Base>
317   {
318     return __iterator{*__i.__parent_, __i.__current_ + __n};
319   }
320 
321   _LIBCPP_HIDE_FROM_ABI
322   friend constexpr __iterator operator+(difference_type __n, __iterator __i)
323     requires random_access_range<_Base>
324   {
325     return __iterator{*__i.__parent_, __i.__current_ + __n};
326   }
327 
328   _LIBCPP_HIDE_FROM_ABI
329   friend constexpr __iterator operator-(__iterator __i, difference_type __n)
330     requires random_access_range<_Base>
331   {
332     return __iterator{*__i.__parent_, __i.__current_ - __n};
333   }
334 
335   _LIBCPP_HIDE_FROM_ABI
336   friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y)
337     requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
338   {
339     return __x.__current_ - __y.__current_;
340   }
341 
342   _LIBCPP_HIDE_FROM_ABI
343   friend constexpr decltype(auto) iter_move(const __iterator& __i)
344     noexcept(noexcept(*__i))
345   {
346     if constexpr (is_lvalue_reference_v<decltype(*__i)>)
347       return std::move(*__i);
348     else
349       return *__i;
350   }
351 };
352 
353 template<input_range _View, copy_constructible _Fn>
354   requires __transform_view_constraints<_View, _Fn>
355 template<bool _Const>
356 class transform_view<_View, _Fn>::__sentinel {
357   using _Parent = __maybe_const<_Const, transform_view>;
358   using _Base = __maybe_const<_Const, _View>;
359 
360   sentinel_t<_Base> __end_ = sentinel_t<_Base>();
361 
362   template<bool>
363   friend class transform_view<_View, _Fn>::__iterator;
364 
365   template<bool>
366   friend class transform_view<_View, _Fn>::__sentinel;
367 
368 public:
369   _LIBCPP_HIDE_FROM_ABI
370   __sentinel() = default;
371 
372   _LIBCPP_HIDE_FROM_ABI
373   constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(__end) {}
374 
375   // Note: `__i` should always be `__sentinel<false>`, but directly using
376   // `__sentinel<false>` is ill-formed when `_Const` is false
377   // (see http://wg21.link/class.copy.ctor#5).
378   _LIBCPP_HIDE_FROM_ABI
379   constexpr __sentinel(__sentinel<!_Const> __i)
380     requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
381     : __end_(std::move(__i.__end_)) {}
382 
383   _LIBCPP_HIDE_FROM_ABI
384   constexpr sentinel_t<_Base> base() const { return __end_; }
385 
386   template<bool _OtherConst>
387     requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
388   _LIBCPP_HIDE_FROM_ABI
389   friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
390     return __x.__current_ == __y.__end_;
391   }
392 
393   template<bool _OtherConst>
394     requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
395   _LIBCPP_HIDE_FROM_ABI
396   friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
397   operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
398     return __x.__current_ - __y.__end_;
399   }
400 
401   template<bool _OtherConst>
402     requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
403   _LIBCPP_HIDE_FROM_ABI
404   friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
405   operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
406     return __x.__end_ - __y.__current_;
407   }
408 };
409 
410 namespace views {
411 namespace __transform {
412   struct __fn {
413     template<class _Range, class _Fn>
414     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
415     constexpr auto operator()(_Range&& __range, _Fn&& __f) const
416       noexcept(noexcept(transform_view(std::forward<_Range>(__range), std::forward<_Fn>(__f))))
417       -> decltype(      transform_view(std::forward<_Range>(__range), std::forward<_Fn>(__f)))
418       { return          transform_view(std::forward<_Range>(__range), std::forward<_Fn>(__f)); }
419 
420     template<class _Fn>
421       requires constructible_from<decay_t<_Fn>, _Fn>
422     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
423     constexpr auto operator()(_Fn&& __f) const
424       noexcept(is_nothrow_constructible_v<decay_t<_Fn>, _Fn>)
425     { return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Fn>(__f))); }
426   };
427 } // namespace __transform
428 
429 inline namespace __cpo {
430   inline constexpr auto transform = __transform::__fn{};
431 } // namespace __cpo
432 } // namespace views
433 
434 } // namespace ranges
435 
436 #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
437 
438 _LIBCPP_END_NAMESPACE_STD
439 
440 #endif // _LIBCPP___RANGES_TRANSFORM_VIEW_H
441