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_SIZE_H 11 #define _LIBCPP___RANGES_SIZE_H 12 13 #include <__concepts/arithmetic.h> 14 #include <__concepts/class_or_enum.h> 15 #include <__config> 16 #include <__iterator/concepts.h> 17 #include <__iterator/iterator_traits.h> 18 #include <__ranges/access.h> 19 #include <__type_traits/decay.h> 20 #include <__type_traits/make_signed.h> 21 #include <__type_traits/make_unsigned.h> 22 #include <__type_traits/remove_cvref.h> 23 #include <__utility/auto_cast.h> 24 #include <__utility/declval.h> 25 #include <cstddef> 26 27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 28 # pragma GCC system_header 29 #endif 30 31 _LIBCPP_BEGIN_NAMESPACE_STD 32 33 #if _LIBCPP_STD_VER >= 20 34 35 namespace ranges { 36 template <class> 37 inline constexpr bool disable_sized_range = false; 38 } // namespace ranges 39 40 // [range.prim.size] 41 42 namespace ranges { 43 namespace __size { 44 void size() = delete; 45 46 template <class _Tp> 47 concept __size_enabled = !disable_sized_range<remove_cvref_t<_Tp>>; 48 49 template <class _Tp> 50 concept __member_size = __size_enabled<_Tp> && requires(_Tp&& __t) { 51 { _LIBCPP_AUTO_CAST(__t.size()) } -> __integer_like; 52 }; 53 54 template <class _Tp> 55 concept __unqualified_size = 56 __size_enabled<_Tp> && !__member_size<_Tp> && __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) { 57 { _LIBCPP_AUTO_CAST(size(__t)) } -> __integer_like; 58 }; 59 60 template <class _Tp> 61 concept __difference = 62 !__member_size<_Tp> && !__unqualified_size<_Tp> && __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) { 63 { ranges::begin(__t) } -> forward_iterator; 64 { ranges::end(__t) } -> sized_sentinel_for<decltype(ranges::begin(std::declval<_Tp>()))>; 65 }; 66 67 struct __fn { 68 // `[range.prim.size]`: the array case (for rvalues). 69 template <class _Tp, size_t _Sz> 70 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&&)[_Sz]) const noexcept { 71 return _Sz; 72 } 73 74 // `[range.prim.size]`: the array case (for lvalues). 75 template <class _Tp, size_t _Sz> 76 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&)[_Sz]) const noexcept { 77 return _Sz; 78 } 79 80 // `[range.prim.size]`: `auto(t.size())` is a valid expression. 81 template <__member_size _Tp> 82 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const 83 noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.size()))) { 84 return _LIBCPP_AUTO_CAST(__t.size()); 85 } 86 87 // `[range.prim.size]`: `auto(size(t))` is a valid expression. 88 template <__unqualified_size _Tp> 89 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const 90 noexcept(noexcept(_LIBCPP_AUTO_CAST(size(__t)))) { 91 return _LIBCPP_AUTO_CAST(size(__t)); 92 } 93 94 // [range.prim.size]: the `to-unsigned-like` case. 95 template <__difference _Tp> 96 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const 97 noexcept(noexcept(std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)))) 98 -> decltype(std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t))) { 99 return std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)); 100 } 101 }; 102 103 } // namespace __size 104 105 inline namespace __cpo { 106 inline constexpr auto size = __size::__fn{}; 107 } // namespace __cpo 108 } // namespace ranges 109 110 // [range.prim.ssize] 111 112 namespace ranges { 113 namespace __ssize { 114 struct __fn { 115 template <class _Tp> 116 requires requires(_Tp&& __t) { ranges::size(__t); } 117 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr integral auto operator()(_Tp&& __t) const 118 noexcept(noexcept(ranges::size(__t))) { 119 using _Signed = make_signed_t<decltype(ranges::size(__t))>; 120 if constexpr (sizeof(ptrdiff_t) > sizeof(_Signed)) 121 return static_cast<ptrdiff_t>(ranges::size(__t)); 122 else 123 return static_cast<_Signed>(ranges::size(__t)); 124 } 125 }; 126 } // namespace __ssize 127 128 inline namespace __cpo { 129 inline constexpr auto ssize = __ssize::__fn{}; 130 } // namespace __cpo 131 } // namespace ranges 132 133 #endif // _LIBCPP_STD_VER >= 20 134 135 _LIBCPP_END_NAMESPACE_STD 136 137 #endif // _LIBCPP___RANGES_SIZE_H 138