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_ALLOCATOR_TRAITS_H 11 #define _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H 12 13 #include <__config> 14 #include <__memory/construct_at.h> 15 #include <__memory/pointer_traits.h> 16 #include <__type_traits/enable_if.h> 17 #include <__type_traits/is_constructible.h> 18 #include <__type_traits/is_empty.h> 19 #include <__type_traits/is_same.h> 20 #include <__type_traits/make_unsigned.h> 21 #include <__type_traits/remove_reference.h> 22 #include <__type_traits/void_t.h> 23 #include <__utility/declval.h> 24 #include <__utility/forward.h> 25 #include <cstddef> 26 #include <limits> 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 #define _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(NAME, PROPERTY) \ 38 template <class _Tp, class = void> \ 39 struct NAME : false_type {}; \ 40 template <class _Tp> \ 41 struct NAME<_Tp, __void_t<typename _Tp::PROPERTY > > : true_type {} 42 43 // __pointer 44 template <class _Tp, 45 class _Alloc, 46 class _RawAlloc = __libcpp_remove_reference_t<_Alloc>, 47 bool = __has_pointer<_RawAlloc>::value> 48 struct __pointer { 49 using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer; 50 }; 51 template <class _Tp, class _Alloc, class _RawAlloc> 52 struct __pointer<_Tp, _Alloc, _RawAlloc, false> { 53 using type _LIBCPP_NODEBUG = _Tp*; 54 }; 55 56 // __const_pointer 57 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_pointer, const_pointer); 58 template <class _Tp, class _Ptr, class _Alloc, bool = __has_const_pointer<_Alloc>::value> 59 struct __const_pointer { 60 using type _LIBCPP_NODEBUG = typename _Alloc::const_pointer; 61 }; 62 template <class _Tp, class _Ptr, class _Alloc> 63 struct __const_pointer<_Tp, _Ptr, _Alloc, false> { 64 #ifdef _LIBCPP_CXX03_LANG 65 using type = typename pointer_traits<_Ptr>::template rebind<const _Tp>::other; 66 #else 67 using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<const _Tp>; 68 #endif 69 }; 70 71 // __void_pointer 72 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_void_pointer, void_pointer); 73 template <class _Ptr, class _Alloc, bool = __has_void_pointer<_Alloc>::value> 74 struct __void_pointer { 75 using type _LIBCPP_NODEBUG = typename _Alloc::void_pointer; 76 }; 77 template <class _Ptr, class _Alloc> 78 struct __void_pointer<_Ptr, _Alloc, false> { 79 #ifdef _LIBCPP_CXX03_LANG 80 using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<void>::other; 81 #else 82 using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<void>; 83 #endif 84 }; 85 86 // __const_void_pointer 87 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_void_pointer, const_void_pointer); 88 template <class _Ptr, class _Alloc, bool = __has_const_void_pointer<_Alloc>::value> 89 struct __const_void_pointer { 90 using type _LIBCPP_NODEBUG = typename _Alloc::const_void_pointer; 91 }; 92 template <class _Ptr, class _Alloc> 93 struct __const_void_pointer<_Ptr, _Alloc, false> { 94 #ifdef _LIBCPP_CXX03_LANG 95 using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<const void>::other; 96 #else 97 using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<const void>; 98 #endif 99 }; 100 101 // __size_type 102 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_size_type, size_type); 103 template <class _Alloc, class _DiffType, bool = __has_size_type<_Alloc>::value> 104 struct __size_type : make_unsigned<_DiffType> {}; 105 template <class _Alloc, class _DiffType> 106 struct __size_type<_Alloc, _DiffType, true> { 107 using type _LIBCPP_NODEBUG = typename _Alloc::size_type; 108 }; 109 110 // __alloc_traits_difference_type 111 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_alloc_traits_difference_type, difference_type); 112 template <class _Alloc, class _Ptr, bool = __has_alloc_traits_difference_type<_Alloc>::value> 113 struct __alloc_traits_difference_type { 114 using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::difference_type; 115 }; 116 template <class _Alloc, class _Ptr> 117 struct __alloc_traits_difference_type<_Alloc, _Ptr, true> { 118 using type _LIBCPP_NODEBUG = typename _Alloc::difference_type; 119 }; 120 121 // __propagate_on_container_copy_assignment 122 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_copy_assignment, propagate_on_container_copy_assignment); 123 template <class _Alloc, bool = __has_propagate_on_container_copy_assignment<_Alloc>::value> 124 struct __propagate_on_container_copy_assignment : false_type {}; 125 template <class _Alloc> 126 struct __propagate_on_container_copy_assignment<_Alloc, true> { 127 using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_copy_assignment; 128 }; 129 130 // __propagate_on_container_move_assignment 131 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_move_assignment, propagate_on_container_move_assignment); 132 template <class _Alloc, bool = __has_propagate_on_container_move_assignment<_Alloc>::value> 133 struct __propagate_on_container_move_assignment : false_type {}; 134 template <class _Alloc> 135 struct __propagate_on_container_move_assignment<_Alloc, true> { 136 using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_move_assignment; 137 }; 138 139 // __propagate_on_container_swap 140 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_swap, propagate_on_container_swap); 141 template <class _Alloc, bool = __has_propagate_on_container_swap<_Alloc>::value> 142 struct __propagate_on_container_swap : false_type {}; 143 template <class _Alloc> 144 struct __propagate_on_container_swap<_Alloc, true> { 145 using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_swap; 146 }; 147 148 // __is_always_equal 149 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_is_always_equal, is_always_equal); 150 template <class _Alloc, bool = __has_is_always_equal<_Alloc>::value> 151 struct __is_always_equal : is_empty<_Alloc> {}; 152 template <class _Alloc> 153 struct __is_always_equal<_Alloc, true> { 154 using type _LIBCPP_NODEBUG = typename _Alloc::is_always_equal; 155 }; 156 157 // __allocator_traits_rebind 158 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 159 template <class _Tp, class _Up, class = void> 160 struct __has_rebind_other : false_type {}; 161 template <class _Tp, class _Up> 162 struct __has_rebind_other<_Tp, _Up, __void_t<typename _Tp::template rebind<_Up>::other> > : true_type {}; 163 164 template <class _Tp, class _Up, bool = __has_rebind_other<_Tp, _Up>::value> 165 struct __allocator_traits_rebind { 166 static_assert(__has_rebind_other<_Tp, _Up>::value, "This allocator has to implement rebind"); 167 using type _LIBCPP_NODEBUG = typename _Tp::template rebind<_Up>::other; 168 }; 169 template <template <class, class...> class _Alloc, class _Tp, class... _Args, class _Up> 170 struct __allocator_traits_rebind<_Alloc<_Tp, _Args...>, _Up, true> { 171 using type _LIBCPP_NODEBUG = typename _Alloc<_Tp, _Args...>::template rebind<_Up>::other; 172 }; 173 template <template <class, class...> class _Alloc, class _Tp, class... _Args, class _Up> 174 struct __allocator_traits_rebind<_Alloc<_Tp, _Args...>, _Up, false> { 175 using type _LIBCPP_NODEBUG = _Alloc<_Up, _Args...>; 176 }; 177 _LIBCPP_SUPPRESS_DEPRECATED_POP 178 179 template <class _Alloc, class _Tp> 180 using __allocator_traits_rebind_t = typename __allocator_traits_rebind<_Alloc, _Tp>::type; 181 182 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 183 184 // __has_allocate_hint 185 template <class _Alloc, class _SizeType, class _ConstVoidPtr, class = void> 186 struct __has_allocate_hint : false_type {}; 187 188 template <class _Alloc, class _SizeType, class _ConstVoidPtr> 189 struct __has_allocate_hint< 190 _Alloc, 191 _SizeType, 192 _ConstVoidPtr, 193 decltype((void)std::declval<_Alloc>().allocate(std::declval<_SizeType>(), std::declval<_ConstVoidPtr>()))> 194 : true_type {}; 195 196 // __has_construct 197 template <class, class _Alloc, class... _Args> 198 struct __has_construct_impl : false_type {}; 199 200 template <class _Alloc, class... _Args> 201 struct __has_construct_impl<decltype((void)std::declval<_Alloc>().construct(std::declval<_Args>()...)), 202 _Alloc, 203 _Args...> : true_type {}; 204 205 template <class _Alloc, class... _Args> 206 struct __has_construct : __has_construct_impl<void, _Alloc, _Args...> {}; 207 208 // __has_destroy 209 template <class _Alloc, class _Pointer, class = void> 210 struct __has_destroy : false_type {}; 211 212 template <class _Alloc, class _Pointer> 213 struct __has_destroy<_Alloc, _Pointer, decltype((void)std::declval<_Alloc>().destroy(std::declval<_Pointer>()))> 214 : true_type {}; 215 216 // __has_max_size 217 template <class _Alloc, class = void> 218 struct __has_max_size : false_type {}; 219 220 template <class _Alloc> 221 struct __has_max_size<_Alloc, decltype((void)std::declval<_Alloc&>().max_size())> : true_type {}; 222 223 // __has_select_on_container_copy_construction 224 template <class _Alloc, class = void> 225 struct __has_select_on_container_copy_construction : false_type {}; 226 227 template <class _Alloc> 228 struct __has_select_on_container_copy_construction< 229 _Alloc, 230 decltype((void)std::declval<_Alloc>().select_on_container_copy_construction())> : true_type {}; 231 232 _LIBCPP_SUPPRESS_DEPRECATED_POP 233 234 #if _LIBCPP_STD_VER >= 23 235 236 template <class _Pointer, class _SizeType = size_t> 237 struct allocation_result { 238 _Pointer ptr; 239 _SizeType count; 240 }; 241 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(allocation_result); 242 243 #endif // _LIBCPP_STD_VER 244 245 template <class _Alloc> 246 struct _LIBCPP_TEMPLATE_VIS allocator_traits { 247 using allocator_type = _Alloc; 248 using value_type = typename allocator_type::value_type; 249 using pointer = typename __pointer<value_type, allocator_type>::type; 250 using const_pointer = typename __const_pointer<value_type, pointer, allocator_type>::type; 251 using void_pointer = typename __void_pointer<pointer, allocator_type>::type; 252 using const_void_pointer = typename __const_void_pointer<pointer, allocator_type>::type; 253 using difference_type = typename __alloc_traits_difference_type<allocator_type, pointer>::type; 254 using size_type = typename __size_type<allocator_type, difference_type>::type; 255 using propagate_on_container_copy_assignment = 256 typename __propagate_on_container_copy_assignment<allocator_type>::type; 257 using propagate_on_container_move_assignment = 258 typename __propagate_on_container_move_assignment<allocator_type>::type; 259 using propagate_on_container_swap = typename __propagate_on_container_swap<allocator_type>::type; 260 using is_always_equal = typename __is_always_equal<allocator_type>::type; 261 262 #ifndef _LIBCPP_CXX03_LANG 263 template <class _Tp> 264 using rebind_alloc = __allocator_traits_rebind_t<allocator_type, _Tp>; 265 template <class _Tp> 266 using rebind_traits = allocator_traits<rebind_alloc<_Tp> >; 267 #else // _LIBCPP_CXX03_LANG 268 template <class _Tp> 269 struct rebind_alloc { 270 using other = __allocator_traits_rebind_t<allocator_type, _Tp>; 271 }; 272 template <class _Tp> 273 struct rebind_traits { 274 using other = allocator_traits<typename rebind_alloc<_Tp>::other>; 275 }; 276 #endif // _LIBCPP_CXX03_LANG 277 278 _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer 279 allocate(allocator_type& __a, size_type __n) { 280 return __a.allocate(__n); 281 } 282 283 template <class _Ap = _Alloc, __enable_if_t<__has_allocate_hint<_Ap, size_type, const_void_pointer>::value, int> = 0> 284 _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer 285 allocate(allocator_type& __a, size_type __n, const_void_pointer __hint) { 286 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 287 return __a.allocate(__n, __hint); 288 _LIBCPP_SUPPRESS_DEPRECATED_POP 289 } 290 template <class _Ap = _Alloc, 291 class = void, 292 __enable_if_t<!__has_allocate_hint<_Ap, size_type, const_void_pointer>::value, int> = 0> 293 _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer 294 allocate(allocator_type& __a, size_type __n, const_void_pointer) { 295 return __a.allocate(__n); 296 } 297 298 #if _LIBCPP_STD_VER >= 23 299 template <class _Ap = _Alloc> 300 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr allocation_result<pointer, size_type> 301 allocate_at_least(_Ap& __alloc, size_type __n) { 302 if constexpr (requires { __alloc.allocate_at_least(__n); }) { 303 return __alloc.allocate_at_least(__n); 304 } else { 305 return {__alloc.allocate(__n), __n}; 306 } 307 } 308 #endif 309 310 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void 311 deallocate(allocator_type& __a, pointer __p, size_type __n) _NOEXCEPT { 312 __a.deallocate(__p, __n); 313 } 314 315 template <class _Tp, class... _Args, __enable_if_t<__has_construct<allocator_type, _Tp*, _Args...>::value, int> = 0> 316 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void 317 construct(allocator_type& __a, _Tp* __p, _Args&&... __args) { 318 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 319 __a.construct(__p, std::forward<_Args>(__args)...); 320 _LIBCPP_SUPPRESS_DEPRECATED_POP 321 } 322 template <class _Tp, 323 class... _Args, 324 class = void, 325 __enable_if_t<!__has_construct<allocator_type, _Tp*, _Args...>::value, int> = 0> 326 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void 327 construct(allocator_type&, _Tp* __p, _Args&&... __args) { 328 std::__construct_at(__p, std::forward<_Args>(__args)...); 329 } 330 331 template <class _Tp, __enable_if_t<__has_destroy<allocator_type, _Tp*>::value, int> = 0> 332 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void destroy(allocator_type& __a, _Tp* __p) { 333 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 334 __a.destroy(__p); 335 _LIBCPP_SUPPRESS_DEPRECATED_POP 336 } 337 template <class _Tp, class = void, __enable_if_t<!__has_destroy<allocator_type, _Tp*>::value, int> = 0> 338 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void destroy(allocator_type&, _Tp* __p) { 339 std::__destroy_at(__p); 340 } 341 342 template <class _Ap = _Alloc, __enable_if_t<__has_max_size<const _Ap>::value, int> = 0> 343 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type max_size(const allocator_type& __a) _NOEXCEPT { 344 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 345 return __a.max_size(); 346 _LIBCPP_SUPPRESS_DEPRECATED_POP 347 } 348 template <class _Ap = _Alloc, class = void, __enable_if_t<!__has_max_size<const _Ap>::value, int> = 0> 349 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type max_size(const allocator_type&) _NOEXCEPT { 350 return numeric_limits<size_type>::max() / sizeof(value_type); 351 } 352 353 template <class _Ap = _Alloc, __enable_if_t<__has_select_on_container_copy_construction<const _Ap>::value, int> = 0> 354 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type 355 select_on_container_copy_construction(const allocator_type& __a) { 356 return __a.select_on_container_copy_construction(); 357 } 358 template <class _Ap = _Alloc, 359 class = void, 360 __enable_if_t<!__has_select_on_container_copy_construction<const _Ap>::value, int> = 0> 361 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type 362 select_on_container_copy_construction(const allocator_type& __a) { 363 return __a; 364 } 365 }; 366 367 #ifndef _LIBCPP_CXX03_LANG 368 template <class _Traits, class _Tp> 369 using __rebind_alloc _LIBCPP_NODEBUG = typename _Traits::template rebind_alloc<_Tp>; 370 #else 371 template <class _Traits, class _Tp> 372 using __rebind_alloc = typename _Traits::template rebind_alloc<_Tp>::other; 373 #endif 374 375 template <class _Alloc> 376 struct __check_valid_allocator : true_type { 377 using _Traits = std::allocator_traits<_Alloc>; 378 static_assert(is_same<_Alloc, __rebind_alloc<_Traits, typename _Traits::value_type> >::value, 379 "[allocator.requirements] states that rebinding an allocator to the same type should result in the " 380 "original allocator"); 381 }; 382 383 // __is_default_allocator 384 template <class _Tp> 385 struct __is_default_allocator : false_type {}; 386 387 template <class> 388 class allocator; 389 390 template <class _Tp> 391 struct __is_default_allocator<allocator<_Tp> > : true_type {}; 392 393 // __is_cpp17_move_insertable 394 template <class _Alloc, class = void> 395 struct __is_cpp17_move_insertable : is_move_constructible<typename _Alloc::value_type> {}; 396 397 template <class _Alloc> 398 struct __is_cpp17_move_insertable< 399 _Alloc, 400 __enable_if_t< !__is_default_allocator<_Alloc>::value && 401 __has_construct<_Alloc, typename _Alloc::value_type*, typename _Alloc::value_type&&>::value > > 402 : true_type {}; 403 404 // __is_cpp17_copy_insertable 405 template <class _Alloc, class = void> 406 struct __is_cpp17_copy_insertable 407 : integral_constant<bool, 408 is_copy_constructible<typename _Alloc::value_type>::value && 409 __is_cpp17_move_insertable<_Alloc>::value > {}; 410 411 template <class _Alloc> 412 struct __is_cpp17_copy_insertable< 413 _Alloc, 414 __enable_if_t< !__is_default_allocator<_Alloc>::value && 415 __has_construct<_Alloc, typename _Alloc::value_type*, const typename _Alloc::value_type&>::value > > 416 : __is_cpp17_move_insertable<_Alloc> {}; 417 418 #undef _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX 419 420 _LIBCPP_END_NAMESPACE_STD 421 422 _LIBCPP_POP_MACROS 423 424 #endif // _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H 425