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