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 
10 #ifndef _LIBCPP___RANGES_REND_H
11 #define _LIBCPP___RANGES_REND_H
12 
13 #include <__concepts/class_or_enum.h>
14 #include <__concepts/same_as.h>
15 #include <__config>
16 #include <__iterator/concepts.h>
17 #include <__iterator/readable_traits.h>
18 #include <__iterator/reverse_iterator.h>
19 #include <__ranges/access.h>
20 #include <__ranges/rbegin.h>
21 #include <__utility/auto_cast.h>
22 #include <type_traits>
23 
24 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25 #  pragma GCC system_header
26 #endif
27 
28 _LIBCPP_BEGIN_NAMESPACE_STD
29 
30 #if _LIBCPP_STD_VER > 17
31 
32 // [range.access.rend]
33 
34 namespace ranges {
35 namespace __rend {
36 template <class _Tp>
37 concept __member_rend =
38   __can_borrow<_Tp> &&
39   __workaround_52970<_Tp> &&
40   requires(_Tp&& __t) {
41     ranges::rbegin(__t);
42     { _LIBCPP_AUTO_CAST(__t.rend()) } -> sentinel_for<decltype(ranges::rbegin(__t))>;
43   };
44 
45 void rend(auto&) = delete;
46 void rend(const auto&) = delete;
47 
48 template <class _Tp>
49 concept __unqualified_rend =
50   !__member_rend<_Tp> &&
51   __can_borrow<_Tp> &&
52   __class_or_enum<remove_cvref_t<_Tp>> &&
53   requires(_Tp&& __t) {
54     ranges::rbegin(__t);
55     { _LIBCPP_AUTO_CAST(rend(__t)) } -> sentinel_for<decltype(ranges::rbegin(__t))>;
56   };
57 
58 template <class _Tp>
59 concept __can_reverse =
60   __can_borrow<_Tp> &&
61   !__member_rend<_Tp> &&
62   !__unqualified_rend<_Tp> &&
63   requires(_Tp&& __t) {
64     { ranges::begin(__t) } -> same_as<decltype(ranges::end(__t))>;
65     { ranges::begin(__t) } -> bidirectional_iterator;
66   };
67 
68 class __fn {
69 public:
70   template <class _Tp>
71     requires __member_rend<_Tp>
72   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
73     noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.rend())))
74   {
75     return _LIBCPP_AUTO_CAST(__t.rend());
76   }
77 
78   template <class _Tp>
79     requires __unqualified_rend<_Tp>
80   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
81     noexcept(noexcept(_LIBCPP_AUTO_CAST(rend(__t))))
82   {
83     return _LIBCPP_AUTO_CAST(rend(__t));
84   }
85 
86   template <class _Tp>
87     requires __can_reverse<_Tp>
88   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
89     noexcept(noexcept(ranges::begin(__t)))
90   {
91     return std::make_reverse_iterator(ranges::begin(__t));
92   }
93 
94   void operator()(auto&&) const = delete;
95 };
96 } // namespace __rend
97 
98 inline namespace __cpo {
99   inline constexpr auto rend = __rend::__fn{};
100 } // namespace __cpo
101 } // namespace ranges
102 
103 // [range.access.crend]
104 
105 namespace ranges {
106 namespace __crend {
107 struct __fn {
108   template <class _Tp>
109     requires is_lvalue_reference_v<_Tp&&>
110   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
111   constexpr auto operator()(_Tp&& __t) const
112     noexcept(noexcept(ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t))))
113     -> decltype(      ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t)))
114     { return          ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t)); }
115 
116   template <class _Tp>
117     requires is_rvalue_reference_v<_Tp&&>
118   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
119   constexpr auto operator()(_Tp&& __t) const
120     noexcept(noexcept(ranges::rend(static_cast<const _Tp&&>(__t))))
121     -> decltype(      ranges::rend(static_cast<const _Tp&&>(__t)))
122     { return          ranges::rend(static_cast<const _Tp&&>(__t)); }
123 };
124 } // namespace __crend
125 
126 inline namespace __cpo {
127   inline constexpr auto crend = __crend::__fn{};
128 } // namespace __cpo
129 } // namespace ranges
130 
131 #endif // _LIBCPP_STD_VER > 17
132 
133 _LIBCPP_END_NAMESPACE_STD
134 
135 #endif // _LIBCPP___RANGES_REND_H
136