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
14 #include <__cstddef/byte.h>
15 #include <__cstddef/max_align_t.h>
16 #include <__fwd/pair.h>
17 #include <__memory_resource/memory_resource.h>
18 #include <__utility/exception_guard.h>
23 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24 # pragma GCC system_header
28 #include <__undef_macros>
30 #if _LIBCPP_STD_VER >= 17
32 _LIBCPP_BEGIN_NAMESPACE_STD
36 // [mem.poly.allocator.class]
38 template <class _ValueType
39 # if _LIBCPP_STD_VER >= 20
43 class _LIBCPP_AVAILABILITY_PMR _LIBCPP_TEMPLATE_VIS polymorphic_allocator
{
46 using value_type
= _ValueType
;
48 // [mem.poly.allocator.ctor]
50 _LIBCPP_HIDE_FROM_ABI
polymorphic_allocator() noexcept
: __res_(std::pmr::get_default_resource()) {}
52 _LIBCPP_HIDE_FROM_ABI
polymorphic_allocator(memory_resource
* __r
) noexcept
: __res_(__r
) {}
54 _LIBCPP_HIDE_FROM_ABI
polymorphic_allocator(const polymorphic_allocator
&) = default;
57 _LIBCPP_HIDE_FROM_ABI
polymorphic_allocator(const polymorphic_allocator
<_Tp
>& __other
) noexcept
58 : __res_(__other
.resource()) {}
60 polymorphic_allocator
& operator=(const polymorphic_allocator
&) = delete;
62 // [mem.poly.allocator.mem]
64 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI _ValueType
* allocate(size_t __n
) {
65 if (__n
> __max_size()) {
66 __throw_bad_array_new_length();
68 return static_cast<_ValueType
*>(__res_
->allocate(__n
* sizeof(_ValueType
), alignof(_ValueType
)));
71 _LIBCPP_HIDE_FROM_ABI
void deallocate(_ValueType
* __p
, size_t __n
) {
72 _LIBCPP_ASSERT_VALID_DEALLOCATION(
74 "deallocate() called for a size which exceeds max_size(), leading to a memory leak "
75 "(the argument will overflow and result in too few objects being deleted)");
76 __res_
->deallocate(__p
, __n
* sizeof(_ValueType
), alignof(_ValueType
));
79 # if _LIBCPP_STD_VER >= 20
81 [[nodiscard
]] [[using __gnu__
: __alloc_size__(2), __alloc_align__(3)]] _LIBCPP_HIDE_FROM_ABI
void*
82 allocate_bytes(size_t __nbytes
, size_t __alignment
= alignof(max_align_t
)) {
83 return __res_
->allocate(__nbytes
, __alignment
);
86 _LIBCPP_HIDE_FROM_ABI
void deallocate_bytes(void* __ptr
, size_t __nbytes
, size_t __alignment
= alignof(max_align_t
)) {
87 __res_
->deallocate(__ptr
, __nbytes
, __alignment
);
90 template <class _Type
>
91 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI _Type
* allocate_object(size_t __n
= 1) {
92 if (numeric_limits
<size_t>::max() / sizeof(_Type
) < __n
)
93 std::__throw_bad_array_new_length();
94 return static_cast<_Type
*>(allocate_bytes(__n
* sizeof(_Type
), alignof(_Type
)));
97 template <class _Type
>
98 _LIBCPP_HIDE_FROM_ABI
void deallocate_object(_Type
* __ptr
, size_t __n
= 1) {
99 deallocate_bytes(__ptr
, __n
* sizeof(_Type
), alignof(_Type
));
102 template <class _Type
, class... _CtorArgs
>
103 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI _Type
* new_object(_CtorArgs
&&... __ctor_args
) {
104 _Type
* __ptr
= allocate_object
<_Type
>();
105 auto __guard
= std::__make_exception_guard([&] { deallocate_object(__ptr
); });
106 construct(__ptr
, std::forward
<_CtorArgs
>(__ctor_args
)...);
107 __guard
.__complete();
111 template <class _Type
>
112 _LIBCPP_HIDE_FROM_ABI
void delete_object(_Type
* __ptr
) {
114 deallocate_object(__ptr
);
117 # endif // _LIBCPP_STD_VER >= 20
119 template <class _Tp
, class... _Ts
>
120 _LIBCPP_HIDE_FROM_ABI
void construct(_Tp
* __p
, _Ts
&&... __args
) {
121 std::__user_alloc_construct_impl(
122 typename __uses_alloc_ctor
<_Tp
, polymorphic_allocator
&, _Ts
...>::type(),
125 std::forward
<_Ts
>(__args
)...);
128 template <class _T1
, class _T2
, class... _Args1
, class... _Args2
>
129 _LIBCPP_HIDE_FROM_ABI
void
130 construct(pair
<_T1
, _T2
>* __p
, piecewise_construct_t
, tuple
<_Args1
...> __x
, tuple
<_Args2
...> __y
) {
131 ::new ((void*)__p
) pair
<_T1
, _T2
>(
133 __transform_tuple(typename __uses_alloc_ctor
< _T1
, polymorphic_allocator
&, _Args1
... >::type(),
135 typename __make_tuple_indices
<sizeof...(_Args1
)>::type
{}),
136 __transform_tuple(typename __uses_alloc_ctor
< _T2
, polymorphic_allocator
&, _Args2
... >::type(),
138 typename __make_tuple_indices
<sizeof...(_Args2
)>::type
{}));
141 template <class _T1
, class _T2
>
142 _LIBCPP_HIDE_FROM_ABI
void construct(pair
<_T1
, _T2
>* __p
) {
143 construct(__p
, piecewise_construct
, tuple
<>(), tuple
<>());
146 template <class _T1
, class _T2
, class _Up
, class _Vp
>
147 _LIBCPP_HIDE_FROM_ABI
void construct(pair
<_T1
, _T2
>* __p
, _Up
&& __u
, _Vp
&& __v
) {
150 std::forward_as_tuple(std::forward
<_Up
>(__u
)),
151 std::forward_as_tuple(std::forward
<_Vp
>(__v
)));
154 template <class _T1
, class _T2
, class _U1
, class _U2
>
155 _LIBCPP_HIDE_FROM_ABI
void construct(pair
<_T1
, _T2
>* __p
, const pair
<_U1
, _U2
>& __pr
) {
156 construct(__p
, piecewise_construct
, std::forward_as_tuple(__pr
.first
), std::forward_as_tuple(__pr
.second
));
159 template <class _T1
, class _T2
, class _U1
, class _U2
>
160 _LIBCPP_HIDE_FROM_ABI
void construct(pair
<_T1
, _T2
>* __p
, pair
<_U1
, _U2
>&& __pr
) {
163 std::forward_as_tuple(std::forward
<_U1
>(__pr
.first
)),
164 std::forward_as_tuple(std::forward
<_U2
>(__pr
.second
)));
168 _LIBCPP_HIDE_FROM_ABI
void destroy(_Tp
* __p
) {
172 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator
select_on_container_copy_construction() const noexcept
{
173 return polymorphic_allocator();
176 _LIBCPP_HIDE_FROM_ABI memory_resource
* resource() const noexcept
{ return __res_
; }
178 _LIBCPP_HIDE_FROM_ABI
friend bool
179 operator==(const polymorphic_allocator
& __lhs
, const polymorphic_allocator
& __rhs
) noexcept
{
180 return *__lhs
.resource() == *__rhs
.resource();
183 # if _LIBCPP_STD_VER <= 17
184 // This overload is not specified, it was added due to LWG3683.
185 _LIBCPP_HIDE_FROM_ABI
friend bool
186 operator!=(const polymorphic_allocator
& __lhs
, const polymorphic_allocator
& __rhs
) noexcept
{
187 return *__lhs
.resource() != *__rhs
.resource();
192 template <class... _Args
, size_t... _Is
>
193 _LIBCPP_HIDE_FROM_ABI tuple
<_Args
&&...>
194 __transform_tuple(integral_constant
<int, 0>, tuple
<_Args
...>&& __t
, __tuple_indices
<_Is
...>) {
195 return std::forward_as_tuple(std::get
<_Is
>(std::move(__t
))...);
198 template <class... _Args
, size_t... _Is
>
199 _LIBCPP_HIDE_FROM_ABI tuple
<allocator_arg_t
const&, polymorphic_allocator
&, _Args
&&...>
200 __transform_tuple(integral_constant
<int, 1>, tuple
<_Args
...>&& __t
, __tuple_indices
<_Is
...>) {
201 using _Tup
= tuple
<allocator_arg_t
const&, polymorphic_allocator
&, _Args
&&...>;
202 return _Tup(allocator_arg
, *this, std::get
<_Is
>(std::move(__t
))...);
205 template <class... _Args
, size_t... _Is
>
206 _LIBCPP_HIDE_FROM_ABI tuple
<_Args
&&..., polymorphic_allocator
&>
207 __transform_tuple(integral_constant
<int, 2>, tuple
<_Args
...>&& __t
, __tuple_indices
<_Is
...>) {
208 using _Tup
= tuple
<_Args
&&..., polymorphic_allocator
&>;
209 return _Tup(std::get
<_Is
>(std::move(__t
))..., *this);
212 _LIBCPP_HIDE_FROM_ABI
size_t __max_size() const noexcept
{
213 return numeric_limits
<size_t>::max() / sizeof(value_type
);
216 memory_resource
* __res_
;
219 // [mem.poly.allocator.eq]
221 template <class _Tp
, class _Up
>
222 inline _LIBCPP_HIDE_FROM_ABI
bool
223 operator==(const polymorphic_allocator
<_Tp
>& __lhs
, const polymorphic_allocator
<_Up
>& __rhs
) noexcept
{
224 return *__lhs
.resource() == *__rhs
.resource();
227 # if _LIBCPP_STD_VER <= 17
229 template <class _Tp
, class _Up
>
230 inline _LIBCPP_HIDE_FROM_ABI
bool
231 operator!=(const polymorphic_allocator
<_Tp
>& __lhs
, const polymorphic_allocator
<_Up
>& __rhs
) noexcept
{
232 return !(__lhs
== __rhs
);
239 _LIBCPP_END_NAMESPACE_STD
241 #endif // _LIBCPP_STD_VER >= 17
245 #endif // _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H