xref: /llvm-project/libcxx/include/__memory/pointer_traits.h (revision f69585235ec85d54e0f3fc41b2d5700430907f99)
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 _LIBCPP_TEMPLATE_VIS pointer_traits : __pointer_traits_impl<_Ptr> {};
150 
151 template <class _Tp>
152 struct _LIBCPP_TEMPLATE_VIS 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
249 to_address(const _Pointer& __p) noexcept -> 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 = 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 = 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 = 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 _LIBCPP_END_NAMESPACE_STD
306 
307 _LIBCPP_POP_MACROS
308 
309 #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H
310