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