2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H
11 #define _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H
14 #include <__memory/construct_at.h>
15 #include <__memory/pointer_traits.h>
16 #include <__utility/forward.h>
18 #include <type_traits>
20 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21 #pragma GCC system_header
25 #include <__undef_macros>
27 _LIBCPP_BEGIN_NAMESPACE_STD
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 { }
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
>
39 using type _LIBCPP_NODEBUG
= typename
_RawAlloc::pointer
;
41 template <class _Tp
, class _Alloc
, class _RawAlloc
>
42 struct __pointer
<_Tp
, _Alloc
, _RawAlloc
, false> {
43 using type _LIBCPP_NODEBUG
= _Tp
*;
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
;
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
;
58 using type _LIBCPP_NODEBUG
= typename pointer_traits
<_Ptr
>::template rebind
<const _Tp
>;
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
;
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
;
74 using type _LIBCPP_NODEBUG
= typename pointer_traits
<_Ptr
>::template rebind
<void>;
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
;
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
;
90 using type _LIBCPP_NODEBUG
= typename pointer_traits
<_Ptr
>::template rebind
<const void>;
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
;
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
;
109 template <class _Alloc
, class _Ptr
>
110 struct __alloc_traits_difference_type
<_Alloc
, _Ptr
, true> {
111 using type _LIBCPP_NODEBUG
= typename
_Alloc::difference_type
;
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
;
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
;
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
;
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
;
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
{ };
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
;
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
;
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
...>;
171 _LIBCPP_SUPPRESS_DEPRECATED_POP
173 template<class _Alloc
, class _Tp
>
174 using __allocator_traits_rebind_t
= typename __allocator_traits_rebind
<_Alloc
, _Tp
>::type
;
176 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
178 // __has_allocate_hint
179 template <class _Alloc
, class _SizeType
, class _ConstVoidPtr
, class = void>
180 struct __has_allocate_hint
: false_type
{ };
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
>())
188 template <class, class _Alloc
, class ..._Args
>
189 struct __has_construct_impl
: false_type
{ };
191 template <class _Alloc
, class ..._Args
>
192 struct __has_construct_impl
<decltype(
193 (void)declval
<_Alloc
>().construct(declval
<_Args
>()...)
194 ), _Alloc
, _Args
...> : true_type
{ };
196 template <class _Alloc
, class ..._Args
>
197 struct __has_construct
: __has_construct_impl
<void, _Alloc
, _Args
...> { };
200 template <class _Alloc
, class _Pointer
, class = void>
201 struct __has_destroy
: false_type
{ };
203 template <class _Alloc
, class _Pointer
>
204 struct __has_destroy
<_Alloc
, _Pointer
, decltype(
205 (void)declval
<_Alloc
>().destroy(declval
<_Pointer
>())
209 template <class _Alloc
, class = void>
210 struct __has_max_size
: false_type
{ };
212 template <class _Alloc
>
213 struct __has_max_size
<_Alloc
, decltype(
214 (void)declval
<_Alloc
&>().max_size()
217 // __has_select_on_container_copy_construction
218 template <class _Alloc
, class = void>
219 struct __has_select_on_container_copy_construction
: false_type
{ };
221 template <class _Alloc
>
222 struct __has_select_on_container_copy_construction
<_Alloc
, decltype(
223 (void)declval
<_Alloc
>().select_on_container_copy_construction()
226 _LIBCPP_SUPPRESS_DEPRECATED_POP
228 template <class _Alloc
>
229 struct _LIBCPP_TEMPLATE_VIS allocator_traits
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
;
244 #ifndef _LIBCPP_CXX03_LANG
246 using rebind_alloc
= __allocator_traits_rebind_t
<allocator_type
, _Tp
>;
248 using rebind_traits
= allocator_traits
<rebind_alloc
<_Tp
> >;
249 #else // _LIBCPP_CXX03_LANG
251 struct rebind_alloc
{
252 using other
= __allocator_traits_rebind_t
<allocator_type
, _Tp
>;
255 struct rebind_traits
{
256 using other
= allocator_traits
<typename rebind_alloc
<_Tp
>::other
>;
258 #endif // _LIBCPP_CXX03_LANG
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
);
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
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
);
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
);
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
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
)...);
300 ::new ((void*)__p
) _Tp(_VSTD::forward
<_Args
>(__args
)...);
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
310 _LIBCPP_SUPPRESS_DEPRECATED_POP
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
);
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
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
);
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();
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
) {
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
>;
357 using type
= typename
_Traits::template rebind_alloc
<_Tp
>::other
;
361 // __is_default_allocator
363 struct __is_default_allocator
: false_type
{ };
365 template <class> class allocator
;
368 struct __is_default_allocator
<allocator
<_Tp
> > : true_type
{ };
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
>
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
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
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
396 : __is_cpp17_move_insertable
<_Alloc
>
399 #undef _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX
401 _LIBCPP_END_NAMESPACE_STD
405 #endif // _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H