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