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 | |
10 | #ifndef _LIBCPP___RANGES_TAKE_VIEW_H |
11 | #define _LIBCPP___RANGES_TAKE_VIEW_H |
12 | |
13 | #include <__algorithm/min.h> |
14 | #include <__algorithm/ranges_min.h> |
15 | #include <__assert> |
16 | #include <__concepts/constructible.h> |
17 | #include <__concepts/convertible_to.h> |
18 | #include <__config> |
19 | #include <__functional/bind_back.h> |
20 | #include <__fwd/span.h> |
21 | #include <__fwd/string_view.h> |
22 | #include <__iterator/concepts.h> |
23 | #include <__iterator/counted_iterator.h> |
24 | #include <__iterator/default_sentinel.h> |
25 | #include <__iterator/distance.h> |
26 | #include <__iterator/iterator_traits.h> |
27 | #include <__ranges/access.h> |
28 | #include <__ranges/all.h> |
29 | #include <__ranges/concepts.h> |
30 | #include <__ranges/empty_view.h> |
31 | #include <__ranges/enable_borrowed_range.h> |
32 | #include <__ranges/iota_view.h> |
33 | #include <__ranges/range_adaptor.h> |
34 | #include <__ranges/repeat_view.h> |
35 | #include <__ranges/size.h> |
36 | #include <__ranges/subrange.h> |
37 | #include <__ranges/view_interface.h> |
38 | #include <__type_traits/decay.h> |
39 | #include <__type_traits/is_nothrow_constructible.h> |
40 | #include <__type_traits/maybe_const.h> |
41 | #include <__type_traits/remove_cvref.h> |
42 | #include <__utility/auto_cast.h> |
43 | #include <__utility/forward.h> |
44 | #include <__utility/move.h> |
45 | |
46 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
47 | # pragma GCC system_header |
48 | #endif |
49 | |
50 | _LIBCPP_PUSH_MACROS |
51 | #include <__undef_macros> |
52 | |
53 | _LIBCPP_BEGIN_NAMESPACE_STD |
54 | |
55 | #if _LIBCPP_STD_VER >= 20 |
56 | |
57 | namespace ranges { |
58 | |
59 | template <view _View> |
60 | class take_view : public view_interface<take_view<_View>> { |
61 | _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); |
62 | range_difference_t<_View> __count_ = 0; |
63 | |
64 | template <bool> |
65 | class __sentinel; |
66 | |
67 | public: |
68 | _LIBCPP_HIDE_FROM_ABI take_view() |
69 | requires default_initializable<_View> |
70 | = default; |
71 | |
72 | _LIBCPP_HIDE_FROM_ABI constexpr _LIBCPP_EXPLICIT_SINCE_CXX23 |
73 | take_view(_View __base, range_difference_t<_View> __count) |
74 | : __base_(std::move(__base)), __count_(__count) { |
75 | _LIBCPP_ASSERT_UNCATEGORIZED(__count >= 0, "count has to be greater than or equal to zero" ); |
76 | } |
77 | |
78 | _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& |
79 | requires copy_constructible<_View> |
80 | { |
81 | return __base_; |
82 | } |
83 | |
84 | _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } |
85 | |
86 | _LIBCPP_HIDE_FROM_ABI constexpr auto begin() |
87 | requires(!__simple_view<_View>) |
88 | { |
89 | if constexpr (sized_range<_View>) { |
90 | if constexpr (random_access_range<_View>) { |
91 | return ranges::begin(__base_); |
92 | } else { |
93 | using _DifferenceT = range_difference_t<_View>; |
94 | auto __size = size(); |
95 | return counted_iterator(ranges::begin(__base_), static_cast<_DifferenceT>(__size)); |
96 | } |
97 | } else { |
98 | return counted_iterator(ranges::begin(__base_), __count_); |
99 | } |
100 | } |
101 | |
102 | _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const |
103 | requires range<const _View> |
104 | { |
105 | if constexpr (sized_range<const _View>) { |
106 | if constexpr (random_access_range<const _View>) { |
107 | return ranges::begin(__base_); |
108 | } else { |
109 | using _DifferenceT = range_difference_t<const _View>; |
110 | auto __size = size(); |
111 | return counted_iterator(ranges::begin(__base_), static_cast<_DifferenceT>(__size)); |
112 | } |
113 | } else { |
114 | return counted_iterator(ranges::begin(__base_), __count_); |
115 | } |
116 | } |
117 | |
118 | _LIBCPP_HIDE_FROM_ABI constexpr auto end() |
119 | requires(!__simple_view<_View>) |
120 | { |
121 | if constexpr (sized_range<_View>) { |
122 | if constexpr (random_access_range<_View>) { |
123 | return ranges::begin(__base_) + size(); |
124 | } else { |
125 | return default_sentinel; |
126 | } |
127 | } else { |
128 | return __sentinel<false>{ranges::end(__base_)}; |
129 | } |
130 | } |
131 | |
132 | _LIBCPP_HIDE_FROM_ABI constexpr auto end() const |
133 | requires range<const _View> |
134 | { |
135 | if constexpr (sized_range<const _View>) { |
136 | if constexpr (random_access_range<const _View>) { |
137 | return ranges::begin(__base_) + size(); |
138 | } else { |
139 | return default_sentinel; |
140 | } |
141 | } else { |
142 | return __sentinel<true>{ranges::end(__base_)}; |
143 | } |
144 | } |
145 | |
146 | _LIBCPP_HIDE_FROM_ABI constexpr auto size() |
147 | requires sized_range<_View> |
148 | { |
149 | auto __n = ranges::size(__base_); |
150 | return ranges::min(__n, static_cast<decltype(__n)>(__count_)); |
151 | } |
152 | |
153 | _LIBCPP_HIDE_FROM_ABI constexpr auto size() const |
154 | requires sized_range<const _View> |
155 | { |
156 | auto __n = ranges::size(__base_); |
157 | return ranges::min(__n, static_cast<decltype(__n)>(__count_)); |
158 | } |
159 | }; |
160 | |
161 | template <view _View> |
162 | template <bool _Const> |
163 | class take_view<_View>::__sentinel { |
164 | using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; |
165 | template <bool _OtherConst> |
166 | using _Iter _LIBCPP_NODEBUG = counted_iterator<iterator_t<__maybe_const<_OtherConst, _View>>>; |
167 | _LIBCPP_NO_UNIQUE_ADDRESS sentinel_t<_Base> __end_ = sentinel_t<_Base>(); |
168 | |
169 | template <bool> |
170 | friend class take_view<_View>::__sentinel; |
171 | |
172 | public: |
173 | _LIBCPP_HIDE_FROM_ABI __sentinel() = default; |
174 | |
175 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {} |
176 | |
177 | _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __s) |
178 | requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>> |
179 | : __end_(std::move(__s.__end_)) {} |
180 | |
181 | _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; } |
182 | |
183 | _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) { |
184 | return __lhs.count() == 0 || __lhs.base() == __rhs.__end_; |
185 | } |
186 | |
187 | template <bool _OtherConst = !_Const> |
188 | requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> |
189 | _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const _Iter<_OtherConst>& __lhs, const __sentinel& __rhs) { |
190 | return __lhs.count() == 0 || __lhs.base() == __rhs.__end_; |
191 | } |
192 | }; |
193 | |
194 | template <class _Range> |
195 | take_view(_Range&&, range_difference_t<_Range>) -> take_view<views::all_t<_Range>>; |
196 | |
197 | template <class _Tp> |
198 | inline constexpr bool enable_borrowed_range<take_view<_Tp>> = enable_borrowed_range<_Tp>; |
199 | |
200 | namespace views { |
201 | namespace __take { |
202 | |
203 | template <class _Tp> |
204 | inline constexpr bool __is_empty_view = false; |
205 | |
206 | template <class _Tp> |
207 | inline constexpr bool __is_empty_view<empty_view<_Tp>> = true; |
208 | |
209 | template <class _Tp> |
210 | inline constexpr bool __is_passthrough_specialization = false; |
211 | |
212 | template <class _Tp, size_t _Extent> |
213 | inline constexpr bool __is_passthrough_specialization<span<_Tp, _Extent>> = true; |
214 | |
215 | template <class _CharT, class _Traits> |
216 | inline constexpr bool __is_passthrough_specialization<basic_string_view<_CharT, _Traits>> = true; |
217 | |
218 | template <class _Iter, class _Sent, subrange_kind _Kind> |
219 | inline constexpr bool __is_passthrough_specialization<subrange<_Iter, _Sent, _Kind>> = true; |
220 | |
221 | template <class _Tp> |
222 | inline constexpr bool __is_iota_specialization = false; |
223 | |
224 | template <class _Np, class _Bound> |
225 | inline constexpr bool __is_iota_specialization<iota_view<_Np, _Bound>> = true; |
226 | |
227 | template <class _Tp> |
228 | struct __passthrough_type; |
229 | |
230 | template <class _Tp, size_t _Extent> |
231 | struct __passthrough_type<span<_Tp, _Extent>> { |
232 | using type _LIBCPP_NODEBUG = span<_Tp>; |
233 | }; |
234 | |
235 | template <class _CharT, class _Traits> |
236 | struct __passthrough_type<basic_string_view<_CharT, _Traits>> { |
237 | using type _LIBCPP_NODEBUG = basic_string_view<_CharT, _Traits>; |
238 | }; |
239 | |
240 | template <class _Iter, class _Sent, subrange_kind _Kind> |
241 | requires requires { typename subrange<_Iter>; } |
242 | struct __passthrough_type<subrange<_Iter, _Sent, _Kind>> { |
243 | using type _LIBCPP_NODEBUG = subrange<_Iter>; |
244 | }; |
245 | |
246 | template <class _Tp> |
247 | using __passthrough_type_t _LIBCPP_NODEBUG = typename __passthrough_type<_Tp>::type; |
248 | |
249 | struct __fn { |
250 | // [range.take.overview]: the `empty_view` case. |
251 | template <class _Range, convertible_to<range_difference_t<_Range>> _Np> |
252 | requires __is_empty_view<remove_cvref_t<_Range>> |
253 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&&) const |
254 | noexcept(noexcept(_LIBCPP_AUTO_CAST(std::forward<_Range>(__range)))) |
255 | -> decltype(_LIBCPP_AUTO_CAST(std::forward<_Range>(__range))) { |
256 | return _LIBCPP_AUTO_CAST(std::forward<_Range>(__range)); |
257 | } |
258 | |
259 | // [range.take.overview]: the `span | basic_string_view | subrange` case. |
260 | template <class _Range, |
261 | convertible_to<range_difference_t<_Range>> _Np, |
262 | class _RawRange = remove_cvref_t<_Range>, |
263 | class _Dist = range_difference_t<_Range>> |
264 | requires(!__is_empty_view<_RawRange> && random_access_range<_RawRange> && sized_range<_RawRange> && |
265 | __is_passthrough_specialization<_RawRange>) |
266 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto |
267 | operator()(_Range&& __rng, _Np&& __n) const noexcept(noexcept(__passthrough_type_t<_RawRange>( |
268 | ranges::begin(__rng), ranges::begin(__rng) + std::min<_Dist>(ranges::distance(__rng), std::forward<_Np>(__n))))) |
269 | -> decltype(__passthrough_type_t<_RawRange>( |
270 | // Note: deliberately not forwarding `__rng` to guard against double moves. |
271 | ranges::begin(__rng), |
272 | ranges::begin(__rng) + std::min<_Dist>(ranges::distance(__rng), std::forward<_Np>(__n)))) { |
273 | return __passthrough_type_t<_RawRange>( |
274 | ranges::begin(__rng), ranges::begin(__rng) + std::min<_Dist>(ranges::distance(__rng), std::forward<_Np>(__n))); |
275 | } |
276 | |
277 | // [range.take.overview]: the `iota_view` case. |
278 | // clang-format off |
279 | template <class _Range, |
280 | convertible_to<range_difference_t<_Range>> _Np, |
281 | class _RawRange = remove_cvref_t<_Range>, |
282 | class _Dist = range_difference_t<_Range>> |
283 | requires (!__is_empty_view<_RawRange> && |
284 | random_access_range<_RawRange> && |
285 | sized_range<_RawRange> && |
286 | __is_iota_specialization<_RawRange>) |
287 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI |
288 | constexpr auto operator()(_Range&& __rng, _Np&& __n) const |
289 | noexcept(noexcept(ranges::iota_view( |
290 | *ranges::begin(__rng), |
291 | *(ranges::begin(__rng) + std::min<_Dist>(ranges::distance(__rng), std::forward<_Np>(__n))) |
292 | ))) |
293 | -> decltype( ranges::iota_view( |
294 | // Note: deliberately not forwarding `__rng` to guard against double moves. |
295 | *ranges::begin(__rng), |
296 | *(ranges::begin(__rng) + std::min<_Dist>(ranges::distance(__rng), std::forward<_Np>(__n))) |
297 | )) |
298 | { return ranges::iota_view( |
299 | *ranges::begin(__rng), |
300 | *(ranges::begin(__rng) + std::min<_Dist>(ranges::distance(__rng), std::forward<_Np>(__n))) |
301 | ); } |
302 | |
303 | #if _LIBCPP_STD_VER >= 23 |
304 | // [range.take.overview]: the `repeat_view` "_RawRange models sized_range" case. |
305 | template <class _Range, |
306 | convertible_to<range_difference_t<_Range>> _Np, |
307 | class _RawRange = remove_cvref_t<_Range>, |
308 | class _Dist = range_difference_t<_Range>> |
309 | requires(__is_repeat_specialization<_RawRange> && sized_range<_RawRange>) |
310 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const |
311 | noexcept(noexcept(views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))))) |
312 | -> decltype( views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n)))) |
313 | { return views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))); } |
314 | |
315 | // [range.take.overview]: the `repeat_view` "otherwise" case. |
316 | template <class _Range, |
317 | convertible_to<range_difference_t<_Range>> _Np, |
318 | class _RawRange = remove_cvref_t<_Range>, |
319 | class _Dist = range_difference_t<_Range>> |
320 | requires(__is_repeat_specialization<_RawRange> && !sized_range<_RawRange>) |
321 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const |
322 | noexcept(noexcept(views::repeat(*__range.__value_, static_cast<_Dist>(__n)))) |
323 | -> decltype( views::repeat(*__range.__value_, static_cast<_Dist>(__n))) |
324 | { return views::repeat(*__range.__value_, static_cast<_Dist>(__n)); } |
325 | #endif |
326 | // clang-format on |
327 | |
328 | // [range.take.overview]: the "otherwise" case. |
329 | template <class _Range, convertible_to<range_difference_t<_Range>> _Np, class _RawRange = remove_cvref_t<_Range>> |
330 | // Note: without specifically excluding the other cases, GCC sees this overload as ambiguous with the other |
331 | // overloads. |
332 | requires(!(__is_empty_view<_RawRange> || |
333 | # if _LIBCPP_STD_VER >= 23 |
334 | __is_repeat_specialization<_RawRange> || |
335 | # endif |
336 | (__is_iota_specialization<_RawRange> && sized_range<_RawRange> && random_access_range<_RawRange>) || |
337 | (__is_passthrough_specialization<_RawRange> && sized_range<_RawRange> && |
338 | random_access_range<_RawRange>))) |
339 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const |
340 | noexcept(noexcept(take_view(std::forward<_Range>(__range), std::forward<_Np>(__n)))) |
341 | -> decltype(take_view(std::forward<_Range>(__range), std::forward<_Np>(__n))) { |
342 | return take_view(std::forward<_Range>(__range), std::forward<_Np>(__n)); |
343 | } |
344 | |
345 | template <class _Np> |
346 | requires constructible_from<decay_t<_Np>, _Np> |
347 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Np&& __n) const |
348 | noexcept(is_nothrow_constructible_v<decay_t<_Np>, _Np>) { |
349 | return __pipeable(std::__bind_back(*this, std::forward<_Np>(__n))); |
350 | } |
351 | }; |
352 | |
353 | } // namespace __take |
354 | |
355 | inline namespace __cpo { |
356 | inline constexpr auto take = __take::__fn{}; |
357 | } // namespace __cpo |
358 | } // namespace views |
359 | |
360 | } // namespace ranges |
361 | |
362 | #endif // _LIBCPP_STD_VER >= 20 |
363 | |
364 | _LIBCPP_END_NAMESPACE_STD |
365 | |
366 | _LIBCPP_POP_MACROS |
367 | |
368 | #endif // _LIBCPP___RANGES_TAKE_VIEW_H |
369 | |