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