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 #ifndef _LIBCPP___RANGES_SIZE_H 10 #define _LIBCPP___RANGES_SIZE_H 11 12 #include <__config> 13 #include <__iterator/concepts.h> 14 #include <__iterator/iterator_traits.h> 15 #include <__ranges/access.h> 16 #include <type_traits> 17 18 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 19 #pragma GCC system_header 20 #endif 21 22 _LIBCPP_PUSH_MACROS 23 #include <__undef_macros> 24 25 _LIBCPP_BEGIN_NAMESPACE_STD 26 27 #if !defined(_LIBCPP_HAS_NO_RANGES) 28 29 // clang-format off 30 namespace ranges { 31 template<class> 32 inline constexpr bool disable_sized_range = false; 33 34 // [range.prim.size] 35 namespace __size { 36 void size(auto&) = delete; 37 void size(const auto&) = delete; 38 39 template <class _Tp> 40 concept __size_enabled = !disable_sized_range<remove_cvref_t<_Tp>>; 41 42 template <class _Tp> requires(_Tp && __t)43 concept __member_size = __size_enabled<_Tp> && requires(_Tp&& __t) { 44 { _VSTD::__decay_copy(_VSTD::forward<_Tp>(__t).size()) } -> __integer_like; 45 }; 46 47 template <class _Tp> 48 concept __unqualified_size = 49 __size_enabled<_Tp> && 50 !__member_size<_Tp> && 51 __class_or_enum<remove_cvref_t<_Tp>> && 52 requires(_Tp&& __t) { 53 { _VSTD::__decay_copy(size(_VSTD::forward<_Tp>(__t))) } -> __integer_like; 54 }; 55 56 template <class _Tp> 57 concept __difference = 58 !__member_size<_Tp> && 59 !__unqualified_size<_Tp> && 60 __class_or_enum<remove_cvref_t<_Tp>> && 61 requires(_Tp&& __t) { 62 { ranges::begin(__t) } -> forward_iterator; 63 { ranges::end(__t) } -> sized_sentinel_for<decltype(ranges::begin(declval<_Tp>()))>; 64 }; 65 66 struct __fn { 67 template <class _Tp, size_t _Sz> operator__fn68 [[nodiscard]] constexpr size_t operator()(_Tp (&&)[_Sz]) const noexcept { 69 return _Sz; 70 } 71 72 template <class _Tp, size_t _Sz> operator__fn73 [[nodiscard]] constexpr size_t operator()(_Tp (&)[_Sz]) const noexcept { 74 return _Sz; 75 } 76 77 template <__member_size _Tp> operator__fn78 [[nodiscard]] constexpr __integer_like auto operator()(_Tp&& __t) const 79 noexcept(noexcept(_VSTD::forward<_Tp>(__t).size())) { 80 return _VSTD::forward<_Tp>(__t).size(); 81 } 82 83 template <__unqualified_size _Tp> operator__fn84 [[nodiscard]] constexpr __integer_like auto operator()(_Tp&& __t) const 85 noexcept(noexcept(size(_VSTD::forward<_Tp>(__t)))) { 86 return size(_VSTD::forward<_Tp>(__t)); 87 } 88 89 template<__difference _Tp> operator__fn90 [[nodiscard]] constexpr __integer_like auto operator()(_Tp&& __t) const 91 noexcept(noexcept(ranges::end(__t) - ranges::begin(__t))) { 92 return _VSTD::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)); 93 } 94 }; 95 } // end namespace __size 96 97 inline namespace __cpo { 98 inline constexpr auto size = __size::__fn{}; 99 } // namespace __cpo 100 101 namespace __ssize { 102 struct __fn { 103 template<class _Tp> requires__fn104 requires requires (_Tp&& __t) { ranges::size(__t); } operator__fn105 [[nodiscard]] constexpr integral auto operator()(_Tp&& __t) const 106 noexcept(noexcept(ranges::size(__t))) { 107 using _Signed = make_signed_t<decltype(ranges::size(__t))>; 108 if constexpr (sizeof(ptrdiff_t) > sizeof(_Signed)) 109 return static_cast<ptrdiff_t>(ranges::size(__t)); 110 else 111 return static_cast<_Signed>(ranges::size(__t)); 112 } 113 }; 114 } 115 116 inline namespace __cpo { 117 inline constexpr const auto ssize = __ssize::__fn{}; 118 } // namespace __cpo 119 120 } // namespace ranges 121 122 // clang-format off 123 124 #endif // !defined(_LIBCPP_HAS_NO_RANGES) 125 126 _LIBCPP_END_NAMESPACE_STD 127 128 _LIBCPP_POP_MACROS 129 130 #endif // _LIBCPP___RANGES_SIZE_H 131