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_ACCESS_H |
11 | #define _LIBCPP___RANGES_ACCESS_H |
12 | |
13 | #include <__concepts/class_or_enum.h> |
14 | #include <__config> |
15 | #include <__iterator/concepts.h> |
16 | #include <__iterator/readable_traits.h> |
17 | #include <__ranges/enable_borrowed_range.h> |
18 | #include <__type_traits/decay.h> |
19 | #include <__type_traits/is_reference.h> |
20 | #include <__type_traits/remove_cvref.h> |
21 | #include <__type_traits/remove_reference.h> |
22 | #include <__utility/auto_cast.h> |
23 | #include <__utility/declval.h> |
24 | #include <cstddef> |
25 | |
26 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
27 | # pragma GCC system_header |
28 | #endif |
29 | |
30 | _LIBCPP_BEGIN_NAMESPACE_STD |
31 | |
32 | #if _LIBCPP_STD_VER >= 20 |
33 | |
34 | namespace ranges { |
35 | template <class _Tp> |
36 | concept __can_borrow = is_lvalue_reference_v<_Tp> || enable_borrowed_range<remove_cvref_t<_Tp>>; |
37 | } // namespace ranges |
38 | |
39 | // [range.access.begin] |
40 | |
41 | namespace ranges { |
42 | namespace __begin { |
43 | template <class _Tp> |
44 | concept __member_begin = __can_borrow<_Tp> && requires(_Tp&& __t) { |
45 | { _LIBCPP_AUTO_CAST(__t.begin()) } -> input_or_output_iterator; |
46 | }; |
47 | |
48 | void begin() = delete; |
49 | |
50 | template <class _Tp> |
51 | concept __unqualified_begin = |
52 | !__member_begin<_Tp> && __can_borrow<_Tp> && __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) { |
53 | { _LIBCPP_AUTO_CAST(begin(__t)) } -> input_or_output_iterator; |
54 | }; |
55 | |
56 | struct __fn { |
57 | template <class _Tp> |
58 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[]) const noexcept |
59 | requires(sizeof(_Tp) >= 0) // Disallow incomplete element types. |
60 | { |
61 | return __t + 0; |
62 | } |
63 | |
64 | template <class _Tp, size_t _Np> |
65 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept |
66 | requires(sizeof(_Tp) >= 0) // Disallow incomplete element types. |
67 | { |
68 | return __t + 0; |
69 | } |
70 | |
71 | template <class _Tp> |
72 | requires __member_begin<_Tp> |
73 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const |
74 | noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.begin()))) { |
75 | return _LIBCPP_AUTO_CAST(__t.begin()); |
76 | } |
77 | |
78 | template <class _Tp> |
79 | requires __unqualified_begin<_Tp> |
80 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const |
81 | noexcept(noexcept(_LIBCPP_AUTO_CAST(begin(__t)))) { |
82 | return _LIBCPP_AUTO_CAST(begin(__t)); |
83 | } |
84 | |
85 | void operator()(auto&&) const = delete; |
86 | }; |
87 | } // namespace __begin |
88 | |
89 | inline namespace __cpo { |
90 | inline constexpr auto begin = __begin::__fn{}; |
91 | } // namespace __cpo |
92 | } // namespace ranges |
93 | |
94 | // [range.range] |
95 | |
96 | namespace ranges { |
97 | template <class _Tp> |
98 | using iterator_t = decltype(ranges::begin(std::declval<_Tp&>())); |
99 | } // namespace ranges |
100 | |
101 | // [range.access.end] |
102 | |
103 | namespace ranges { |
104 | namespace __end { |
105 | template <class _Tp> |
106 | concept __member_end = __can_borrow<_Tp> && requires(_Tp&& __t) { |
107 | typename iterator_t<_Tp>; |
108 | { _LIBCPP_AUTO_CAST(__t.end()) } -> sentinel_for<iterator_t<_Tp>>; |
109 | }; |
110 | |
111 | void end() = delete; |
112 | |
113 | template <class _Tp> |
114 | concept __unqualified_end = |
115 | !__member_end<_Tp> && __can_borrow<_Tp> && __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) { |
116 | typename iterator_t<_Tp>; |
117 | { _LIBCPP_AUTO_CAST(end(__t)) } -> sentinel_for<iterator_t<_Tp>>; |
118 | }; |
119 | |
120 | struct __fn { |
121 | template <class _Tp, size_t _Np> |
122 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept |
123 | requires(sizeof(_Tp) >= 0) // Disallow incomplete element types. |
124 | { |
125 | return __t + _Np; |
126 | } |
127 | |
128 | template <class _Tp> |
129 | requires __member_end<_Tp> |
130 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const |
131 | noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.end()))) { |
132 | return _LIBCPP_AUTO_CAST(__t.end()); |
133 | } |
134 | |
135 | template <class _Tp> |
136 | requires __unqualified_end<_Tp> |
137 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const |
138 | noexcept(noexcept(_LIBCPP_AUTO_CAST(end(__t)))) { |
139 | return _LIBCPP_AUTO_CAST(end(__t)); |
140 | } |
141 | |
142 | void operator()(auto&&) const = delete; |
143 | }; |
144 | } // namespace __end |
145 | |
146 | inline namespace __cpo { |
147 | inline constexpr auto end = __end::__fn{}; |
148 | } // namespace __cpo |
149 | } // namespace ranges |
150 | |
151 | // [range.access.cbegin] |
152 | |
153 | namespace ranges { |
154 | namespace __cbegin { |
155 | struct __fn { |
156 | template <class _Tp> |
157 | requires is_lvalue_reference_v<_Tp&&> |
158 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const |
159 | noexcept(noexcept(ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t)))) |
160 | -> decltype(ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t))) { |
161 | return ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t)); |
162 | } |
163 | |
164 | template <class _Tp> |
165 | requires is_rvalue_reference_v<_Tp&&> |
166 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const |
167 | noexcept(noexcept(ranges::begin(static_cast<const _Tp&&>(__t)))) |
168 | -> decltype(ranges::begin(static_cast<const _Tp&&>(__t))) { |
169 | return ranges::begin(static_cast<const _Tp&&>(__t)); |
170 | } |
171 | }; |
172 | } // namespace __cbegin |
173 | |
174 | inline namespace __cpo { |
175 | inline constexpr auto cbegin = __cbegin::__fn{}; |
176 | } // namespace __cpo |
177 | } // namespace ranges |
178 | |
179 | // [range.access.cend] |
180 | |
181 | namespace ranges { |
182 | namespace __cend { |
183 | struct __fn { |
184 | template <class _Tp> |
185 | requires is_lvalue_reference_v<_Tp&&> |
186 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const |
187 | noexcept(noexcept(ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t)))) |
188 | -> decltype(ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t))) { |
189 | return ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t)); |
190 | } |
191 | |
192 | template <class _Tp> |
193 | requires is_rvalue_reference_v<_Tp&&> |
194 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept( |
195 | noexcept(ranges::end(static_cast<const _Tp&&>(__t)))) -> decltype(ranges::end(static_cast<const _Tp&&>(__t))) { |
196 | return ranges::end(static_cast<const _Tp&&>(__t)); |
197 | } |
198 | }; |
199 | } // namespace __cend |
200 | |
201 | inline namespace __cpo { |
202 | inline constexpr auto cend = __cend::__fn{}; |
203 | } // namespace __cpo |
204 | } // namespace ranges |
205 | |
206 | #endif // _LIBCPP_STD_VER >= 20 |
207 | |
208 | _LIBCPP_END_NAMESPACE_STD |
209 | |
210 | #endif // _LIBCPP___RANGES_ACCESS_H |
211 | |