1 | // Pointer Traits -*- C++ -*- |
2 | |
3 | // Copyright (C) 2011-2024 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file bits/ptr_traits.h |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{memory} |
28 | */ |
29 | |
30 | #ifndef _PTR_TRAITS_H |
31 | #define _PTR_TRAITS_H 1 |
32 | |
33 | #if __cplusplus >= 201103L |
34 | |
35 | #include <bits/move.h> |
36 | |
37 | #if __cplusplus > 201703L |
38 | #include <concepts> |
39 | namespace __gnu_debug { struct _Safe_iterator_base; } |
40 | #endif |
41 | |
42 | namespace std _GLIBCXX_VISIBILITY(default) |
43 | { |
44 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
45 | |
46 | /// @cond undocumented |
47 | |
48 | class __undefined; |
49 | |
50 | // For a specialization `SomeTemplate<T, Types...>` the member `type` is T, |
51 | // otherwise `type` is `__undefined`. |
52 | template<typename _Tp> |
53 | struct __get_first_arg |
54 | { using type = __undefined; }; |
55 | |
56 | template<template<typename, typename...> class _SomeTemplate, typename _Tp, |
57 | typename... _Types> |
58 | struct __get_first_arg<_SomeTemplate<_Tp, _Types...>> |
59 | { using type = _Tp; }; |
60 | |
61 | // For a specialization `SomeTemplate<T, Args...>` and a type `U` the member |
62 | // `type` is `SomeTemplate<U, Args...>`, otherwise there is no member `type`. |
63 | template<typename _Tp, typename _Up> |
64 | struct __replace_first_arg |
65 | { }; |
66 | |
67 | template<template<typename, typename...> class _SomeTemplate, typename _Up, |
68 | typename _Tp, typename... _Types> |
69 | struct __replace_first_arg<_SomeTemplate<_Tp, _Types...>, _Up> |
70 | { using type = _SomeTemplate<_Up, _Types...>; }; |
71 | |
72 | // Detect the element type of a pointer-like type. |
73 | template<typename _Ptr, typename = void> |
74 | struct __ptr_traits_elem : __get_first_arg<_Ptr> |
75 | { }; |
76 | |
77 | // Use _Ptr::element_type if is a valid type. |
78 | #if __cpp_concepts |
79 | template<typename _Ptr> requires requires { typename _Ptr::element_type; } |
80 | struct __ptr_traits_elem<_Ptr, void> |
81 | { using type = typename _Ptr::element_type; }; |
82 | #else |
83 | template<typename _Ptr> |
84 | struct __ptr_traits_elem<_Ptr, __void_t<typename _Ptr::element_type>> |
85 | { using type = typename _Ptr::element_type; }; |
86 | #endif |
87 | |
88 | template<typename _Ptr> |
89 | using __ptr_traits_elem_t = typename __ptr_traits_elem<_Ptr>::type; |
90 | |
91 | /// @endcond |
92 | |
93 | // Define pointer_traits<P>::pointer_to. |
94 | template<typename _Ptr, typename _Elt, bool = is_void<_Elt>::value> |
95 | struct __ptr_traits_ptr_to |
96 | { |
97 | using pointer = _Ptr; |
98 | using element_type = _Elt; |
99 | |
100 | /** |
101 | * @brief Obtain a pointer to an object |
102 | * @param __r A reference to an object of type `element_type` |
103 | * @return `pointer::pointer_to(__r)` |
104 | * @pre `pointer::pointer_to(__r)` is a valid expression. |
105 | */ |
106 | static pointer |
107 | pointer_to(element_type& __r) |
108 | #if __cpp_lib_concepts |
109 | requires requires { |
110 | { pointer::pointer_to(__r) } -> convertible_to<pointer>; |
111 | } |
112 | #endif |
113 | { return pointer::pointer_to(__r); } |
114 | }; |
115 | |
116 | // Do not define pointer_traits<P>::pointer_to if element type is void. |
117 | template<typename _Ptr, typename _Elt> |
118 | struct __ptr_traits_ptr_to<_Ptr, _Elt, true> |
119 | { }; |
120 | |
121 | // Partial specialization defining pointer_traits<T*>::pointer_to(T&). |
122 | template<typename _Tp> |
123 | struct __ptr_traits_ptr_to<_Tp*, _Tp, false> |
124 | { |
125 | using pointer = _Tp*; |
126 | using element_type = _Tp; |
127 | |
128 | /** |
129 | * @brief Obtain a pointer to an object |
130 | * @param __r A reference to an object of type `element_type` |
131 | * @return `addressof(__r)` |
132 | */ |
133 | static _GLIBCXX20_CONSTEXPR pointer |
134 | pointer_to(element_type& __r) noexcept |
135 | { return std::addressof(__r); } |
136 | }; |
137 | |
138 | template<typename _Ptr, typename _Elt> |
139 | struct __ptr_traits_impl : __ptr_traits_ptr_to<_Ptr, _Elt> |
140 | { |
141 | private: |
142 | template<typename _Tp> |
143 | using __diff_t = typename _Tp::difference_type; |
144 | |
145 | template<typename _Tp, typename _Up> |
146 | using __rebind = __type_identity<typename _Tp::template rebind<_Up>>; |
147 | |
148 | public: |
149 | /// The pointer type. |
150 | using pointer = _Ptr; |
151 | |
152 | /// The type pointed to. |
153 | using element_type = _Elt; |
154 | |
155 | /// The type used to represent the difference between two pointers. |
156 | using difference_type = __detected_or_t<ptrdiff_t, __diff_t, _Ptr>; |
157 | |
158 | /// A pointer to a different type. |
159 | template<typename _Up> |
160 | using rebind = typename __detected_or_t<__replace_first_arg<_Ptr, _Up>, |
161 | __rebind, _Ptr, _Up>::type; |
162 | }; |
163 | |
164 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
165 | // 3545. std::pointer_traits should be SFINAE-friendly |
166 | template<typename _Ptr> |
167 | struct __ptr_traits_impl<_Ptr, __undefined> |
168 | { }; |
169 | |
170 | /** |
171 | * @brief Uniform interface to all pointer-like types |
172 | * @headerfile memory |
173 | * @ingroup pointer_abstractions |
174 | * @since C++11 |
175 | */ |
176 | template<typename _Ptr> |
177 | struct pointer_traits : __ptr_traits_impl<_Ptr, __ptr_traits_elem_t<_Ptr>> |
178 | { }; |
179 | |
180 | /** |
181 | * @brief Partial specialization for built-in pointers. |
182 | * @headerfile memory |
183 | * @ingroup pointer_abstractions |
184 | * @since C++11 |
185 | */ |
186 | template<typename _Tp> |
187 | struct pointer_traits<_Tp*> : __ptr_traits_ptr_to<_Tp*, _Tp> |
188 | { |
189 | /// The pointer type |
190 | typedef _Tp* pointer; |
191 | /// The type pointed to |
192 | typedef _Tp element_type; |
193 | /// Type used to represent the difference between two pointers |
194 | typedef ptrdiff_t difference_type; |
195 | /// A pointer to a different type. |
196 | template<typename _Up> using rebind = _Up*; |
197 | }; |
198 | |
199 | /// Convenience alias for rebinding pointers. |
200 | template<typename _Ptr, typename _Tp> |
201 | using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>; |
202 | |
203 | template<typename _Tp> |
204 | constexpr _Tp* |
205 | __to_address(_Tp* __ptr) noexcept |
206 | { |
207 | static_assert(!std::is_function<_Tp>::value, "not a function pointer" ); |
208 | return __ptr; |
209 | } |
210 | |
211 | #ifndef __glibcxx_to_address // C++ < 20 |
212 | template<typename _Ptr> |
213 | constexpr typename std::pointer_traits<_Ptr>::element_type* |
214 | __to_address(const _Ptr& __ptr) |
215 | { return std::__to_address(__ptr.operator->()); } |
216 | #else |
217 | template<typename _Ptr> |
218 | constexpr auto |
219 | __to_address(const _Ptr& __ptr) noexcept |
220 | -> decltype(std::pointer_traits<_Ptr>::to_address(__ptr)) |
221 | { return std::pointer_traits<_Ptr>::to_address(__ptr); } |
222 | |
223 | template<typename _Ptr, typename... _None> |
224 | constexpr auto |
225 | __to_address(const _Ptr& __ptr, _None...) noexcept |
226 | { |
227 | if constexpr (is_base_of_v<__gnu_debug::_Safe_iterator_base, _Ptr>) |
228 | return std::__to_address(__ptr.base().operator->()); |
229 | else |
230 | return std::__to_address(__ptr.operator->()); |
231 | } |
232 | |
233 | /** |
234 | * @brief Obtain address referenced by a pointer to an object |
235 | * @param __ptr A pointer to an object |
236 | * @return @c __ptr |
237 | * @ingroup pointer_abstractions |
238 | */ |
239 | template<typename _Tp> |
240 | constexpr _Tp* |
241 | to_address(_Tp* __ptr) noexcept |
242 | { return std::__to_address(__ptr); } |
243 | |
244 | /** |
245 | * @brief Obtain address referenced by a pointer to an object |
246 | * @param __ptr A pointer to an object |
247 | * @return @c pointer_traits<_Ptr>::to_address(__ptr) if that expression is |
248 | well-formed, otherwise @c to_address(__ptr.operator->()) |
249 | * @ingroup pointer_abstractions |
250 | */ |
251 | template<typename _Ptr> |
252 | constexpr auto |
253 | to_address(const _Ptr& __ptr) noexcept |
254 | { return std::__to_address(__ptr); } |
255 | #endif // __glibcxx_to_address |
256 | |
257 | _GLIBCXX_END_NAMESPACE_VERSION |
258 | } // namespace std |
259 | |
260 | #endif |
261 | |
262 | #endif |
263 | |