xref: /freebsd/contrib/llvm-project/libcxx/include/__memory/pointer_traits.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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