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 | |