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/decay.h>
18#include <__type_traits/detected_or.h>
19#include <__type_traits/enable_if.h>
20#include <__type_traits/integral_constant.h>
21#include <__type_traits/is_function.h>
22#include <__type_traits/is_void.h>
23#include <__type_traits/nat.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
37template <class _Ptr>
38struct __pointer_traits_element_type_impl {};
39
40template <template <class, class...> class _Sp, class _Tp, class... _Args>
41struct __pointer_traits_element_type_impl<_Sp<_Tp, _Args...> > {
42 using type _LIBCPP_NODEBUG = _Tp;
43};
44
45template <class _Ptr, class = void>
46struct __pointer_traits_element_type : __pointer_traits_element_type_impl<_Ptr> {};
47
48template <class _Ptr>
49struct __pointer_traits_element_type<_Ptr, __void_t<typename _Ptr::element_type> > {
50 using type _LIBCPP_NODEBUG = typename _Ptr::element_type;
51};
52
53template <class _Tp, class _Up>
54struct __pointer_traits_rebind_impl {
55 static_assert(false, "Cannot rebind pointer; did you forget to add a rebind member to your pointer?");
56};
57
58template <template <class, class...> class _Sp, class _Tp, class... _Args, class _Up>
59struct __pointer_traits_rebind_impl<_Sp<_Tp, _Args...>, _Up> {
60 using type _LIBCPP_NODEBUG = _Sp<_Up, _Args...>;
61};
62
63template <class _Tp, class _Up, class = void>
64struct __pointer_traits_rebind : __pointer_traits_rebind_impl<_Tp, _Up> {};
65
66template <class _Tp, class _Up>
67struct __pointer_traits_rebind<_Tp, _Up, __void_t<typename _Tp::template rebind<_Up> > > {
68#ifndef _LIBCPP_CXX03_LANG
69 using type _LIBCPP_NODEBUG = typename _Tp::template rebind<_Up>;
70#else
71 using type _LIBCPP_NODEBUG = typename _Tp::template rebind<_Up>::other;
72#endif
73};
74
75template <class _Tp>
76using __difference_type_member _LIBCPP_NODEBUG = typename _Tp::difference_type;
77
78template <class _Ptr, class = void>
79struct __pointer_traits_impl {};
80
81template <class _Ptr>
82struct __pointer_traits_impl<_Ptr, __void_t<typename __pointer_traits_element_type<_Ptr>::type> > {
83 typedef _Ptr pointer;
84 typedef typename __pointer_traits_element_type<pointer>::type element_type;
85 using difference_type = __detected_or_t<ptrdiff_t, __difference_type_member, pointer>;
86
87#ifndef _LIBCPP_CXX03_LANG
88 template <class _Up>
89 using rebind = typename __pointer_traits_rebind<pointer, _Up>::type;
90#else
91 template <class _Up>
92 struct rebind {
93 typedef typename __pointer_traits_rebind<pointer, _Up>::type other;
94 };
95#endif // _LIBCPP_CXX03_LANG
96
97public:
98 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer
99 pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) {
100 return pointer::pointer_to(__r);
101 }
102};
103
104template <class _Ptr>
105struct pointer_traits : __pointer_traits_impl<_Ptr> {};
106
107template <class _Tp>
108struct pointer_traits<_Tp*> {
109 typedef _Tp* pointer;
110 typedef _Tp element_type;
111 typedef ptrdiff_t difference_type;
112
113#ifndef _LIBCPP_CXX03_LANG
114 template <class _Up>
115 using rebind = _Up*;
116#else
117 template <class _Up>
118 struct rebind {
119 typedef _Up* other;
120 };
121#endif
122
123public:
124 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer
125 pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) _NOEXCEPT {
126 return std::addressof(__r);
127 }
128};
129
130#ifndef _LIBCPP_CXX03_LANG
131template <class _From, class _To>
132using __rebind_pointer_t _LIBCPP_NODEBUG = typename pointer_traits<_From>::template rebind<_To>;
133#else
134template <class _From, class _To>
135using __rebind_pointer_t _LIBCPP_NODEBUG = typename pointer_traits<_From>::template rebind<_To>::other;
136#endif
137
138// to_address
139
140template <class _Tp>
141_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* __to_address(_Tp* __p) _NOEXCEPT {
142 static_assert(!is_function<_Tp>::value, "_Tp is a function type");
143 return __p;
144}
145
146template <class _Pointer, class = void>
147inline const bool __has_to_address_v = false;
148
149template <class _Pointer>
150inline const bool
151 __has_to_address_v<_Pointer,
152 decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))> = true;
153
154template <class _Pointer, class = void>
155inline const bool __has_arrow_v = false;
156
157template <class _Pointer>
158inline const bool __has_arrow_v<_Pointer, decltype((void)std::declval<const _Pointer&>().operator->()) > = true;
159
160template <class _Pointer, __enable_if_t<__has_to_address_v<_Pointer>, int> = 0>
161_LIBCPP_CONSTEXPR __decay_t<decltype(pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))>
162__to_address(const _Pointer& __p) _NOEXCEPT {
163 return pointer_traits<_Pointer>::to_address(__p);
164}
165
166template <class _Pointer>
167struct __to_address_arrow_result;
168
169template <class _Pointer, __enable_if_t<!__has_to_address_v<_Pointer> && __has_arrow_v<_Pointer>, int> = 0>
170_LIBCPP_CONSTEXPR typename __to_address_arrow_result<_Pointer>::type __to_address(const _Pointer& __p) _NOEXCEPT {
171 return std::__to_address(__p.operator->());
172}
173
174// The return type needs to see all `__to_address` overloads, so this is delayed until after all the overloads have been
175// defined. This could also be moved to a trailing return type, but that's not available in C++03.
176template <class _Pointer>
177struct __to_address_arrow_result {
178 using type _LIBCPP_NODEBUG = __decay_t<decltype(std::__to_address(std::declval<const _Pointer&>().operator->()))>;
179};
180
181#if _LIBCPP_STD_VER >= 20
182template <class _Tp>
183inline _LIBCPP_HIDE_FROM_ABI constexpr auto to_address(_Tp* __p) noexcept {
184 return std::__to_address(__p);
185}
186
187template <class _Pointer>
188inline _LIBCPP_HIDE_FROM_ABI constexpr auto to_address(const _Pointer& __p) noexcept
189 -> decltype(std::__to_address(__p)) {
190 return std::__to_address(__p);
191}
192#endif
193
194#if _LIBCPP_STD_VER >= 23
195
196template <class _Tp>
197struct __pointer_of {};
198
199template <class _Tp>
200concept __has_pointer_member = requires { typename _Tp::pointer; };
201
202template <class _Tp>
203concept __has_element_type_member = requires { typename _Tp::element_type; };
204
205template <class _Tp>
206 requires __has_pointer_member<_Tp>
207struct __pointer_of<_Tp> {
208 using type _LIBCPP_NODEBUG = typename _Tp::pointer;
209};
210
211template <class _Tp>
212 requires(!__has_pointer_member<_Tp> && __has_element_type_member<_Tp>)
213struct __pointer_of<_Tp> {
214 using type _LIBCPP_NODEBUG = typename _Tp::element_type*;
215};
216
217template <class _Tp>
218 requires(!__has_pointer_member<_Tp> && !__has_element_type_member<_Tp> &&
219 __has_element_type_member<pointer_traits<_Tp>>)
220struct __pointer_of<_Tp> {
221 using type _LIBCPP_NODEBUG = typename pointer_traits<_Tp>::element_type*;
222};
223
224template <typename _Tp>
225using __pointer_of_t _LIBCPP_NODEBUG = typename __pointer_of<_Tp>::type;
226
227template <typename _Tp, typename _Up>
228using __pointer_of_or_t _LIBCPP_NODEBUG = __detected_or_t<_Up, __pointer_of_t, _Tp>;
229
230template <class _Smart>
231concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); };
232
233template <class _Smart, class _Pointer, class... _Args>
234concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p, _Args... __args) {
235 __s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...);
236};
237
238#endif
239
240// This function ensures safe conversions between fancy pointers at compile-time, where we avoid casts from/to
241// `__void_pointer` by obtaining the underlying raw pointer from the fancy pointer using `std::to_address`,
242// then dereferencing it to retrieve the pointed-to object, and finally constructing the target fancy pointer
243// to that object using the `std::pointer_traits<>::pointer_to` function.
244template <class _PtrTo, class _PtrFrom>
245_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _PtrTo __static_fancy_pointer_cast(const _PtrFrom& __p) {
246 using __ptr_traits = pointer_traits<_PtrTo>;
247 using __element_type = typename __ptr_traits::element_type;
248 return __p ? __ptr_traits::pointer_to(*static_cast<__element_type*>(std::addressof(*__p)))
249 : static_cast<_PtrTo>(nullptr);
250}
251
252_LIBCPP_END_NAMESPACE_STD
253
254_LIBCPP_POP_MACROS
255
256#endif // _LIBCPP___MEMORY_POINTER_TRAITS_H
257