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