1// Pointer Traits -*- C++ -*-
2
3// Copyright (C) 2011-2022 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# ifndef __cpp_lib_constexpr_memory
40// Defined to a newer value in bits/unique_ptr.h for C++23
41# define __cpp_lib_constexpr_memory 201811L
42# endif
43namespace __gnu_debug { struct _Safe_iterator_base; }
44#endif
45
46namespace std _GLIBCXX_VISIBILITY(default)
47{
48_GLIBCXX_BEGIN_NAMESPACE_VERSION
49
50 class __undefined;
51
52 // For a specialization `SomeTemplate<T, Types...>` the member `type` is T,
53 // otherwise `type` is `__undefined`.
54 template<typename _Tp>
55 struct __get_first_arg
56 { using type = __undefined; };
57
58 template<template<typename, typename...> class _SomeTemplate, typename _Tp,
59 typename... _Types>
60 struct __get_first_arg<_SomeTemplate<_Tp, _Types...>>
61 { using type = _Tp; };
62
63 // For a specialization `SomeTemplate<T, Args...>` and a type `U` the member
64 // `type` is `SomeTemplate<U, Args...>`, otherwise there is no member `type`.
65 template<typename _Tp, typename _Up>
66 struct __replace_first_arg
67 { };
68
69 template<template<typename, typename...> class _SomeTemplate, typename _Up,
70 typename _Tp, typename... _Types>
71 struct __replace_first_arg<_SomeTemplate<_Tp, _Types...>, _Up>
72 { using type = _SomeTemplate<_Up, _Types...>; };
73
74#if __cpp_concepts
75 // When concepts are supported detection of _Ptr::element_type is done
76 // by a requires-clause, so __ptr_traits_elem_t only needs to do this:
77 template<typename _Ptr>
78 using __ptr_traits_elem_t = typename __get_first_arg<_Ptr>::type;
79#else
80 // Detect the element type of a pointer-like type.
81 template<typename _Ptr, typename = void>
82 struct __ptr_traits_elem : __get_first_arg<_Ptr>
83 { };
84
85 // Use _Ptr::element_type if is a valid type.
86 template<typename _Ptr>
87 struct __ptr_traits_elem<_Ptr, __void_t<typename _Ptr::element_type>>
88 { using type = typename _Ptr::element_type; };
89
90 template<typename _Ptr>
91 using __ptr_traits_elem_t = typename __ptr_traits_elem<_Ptr>::type;
92#endif
93
94 // Define pointer_traits<P>::pointer_to.
95 template<typename _Ptr, typename _Elt, bool = is_void<_Elt>::value>
96 struct __ptr_traits_ptr_to
97 {
98 using pointer = _Ptr;
99 using element_type = _Elt;
100
101 /**
102 * @brief Obtain a pointer to an object
103 * @param __r A reference to an object of type `element_type`
104 * @return `pointer::pointer_to(__e)`
105 * @pre `pointer::pointer_to(__e)` is a valid expression.
106 */
107 static pointer
108 pointer_to(element_type& __e)
109#if __cpp_lib_concepts
110 requires requires {
111 { pointer::pointer_to(__e) } -> convertible_to<pointer>;
112 }
113#endif
114 { return pointer::pointer_to(__e); }
115 };
116
117 // Do not define pointer_traits<P>::pointer_to if element type is void.
118 template<typename _Ptr, typename _Elt>
119 struct __ptr_traits_ptr_to<_Ptr, _Elt, true>
120 { };
121
122 // Partial specialization defining pointer_traits<T*>::pointer_to(T&).
123 template<typename _Tp>
124 struct __ptr_traits_ptr_to<_Tp*, _Tp, false>
125 {
126 using pointer = _Tp*;
127 using element_type = _Tp;
128
129 /**
130 * @brief Obtain a pointer to an object
131 * @param __r A reference to an object of type `element_type`
132 * @return `addressof(__r)`
133 */
134 static _GLIBCXX20_CONSTEXPR pointer
135 pointer_to(element_type& __r) noexcept
136 { return std::addressof(__r); }
137 };
138
139 template<typename _Ptr, typename _Elt>
140 struct __ptr_traits_impl : __ptr_traits_ptr_to<_Ptr, _Elt>
141 {
142 private:
143 template<typename _Tp, typename = void>
144 struct __difference { using type = ptrdiff_t; };
145
146 template<typename _Tp>
147#if __cpp_concepts
148 requires requires { typename _Tp::difference_type; }
149 struct __difference<_Tp>
150#else
151 struct __difference<_Tp, __void_t<typename _Tp::difference_type>>
152#endif
153 { using type = typename _Tp::difference_type; };
154
155 template<typename _Tp, typename _Up, typename = void>
156 struct __rebind : __replace_first_arg<_Tp, _Up> { };
157
158 template<typename _Tp, typename _Up>
159#if __cpp_concepts
160 requires requires { typename _Tp::template rebind<_Up>; }
161 struct __rebind<_Tp, _Up>
162#else
163 struct __rebind<_Tp, _Up, __void_t<typename _Tp::template rebind<_Up>>>
164#endif
165 { using type = typename _Tp::template rebind<_Up>; };
166
167 public:
168 /// The pointer type.
169 using pointer = _Ptr;
170
171 /// The type pointed to.
172 using element_type = _Elt;
173
174 /// The type used to represent the difference between two pointers.
175 using difference_type = typename __difference<_Ptr>::type;
176
177 /// A pointer to a different type.
178 template<typename _Up>
179 using rebind = typename __rebind<_Ptr, _Up>::type;
180 };
181
182 // _GLIBCXX_RESOLVE_LIB_DEFECTS
183 // 3545. std::pointer_traits should be SFINAE-friendly
184 template<typename _Ptr>
185 struct __ptr_traits_impl<_Ptr, __undefined>
186 { };
187
188 /**
189 * @brief Uniform interface to all pointer-like types
190 * @ingroup pointer_abstractions
191 * @since C++11
192 */
193 template<typename _Ptr>
194 struct pointer_traits : __ptr_traits_impl<_Ptr, __ptr_traits_elem_t<_Ptr>>
195 { };
196
197#if __cpp_concepts
198 template<typename _Ptr> requires requires { typename _Ptr::element_type; }
199 struct pointer_traits<_Ptr>
200 : __ptr_traits_impl<_Ptr, typename _Ptr::element_type>
201 { };
202#endif
203
204 /**
205 * @brief Partial specialization for built-in pointers.
206 * @ingroup pointer_abstractions
207 * @since C++11
208 */
209 template<typename _Tp>
210 struct pointer_traits<_Tp*> : __ptr_traits_ptr_to<_Tp*, _Tp>
211 {
212 /// The pointer type
213 typedef _Tp* pointer;
214 /// The type pointed to
215 typedef _Tp element_type;
216 /// Type used to represent the difference between two pointers
217 typedef ptrdiff_t difference_type;
218 /// A pointer to a different type.
219 template<typename _Up> using rebind = _Up*;
220 };
221
222 /// Convenience alias for rebinding pointers.
223 template<typename _Ptr, typename _Tp>
224 using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>;
225
226 template<typename _Tp>
227 constexpr _Tp*
228 __to_address(_Tp* __ptr) noexcept
229 {
230 static_assert(!std::is_function<_Tp>::value, "not a function pointer");
231 return __ptr;
232 }
233
234#if __cplusplus <= 201703L
235 template<typename _Ptr>
236 constexpr typename std::pointer_traits<_Ptr>::element_type*
237 __to_address(const _Ptr& __ptr)
238 { return std::__to_address(__ptr.operator->()); }
239#else
240 template<typename _Ptr>
241 constexpr auto
242 __to_address(const _Ptr& __ptr) noexcept
243 -> decltype(std::pointer_traits<_Ptr>::to_address(__ptr))
244 { return std::pointer_traits<_Ptr>::to_address(__ptr); }
245
246 template<typename _Ptr, typename... _None>
247 constexpr auto
248 __to_address(const _Ptr& __ptr, _None...) noexcept
249 {
250 if constexpr (is_base_of_v<__gnu_debug::_Safe_iterator_base, _Ptr>)
251 return std::__to_address(__ptr.base().operator->());
252 else
253 return std::__to_address(__ptr.operator->());
254 }
255
256#define __cpp_lib_to_address 201711L
257
258 /**
259 * @brief Obtain address referenced by a pointer to an object
260 * @param __ptr A pointer to an object
261 * @return @c __ptr
262 * @ingroup pointer_abstractions
263 */
264 template<typename _Tp>
265 constexpr _Tp*
266 to_address(_Tp* __ptr) noexcept
267 { return std::__to_address(__ptr); }
268
269 /**
270 * @brief Obtain address referenced by a pointer to an object
271 * @param __ptr A pointer to an object
272 * @return @c pointer_traits<_Ptr>::to_address(__ptr) if that expression is
273 well-formed, otherwise @c to_address(__ptr.operator->())
274 * @ingroup pointer_abstractions
275 */
276 template<typename _Ptr>
277 constexpr auto
278 to_address(const _Ptr& __ptr) noexcept
279 { return std::__to_address(__ptr); }
280#endif // C++2a
281
282_GLIBCXX_END_NAMESPACE_VERSION
283} // namespace std
284
285#endif
286
287#endif
288