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 <cstddef>
16 #include <type_traits>
17 
18 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19 #  pragma GCC system_header
20 #endif
21 
22 _LIBCPP_BEGIN_NAMESPACE_STD
23 
24 template <class _Tp, class = void>
25 struct __has_element_type : false_type {};
26 
27 template <class _Tp>
28 struct __has_element_type<_Tp,
29               typename __void_t<typename _Tp::element_type>::type> : true_type {};
30 
31 template <class _Ptr, bool = __has_element_type<_Ptr>::value>
32 struct __pointer_traits_element_type;
33 
34 template <class _Ptr>
35 struct __pointer_traits_element_type<_Ptr, true>
36 {
37     typedef _LIBCPP_NODEBUG typename _Ptr::element_type type;
38 };
39 
40 template <template <class, class...> class _Sp, class _Tp, class ..._Args>
41 struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, true>
42 {
43     typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::element_type type;
44 };
45 
46 template <template <class, class...> class _Sp, class _Tp, class ..._Args>
47 struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, false>
48 {
49     typedef _LIBCPP_NODEBUG _Tp type;
50 };
51 
52 template <class _Tp, class = void>
53 struct __has_difference_type : false_type {};
54 
55 template <class _Tp>
56 struct __has_difference_type<_Tp,
57             typename __void_t<typename _Tp::difference_type>::type> : true_type {};
58 
59 template <class _Ptr, bool = __has_difference_type<_Ptr>::value>
60 struct __pointer_traits_difference_type
61 {
62     typedef _LIBCPP_NODEBUG ptrdiff_t type;
63 };
64 
65 template <class _Ptr>
66 struct __pointer_traits_difference_type<_Ptr, true>
67 {
68     typedef _LIBCPP_NODEBUG typename _Ptr::difference_type type;
69 };
70 
71 template <class _Tp, class _Up>
72 struct __has_rebind
73 {
74 private:
75     template <class _Xp> static false_type __test(...);
76     _LIBCPP_SUPPRESS_DEPRECATED_PUSH
77     template <class _Xp> static true_type __test(typename _Xp::template rebind<_Up>* = 0);
78     _LIBCPP_SUPPRESS_DEPRECATED_POP
79 public:
80     static const bool value = decltype(__test<_Tp>(0))::value;
81 };
82 
83 template <class _Tp, class _Up, bool = __has_rebind<_Tp, _Up>::value>
84 struct __pointer_traits_rebind
85 {
86 #ifndef _LIBCPP_CXX03_LANG
87     typedef _LIBCPP_NODEBUG typename _Tp::template rebind<_Up> type;
88 #else
89     typedef _LIBCPP_NODEBUG typename _Tp::template rebind<_Up>::other type;
90 #endif
91 };
92 
93 template <template <class, class...> class _Sp, class _Tp, class ..._Args, class _Up>
94 struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, true>
95 {
96 #ifndef _LIBCPP_CXX03_LANG
97     typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::template rebind<_Up> type;
98 #else
99     typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::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, false>
105 {
106     typedef _Sp<_Up, _Args...> type;
107 };
108 
109 template <class _Ptr>
110 struct _LIBCPP_TEMPLATE_VIS pointer_traits
111 {
112     typedef _Ptr                                                     pointer;
113     typedef typename __pointer_traits_element_type<pointer>::type    element_type;
114     typedef typename __pointer_traits_difference_type<pointer>::type difference_type;
115 
116 #ifndef _LIBCPP_CXX03_LANG
117     template <class _Up> using rebind = typename __pointer_traits_rebind<pointer, _Up>::type;
118 #else
119     template <class _Up> struct rebind
120         {typedef typename __pointer_traits_rebind<pointer, _Up>::type other;};
121 #endif // _LIBCPP_CXX03_LANG
122 
123 private:
124     struct __nat {};
125 public:
126     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
127     static pointer pointer_to(typename conditional<is_void<element_type>::value,
128                                            __nat, element_type>::type& __r)
129         {return pointer::pointer_to(__r);}
130 };
131 
132 template <class _Tp>
133 struct _LIBCPP_TEMPLATE_VIS pointer_traits<_Tp*>
134 {
135     typedef _Tp*      pointer;
136     typedef _Tp       element_type;
137     typedef ptrdiff_t difference_type;
138 
139 #ifndef _LIBCPP_CXX03_LANG
140     template <class _Up> using rebind = _Up*;
141 #else
142     template <class _Up> struct rebind {typedef _Up* other;};
143 #endif
144 
145 private:
146     struct __nat {};
147 public:
148     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
149     static pointer pointer_to(typename conditional<is_void<element_type>::value,
150                                       __nat, element_type>::type& __r) _NOEXCEPT
151         {return _VSTD::addressof(__r);}
152 };
153 
154 template <class _From, class _To>
155 struct __rebind_pointer {
156 #ifndef _LIBCPP_CXX03_LANG
157     typedef typename pointer_traits<_From>::template rebind<_To>        type;
158 #else
159     typedef typename pointer_traits<_From>::template rebind<_To>::other type;
160 #endif
161 };
162 
163 // to_address
164 
165 template <class _Pointer, class = void>
166 struct __to_address_helper;
167 
168 template <class _Tp>
169 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
170 _Tp* __to_address(_Tp* __p) _NOEXCEPT {
171     static_assert(!is_function<_Tp>::value, "_Tp is a function type");
172     return __p;
173 }
174 
175 template <class _Pointer, class = void>
176 struct _HasToAddress : false_type {};
177 
178 template <class _Pointer>
179 struct _HasToAddress<_Pointer,
180     decltype((void)pointer_traits<_Pointer>::to_address(declval<const _Pointer&>()))
181 > : true_type {};
182 
183 template <class _Pointer, class = void>
184 struct _HasArrow : false_type {};
185 
186 template <class _Pointer>
187 struct _HasArrow<_Pointer,
188     decltype((void)declval<const _Pointer&>().operator->())
189 > : true_type {};
190 
191 template <class _Pointer>
192 struct _IsFancyPointer {
193   static const bool value = _HasArrow<_Pointer>::value || _HasToAddress<_Pointer>::value;
194 };
195 
196 // enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers
197 template <class _Pointer, class = __enable_if_t<
198     _And<is_class<_Pointer>, _IsFancyPointer<_Pointer> >::value
199 > >
200 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
201 typename decay<decltype(__to_address_helper<_Pointer>::__call(declval<const _Pointer&>()))>::type
202 __to_address(const _Pointer& __p) _NOEXCEPT {
203     return __to_address_helper<_Pointer>::__call(__p);
204 }
205 
206 template <class _Pointer, class>
207 struct __to_address_helper {
208     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
209     static decltype(_VSTD::__to_address(declval<const _Pointer&>().operator->()))
210     __call(const _Pointer& __p) _NOEXCEPT {
211         return _VSTD::__to_address(__p.operator->());
212     }
213 };
214 
215 template <class _Pointer>
216 struct __to_address_helper<_Pointer, decltype((void)pointer_traits<_Pointer>::to_address(declval<const _Pointer&>()))> {
217     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
218     static decltype(pointer_traits<_Pointer>::to_address(declval<const _Pointer&>()))
219     __call(const _Pointer& __p) _NOEXCEPT {
220         return pointer_traits<_Pointer>::to_address(__p);
221     }
222 };
223 
224 #if _LIBCPP_STD_VER > 17
225 template <class _Tp>
226 inline _LIBCPP_INLINE_VISIBILITY constexpr
227 auto to_address(_Tp *__p) noexcept {
228     return _VSTD::__to_address(__p);
229 }
230 
231 template <class _Pointer>
232 inline _LIBCPP_INLINE_VISIBILITY constexpr
233 auto to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) {
234     return _VSTD::__to_address(__p);
235 }
236 #endif
237 
238 _LIBCPP_END_NAMESPACE_STD
239 
240 #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H
241