Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===----------------------------------------------------------------------===// |
---|---|
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H |
10 | #define _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H |
11 | |
12 | #include <__assert> |
13 | #include <__config> |
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 <__new/exceptions.h> |
19 | #include <__new/placement_new_delete.h> |
20 | #include <__utility/exception_guard.h> |
21 | #include <limits> |
22 | #include <tuple> |
23 | |
24 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
25 | # pragma GCC system_header |
26 | #endif |
27 | |
28 | _LIBCPP_PUSH_MACROS |
29 | #include <__undef_macros> |
30 | |
31 | #if _LIBCPP_STD_VER >= 17 |
32 | |
33 | _LIBCPP_BEGIN_NAMESPACE_STD |
34 | |
35 | namespace pmr { |
36 | |
37 | // [mem.poly.allocator.class] |
38 | |
39 | template <class _ValueType |
40 | # if _LIBCPP_STD_VER >= 20 |
41 | = byte |
42 | # endif |
43 | > |
44 | class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator { |
45 | |
46 | public: |
47 | using value_type = _ValueType; |
48 | |
49 | // [mem.poly.allocator.ctor] |
50 | |
51 | _LIBCPP_HIDE_FROM_ABI polymorphic_allocator() noexcept : __res_(std::pmr::get_default_resource()) {} |
52 | |
53 | _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* __r) noexcept : __res_(__r) {} |
54 | |
55 | _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(const polymorphic_allocator&) = default; |
56 | |
57 | template <class _Tp> |
58 | _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(const polymorphic_allocator<_Tp>& __other) noexcept |
59 | : __res_(__other.resource()) {} |
60 | |
61 | polymorphic_allocator& operator=(const polymorphic_allocator&) = delete; |
62 | |
63 | // [mem.poly.allocator.mem] |
64 | |
65 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ValueType* allocate(size_t __n) { |
66 | if (__n > __max_size()) { |
67 | std::__throw_bad_array_new_length(); |
68 | } |
69 | return static_cast<_ValueType*>(__res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType))); |
70 | } |
71 | |
72 | _LIBCPP_HIDE_FROM_ABI void deallocate(_ValueType* __p, size_t __n) { |
73 | _LIBCPP_ASSERT_VALID_DEALLOCATION( |
74 | __n <= __max_size(), |
75 | "deallocate() called for a size which exceeds max_size(), leading to a memory leak " |
76 | "(the argument will overflow and result in too few objects being deleted)"); |
77 | __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType)); |
78 | } |
79 | |
80 | # if _LIBCPP_STD_VER >= 20 |
81 | |
82 | [[nodiscard]] [[using __gnu__: __alloc_size__(2), __alloc_align__(3)]] _LIBCPP_HIDE_FROM_ABI void* |
83 | allocate_bytes(size_t __nbytes, size_t __alignment = alignof(max_align_t)) { |
84 | return __res_->allocate(__nbytes, __alignment); |
85 | } |
86 | |
87 | _LIBCPP_HIDE_FROM_ABI void deallocate_bytes(void* __ptr, size_t __nbytes, size_t __alignment = alignof(max_align_t)) { |
88 | __res_->deallocate(__ptr, __nbytes, __alignment); |
89 | } |
90 | |
91 | template <class _Type> |
92 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Type* allocate_object(size_t __n = 1) { |
93 | if (numeric_limits<size_t>::max() / sizeof(_Type) < __n) |
94 | std::__throw_bad_array_new_length(); |
95 | return static_cast<_Type*>(allocate_bytes(__n * sizeof(_Type), alignof(_Type))); |
96 | } |
97 | |
98 | template <class _Type> |
99 | _LIBCPP_HIDE_FROM_ABI void deallocate_object(_Type* __ptr, size_t __n = 1) { |
100 | deallocate_bytes(__ptr, __n * sizeof(_Type), alignof(_Type)); |
101 | } |
102 | |
103 | template <class _Type, class... _CtorArgs> |
104 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Type* new_object(_CtorArgs&&... __ctor_args) { |
105 | _Type* __ptr = allocate_object<_Type>(); |
106 | auto __guard = std::__make_exception_guard([&] { deallocate_object(__ptr); }); |
107 | construct(__ptr, std::forward<_CtorArgs>(__ctor_args)...); |
108 | __guard.__complete(); |
109 | return __ptr; |
110 | } |
111 | |
112 | template <class _Type> |
113 | _LIBCPP_HIDE_FROM_ABI void delete_object(_Type* __ptr) { |
114 | destroy(__ptr); |
115 | deallocate_object(__ptr); |
116 | } |
117 | |
118 | # endif // _LIBCPP_STD_VER >= 20 |
119 | |
120 | template <class _Tp, class... _Ts> |
121 | _LIBCPP_HIDE_FROM_ABI void construct(_Tp* __p, _Ts&&... __args) { |
122 | std::__user_alloc_construct_impl( |
123 | typename __uses_alloc_ctor<_Tp, polymorphic_allocator&, _Ts...>::type(), |
124 | __p, |
125 | *this, |
126 | std::forward<_Ts>(__args)...); |
127 | } |
128 | |
129 | template <class _T1, class _T2, class... _Args1, class... _Args2> |
130 | _LIBCPP_HIDE_FROM_ABI void |
131 | construct(pair<_T1, _T2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) { |
132 | ::new ((void*)__p) pair<_T1, _T2>( |
133 | piecewise_construct, |
134 | __transform_tuple(typename __uses_alloc_ctor< _T1, polymorphic_allocator&, _Args1... >::type(), |
135 | std::move(__x), |
136 | typename __make_tuple_indices<sizeof...(_Args1)>::type{}), |
137 | __transform_tuple(typename __uses_alloc_ctor< _T2, polymorphic_allocator&, _Args2... >::type(), |
138 | std::move(__y), |
139 | typename __make_tuple_indices<sizeof...(_Args2)>::type{})); |
140 | } |
141 | |
142 | template <class _T1, class _T2> |
143 | _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p) { |
144 | construct(__p, piecewise_construct, tuple<>(), tuple<>()); |
145 | } |
146 | |
147 | template <class _T1, class _T2, class _Up, class _Vp> |
148 | _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, _Up&& __u, _Vp&& __v) { |
149 | construct(__p, |
150 | piecewise_construct, |
151 | std::forward_as_tuple(std::forward<_Up>(__u)), |
152 | std::forward_as_tuple(std::forward<_Vp>(__v))); |
153 | } |
154 | |
155 | template <class _T1, class _T2, class _U1, class _U2> |
156 | _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, const pair<_U1, _U2>& __pr) { |
157 | construct(__p, piecewise_construct, std::forward_as_tuple(__pr.first), std::forward_as_tuple(__pr.second)); |
158 | } |
159 | |
160 | template <class _T1, class _T2, class _U1, class _U2> |
161 | _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, pair<_U1, _U2>&& __pr) { |
162 | construct(__p, |
163 | piecewise_construct, |
164 | std::forward_as_tuple(std::forward<_U1>(__pr.first)), |
165 | std::forward_as_tuple(std::forward<_U2>(__pr.second))); |
166 | } |
167 | |
168 | template <class _Tp> |
169 | _LIBCPP_HIDE_FROM_ABI void destroy(_Tp* __p) { |
170 | __p->~_Tp(); |
171 | } |
172 | |
173 | _LIBCPP_HIDE_FROM_ABI polymorphic_allocator select_on_container_copy_construction() const noexcept { |
174 | return polymorphic_allocator(); |
175 | } |
176 | |
177 | _LIBCPP_HIDE_FROM_ABI memory_resource* resource() const noexcept { return __res_; } |
178 | |
179 | _LIBCPP_HIDE_FROM_ABI friend bool |
180 | operator==(const polymorphic_allocator& __lhs, const polymorphic_allocator& __rhs) noexcept { |
181 | return *__lhs.resource() == *__rhs.resource(); |
182 | } |
183 | |
184 | # if _LIBCPP_STD_VER <= 17 |
185 | // This overload is not specified, it was added due to LWG3683. |
186 | _LIBCPP_HIDE_FROM_ABI friend bool |
187 | operator!=(const polymorphic_allocator& __lhs, const polymorphic_allocator& __rhs) noexcept { |
188 | return *__lhs.resource() != *__rhs.resource(); |
189 | } |
190 | # endif |
191 | |
192 | private: |
193 | template <class... _Args, size_t... _Is> |
194 | _LIBCPP_HIDE_FROM_ABI tuple<_Args&&...> |
195 | __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { |
196 | return std::forward_as_tuple(std::get<_Is>(std::move(__t))...); |
197 | } |
198 | |
199 | template <class... _Args, size_t... _Is> |
200 | _LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...> |
201 | __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { |
202 | using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>; |
203 | return _Tup(allocator_arg, *this, std::get<_Is>(std::move(__t))...); |
204 | } |
205 | |
206 | template <class... _Args, size_t... _Is> |
207 | _LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., polymorphic_allocator&> |
208 | __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { |
209 | using _Tup = tuple<_Args&&..., polymorphic_allocator&>; |
210 | return _Tup(std::get<_Is>(std::move(__t))..., *this); |
211 | } |
212 | |
213 | _LIBCPP_HIDE_FROM_ABI size_t __max_size() const noexcept { |
214 | return numeric_limits<size_t>::max() / sizeof(value_type); |
215 | } |
216 | |
217 | memory_resource* __res_; |
218 | }; |
219 | |
220 | // [mem.poly.allocator.eq] |
221 | |
222 | template <class _Tp, class _Up> |
223 | inline _LIBCPP_HIDE_FROM_ABI bool |
224 | operator==(const polymorphic_allocator<_Tp>& __lhs, const polymorphic_allocator<_Up>& __rhs) noexcept { |
225 | return *__lhs.resource() == *__rhs.resource(); |
226 | } |
227 | |
228 | # if _LIBCPP_STD_VER <= 17 |
229 | |
230 | template <class _Tp, class _Up> |
231 | inline _LIBCPP_HIDE_FROM_ABI bool |
232 | operator!=(const polymorphic_allocator<_Tp>& __lhs, const polymorphic_allocator<_Up>& __rhs) noexcept { |
233 | return !(__lhs == __rhs); |
234 | } |
235 | |
236 | # endif |
237 | |
238 | } // namespace pmr |
239 | |
240 | _LIBCPP_END_NAMESPACE_STD |
241 | |
242 | #endif // _LIBCPP_STD_VER >= 17 |
243 | |
244 | _LIBCPP_POP_MACROS |
245 | |
246 | #endif // _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H |
247 |
Warning: This file is not a C or C++ file. It does not have highlighting.