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