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