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