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 <__cstddef/ptrdiff_t.h> 15 #include <__memory/addressof.h> 16 #include <__type_traits/conditional.h> 17 #include <__type_traits/conjunction.h> 18 #include <__type_traits/decay.h> 19 #include <__type_traits/enable_if.h> 20 #include <__type_traits/integral_constant.h> 21 #include <__type_traits/is_class.h> 22 #include <__type_traits/is_function.h> 23 #include <__type_traits/is_void.h> 24 #include <__type_traits/void_t.h> 25 #include <__utility/declval.h> 26 #include <__utility/forward.h> 27 28 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 29 # pragma GCC system_header 30 #endif 31 32 _LIBCPP_PUSH_MACROS 33 #include <__undef_macros> 34 35 _LIBCPP_BEGIN_NAMESPACE_STD 36 37 // clang-format off 38 #define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY) \ 39 template <class _Tp, class = void> \ 40 struct NAME : false_type {}; \ 41 template <class _Tp> \ 42 struct NAME<_Tp, __void_t<typename _Tp::PROPERTY> > : true_type {} 43 // clang-format on 44 45 _LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer); 46 _LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type); 47 48 template <class _Ptr, bool = __has_element_type<_Ptr>::value> 49 struct __pointer_traits_element_type {}; 50 51 template <class _Ptr> 52 struct __pointer_traits_element_type<_Ptr, true> { 53 using type _LIBCPP_NODEBUG = typename _Ptr::element_type; 54 }; 55 56 template <template <class, class...> class _Sp, class _Tp, class... _Args> 57 struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, true> { 58 using type _LIBCPP_NODEBUG = typename _Sp<_Tp, _Args...>::element_type; 59 }; 60 61 template <template <class, class...> class _Sp, class _Tp, class... _Args> 62 struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, false> { 63 using type _LIBCPP_NODEBUG = _Tp; 64 }; 65 66 template <class _Tp, class = void> 67 struct __has_difference_type : false_type {}; 68 69 template <class _Tp> 70 struct __has_difference_type<_Tp, __void_t<typename _Tp::difference_type> > : true_type {}; 71 72 template <class _Ptr, bool = __has_difference_type<_Ptr>::value> 73 struct __pointer_traits_difference_type { 74 using type _LIBCPP_NODEBUG = ptrdiff_t; 75 }; 76 77 template <class _Ptr> 78 struct __pointer_traits_difference_type<_Ptr, true> { 79 using type _LIBCPP_NODEBUG = typename _Ptr::difference_type; 80 }; 81 82 template <class _Tp, class _Up> 83 struct __has_rebind { 84 private: 85 template <class _Xp> 86 static false_type __test(...); 87 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 88 template <class _Xp> 89 static true_type __test(typename _Xp::template rebind<_Up>* = 0); 90 _LIBCPP_SUPPRESS_DEPRECATED_POP 91 92 public: 93 static const bool value = decltype(__test<_Tp>(0))::value; 94 }; 95 96 template <class _Tp, class _Up, bool = __has_rebind<_Tp, _Up>::value> 97 struct __pointer_traits_rebind { 98 #ifndef _LIBCPP_CXX03_LANG 99 using type _LIBCPP_NODEBUG = typename _Tp::template rebind<_Up>; 100 #else 101 using type _LIBCPP_NODEBUG = typename _Tp::template rebind<_Up>::other; 102 #endif 103 }; 104 105 template <template <class, class...> class _Sp, class _Tp, class... _Args, class _Up> 106 struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, true> { 107 #ifndef _LIBCPP_CXX03_LANG 108 using type _LIBCPP_NODEBUG = typename _Sp<_Tp, _Args...>::template rebind<_Up>; 109 #else 110 using type _LIBCPP_NODEBUG = typename _Sp<_Tp, _Args...>::template rebind<_Up>::other; 111 #endif 112 }; 113 114 template <template <class, class...> class _Sp, class _Tp, class... _Args, class _Up> 115 struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, false> { 116 typedef _Sp<_Up, _Args...> type; 117 }; 118 119 template <class _Ptr, class = void> 120 struct __pointer_traits_impl {}; 121 122 template <class _Ptr> 123 struct __pointer_traits_impl<_Ptr, __void_t<typename __pointer_traits_element_type<_Ptr>::type> > { 124 typedef _Ptr pointer; 125 typedef typename __pointer_traits_element_type<pointer>::type element_type; 126 typedef typename __pointer_traits_difference_type<pointer>::type difference_type; 127 128 #ifndef _LIBCPP_CXX03_LANG 129 template <class _Up> 130 using rebind = typename __pointer_traits_rebind<pointer, _Up>::type; 131 #else 132 template <class _Up> 133 struct rebind { 134 typedef typename __pointer_traits_rebind<pointer, _Up>::type other; 135 }; 136 #endif // _LIBCPP_CXX03_LANG 137 138 private: 139 struct __nat {}; 140 141 public: 142 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer 143 pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) { 144 return pointer::pointer_to(__r); 145 } 146 }; 147 148 template <class _Ptr> 149 struct _LIBCPP_TEMPLATE_VIS pointer_traits : __pointer_traits_impl<_Ptr> {}; 150 151 template <class _Tp> 152 struct _LIBCPP_TEMPLATE_VIS pointer_traits<_Tp*> { 153 typedef _Tp* pointer; 154 typedef _Tp element_type; 155 typedef ptrdiff_t difference_type; 156 157 #ifndef _LIBCPP_CXX03_LANG 158 template <class _Up> 159 using rebind = _Up*; 160 #else 161 template <class _Up> 162 struct rebind { 163 typedef _Up* other; 164 }; 165 #endif 166 167 private: 168 struct __nat {}; 169 170 public: 171 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer 172 pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) _NOEXCEPT { 173 return std::addressof(__r); 174 } 175 }; 176 177 #ifndef _LIBCPP_CXX03_LANG 178 template <class _From, class _To> 179 using __rebind_pointer_t _LIBCPP_NODEBUG = typename pointer_traits<_From>::template rebind<_To>; 180 #else 181 template <class _From, class _To> 182 using __rebind_pointer_t _LIBCPP_NODEBUG = typename pointer_traits<_From>::template rebind<_To>::other; 183 #endif 184 185 // to_address 186 187 template <class _Pointer, class = void> 188 struct __to_address_helper; 189 190 template <class _Tp> 191 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* __to_address(_Tp* __p) _NOEXCEPT { 192 static_assert(!is_function<_Tp>::value, "_Tp is a function type"); 193 return __p; 194 } 195 196 template <class _Pointer, class = void> 197 struct _HasToAddress : false_type {}; 198 199 template <class _Pointer> 200 struct _HasToAddress<_Pointer, decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>())) > 201 : true_type {}; 202 203 template <class _Pointer, class = void> 204 struct _HasArrow : false_type {}; 205 206 template <class _Pointer> 207 struct _HasArrow<_Pointer, decltype((void)std::declval<const _Pointer&>().operator->()) > : true_type {}; 208 209 template <class _Pointer> 210 struct _IsFancyPointer { 211 static const bool value = _HasArrow<_Pointer>::value || _HasToAddress<_Pointer>::value; 212 }; 213 214 // enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers 215 template <class _Pointer, __enable_if_t< _And<is_class<_Pointer>, _IsFancyPointer<_Pointer> >::value, int> = 0> 216 _LIBCPP_HIDE_FROM_ABI 217 _LIBCPP_CONSTEXPR __decay_t<decltype(__to_address_helper<_Pointer>::__call(std::declval<const _Pointer&>()))> 218 __to_address(const _Pointer& __p) _NOEXCEPT { 219 return __to_address_helper<_Pointer>::__call(__p); 220 } 221 222 template <class _Pointer, class> 223 struct __to_address_helper { 224 _LIBCPP_HIDE_FROM_ABI 225 _LIBCPP_CONSTEXPR static decltype(std::__to_address(std::declval<const _Pointer&>().operator->())) 226 __call(const _Pointer& __p) _NOEXCEPT { 227 return std::__to_address(__p.operator->()); 228 } 229 }; 230 231 template <class _Pointer> 232 struct __to_address_helper<_Pointer, 233 decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))> { 234 _LIBCPP_HIDE_FROM_ABI 235 _LIBCPP_CONSTEXPR static decltype(pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>())) 236 __call(const _Pointer& __p) _NOEXCEPT { 237 return pointer_traits<_Pointer>::to_address(__p); 238 } 239 }; 240 241 #if _LIBCPP_STD_VER >= 20 242 template <class _Tp> 243 inline _LIBCPP_HIDE_FROM_ABI constexpr auto to_address(_Tp* __p) noexcept { 244 return std::__to_address(__p); 245 } 246 247 template <class _Pointer> 248 inline _LIBCPP_HIDE_FROM_ABI constexpr auto 249 to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) { 250 return std::__to_address(__p); 251 } 252 #endif 253 254 #if _LIBCPP_STD_VER >= 23 255 256 template <class _Tp> 257 struct __pointer_of {}; 258 259 template <class _Tp> 260 requires(__has_pointer<_Tp>::value) 261 struct __pointer_of<_Tp> { 262 using type = typename _Tp::pointer; 263 }; 264 265 template <class _Tp> 266 requires(!__has_pointer<_Tp>::value && __has_element_type<_Tp>::value) 267 struct __pointer_of<_Tp> { 268 using type = typename _Tp::element_type*; 269 }; 270 271 template <class _Tp> 272 requires(!__has_pointer<_Tp>::value && !__has_element_type<_Tp>::value && 273 __has_element_type<pointer_traits<_Tp>>::value) 274 struct __pointer_of<_Tp> { 275 using type = typename pointer_traits<_Tp>::element_type*; 276 }; 277 278 template <typename _Tp> 279 using __pointer_of_t _LIBCPP_NODEBUG = typename __pointer_of<_Tp>::type; 280 281 template <class _Tp, class _Up> 282 struct __pointer_of_or { 283 using type _LIBCPP_NODEBUG = _Up; 284 }; 285 286 template <class _Tp, class _Up> 287 requires requires { typename __pointer_of_t<_Tp>; } 288 struct __pointer_of_or<_Tp, _Up> { 289 using type _LIBCPP_NODEBUG = __pointer_of_t<_Tp>; 290 }; 291 292 template <typename _Tp, typename _Up> 293 using __pointer_of_or_t _LIBCPP_NODEBUG = typename __pointer_of_or<_Tp, _Up>::type; 294 295 template <class _Smart> 296 concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); }; 297 298 template <class _Smart, class _Pointer, class... _Args> 299 concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p, _Args... __args) { 300 __s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...); 301 }; 302 303 #endif 304 305 _LIBCPP_END_NAMESPACE_STD 306 307 _LIBCPP_POP_MACROS 308 309 #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H 310