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