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___MEMORY_POINTER_TRAITS_H |
11 | #define _LIBCPP___MEMORY_POINTER_TRAITS_H |
12 | |
13 | #include <__config> |
14 | #include <__memory/addressof.h> |
15 | #include <__type_traits/conditional.h> |
16 | #include <__type_traits/conjunction.h> |
17 | #include <__type_traits/decay.h> |
18 | #include <__type_traits/is_class.h> |
19 | #include <__type_traits/is_function.h> |
20 | #include <__type_traits/is_void.h> |
21 | #include <__type_traits/void_t.h> |
22 | #include <__utility/declval.h> |
23 | #include <__utility/forward.h> |
24 | #include <cstddef> |
25 | |
26 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
27 | # pragma GCC system_header |
28 | #endif |
29 | |
30 | _LIBCPP_PUSH_MACROS |
31 | #include <__undef_macros> |
32 | |
33 | _LIBCPP_BEGIN_NAMESPACE_STD |
34 | |
35 | // clang-format off |
36 | #define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY) \ |
37 | template <class _Tp, class = void> \ |
38 | struct NAME : false_type {}; \ |
39 | template <class _Tp> \ |
40 | struct NAME<_Tp, __void_t<typename _Tp::PROPERTY> > : true_type {} |
41 | // clang-format on |
42 | |
43 | _LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer); |
44 | _LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type); |
45 | |
46 | template <class _Ptr, bool = __has_element_type<_Ptr>::value> |
47 | struct __pointer_traits_element_type {}; |
48 | |
49 | template <class _Ptr> |
50 | struct __pointer_traits_element_type<_Ptr, true> { |
51 | typedef _LIBCPP_NODEBUG typename _Ptr::element_type type; |
52 | }; |
53 | |
54 | template <template <class, class...> class _Sp, class _Tp, class... _Args> |
55 | struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, true> { |
56 | typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::element_type type; |
57 | }; |
58 | |
59 | template <template <class, class...> class _Sp, class _Tp, class... _Args> |
60 | struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, false> { |
61 | typedef _LIBCPP_NODEBUG _Tp type; |
62 | }; |
63 | |
64 | template <class _Tp, class = void> |
65 | struct __has_difference_type : false_type {}; |
66 | |
67 | template <class _Tp> |
68 | struct __has_difference_type<_Tp, __void_t<typename _Tp::difference_type> > : true_type {}; |
69 | |
70 | template <class _Ptr, bool = __has_difference_type<_Ptr>::value> |
71 | struct __pointer_traits_difference_type { |
72 | typedef _LIBCPP_NODEBUG ptrdiff_t type; |
73 | }; |
74 | |
75 | template <class _Ptr> |
76 | struct __pointer_traits_difference_type<_Ptr, true> { |
77 | typedef _LIBCPP_NODEBUG typename _Ptr::difference_type type; |
78 | }; |
79 | |
80 | template <class _Tp, class _Up> |
81 | struct __has_rebind { |
82 | private: |
83 | template <class _Xp> |
84 | static false_type __test(...); |
85 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH |
86 | template <class _Xp> |
87 | static true_type __test(typename _Xp::template rebind<_Up>* = 0); |
88 | _LIBCPP_SUPPRESS_DEPRECATED_POP |
89 | |
90 | public: |
91 | static const bool value = decltype(__test<_Tp>(0))::value; |
92 | }; |
93 | |
94 | template <class _Tp, class _Up, bool = __has_rebind<_Tp, _Up>::value> |
95 | struct __pointer_traits_rebind { |
96 | #ifndef _LIBCPP_CXX03_LANG |
97 | typedef _LIBCPP_NODEBUG typename _Tp::template rebind<_Up> type; |
98 | #else |
99 | typedef _LIBCPP_NODEBUG typename _Tp::template rebind<_Up>::other type; |
100 | #endif |
101 | }; |
102 | |
103 | template <template <class, class...> class _Sp, class _Tp, class... _Args, class _Up> |
104 | struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, true> { |
105 | #ifndef _LIBCPP_CXX03_LANG |
106 | typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::template rebind<_Up> type; |
107 | #else |
108 | typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::template rebind<_Up>::other type; |
109 | #endif |
110 | }; |
111 | |
112 | template <template <class, class...> class _Sp, class _Tp, class... _Args, class _Up> |
113 | struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, false> { |
114 | typedef _Sp<_Up, _Args...> type; |
115 | }; |
116 | |
117 | template <class _Ptr, class = void> |
118 | struct __pointer_traits_impl {}; |
119 | |
120 | template <class _Ptr> |
121 | struct __pointer_traits_impl<_Ptr, __void_t<typename __pointer_traits_element_type<_Ptr>::type> > { |
122 | typedef _Ptr pointer; |
123 | typedef typename __pointer_traits_element_type<pointer>::type element_type; |
124 | typedef typename __pointer_traits_difference_type<pointer>::type difference_type; |
125 | |
126 | #ifndef _LIBCPP_CXX03_LANG |
127 | template <class _Up> |
128 | using rebind = typename __pointer_traits_rebind<pointer, _Up>::type; |
129 | #else |
130 | template <class _Up> |
131 | struct rebind { |
132 | typedef typename __pointer_traits_rebind<pointer, _Up>::type other; |
133 | }; |
134 | #endif // _LIBCPP_CXX03_LANG |
135 | |
136 | private: |
137 | struct __nat {}; |
138 | |
139 | public: |
140 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer |
141 | pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) { |
142 | return pointer::pointer_to(__r); |
143 | } |
144 | }; |
145 | |
146 | template <class _Ptr> |
147 | struct _LIBCPP_TEMPLATE_VIS pointer_traits : __pointer_traits_impl<_Ptr> {}; |
148 | |
149 | template <class _Tp> |
150 | struct _LIBCPP_TEMPLATE_VIS pointer_traits<_Tp*> { |
151 | typedef _Tp* pointer; |
152 | typedef _Tp element_type; |
153 | typedef ptrdiff_t difference_type; |
154 | |
155 | #ifndef _LIBCPP_CXX03_LANG |
156 | template <class _Up> |
157 | using rebind = _Up*; |
158 | #else |
159 | template <class _Up> |
160 | struct rebind { |
161 | typedef _Up* other; |
162 | }; |
163 | #endif |
164 | |
165 | private: |
166 | struct __nat {}; |
167 | |
168 | public: |
169 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer |
170 | pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) _NOEXCEPT { |
171 | return std::addressof(__r); |
172 | } |
173 | }; |
174 | |
175 | #ifndef _LIBCPP_CXX03_LANG |
176 | template <class _From, class _To> |
177 | using __rebind_pointer_t = typename pointer_traits<_From>::template rebind<_To>; |
178 | #else |
179 | template <class _From, class _To> |
180 | using __rebind_pointer_t = typename pointer_traits<_From>::template rebind<_To>::other; |
181 | #endif |
182 | |
183 | // to_address |
184 | |
185 | template <class _Pointer, class = void> |
186 | struct __to_address_helper; |
187 | |
188 | template <class _Tp> |
189 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* __to_address(_Tp* __p) _NOEXCEPT { |
190 | static_assert(!is_function<_Tp>::value, "_Tp is a function type" ); |
191 | return __p; |
192 | } |
193 | |
194 | template <class _Pointer, class = void> |
195 | struct _HasToAddress : false_type {}; |
196 | |
197 | template <class _Pointer> |
198 | struct _HasToAddress<_Pointer, decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>())) > |
199 | : true_type {}; |
200 | |
201 | template <class _Pointer, class = void> |
202 | struct _HasArrow : false_type {}; |
203 | |
204 | template <class _Pointer> |
205 | struct _HasArrow<_Pointer, decltype((void)std::declval<const _Pointer&>().operator->()) > : true_type {}; |
206 | |
207 | template <class _Pointer> |
208 | struct _IsFancyPointer { |
209 | static const bool value = _HasArrow<_Pointer>::value || _HasToAddress<_Pointer>::value; |
210 | }; |
211 | |
212 | // enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers |
213 | template <class _Pointer, __enable_if_t< _And<is_class<_Pointer>, _IsFancyPointer<_Pointer> >::value, int> = 0> |
214 | _LIBCPP_HIDE_FROM_ABI |
215 | _LIBCPP_CONSTEXPR __decay_t<decltype(__to_address_helper<_Pointer>::__call(std::declval<const _Pointer&>()))> |
216 | __to_address(const _Pointer& __p) _NOEXCEPT { |
217 | return __to_address_helper<_Pointer>::__call(__p); |
218 | } |
219 | |
220 | template <class _Pointer, class> |
221 | struct __to_address_helper { |
222 | _LIBCPP_HIDE_FROM_ABI |
223 | _LIBCPP_CONSTEXPR static decltype(std::__to_address(std::declval<const _Pointer&>().operator->())) |
224 | __call(const _Pointer& __p) _NOEXCEPT { |
225 | return std::__to_address(__p.operator->()); |
226 | } |
227 | }; |
228 | |
229 | template <class _Pointer> |
230 | struct __to_address_helper<_Pointer, |
231 | decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))> { |
232 | _LIBCPP_HIDE_FROM_ABI |
233 | _LIBCPP_CONSTEXPR static decltype(pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>())) |
234 | __call(const _Pointer& __p) _NOEXCEPT { |
235 | return pointer_traits<_Pointer>::to_address(__p); |
236 | } |
237 | }; |
238 | |
239 | #if _LIBCPP_STD_VER >= 20 |
240 | template <class _Tp> |
241 | inline _LIBCPP_HIDE_FROM_ABI constexpr auto to_address(_Tp* __p) noexcept { |
242 | return std::__to_address(__p); |
243 | } |
244 | |
245 | template <class _Pointer> |
246 | inline _LIBCPP_HIDE_FROM_ABI constexpr auto |
247 | to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) { |
248 | return std::__to_address(__p); |
249 | } |
250 | #endif |
251 | |
252 | #if _LIBCPP_STD_VER >= 23 |
253 | |
254 | template <class _Tp> |
255 | struct __pointer_of {}; |
256 | |
257 | template <class _Tp> |
258 | requires(__has_pointer<_Tp>::value) |
259 | struct __pointer_of<_Tp> { |
260 | using type = typename _Tp::pointer; |
261 | }; |
262 | |
263 | template <class _Tp> |
264 | requires(!__has_pointer<_Tp>::value && __has_element_type<_Tp>::value) |
265 | struct __pointer_of<_Tp> { |
266 | using type = typename _Tp::element_type*; |
267 | }; |
268 | |
269 | template <class _Tp> |
270 | requires(!__has_pointer<_Tp>::value && !__has_element_type<_Tp>::value && |
271 | __has_element_type<pointer_traits<_Tp>>::value) |
272 | struct __pointer_of<_Tp> { |
273 | using type = typename pointer_traits<_Tp>::element_type*; |
274 | }; |
275 | |
276 | template <typename _Tp> |
277 | using __pointer_of_t = typename __pointer_of<_Tp>::type; |
278 | |
279 | template <class _Tp, class _Up> |
280 | struct __pointer_of_or { |
281 | using type _LIBCPP_NODEBUG = _Up; |
282 | }; |
283 | |
284 | template <class _Tp, class _Up> |
285 | requires requires { typename __pointer_of_t<_Tp>; } |
286 | struct __pointer_of_or<_Tp, _Up> { |
287 | using type _LIBCPP_NODEBUG = __pointer_of_t<_Tp>; |
288 | }; |
289 | |
290 | template <typename _Tp, typename _Up> |
291 | using __pointer_of_or_t = typename __pointer_of_or<_Tp, _Up>::type; |
292 | |
293 | template <class _Smart> |
294 | concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); }; |
295 | |
296 | template <class _Smart, class _Pointer, class... _Args> |
297 | concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p, _Args... __args) { |
298 | __s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...); |
299 | }; |
300 | |
301 | #endif |
302 | |
303 | _LIBCPP_END_NAMESPACE_STD |
304 | |
305 | _LIBCPP_POP_MACROS |
306 | |
307 | #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H |
308 | |