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