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