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