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