xref: /freebsd/contrib/llvm-project/libcxx/include/__ranges/take_view.h (revision 1165fc9a526630487a1feb63daef65c5aee1a583)
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_TAKE_VIEW_H
10 #define _LIBCPP___RANGES_TAKE_VIEW_H
11 
12 #include <__algorithm/min.h>
13 #include <__config>
14 #include <__iterator/concepts.h>
15 #include <__iterator/counted_iterator.h>
16 #include <__iterator/default_sentinel.h>
17 #include <__iterator/iterator_traits.h>
18 #include <__ranges/access.h>
19 #include <__ranges/all.h>
20 #include <__ranges/concepts.h>
21 #include <__ranges/enable_borrowed_range.h>
22 #include <__ranges/size.h>
23 #include <__ranges/view_interface.h>
24 #include <__utility/move.h>
25 #include <concepts>
26 #include <type_traits>
27 
28 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
29 #pragma GCC system_header
30 #endif
31 
32 _LIBCPP_PUSH_MACROS
33 #include <__undef_macros>
34 
35 _LIBCPP_BEGIN_NAMESPACE_STD
36 
37 #if !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
38 
39 namespace ranges {
40   template<view _View>
41   class take_view : public view_interface<take_view<_View>> {
42     [[no_unique_address]] _View __base_ = _View();
43     range_difference_t<_View> __count_ = 0;
44 
45     template<bool> class __sentinel;
46 
47   public:
48     _LIBCPP_HIDE_FROM_ABI
49     take_view() requires default_initializable<_View> = default;
50 
51     _LIBCPP_HIDE_FROM_ABI
52     constexpr take_view(_View __base, range_difference_t<_View> __count)
53       : __base_(_VSTD::move(__base)), __count_(__count) {}
54 
55     _LIBCPP_HIDE_FROM_ABI
56     constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
57 
58     _LIBCPP_HIDE_FROM_ABI
59     constexpr _View base() && { return _VSTD::move(__base_); }
60 
61     _LIBCPP_HIDE_FROM_ABI
62     constexpr auto begin() requires (!__simple_view<_View>) {
63       if constexpr (sized_range<_View>) {
64         if constexpr (random_access_range<_View>) {
65           return ranges::begin(__base_);
66         } else {
67           using _DifferenceT = range_difference_t<_View>;
68           auto __size = size();
69           return counted_iterator(ranges::begin(__base_), static_cast<_DifferenceT>(__size));
70         }
71       } else {
72         return counted_iterator(ranges::begin(__base_), __count_);
73       }
74     }
75 
76     _LIBCPP_HIDE_FROM_ABI
77     constexpr auto begin() const requires range<const _View> {
78       if constexpr (sized_range<const _View>) {
79         if constexpr (random_access_range<const _View>) {
80           return ranges::begin(__base_);
81         } else {
82           using _DifferenceT = range_difference_t<const _View>;
83           auto __size = size();
84           return counted_iterator(ranges::begin(__base_), static_cast<_DifferenceT>(__size));
85         }
86       } else {
87         return counted_iterator(ranges::begin(__base_), __count_);
88       }
89     }
90 
91     _LIBCPP_HIDE_FROM_ABI
92     constexpr auto end() requires (!__simple_view<_View>) {
93       if constexpr (sized_range<_View>) {
94         if constexpr (random_access_range<_View>) {
95           return ranges::begin(__base_) + size();
96         } else {
97           return default_sentinel;
98         }
99       } else {
100         return __sentinel<false>{ranges::end(__base_)};
101       }
102     }
103 
104     _LIBCPP_HIDE_FROM_ABI
105     constexpr auto end() const requires range<const _View> {
106       if constexpr (sized_range<const _View>) {
107         if constexpr (random_access_range<const _View>) {
108           return ranges::begin(__base_) + size();
109         } else {
110           return default_sentinel;
111         }
112       } else {
113         return __sentinel<true>{ranges::end(__base_)};
114       }
115     }
116 
117 
118     _LIBCPP_HIDE_FROM_ABI
119     constexpr auto size() requires sized_range<_View> {
120       auto __n = ranges::size(__base_);
121       // TODO: use ranges::min here.
122       return _VSTD::min(__n, static_cast<decltype(__n)>(__count_));
123     }
124 
125     _LIBCPP_HIDE_FROM_ABI
126     constexpr auto size() const requires sized_range<const _View> {
127       auto __n = ranges::size(__base_);
128       // TODO: use ranges::min here.
129       return _VSTD::min(__n, static_cast<decltype(__n)>(__count_));
130     }
131   };
132 
133   template<view _View>
134   template<bool _Const>
135   class take_view<_View>::__sentinel {
136     using _Base = __maybe_const<_Const, _View>;
137     template<bool _OtherConst>
138     using _Iter = counted_iterator<iterator_t<__maybe_const<_OtherConst, _View>>>;
139     [[no_unique_address]] sentinel_t<_Base> __end_ = sentinel_t<_Base>();
140 
141     template<bool>
142     friend class take_view<_View>::__sentinel;
143 
144 public:
145     _LIBCPP_HIDE_FROM_ABI
146     __sentinel() = default;
147 
148     _LIBCPP_HIDE_FROM_ABI
149     constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(_VSTD::move(__end)) {}
150 
151     _LIBCPP_HIDE_FROM_ABI
152     constexpr __sentinel(__sentinel<!_Const> __s)
153       requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
154       : __end_(_VSTD::move(__s.__end_)) {}
155 
156     _LIBCPP_HIDE_FROM_ABI
157     constexpr sentinel_t<_Base> base() const { return __end_; }
158 
159     _LIBCPP_HIDE_FROM_ABI
160     friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) {
161       return __lhs.count() == 0 || __lhs.base() == __rhs.__end_;
162     }
163 
164     template<bool _OtherConst = !_Const>
165       requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
166     _LIBCPP_HIDE_FROM_ABI
167     friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) {
168       return __lhs.count() == 0 || __lhs.base() == __rhs.__end_;
169     }
170   };
171 
172   template<class _Range>
173   take_view(_Range&&, range_difference_t<_Range>) -> take_view<views::all_t<_Range>>;
174 
175   template<class _Tp>
176   inline constexpr bool enable_borrowed_range<take_view<_Tp>> = enable_borrowed_range<_Tp>;
177 } // namespace ranges
178 
179 #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
180 
181 _LIBCPP_END_NAMESPACE_STD
182 
183 _LIBCPP_POP_MACROS
184 
185 #endif // _LIBCPP___RANGES_TAKE_VIEW_H
186