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