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_copy_constructible.h> 18 #include <__type_traits/is_empty.h> 19 #include <__type_traits/is_move_constructible.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 <limits> 26 27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 28 # pragma GCC system_header 29 #endif 30 31 _LIBCPP_PUSH_MACROS 32 #include <__undef_macros> 33 34 _LIBCPP_BEGIN_NAMESPACE_STD 35 36 #define _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(NAME, PROPERTY) \ 37 template <class _Tp, class = void> \ 38 struct NAME : false_type {}; \ 39 template <class _Tp> \ 40 struct NAME<_Tp, __void_t<typename _Tp::PROPERTY > > : true_type {} 41 42 // __pointer 43 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, 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 template <class _Alloc> 235 struct _LIBCPP_TEMPLATE_VIS allocator_traits { 236 using allocator_type = _Alloc; 237 using value_type = typename allocator_type::value_type; 238 using pointer = typename __pointer<value_type, allocator_type>::type; 239 using const_pointer = typename __const_pointer<value_type, pointer, allocator_type>::type; 240 using void_pointer = typename __void_pointer<pointer, allocator_type>::type; 241 using const_void_pointer = typename __const_void_pointer<pointer, allocator_type>::type; 242 using difference_type = typename __alloc_traits_difference_type<allocator_type, pointer>::type; 243 using size_type = typename __size_type<allocator_type, difference_type>::type; 244 using propagate_on_container_copy_assignment = 245 typename __propagate_on_container_copy_assignment<allocator_type>::type; 246 using propagate_on_container_move_assignment = 247 typename __propagate_on_container_move_assignment<allocator_type>::type; 248 using propagate_on_container_swap = typename __propagate_on_container_swap<allocator_type>::type; 249 using is_always_equal = typename __is_always_equal<allocator_type>::type; 250 251 #ifndef _LIBCPP_CXX03_LANG 252 template <class _Tp> 253 using rebind_alloc = __allocator_traits_rebind_t<allocator_type, _Tp>; 254 template <class _Tp> 255 using rebind_traits = allocator_traits<rebind_alloc<_Tp> >; 256 #else // _LIBCPP_CXX03_LANG 257 template <class _Tp> 258 struct rebind_alloc { 259 using other = __allocator_traits_rebind_t<allocator_type, _Tp>; 260 }; 261 template <class _Tp> 262 struct rebind_traits { 263 using other = allocator_traits<typename rebind_alloc<_Tp>::other>; 264 }; 265 #endif // _LIBCPP_CXX03_LANG 266 267 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer 268 allocate(allocator_type& __a, size_type __n) { 269 return __a.allocate(__n); 270 } 271 272 template <class _Ap = _Alloc, class = __enable_if_t<__has_allocate_hint<_Ap, size_type, const_void_pointer>::value> > 273 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer 274 allocate(allocator_type& __a, size_type __n, const_void_pointer __hint) { 275 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 276 return __a.allocate(__n, __hint); 277 _LIBCPP_SUPPRESS_DEPRECATED_POP 278 } 279 template <class _Ap = _Alloc, 280 class = void, 281 class = __enable_if_t<!__has_allocate_hint<_Ap, size_type, const_void_pointer>::value> > 282 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static pointer 283 allocate(allocator_type& __a, size_type __n, const_void_pointer) { 284 return __a.allocate(__n); 285 } 286 287 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void 288 deallocate(allocator_type& __a, pointer __p, size_type __n) _NOEXCEPT { 289 __a.deallocate(__p, __n); 290 } 291 292 template <class _Tp, class... _Args, class = __enable_if_t<__has_construct<allocator_type, _Tp*, _Args...>::value> > 293 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void 294 construct(allocator_type& __a, _Tp* __p, _Args&&... __args) { 295 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 296 __a.construct(__p, std::forward<_Args>(__args)...); 297 _LIBCPP_SUPPRESS_DEPRECATED_POP 298 } 299 template <class _Tp, 300 class... _Args, 301 class = void, 302 class = __enable_if_t<!__has_construct<allocator_type, _Tp*, _Args...>::value> > 303 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void 304 construct(allocator_type&, _Tp* __p, _Args&&... __args) { 305 std::__construct_at(__p, std::forward<_Args>(__args)...); 306 } 307 308 template <class _Tp, class = __enable_if_t<__has_destroy<allocator_type, _Tp*>::value> > 309 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void destroy(allocator_type& __a, _Tp* __p) { 310 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 311 __a.destroy(__p); 312 _LIBCPP_SUPPRESS_DEPRECATED_POP 313 } 314 template <class _Tp, class = void, class = __enable_if_t<!__has_destroy<allocator_type, _Tp*>::value> > 315 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void destroy(allocator_type&, _Tp* __p) { 316 std::__destroy_at(__p); 317 } 318 319 template <class _Ap = _Alloc, class = __enable_if_t<__has_max_size<const _Ap>::value> > 320 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type max_size(const allocator_type& __a) _NOEXCEPT { 321 _LIBCPP_SUPPRESS_DEPRECATED_PUSH 322 return __a.max_size(); 323 _LIBCPP_SUPPRESS_DEPRECATED_POP 324 } 325 template <class _Ap = _Alloc, class = void, class = __enable_if_t<!__has_max_size<const _Ap>::value> > 326 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type max_size(const allocator_type&) _NOEXCEPT { 327 return numeric_limits<size_type>::max() / sizeof(value_type); 328 } 329 330 template <class _Ap = _Alloc, class = __enable_if_t<__has_select_on_container_copy_construction<const _Ap>::value> > 331 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type 332 select_on_container_copy_construction(const allocator_type& __a) { 333 return __a.select_on_container_copy_construction(); 334 } 335 template <class _Ap = _Alloc, 336 class = void, 337 class = __enable_if_t<!__has_select_on_container_copy_construction<const _Ap>::value> > 338 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type 339 select_on_container_copy_construction(const allocator_type& __a) { 340 return __a; 341 } 342 }; 343 344 #ifndef _LIBCPP_CXX03_LANG 345 template <class _Traits, class _Tp> 346 using __rebind_alloc _LIBCPP_NODEBUG = typename _Traits::template rebind_alloc<_Tp>; 347 #else 348 template <class _Traits, class _Tp> 349 using __rebind_alloc = typename _Traits::template rebind_alloc<_Tp>::other; 350 #endif 351 352 // __is_default_allocator 353 template <class _Tp> 354 struct __is_default_allocator : false_type {}; 355 356 template <class> 357 class allocator; 358 359 template <class _Tp> 360 struct __is_default_allocator<allocator<_Tp> > : true_type {}; 361 362 // __is_cpp17_move_insertable 363 template <class _Alloc, class = void> 364 struct __is_cpp17_move_insertable : is_move_constructible<typename _Alloc::value_type> {}; 365 366 template <class _Alloc> 367 struct __is_cpp17_move_insertable< 368 _Alloc, 369 __enable_if_t< !__is_default_allocator<_Alloc>::value && 370 __has_construct<_Alloc, typename _Alloc::value_type*, typename _Alloc::value_type&&>::value > > 371 : true_type {}; 372 373 // __is_cpp17_copy_insertable 374 template <class _Alloc, class = void> 375 struct __is_cpp17_copy_insertable 376 : integral_constant<bool, 377 is_copy_constructible<typename _Alloc::value_type>::value && 378 __is_cpp17_move_insertable<_Alloc>::value > {}; 379 380 template <class _Alloc> 381 struct __is_cpp17_copy_insertable< 382 _Alloc, 383 __enable_if_t< !__is_default_allocator<_Alloc>::value && 384 __has_construct<_Alloc, typename _Alloc::value_type*, const typename _Alloc::value_type&>::value > > 385 : __is_cpp17_move_insertable<_Alloc> {}; 386 387 // ASan choices 388 #ifndef _LIBCPP_HAS_NO_ASAN 389 # define _LIBCPP_HAS_ASAN_CONTAINER_ANNOTATIONS_FOR_ALL_ALLOCATORS 1 390 #endif 391 392 #ifdef _LIBCPP_HAS_ASAN_CONTAINER_ANNOTATIONS_FOR_ALL_ALLOCATORS 393 template <class _Alloc> 394 struct __asan_annotate_container_with_allocator : true_type {}; 395 template <class _Tp> 396 struct __asan_annotate_container_with_allocator<allocator<_Tp> > : true_type {}; 397 #endif 398 399 #undef _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX 400 401 _LIBCPP_END_NAMESPACE_STD 402 403 _LIBCPP_POP_MACROS 404 405 #endif // _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H 406