1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H
10 #define _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H
13 #include <__availability>
15 #include <__memory_resource/memory_resource.h>
16 #include <__utility/exception_guard.h>
22 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23 # pragma GCC system_header
27 #include <__undef_macros>
29 #if _LIBCPP_STD_VER >= 17
31 _LIBCPP_BEGIN_NAMESPACE_STD
35 // [mem.poly.allocator.class]
37 template <class _ValueType
38 # if _LIBCPP_STD_VER >= 20
42 class _LIBCPP_AVAILABILITY_PMR _LIBCPP_TEMPLATE_VIS polymorphic_allocator
{
45 using value_type
= _ValueType
;
47 // [mem.poly.allocator.ctor]
49 _LIBCPP_HIDE_FROM_ABI
polymorphic_allocator() noexcept
: __res_(std::pmr::get_default_resource()) {}
51 _LIBCPP_HIDE_FROM_ABI
polymorphic_allocator(memory_resource
* __r
) noexcept
: __res_(__r
) {}
53 _LIBCPP_HIDE_FROM_ABI
polymorphic_allocator(const polymorphic_allocator
&) = default;
56 _LIBCPP_HIDE_FROM_ABI
polymorphic_allocator(const polymorphic_allocator
<_Tp
>& __other
) noexcept
57 : __res_(__other
.resource()) {}
59 polymorphic_allocator
& operator=(const polymorphic_allocator
&) = delete;
61 // [mem.poly.allocator.mem]
63 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI _ValueType
* allocate(size_t __n
) {
64 if (__n
> __max_size()) {
65 __throw_bad_array_new_length();
67 return static_cast<_ValueType
*>(__res_
->allocate(__n
* sizeof(_ValueType
), alignof(_ValueType
)));
70 _LIBCPP_HIDE_FROM_ABI
void deallocate(_ValueType
* __p
, size_t __n
) {
71 _LIBCPP_ASSERT_UNCATEGORIZED(__n
<= __max_size(), "deallocate called for size which exceeds max_size()");
72 __res_
->deallocate(__p
, __n
* sizeof(_ValueType
), alignof(_ValueType
));
75 # if _LIBCPP_STD_VER >= 20
77 [[nodiscard
]] [[using __gnu__
: __alloc_size__(2), __alloc_align__(3)]] _LIBCPP_HIDE_FROM_ABI
void*
78 allocate_bytes(size_t __nbytes
, size_t __alignment
= alignof(max_align_t
)) {
79 return __res_
->allocate(__nbytes
, __alignment
);
82 _LIBCPP_HIDE_FROM_ABI
void deallocate_bytes(void* __ptr
, size_t __nbytes
, size_t __alignment
= alignof(max_align_t
)) {
83 __res_
->deallocate(__ptr
, __nbytes
, __alignment
);
86 template <class _Type
>
87 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI _Type
* allocate_object(size_t __n
= 1) {
88 if (numeric_limits
<size_t>::max() / sizeof(_Type
) < __n
)
89 std::__throw_bad_array_new_length();
90 return static_cast<_Type
*>(allocate_bytes(__n
* sizeof(_Type
), alignof(_Type
)));
93 template <class _Type
>
94 _LIBCPP_HIDE_FROM_ABI
void deallocate_object(_Type
* __ptr
, size_t __n
= 1) {
95 deallocate_bytes(__ptr
, __n
* sizeof(_Type
), alignof(_Type
));
98 template <class _Type
, class... _CtorArgs
>
99 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI _Type
* new_object(_CtorArgs
&&... __ctor_args
) {
100 _Type
* __ptr
= allocate_object
<_Type
>();
101 auto __guard
= std::__make_exception_guard([&] { deallocate_object(__ptr
); });
102 construct(__ptr
, std::forward
<_CtorArgs
>(__ctor_args
)...);
103 __guard
.__complete();
107 template <class _Type
>
108 _LIBCPP_HIDE_FROM_ABI
void delete_object(_Type
* __ptr
) {
110 deallocate_object(__ptr
);
113 # endif // _LIBCPP_STD_VER >= 20
115 template <class _Tp
, class... _Ts
>
116 _LIBCPP_HIDE_FROM_ABI
void construct(_Tp
* __p
, _Ts
&&... __args
) {
117 std::__user_alloc_construct_impl(
118 typename __uses_alloc_ctor
<_Tp
, polymorphic_allocator
&, _Ts
...>::type(),
121 std::forward
<_Ts
>(__args
)...);
124 template <class _T1
, class _T2
, class... _Args1
, class... _Args2
>
125 _LIBCPP_HIDE_FROM_ABI
void
126 construct(pair
<_T1
, _T2
>* __p
, piecewise_construct_t
, tuple
<_Args1
...> __x
, tuple
<_Args2
...> __y
) {
127 ::new ((void*)__p
) pair
<_T1
, _T2
>(
129 __transform_tuple(typename __uses_alloc_ctor
< _T1
, polymorphic_allocator
&, _Args1
... >::type(),
131 typename __make_tuple_indices
<sizeof...(_Args1
)>::type
{}),
132 __transform_tuple(typename __uses_alloc_ctor
< _T2
, polymorphic_allocator
&, _Args2
... >::type(),
134 typename __make_tuple_indices
<sizeof...(_Args2
)>::type
{}));
137 template <class _T1
, class _T2
>
138 _LIBCPP_HIDE_FROM_ABI
void construct(pair
<_T1
, _T2
>* __p
) {
139 construct(__p
, piecewise_construct
, tuple
<>(), tuple
<>());
142 template <class _T1
, class _T2
, class _Up
, class _Vp
>
143 _LIBCPP_HIDE_FROM_ABI
void construct(pair
<_T1
, _T2
>* __p
, _Up
&& __u
, _Vp
&& __v
) {
146 std::forward_as_tuple(std::forward
<_Up
>(__u
)),
147 std::forward_as_tuple(std::forward
<_Vp
>(__v
)));
150 template <class _T1
, class _T2
, class _U1
, class _U2
>
151 _LIBCPP_HIDE_FROM_ABI
void construct(pair
<_T1
, _T2
>* __p
, const pair
<_U1
, _U2
>& __pr
) {
152 construct(__p
, piecewise_construct
, std::forward_as_tuple(__pr
.first
), std::forward_as_tuple(__pr
.second
));
155 template <class _T1
, class _T2
, class _U1
, class _U2
>
156 _LIBCPP_HIDE_FROM_ABI
void construct(pair
<_T1
, _T2
>* __p
, pair
<_U1
, _U2
>&& __pr
) {
159 std::forward_as_tuple(std::forward
<_U1
>(__pr
.first
)),
160 std::forward_as_tuple(std::forward
<_U2
>(__pr
.second
)));
164 _LIBCPP_HIDE_FROM_ABI
void destroy(_Tp
* __p
) {
168 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator
select_on_container_copy_construction() const noexcept
{
169 return polymorphic_allocator();
172 _LIBCPP_HIDE_FROM_ABI memory_resource
* resource() const noexcept
{ return __res_
; }
175 template <class... _Args
, size_t... _Is
>
176 _LIBCPP_HIDE_FROM_ABI tuple
<_Args
&&...>
177 __transform_tuple(integral_constant
<int, 0>, tuple
<_Args
...>&& __t
, __tuple_indices
<_Is
...>) {
178 return std::forward_as_tuple(std::get
<_Is
>(std::move(__t
))...);
181 template <class... _Args
, size_t... _Is
>
182 _LIBCPP_HIDE_FROM_ABI tuple
<allocator_arg_t
const&, polymorphic_allocator
&, _Args
&&...>
183 __transform_tuple(integral_constant
<int, 1>, tuple
<_Args
...>&& __t
, __tuple_indices
<_Is
...>) {
184 using _Tup
= tuple
<allocator_arg_t
const&, polymorphic_allocator
&, _Args
&&...>;
185 return _Tup(allocator_arg
, *this, std::get
<_Is
>(std::move(__t
))...);
188 template <class... _Args
, size_t... _Is
>
189 _LIBCPP_HIDE_FROM_ABI tuple
<_Args
&&..., polymorphic_allocator
&>
190 __transform_tuple(integral_constant
<int, 2>, tuple
<_Args
...>&& __t
, __tuple_indices
<_Is
...>) {
191 using _Tup
= tuple
<_Args
&&..., polymorphic_allocator
&>;
192 return _Tup(std::get
<_Is
>(std::move(__t
))..., *this);
195 _LIBCPP_HIDE_FROM_ABI
size_t __max_size() const noexcept
{
196 return numeric_limits
<size_t>::max() / sizeof(value_type
);
199 memory_resource
* __res_
;
202 // [mem.poly.allocator.eq]
204 template <class _Tp
, class _Up
>
205 inline _LIBCPP_HIDE_FROM_ABI
bool
206 operator==(const polymorphic_allocator
<_Tp
>& __lhs
, const polymorphic_allocator
<_Up
>& __rhs
) noexcept
{
207 return *__lhs
.resource() == *__rhs
.resource();
210 # if _LIBCPP_STD_VER <= 17
212 template <class _Tp
, class _Up
>
213 inline _LIBCPP_HIDE_FROM_ABI
bool
214 operator!=(const polymorphic_allocator
<_Tp
>& __lhs
, const polymorphic_allocator
<_Up
>& __rhs
) noexcept
{
215 return !(__lhs
== __rhs
);
222 _LIBCPP_END_NAMESPACE_STD
224 #endif // _LIBCPP_STD_VER >= 17
228 #endif // _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H