xref: /freebsd-src/contrib/llvm-project/libcxx/include/__memory/pointer_traits.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1e8d8bef9SDimitry Andric // -*- C++ -*-
2e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
3e8d8bef9SDimitry Andric //
4e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7e8d8bef9SDimitry Andric //
8e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
9e8d8bef9SDimitry Andric 
10e8d8bef9SDimitry Andric #ifndef _LIBCPP___MEMORY_POINTER_TRAITS_H
11e8d8bef9SDimitry Andric #define _LIBCPP___MEMORY_POINTER_TRAITS_H
12e8d8bef9SDimitry Andric 
13e8d8bef9SDimitry Andric #include <__config>
14fe6060f1SDimitry Andric #include <__memory/addressof.h>
15bdd1243dSDimitry Andric #include <__type_traits/conditional.h>
16bdd1243dSDimitry Andric #include <__type_traits/conjunction.h>
17bdd1243dSDimitry Andric #include <__type_traits/decay.h>
18bdd1243dSDimitry Andric #include <__type_traits/is_class.h>
19bdd1243dSDimitry Andric #include <__type_traits/is_function.h>
20bdd1243dSDimitry Andric #include <__type_traits/is_void.h>
21bdd1243dSDimitry Andric #include <__type_traits/void_t.h>
22bdd1243dSDimitry Andric #include <__utility/declval.h>
23*0fca6ea1SDimitry Andric #include <__utility/forward.h>
2461cfbce3SDimitry Andric #include <cstddef>
25e8d8bef9SDimitry Andric 
26e8d8bef9SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27e8d8bef9SDimitry Andric #  pragma GCC system_header
28e8d8bef9SDimitry Andric #endif
29e8d8bef9SDimitry Andric 
30*0fca6ea1SDimitry Andric _LIBCPP_PUSH_MACROS
31*0fca6ea1SDimitry Andric #include <__undef_macros>
32*0fca6ea1SDimitry Andric 
33e8d8bef9SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
34e8d8bef9SDimitry Andric 
35*0fca6ea1SDimitry Andric // clang-format off
36*0fca6ea1SDimitry Andric #define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY)                                                                   \
37*0fca6ea1SDimitry Andric   template <class _Tp, class = void>                                                                                   \
38*0fca6ea1SDimitry Andric   struct NAME : false_type {};                                                                                         \
39*0fca6ea1SDimitry Andric   template <class _Tp>                                                                                                 \
40*0fca6ea1SDimitry Andric   struct NAME<_Tp, __void_t<typename _Tp::PROPERTY> > : true_type {}
41*0fca6ea1SDimitry Andric // clang-format on
42e8d8bef9SDimitry Andric 
43*0fca6ea1SDimitry Andric _LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer);
44*0fca6ea1SDimitry Andric _LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type);
45e8d8bef9SDimitry Andric 
46e8d8bef9SDimitry Andric template <class _Ptr, bool = __has_element_type<_Ptr>::value>
475f757f3fSDimitry Andric struct __pointer_traits_element_type {};
48e8d8bef9SDimitry Andric 
49e8d8bef9SDimitry Andric template <class _Ptr>
50cb14a3feSDimitry Andric struct __pointer_traits_element_type<_Ptr, true> {
51349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG typename _Ptr::element_type type;
52e8d8bef9SDimitry Andric };
53e8d8bef9SDimitry Andric 
54e8d8bef9SDimitry Andric template <template <class, class...> class _Sp, class _Tp, class... _Args>
55cb14a3feSDimitry Andric struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, true> {
56349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::element_type type;
57e8d8bef9SDimitry Andric };
58e8d8bef9SDimitry Andric 
59e8d8bef9SDimitry Andric template <template <class, class...> class _Sp, class _Tp, class... _Args>
60cb14a3feSDimitry Andric struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, false> {
61349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG _Tp type;
62e8d8bef9SDimitry Andric };
63e8d8bef9SDimitry Andric 
64e8d8bef9SDimitry Andric template <class _Tp, class = void>
65e8d8bef9SDimitry Andric struct __has_difference_type : false_type {};
66e8d8bef9SDimitry Andric 
67e8d8bef9SDimitry Andric template <class _Tp>
68bdd1243dSDimitry Andric struct __has_difference_type<_Tp, __void_t<typename _Tp::difference_type> > : true_type {};
69e8d8bef9SDimitry Andric 
70e8d8bef9SDimitry Andric template <class _Ptr, bool = __has_difference_type<_Ptr>::value>
71cb14a3feSDimitry Andric struct __pointer_traits_difference_type {
72349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG ptrdiff_t type;
73e8d8bef9SDimitry Andric };
74e8d8bef9SDimitry Andric 
75e8d8bef9SDimitry Andric template <class _Ptr>
76cb14a3feSDimitry Andric struct __pointer_traits_difference_type<_Ptr, true> {
77349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG typename _Ptr::difference_type type;
78e8d8bef9SDimitry Andric };
79e8d8bef9SDimitry Andric 
80e8d8bef9SDimitry Andric template <class _Tp, class _Up>
81cb14a3feSDimitry Andric struct __has_rebind {
82e8d8bef9SDimitry Andric private:
83cb14a3feSDimitry Andric   template <class _Xp>
84cb14a3feSDimitry Andric   static false_type __test(...);
85e8d8bef9SDimitry Andric   _LIBCPP_SUPPRESS_DEPRECATED_PUSH
86cb14a3feSDimitry Andric   template <class _Xp>
87cb14a3feSDimitry Andric   static true_type __test(typename _Xp::template rebind<_Up>* = 0);
88e8d8bef9SDimitry Andric   _LIBCPP_SUPPRESS_DEPRECATED_POP
89cb14a3feSDimitry Andric 
90e8d8bef9SDimitry Andric public:
9181ad6265SDimitry Andric   static const bool value = decltype(__test<_Tp>(0))::value;
92e8d8bef9SDimitry Andric };
93e8d8bef9SDimitry Andric 
94e8d8bef9SDimitry Andric template <class _Tp, class _Up, bool = __has_rebind<_Tp, _Up>::value>
95cb14a3feSDimitry Andric struct __pointer_traits_rebind {
96e8d8bef9SDimitry Andric #ifndef _LIBCPP_CXX03_LANG
97349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG typename _Tp::template rebind<_Up> type;
98e8d8bef9SDimitry Andric #else
99349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG typename _Tp::template rebind<_Up>::other type;
100e8d8bef9SDimitry Andric #endif
101e8d8bef9SDimitry Andric };
102e8d8bef9SDimitry Andric 
103e8d8bef9SDimitry Andric template <template <class, class...> class _Sp, class _Tp, class... _Args, class _Up>
104cb14a3feSDimitry Andric struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, true> {
105e8d8bef9SDimitry Andric #ifndef _LIBCPP_CXX03_LANG
106349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::template rebind<_Up> type;
107e8d8bef9SDimitry Andric #else
108349cc55cSDimitry Andric   typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::template rebind<_Up>::other type;
109e8d8bef9SDimitry Andric #endif
110e8d8bef9SDimitry Andric };
111e8d8bef9SDimitry Andric 
112e8d8bef9SDimitry Andric template <template <class, class...> class _Sp, class _Tp, class... _Args, class _Up>
113cb14a3feSDimitry Andric struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, false> {
114e8d8bef9SDimitry Andric   typedef _Sp<_Up, _Args...> type;
115e8d8bef9SDimitry Andric };
116e8d8bef9SDimitry Andric 
1175f757f3fSDimitry Andric template <class _Ptr, class = void>
1185f757f3fSDimitry Andric struct __pointer_traits_impl {};
1195f757f3fSDimitry Andric 
120e8d8bef9SDimitry Andric template <class _Ptr>
1215f757f3fSDimitry Andric struct __pointer_traits_impl<_Ptr, __void_t<typename __pointer_traits_element_type<_Ptr>::type> > {
122e8d8bef9SDimitry Andric   typedef _Ptr pointer;
123e8d8bef9SDimitry Andric   typedef typename __pointer_traits_element_type<pointer>::type element_type;
124e8d8bef9SDimitry Andric   typedef typename __pointer_traits_difference_type<pointer>::type difference_type;
125e8d8bef9SDimitry Andric 
126e8d8bef9SDimitry Andric #ifndef _LIBCPP_CXX03_LANG
127cb14a3feSDimitry Andric   template <class _Up>
128cb14a3feSDimitry Andric   using rebind = typename __pointer_traits_rebind<pointer, _Up>::type;
129e8d8bef9SDimitry Andric #else
130cb14a3feSDimitry Andric   template <class _Up>
131cb14a3feSDimitry Andric   struct rebind {
132cb14a3feSDimitry Andric     typedef typename __pointer_traits_rebind<pointer, _Up>::type other;
133cb14a3feSDimitry Andric   };
134e8d8bef9SDimitry Andric #endif // _LIBCPP_CXX03_LANG
135e8d8bef9SDimitry Andric 
136e8d8bef9SDimitry Andric private:
137e8d8bef9SDimitry Andric   struct __nat {};
138cb14a3feSDimitry Andric 
139e8d8bef9SDimitry Andric public:
140cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer
141cb14a3feSDimitry Andric   pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) {
142cb14a3feSDimitry Andric     return pointer::pointer_to(__r);
143cb14a3feSDimitry Andric   }
144e8d8bef9SDimitry Andric };
145e8d8bef9SDimitry Andric 
1465f757f3fSDimitry Andric template <class _Ptr>
1475f757f3fSDimitry Andric struct _LIBCPP_TEMPLATE_VIS pointer_traits : __pointer_traits_impl<_Ptr> {};
1485f757f3fSDimitry Andric 
149e8d8bef9SDimitry Andric template <class _Tp>
150cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS pointer_traits<_Tp*> {
151e8d8bef9SDimitry Andric   typedef _Tp* pointer;
152e8d8bef9SDimitry Andric   typedef _Tp element_type;
153e8d8bef9SDimitry Andric   typedef ptrdiff_t difference_type;
154e8d8bef9SDimitry Andric 
155e8d8bef9SDimitry Andric #ifndef _LIBCPP_CXX03_LANG
156cb14a3feSDimitry Andric   template <class _Up>
157cb14a3feSDimitry Andric   using rebind = _Up*;
158e8d8bef9SDimitry Andric #else
159cb14a3feSDimitry Andric   template <class _Up>
160cb14a3feSDimitry Andric   struct rebind {
161cb14a3feSDimitry Andric     typedef _Up* other;
162cb14a3feSDimitry Andric   };
163e8d8bef9SDimitry Andric #endif
164e8d8bef9SDimitry Andric 
165e8d8bef9SDimitry Andric private:
166e8d8bef9SDimitry Andric   struct __nat {};
167cb14a3feSDimitry Andric 
168e8d8bef9SDimitry Andric public:
169cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer
170cb14a3feSDimitry Andric   pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) _NOEXCEPT {
171cb14a3feSDimitry Andric     return std::addressof(__r);
172cb14a3feSDimitry Andric   }
173e8d8bef9SDimitry Andric };
174e8d8bef9SDimitry Andric 
175e8d8bef9SDimitry Andric #ifndef _LIBCPP_CXX03_LANG
176bdd1243dSDimitry Andric template <class _From, class _To>
177bdd1243dSDimitry Andric using __rebind_pointer_t = typename pointer_traits<_From>::template rebind<_To>;
178e8d8bef9SDimitry Andric #else
179bdd1243dSDimitry Andric template <class _From, class _To>
180bdd1243dSDimitry Andric using __rebind_pointer_t = typename pointer_traits<_From>::template rebind<_To>::other;
181e8d8bef9SDimitry Andric #endif
182e8d8bef9SDimitry Andric 
183fe6060f1SDimitry Andric // to_address
184fe6060f1SDimitry Andric 
185fe6060f1SDimitry Andric template <class _Pointer, class = void>
186fe6060f1SDimitry Andric struct __to_address_helper;
187fe6060f1SDimitry Andric 
188fe6060f1SDimitry Andric template <class _Tp>
189cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* __to_address(_Tp* __p) _NOEXCEPT {
190fe6060f1SDimitry Andric   static_assert(!is_function<_Tp>::value, "_Tp is a function type");
191fe6060f1SDimitry Andric   return __p;
192fe6060f1SDimitry Andric }
193fe6060f1SDimitry Andric 
19461cfbce3SDimitry Andric template <class _Pointer, class = void>
19561cfbce3SDimitry Andric struct _HasToAddress : false_type {};
19661cfbce3SDimitry Andric 
19761cfbce3SDimitry Andric template <class _Pointer>
198cb14a3feSDimitry Andric struct _HasToAddress<_Pointer, decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>())) >
199cb14a3feSDimitry Andric     : true_type {};
20061cfbce3SDimitry Andric 
20161cfbce3SDimitry Andric template <class _Pointer, class = void>
20261cfbce3SDimitry Andric struct _HasArrow : false_type {};
20361cfbce3SDimitry Andric 
20461cfbce3SDimitry Andric template <class _Pointer>
205cb14a3feSDimitry Andric struct _HasArrow<_Pointer, decltype((void)std::declval<const _Pointer&>().operator->()) > : true_type {};
20661cfbce3SDimitry Andric 
20761cfbce3SDimitry Andric template <class _Pointer>
20861cfbce3SDimitry Andric struct _IsFancyPointer {
20961cfbce3SDimitry Andric   static const bool value = _HasArrow<_Pointer>::value || _HasToAddress<_Pointer>::value;
21061cfbce3SDimitry Andric };
21161cfbce3SDimitry Andric 
212fe6060f1SDimitry Andric // enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers
213*0fca6ea1SDimitry Andric template <class _Pointer, __enable_if_t< _And<is_class<_Pointer>, _IsFancyPointer<_Pointer> >::value, int> = 0>
214*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI
215*0fca6ea1SDimitry Andric _LIBCPP_CONSTEXPR __decay_t<decltype(__to_address_helper<_Pointer>::__call(std::declval<const _Pointer&>()))>
216fe6060f1SDimitry Andric __to_address(const _Pointer& __p) _NOEXCEPT {
217fe6060f1SDimitry Andric   return __to_address_helper<_Pointer>::__call(__p);
218fe6060f1SDimitry Andric }
219fe6060f1SDimitry Andric 
220fe6060f1SDimitry Andric template <class _Pointer, class>
221fe6060f1SDimitry Andric struct __to_address_helper {
222*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI
223*0fca6ea1SDimitry Andric   _LIBCPP_CONSTEXPR static decltype(std::__to_address(std::declval<const _Pointer&>().operator->()))
224fe6060f1SDimitry Andric   __call(const _Pointer& __p) _NOEXCEPT {
2255f757f3fSDimitry Andric     return std::__to_address(__p.operator->());
226fe6060f1SDimitry Andric   }
227fe6060f1SDimitry Andric };
228fe6060f1SDimitry Andric 
229fe6060f1SDimitry Andric template <class _Pointer>
230cb14a3feSDimitry Andric struct __to_address_helper<_Pointer,
231cb14a3feSDimitry Andric                            decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))> {
232*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI
233*0fca6ea1SDimitry Andric   _LIBCPP_CONSTEXPR static decltype(pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))
234fe6060f1SDimitry Andric   __call(const _Pointer& __p) _NOEXCEPT {
235fe6060f1SDimitry Andric     return pointer_traits<_Pointer>::to_address(__p);
236fe6060f1SDimitry Andric   }
237fe6060f1SDimitry Andric };
238fe6060f1SDimitry Andric 
23906c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
240349cc55cSDimitry Andric template <class _Tp>
241cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI constexpr auto to_address(_Tp* __p) noexcept {
2425f757f3fSDimitry Andric   return std::__to_address(__p);
243349cc55cSDimitry Andric }
244349cc55cSDimitry Andric 
245fe6060f1SDimitry Andric template <class _Pointer>
246*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI constexpr auto
247*0fca6ea1SDimitry Andric to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) {
2485f757f3fSDimitry Andric   return std::__to_address(__p);
249fe6060f1SDimitry Andric }
250fe6060f1SDimitry Andric #endif
251fe6060f1SDimitry Andric 
252*0fca6ea1SDimitry Andric #if _LIBCPP_STD_VER >= 23
253*0fca6ea1SDimitry Andric 
254*0fca6ea1SDimitry Andric template <class _Tp>
255*0fca6ea1SDimitry Andric struct __pointer_of {};
256*0fca6ea1SDimitry Andric 
257*0fca6ea1SDimitry Andric template <class _Tp>
258*0fca6ea1SDimitry Andric   requires(__has_pointer<_Tp>::value)
259*0fca6ea1SDimitry Andric struct __pointer_of<_Tp> {
260*0fca6ea1SDimitry Andric   using type = typename _Tp::pointer;
261*0fca6ea1SDimitry Andric };
262*0fca6ea1SDimitry Andric 
263*0fca6ea1SDimitry Andric template <class _Tp>
264*0fca6ea1SDimitry Andric   requires(!__has_pointer<_Tp>::value && __has_element_type<_Tp>::value)
265*0fca6ea1SDimitry Andric struct __pointer_of<_Tp> {
266*0fca6ea1SDimitry Andric   using type = typename _Tp::element_type*;
267*0fca6ea1SDimitry Andric };
268*0fca6ea1SDimitry Andric 
269*0fca6ea1SDimitry Andric template <class _Tp>
270*0fca6ea1SDimitry Andric   requires(!__has_pointer<_Tp>::value && !__has_element_type<_Tp>::value &&
271*0fca6ea1SDimitry Andric            __has_element_type<pointer_traits<_Tp>>::value)
272*0fca6ea1SDimitry Andric struct __pointer_of<_Tp> {
273*0fca6ea1SDimitry Andric   using type = typename pointer_traits<_Tp>::element_type*;
274*0fca6ea1SDimitry Andric };
275*0fca6ea1SDimitry Andric 
276*0fca6ea1SDimitry Andric template <typename _Tp>
277*0fca6ea1SDimitry Andric using __pointer_of_t = typename __pointer_of<_Tp>::type;
278*0fca6ea1SDimitry Andric 
279*0fca6ea1SDimitry Andric template <class _Tp, class _Up>
280*0fca6ea1SDimitry Andric struct __pointer_of_or {
281*0fca6ea1SDimitry Andric   using type _LIBCPP_NODEBUG = _Up;
282*0fca6ea1SDimitry Andric };
283*0fca6ea1SDimitry Andric 
284*0fca6ea1SDimitry Andric template <class _Tp, class _Up>
285*0fca6ea1SDimitry Andric   requires requires { typename __pointer_of_t<_Tp>; }
286*0fca6ea1SDimitry Andric struct __pointer_of_or<_Tp, _Up> {
287*0fca6ea1SDimitry Andric   using type _LIBCPP_NODEBUG = __pointer_of_t<_Tp>;
288*0fca6ea1SDimitry Andric };
289*0fca6ea1SDimitry Andric 
290*0fca6ea1SDimitry Andric template <typename _Tp, typename _Up>
291*0fca6ea1SDimitry Andric using __pointer_of_or_t = typename __pointer_of_or<_Tp, _Up>::type;
292*0fca6ea1SDimitry Andric 
293*0fca6ea1SDimitry Andric template <class _Smart>
294*0fca6ea1SDimitry Andric concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); };
295*0fca6ea1SDimitry Andric 
296*0fca6ea1SDimitry Andric template <class _Smart, class _Pointer, class... _Args>
297*0fca6ea1SDimitry Andric concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p, _Args... __args) {
298*0fca6ea1SDimitry Andric   __s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...);
299*0fca6ea1SDimitry Andric };
300*0fca6ea1SDimitry Andric 
301*0fca6ea1SDimitry Andric #endif
302*0fca6ea1SDimitry Andric 
303e8d8bef9SDimitry Andric _LIBCPP_END_NAMESPACE_STD
304e8d8bef9SDimitry Andric 
305*0fca6ea1SDimitry Andric _LIBCPP_POP_MACROS
306*0fca6ea1SDimitry Andric 
307e8d8bef9SDimitry Andric #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H
308