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___CXX03___MEMORY_ALLOCATOR_TRAITS_H
11 #define _LIBCPP___CXX03___MEMORY_ALLOCATOR_TRAITS_H
13 #include <__cxx03/__config>
14 #include <__cxx03/__memory/construct_at.h>
15 #include <__cxx03/__memory/pointer_traits.h>
16 #include <__cxx03/__type_traits/enable_if.h>
17 #include <__cxx03/__type_traits/is_constructible.h>
18 #include <__cxx03/__type_traits/is_empty.h>
19 #include <__cxx03/__type_traits/is_same.h>
20 #include <__cxx03/__type_traits/make_unsigned.h>
21 #include <__cxx03/__type_traits/remove_reference.h>
22 #include <__cxx03/__type_traits/void_t.h>
23 #include <__cxx03/__utility/declval.h>
24 #include <__cxx03/__utility/forward.h>
25 #include <__cxx03/cstddef>
26 #include <__cxx03/limits>
28 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
29 # pragma GCC system_header
33 #include <__cxx03/__undef_macros>
35 _LIBCPP_BEGIN_NAMESPACE_STD
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 {}
46 class _RawAlloc
= __libcpp_remove_reference_t
<_Alloc
>,
47 bool = __has_pointer
<_RawAlloc
>::value
>
49 using type _LIBCPP_NODEBUG
= typename
_RawAlloc::pointer
;
51 template <class _Tp
, class _Alloc
, class _RawAlloc
>
52 struct __pointer
<_Tp
, _Alloc
, _RawAlloc
, false> {
53 using type _LIBCPP_NODEBUG
= _Tp
*;
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
;
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
;
67 using type _LIBCPP_NODEBUG
= typename pointer_traits
<_Ptr
>::template rebind
<const _Tp
>;
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
;
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
;
82 using type _LIBCPP_NODEBUG
= typename pointer_traits
<_Ptr
>::template rebind
<void>;
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
;
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
;
97 using type _LIBCPP_NODEBUG
= typename pointer_traits
<_Ptr
>::template rebind
<const void>;
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
;
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
;
116 template <class _Alloc
, class _Ptr
>
117 struct __alloc_traits_difference_type
<_Alloc
, _Ptr
, true> {
118 using type _LIBCPP_NODEBUG
= typename
_Alloc::difference_type
;
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
;
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
;
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
;
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
;
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
{};
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
;
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
;
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
...>;
177 _LIBCPP_SUPPRESS_DEPRECATED_POP
179 template <class _Alloc
, class _Tp
>
180 using __allocator_traits_rebind_t
= typename __allocator_traits_rebind
<_Alloc
, _Tp
>::type
;
182 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
184 // __has_allocate_hint
185 template <class _Alloc
, class _SizeType
, class _ConstVoidPtr
, class = void>
186 struct __has_allocate_hint
: false_type
{};
188 template <class _Alloc
, class _SizeType
, class _ConstVoidPtr
>
189 struct __has_allocate_hint
<
193 decltype((void)std::declval
<_Alloc
>().allocate(std::declval
<_SizeType
>(), std::declval
<_ConstVoidPtr
>()))>
197 template <class, class _Alloc
, class... _Args
>
198 struct __has_construct_impl
: false_type
{};
200 template <class _Alloc
, class... _Args
>
201 struct __has_construct_impl
<decltype((void)std::declval
<_Alloc
>().construct(std::declval
<_Args
>()...)),
203 _Args
...> : true_type
{};
205 template <class _Alloc
, class... _Args
>
206 struct __has_construct
: __has_construct_impl
<void, _Alloc
, _Args
...> {};
209 template <class _Alloc
, class _Pointer
, class = void>
210 struct __has_destroy
: false_type
{};
212 template <class _Alloc
, class _Pointer
>
213 struct __has_destroy
<_Alloc
, _Pointer
, decltype((void)std::declval
<_Alloc
>().destroy(std::declval
<_Pointer
>()))>
217 template <class _Alloc
, class = void>
218 struct __has_max_size
: false_type
{};
220 template <class _Alloc
>
221 struct __has_max_size
<_Alloc
, decltype((void)std::declval
<_Alloc
&>().max_size())> : true_type
{};
223 // __has_select_on_container_copy_construction
224 template <class _Alloc
, class = void>
225 struct __has_select_on_container_copy_construction
: false_type
{};
227 template <class _Alloc
>
228 struct __has_select_on_container_copy_construction
<
230 decltype((void)std::declval
<_Alloc
>().select_on_container_copy_construction())> : true_type
{};
232 _LIBCPP_SUPPRESS_DEPRECATED_POP
234 #if _LIBCPP_STD_VER >= 23
236 template <class _Pointer
, class _SizeType
= size_t>
237 struct allocation_result
{
241 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(allocation_result
);
243 #endif // _LIBCPP_STD_VER
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
;
262 #ifndef _LIBCPP_CXX03_LANG
264 using rebind_alloc
= __allocator_traits_rebind_t
<allocator_type
, _Tp
>;
266 using rebind_traits
= allocator_traits
<rebind_alloc
<_Tp
> >;
267 #else // _LIBCPP_CXX03_LANG
269 struct rebind_alloc
{
270 using other
= __allocator_traits_rebind_t
<allocator_type
, _Tp
>;
273 struct rebind_traits
{
274 using other
= allocator_traits
<typename rebind_alloc
<_Tp
>::other
>;
276 #endif // _LIBCPP_CXX03_LANG
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
);
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
290 template <class _Ap
= _Alloc
,
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
);
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
);
305 return {__alloc
.allocate(__n
), __n
};
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
);
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
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
)...);
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
335 _LIBCPP_SUPPRESS_DEPRECATED_POP
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
);
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
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
);
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();
358 template <class _Ap
= _Alloc
,
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
) {
367 #ifndef _LIBCPP_CXX03_LANG
368 template <class _Traits
, class _Tp
>
369 using __rebind_alloc _LIBCPP_NODEBUG
= typename
_Traits::template rebind_alloc
<_Tp
>;
371 template <class _Traits
, class _Tp
>
372 using __rebind_alloc
= typename
_Traits::template rebind_alloc
<_Tp
>::other
;
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");
383 // __is_default_allocator
385 struct __is_default_allocator
: false_type
{};
391 struct __is_default_allocator
<allocator
<_Tp
> > : true_type
{};
393 // __is_cpp17_move_insertable
394 template <class _Alloc
, class = void>
395 struct __is_cpp17_move_insertable
: is_move_constructible
<typename
_Alloc::value_type
> {};
397 template <class _Alloc
>
398 struct __is_cpp17_move_insertable
<
400 __enable_if_t
< !__is_default_allocator
<_Alloc
>::value
&&
401 __has_construct
<_Alloc
, typename
_Alloc::value_type
*, typename
_Alloc::value_type
&&>::value
> >
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
> {};
411 template <class _Alloc
>
412 struct __is_cpp17_copy_insertable
<
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
> {};
418 #undef _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX
420 _LIBCPP_END_NAMESPACE_STD
424 #endif // _LIBCPP___CXX03___MEMORY_ALLOCATOR_TRAITS_H