]>
Commit | Line | Data |
---|---|---|
dfaa3c47 JW |
1 | // <memory_resource> -*- C++ -*- |
2 | ||
99dee823 | 3 | // Copyright (C) 2018-2021 Free Software Foundation, Inc. |
dfaa3c47 JW |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
8 | // Free Software Foundation; either version 3, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // Under Section 7 of GPL version 3, you are granted additional | |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
24 | ||
25 | /** @file include/memory_resource | |
26 | * This is a Standard C++ Library header. | |
27 | */ | |
28 | ||
29 | #ifndef _GLIBCXX_MEMORY_RESOURCE | |
30 | #define _GLIBCXX_MEMORY_RESOURCE 1 | |
31 | ||
32 | #pragma GCC system_header | |
33 | ||
34 | #if __cplusplus >= 201703L | |
35 | ||
852a971c | 36 | #include <vector> // vector |
0e318273 | 37 | #include <cstddef> // size_t, max_align_t, byte |
c5be6481 | 38 | #include <shared_mutex> // shared_mutex |
b1e7c6fc JW |
39 | #include <bits/align.h> // align |
40 | #include <bits/functexcept.h> // __throw_bad_array_new_length | |
41 | #include <bits/uses_allocator.h> // __use_alloc | |
42 | #include <bits/uses_allocator_args.h> // uninitialized_construct_using_alloc | |
eb04805b | 43 | #include <ext/numeric_traits.h> |
dfaa3c47 JW |
44 | #include <debug/assertions.h> |
45 | ||
b1e7c6fc JW |
46 | #if ! __cpp_lib_make_obj_using_allocator |
47 | # include <utility> // pair, index_sequence | |
ca021ac6 | 48 | # include <tuple> // tuple, forward_as_tuple |
b1e7c6fc JW |
49 | #endif |
50 | ||
dfaa3c47 JW |
51 | namespace std _GLIBCXX_VISIBILITY(default) |
52 | { | |
53 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
54 | namespace pmr | |
55 | { | |
c5be6481 JW |
56 | #ifdef _GLIBCXX_HAS_GTHREADS |
57 | // Header and all contents are present. | |
b1e7c6fc | 58 | # define __cpp_lib_memory_resource 201603L |
c5be6481 JW |
59 | #else |
60 | // The pmr::synchronized_pool_resource type is missing. | |
61 | # define __cpp_lib_memory_resource 1 | |
62 | #endif | |
dfaa3c47 JW |
63 | |
64 | class memory_resource; | |
65 | ||
0e318273 | 66 | #if __cplusplus == 201703L |
dfaa3c47 JW |
67 | template<typename _Tp> |
68 | class polymorphic_allocator; | |
0e318273 | 69 | #else // C++20 |
56772f62 | 70 | # define __cpp_lib_polymorphic_allocator 201902L |
0e318273 JW |
71 | template<typename _Tp = std::byte> |
72 | class polymorphic_allocator; | |
73 | #endif | |
dfaa3c47 JW |
74 | |
75 | // Global memory resources | |
76 | memory_resource* new_delete_resource() noexcept; | |
77 | memory_resource* null_memory_resource() noexcept; | |
78 | memory_resource* set_default_resource(memory_resource* __r) noexcept; | |
79 | memory_resource* get_default_resource() noexcept | |
80 | __attribute__((__returns_nonnull__)); | |
81 | ||
82 | // Pool resource classes | |
83 | struct pool_options; | |
c5be6481 | 84 | #ifdef _GLIBCXX_HAS_GTHREADS |
dfaa3c47 | 85 | class synchronized_pool_resource; |
c5be6481 | 86 | #endif |
dfaa3c47 JW |
87 | class unsynchronized_pool_resource; |
88 | class monotonic_buffer_resource; | |
89 | ||
90 | /// Class memory_resource | |
91 | class memory_resource | |
92 | { | |
93 | static constexpr size_t _S_max_align = alignof(max_align_t); | |
94 | ||
95 | public: | |
96 | memory_resource() = default; | |
97 | memory_resource(const memory_resource&) = default; | |
d574c8aa | 98 | virtual ~memory_resource(); // key function |
dfaa3c47 JW |
99 | |
100 | memory_resource& operator=(const memory_resource&) = default; | |
101 | ||
102 | [[nodiscard]] | |
103 | void* | |
104 | allocate(size_t __bytes, size_t __alignment = _S_max_align) | |
105 | __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3))) | |
106 | { return do_allocate(__bytes, __alignment); } | |
107 | ||
108 | void | |
109 | deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) | |
110 | __attribute__((__nonnull__)) | |
111 | { return do_deallocate(__p, __bytes, __alignment); } | |
112 | ||
113 | bool | |
114 | is_equal(const memory_resource& __other) const noexcept | |
115 | { return do_is_equal(__other); } | |
116 | ||
117 | private: | |
118 | virtual void* | |
119 | do_allocate(size_t __bytes, size_t __alignment) = 0; | |
120 | ||
121 | virtual void | |
122 | do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; | |
123 | ||
124 | virtual bool | |
125 | do_is_equal(const memory_resource& __other) const noexcept = 0; | |
126 | }; | |
127 | ||
128 | inline bool | |
129 | operator==(const memory_resource& __a, const memory_resource& __b) noexcept | |
130 | { return &__a == &__b || __a.is_equal(__b); } | |
131 | ||
596676d6 | 132 | #if __cpp_impl_three_way_comparison < 201907L |
dfaa3c47 JW |
133 | inline bool |
134 | operator!=(const memory_resource& __a, const memory_resource& __b) noexcept | |
135 | { return !(__a == __b); } | |
596676d6 | 136 | #endif |
dfaa3c47 JW |
137 | |
138 | // C++17 23.12.3 Class template polymorphic_allocator | |
139 | template<typename _Tp> | |
140 | class polymorphic_allocator | |
141 | { | |
142 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
143 | // 2975. Missing case for pair construction in polymorphic allocators | |
144 | template<typename _Up> | |
145 | struct __not_pair { using type = void; }; | |
146 | ||
147 | template<typename _Up1, typename _Up2> | |
148 | struct __not_pair<pair<_Up1, _Up2>> { }; | |
149 | ||
150 | public: | |
151 | using value_type = _Tp; | |
152 | ||
153 | polymorphic_allocator() noexcept | |
154 | : _M_resource(get_default_resource()) | |
155 | { } | |
156 | ||
157 | polymorphic_allocator(memory_resource* __r) noexcept | |
158 | __attribute__((__nonnull__)) | |
159 | : _M_resource(__r) | |
160 | { _GLIBCXX_DEBUG_ASSERT(__r); } | |
161 | ||
162 | polymorphic_allocator(const polymorphic_allocator& __other) = default; | |
163 | ||
164 | template<typename _Up> | |
165 | polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept | |
166 | : _M_resource(__x.resource()) | |
167 | { } | |
168 | ||
169 | polymorphic_allocator& | |
170 | operator=(const polymorphic_allocator&) = delete; | |
171 | ||
172 | [[nodiscard]] | |
173 | _Tp* | |
174 | allocate(size_t __n) | |
175 | __attribute__((__returns_nonnull__)) | |
176 | { | |
f92a504f JW |
177 | if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n) |
178 | std::__throw_bad_array_new_length(); | |
dfaa3c47 JW |
179 | return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), |
180 | alignof(_Tp))); | |
181 | } | |
182 | ||
183 | void | |
184 | deallocate(_Tp* __p, size_t __n) noexcept | |
185 | __attribute__((__nonnull__)) | |
186 | { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } | |
187 | ||
0e318273 | 188 | #if __cplusplus > 201703L |
020a03ee | 189 | [[nodiscard]] void* |
0e318273 JW |
190 | allocate_bytes(size_t __nbytes, |
191 | size_t __alignment = alignof(max_align_t)) | |
192 | { return _M_resource->allocate(__nbytes, __alignment); } | |
193 | ||
194 | void | |
195 | deallocate_bytes(void* __p, size_t __nbytes, | |
196 | size_t __alignment = alignof(max_align_t)) | |
197 | { _M_resource->deallocate(__p, __nbytes, __alignment); } | |
198 | ||
199 | template<typename _Up> | |
020a03ee | 200 | [[nodiscard]] _Up* |
0e318273 JW |
201 | allocate_object(size_t __n = 1) |
202 | { | |
eb04805b | 203 | if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n) |
f92a504f | 204 | std::__throw_bad_array_new_length(); |
0e318273 JW |
205 | return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up), |
206 | alignof(_Up))); | |
207 | } | |
208 | ||
209 | template<typename _Up> | |
210 | void | |
211 | deallocate_object(_Up* __p, size_t __n = 1) | |
212 | { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); } | |
213 | ||
214 | template<typename _Up, typename... _CtorArgs> | |
020a03ee | 215 | [[nodiscard]] _Up* |
0e318273 JW |
216 | new_object(_CtorArgs&&... __ctor_args) |
217 | { | |
218 | _Up* __p = allocate_object<_Up>(); | |
219 | __try | |
220 | { | |
221 | construct(__p, std::forward<_CtorArgs>(__ctor_args)...); | |
222 | } | |
223 | __catch (...) | |
224 | { | |
225 | deallocate_object(__p); | |
226 | __throw_exception_again; | |
227 | } | |
228 | return __p; | |
229 | } | |
230 | ||
231 | template<typename _Up> | |
232 | void | |
233 | delete_object(_Up* __p) | |
234 | { | |
235 | destroy(__p); | |
236 | deallocate_object(__p); | |
237 | } | |
238 | #endif // C++2a | |
239 | ||
b1e7c6fc | 240 | #if ! __cpp_lib_make_obj_using_allocator |
dfaa3c47 JW |
241 | template<typename _Tp1, typename... _Args> |
242 | __attribute__((__nonnull__)) | |
b479fbad | 243 | typename __not_pair<_Tp1>::type |
dfaa3c47 JW |
244 | construct(_Tp1* __p, _Args&&... __args) |
245 | { | |
246 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
247 | // 2969. polymorphic_allocator::construct() shouldn't pass resource() | |
b479fbad JW |
248 | using __use_tag |
249 | = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>; | |
250 | if constexpr (is_base_of_v<__uses_alloc0, __use_tag>) | |
251 | ::new(__p) _Tp1(std::forward<_Args>(__args)...); | |
252 | else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>) | |
253 | ::new(__p) _Tp1(allocator_arg, *this, | |
254 | std::forward<_Args>(__args)...); | |
255 | else | |
256 | ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this); | |
dfaa3c47 JW |
257 | } |
258 | ||
259 | template<typename _Tp1, typename _Tp2, | |
260 | typename... _Args1, typename... _Args2> | |
261 | __attribute__((__nonnull__)) | |
262 | void | |
263 | construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, | |
264 | tuple<_Args1...> __x, tuple<_Args2...> __y) | |
265 | { | |
266 | auto __x_tag = | |
267 | __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this); | |
268 | auto __y_tag = | |
269 | __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this); | |
270 | index_sequence_for<_Args1...> __x_i; | |
271 | index_sequence_for<_Args2...> __y_i; | |
272 | ||
273 | ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct, | |
b479fbad JW |
274 | _S_construct_p(__x_tag, __x_i, __x), |
275 | _S_construct_p(__y_tag, __y_i, __y)); | |
dfaa3c47 JW |
276 | } |
277 | ||
278 | template<typename _Tp1, typename _Tp2> | |
279 | __attribute__((__nonnull__)) | |
280 | void | |
281 | construct(pair<_Tp1, _Tp2>* __p) | |
282 | { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } | |
283 | ||
284 | template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp> | |
285 | __attribute__((__nonnull__)) | |
286 | void | |
287 | construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y) | |
288 | { | |
289 | this->construct(__p, piecewise_construct, | |
ca021ac6 JW |
290 | std::forward_as_tuple(std::forward<_Up>(__x)), |
291 | std::forward_as_tuple(std::forward<_Vp>(__y))); | |
dfaa3c47 JW |
292 | } |
293 | ||
294 | template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> | |
295 | __attribute__((__nonnull__)) | |
296 | void | |
297 | construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr) | |
298 | { | |
299 | this->construct(__p, piecewise_construct, | |
ca021ac6 JW |
300 | std::forward_as_tuple(__pr.first), |
301 | std::forward_as_tuple(__pr.second)); | |
dfaa3c47 JW |
302 | } |
303 | ||
304 | template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp> | |
305 | __attribute__((__nonnull__)) | |
306 | void | |
307 | construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr) | |
308 | { | |
309 | this->construct(__p, piecewise_construct, | |
ca021ac6 JW |
310 | std::forward_as_tuple(std::forward<_Up>(__pr.first)), |
311 | std::forward_as_tuple(std::forward<_Vp>(__pr.second))); | |
dfaa3c47 | 312 | } |
b1e7c6fc | 313 | #else // make_obj_using_allocator |
987bbe48 JW |
314 | template<typename _Tp1, typename... _Args> |
315 | __attribute__((__nonnull__)) | |
316 | void | |
317 | construct(_Tp1* __p, _Args&&... __args) | |
318 | { | |
319 | std::uninitialized_construct_using_allocator(__p, *this, | |
320 | std::forward<_Args>(__args)...); | |
321 | } | |
322 | #endif | |
dfaa3c47 JW |
323 | |
324 | template<typename _Up> | |
325 | __attribute__((__nonnull__)) | |
326 | void | |
327 | destroy(_Up* __p) | |
328 | { __p->~_Up(); } | |
329 | ||
330 | polymorphic_allocator | |
331 | select_on_container_copy_construction() const noexcept | |
332 | { return polymorphic_allocator(); } | |
333 | ||
334 | memory_resource* | |
335 | resource() const noexcept | |
336 | __attribute__((__returns_nonnull__)) | |
337 | { return _M_resource; } | |
338 | ||
339 | private: | |
340 | using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>; | |
341 | using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>; | |
342 | ||
b1e7c6fc | 343 | #if ! __cpp_lib_make_obj_using_allocator |
dfaa3c47 JW |
344 | template<typename _Ind, typename... _Args> |
345 | static tuple<_Args&&...> | |
346 | _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t) | |
347 | { return std::move(__t); } | |
348 | ||
349 | template<size_t... _Ind, typename... _Args> | |
b479fbad | 350 | static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...> |
dfaa3c47 JW |
351 | _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>, |
352 | tuple<_Args...>& __t) | |
353 | { | |
354 | return { | |
355 | allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))... | |
356 | }; | |
357 | } | |
358 | ||
359 | template<size_t... _Ind, typename... _Args> | |
b479fbad | 360 | static tuple<_Args&&..., polymorphic_allocator> |
dfaa3c47 JW |
361 | _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>, |
362 | tuple<_Args...>& __t) | |
363 | { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; } | |
b1e7c6fc | 364 | #endif |
dfaa3c47 JW |
365 | |
366 | memory_resource* _M_resource; | |
367 | }; | |
368 | ||
369 | template<typename _Tp1, typename _Tp2> | |
370 | inline bool | |
371 | operator==(const polymorphic_allocator<_Tp1>& __a, | |
372 | const polymorphic_allocator<_Tp2>& __b) noexcept | |
373 | { return *__a.resource() == *__b.resource(); } | |
374 | ||
596676d6 | 375 | #if __cpp_impl_three_way_comparison < 201907L |
dfaa3c47 JW |
376 | template<typename _Tp1, typename _Tp2> |
377 | inline bool | |
378 | operator!=(const polymorphic_allocator<_Tp1>& __a, | |
379 | const polymorphic_allocator<_Tp2>& __b) noexcept | |
380 | { return !(__a == __b); } | |
596676d6 | 381 | #endif |
dfaa3c47 | 382 | |
36d2acbd | 383 | /// Parameters for tuning a pool resource's behaviour. |
dfaa3c47 JW |
384 | struct pool_options |
385 | { | |
36d2acbd JW |
386 | /** @brief Upper limit on number of blocks in a chunk. |
387 | * | |
388 | * A lower value prevents allocating huge chunks that could remain mostly | |
389 | * unused, but means pools will need to replenished more frequently. | |
390 | */ | |
dfaa3c47 | 391 | size_t max_blocks_per_chunk = 0; |
36d2acbd JW |
392 | |
393 | /* @brief Largest block size (in bytes) that should be served from pools. | |
394 | * | |
395 | * Larger allocations will be served directly by the upstream resource, | |
396 | * not from one of the pools managed by the pool resource. | |
397 | */ | |
dfaa3c47 JW |
398 | size_t largest_required_pool_block = 0; |
399 | }; | |
400 | ||
36d2acbd | 401 | // Common implementation details for un-/synchronized pool resources. |
852a971c JW |
402 | class __pool_resource |
403 | { | |
404 | friend class synchronized_pool_resource; | |
405 | friend class unsynchronized_pool_resource; | |
406 | ||
407 | __pool_resource(const pool_options& __opts, memory_resource* __upstream); | |
408 | ||
409 | ~__pool_resource(); | |
410 | ||
411 | __pool_resource(const __pool_resource&) = delete; | |
412 | __pool_resource& operator=(const __pool_resource&) = delete; | |
413 | ||
414 | // Allocate a large unpooled block. | |
415 | void* | |
416 | allocate(size_t __bytes, size_t __alignment); | |
417 | ||
418 | // Deallocate a large unpooled block. | |
419 | void | |
420 | deallocate(void* __p, size_t __bytes, size_t __alignment); | |
421 | ||
422 | ||
423 | // Deallocate unpooled memory. | |
424 | void release() noexcept; | |
425 | ||
426 | memory_resource* resource() const noexcept | |
427 | { return _M_unpooled.get_allocator().resource(); } | |
428 | ||
429 | struct _Pool; | |
430 | ||
431 | _Pool* _M_alloc_pools(); | |
432 | ||
433 | const pool_options _M_opts; | |
434 | ||
435 | struct _BigBlock; | |
436 | // Collection of blocks too big for any pool, sorted by address. | |
437 | // This also stores the only copy of the upstream memory resource pointer. | |
1f48525d | 438 | _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled; |
852a971c JW |
439 | |
440 | const int _M_npools; | |
441 | }; | |
442 | ||
c5be6481 JW |
443 | #ifdef _GLIBCXX_HAS_GTHREADS |
444 | /// A thread-safe memory resource that manages pools of fixed-size blocks. | |
445 | class synchronized_pool_resource : public memory_resource | |
446 | { | |
447 | public: | |
448 | synchronized_pool_resource(const pool_options& __opts, | |
449 | memory_resource* __upstream) | |
450 | __attribute__((__nonnull__)); | |
451 | ||
452 | synchronized_pool_resource() | |
453 | : synchronized_pool_resource(pool_options(), get_default_resource()) | |
454 | { } | |
455 | ||
456 | explicit | |
457 | synchronized_pool_resource(memory_resource* __upstream) | |
458 | __attribute__((__nonnull__)) | |
459 | : synchronized_pool_resource(pool_options(), __upstream) | |
460 | { } | |
461 | ||
462 | explicit | |
463 | synchronized_pool_resource(const pool_options& __opts) | |
464 | : synchronized_pool_resource(__opts, get_default_resource()) { } | |
465 | ||
466 | synchronized_pool_resource(const synchronized_pool_resource&) = delete; | |
467 | ||
468 | virtual ~synchronized_pool_resource(); | |
469 | ||
470 | synchronized_pool_resource& | |
471 | operator=(const synchronized_pool_resource&) = delete; | |
472 | ||
473 | void release(); | |
474 | ||
475 | memory_resource* | |
476 | upstream_resource() const noexcept | |
477 | __attribute__((__returns_nonnull__)) | |
478 | { return _M_impl.resource(); } | |
479 | ||
480 | pool_options options() const noexcept { return _M_impl._M_opts; } | |
481 | ||
482 | protected: | |
483 | void* | |
484 | do_allocate(size_t __bytes, size_t __alignment) override; | |
485 | ||
486 | void | |
487 | do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; | |
488 | ||
489 | bool | |
490 | do_is_equal(const memory_resource& __other) const noexcept override | |
491 | { return this == &__other; } | |
492 | ||
493 | public: | |
494 | // Thread-specific pools (only public for access by implementation details) | |
495 | struct _TPools; | |
496 | ||
497 | private: | |
498 | _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&); | |
499 | _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&); | |
500 | auto _M_thread_specific_pools() noexcept; | |
501 | ||
502 | __pool_resource _M_impl; | |
503 | __gthread_key_t _M_key; | |
504 | // Linked list of thread-specific pools. All threads share _M_tpools[0]. | |
505 | _TPools* _M_tpools = nullptr; | |
506 | mutable shared_mutex _M_mx; | |
507 | }; | |
508 | #endif | |
852a971c JW |
509 | |
510 | /// A non-thread-safe memory resource that manages pools of fixed-size blocks. | |
511 | class unsynchronized_pool_resource : public memory_resource | |
512 | { | |
513 | public: | |
514 | [[__gnu__::__nonnull__]] | |
515 | unsynchronized_pool_resource(const pool_options& __opts, | |
516 | memory_resource* __upstream); | |
517 | ||
518 | unsynchronized_pool_resource() | |
519 | : unsynchronized_pool_resource(pool_options(), get_default_resource()) | |
520 | { } | |
521 | ||
522 | [[__gnu__::__nonnull__]] | |
523 | explicit | |
524 | unsynchronized_pool_resource(memory_resource* __upstream) | |
525 | : unsynchronized_pool_resource(pool_options(), __upstream) | |
526 | { } | |
527 | ||
528 | explicit | |
529 | unsynchronized_pool_resource(const pool_options& __opts) | |
530 | : unsynchronized_pool_resource(__opts, get_default_resource()) { } | |
531 | ||
532 | unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; | |
533 | ||
534 | virtual ~unsynchronized_pool_resource(); | |
535 | ||
536 | unsynchronized_pool_resource& | |
537 | operator=(const unsynchronized_pool_resource&) = delete; | |
538 | ||
539 | void release(); | |
540 | ||
541 | [[__gnu__::__returns_nonnull__]] | |
542 | memory_resource* | |
543 | upstream_resource() const noexcept | |
544 | { return _M_impl.resource(); } | |
545 | ||
546 | pool_options options() const noexcept { return _M_impl._M_opts; } | |
547 | ||
548 | protected: | |
549 | void* | |
550 | do_allocate(size_t __bytes, size_t __alignment) override; | |
551 | ||
552 | void | |
553 | do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; | |
554 | ||
555 | bool | |
556 | do_is_equal(const memory_resource& __other) const noexcept override | |
557 | { return this == &__other; } | |
558 | ||
559 | private: | |
560 | using _Pool = __pool_resource::_Pool; | |
561 | ||
562 | auto _M_find_pool(size_t) noexcept; | |
563 | ||
564 | __pool_resource _M_impl; | |
565 | _Pool* _M_pools = nullptr; | |
566 | }; | |
dfaa3c47 JW |
567 | |
568 | class monotonic_buffer_resource : public memory_resource | |
569 | { | |
570 | public: | |
571 | explicit | |
572 | monotonic_buffer_resource(memory_resource* __upstream) noexcept | |
573 | __attribute__((__nonnull__)) | |
574 | : _M_upstream(__upstream) | |
575 | { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); } | |
576 | ||
577 | monotonic_buffer_resource(size_t __initial_size, | |
578 | memory_resource* __upstream) noexcept | |
579 | __attribute__((__nonnull__)) | |
580 | : _M_next_bufsiz(__initial_size), | |
581 | _M_upstream(__upstream) | |
582 | { | |
583 | _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); | |
584 | _GLIBCXX_DEBUG_ASSERT(__initial_size > 0); | |
585 | } | |
586 | ||
587 | monotonic_buffer_resource(void* __buffer, size_t __buffer_size, | |
588 | memory_resource* __upstream) noexcept | |
589 | __attribute__((__nonnull__(4))) | |
590 | : _M_current_buf(__buffer), _M_avail(__buffer_size), | |
591 | _M_next_bufsiz(_S_next_bufsize(__buffer_size)), | |
592 | _M_upstream(__upstream), | |
593 | _M_orig_buf(__buffer), _M_orig_size(__buffer_size) | |
594 | { | |
595 | _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); | |
596 | _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0); | |
597 | } | |
598 | ||
599 | monotonic_buffer_resource() noexcept | |
600 | : monotonic_buffer_resource(get_default_resource()) | |
601 | { } | |
602 | ||
603 | explicit | |
604 | monotonic_buffer_resource(size_t __initial_size) noexcept | |
605 | : monotonic_buffer_resource(__initial_size, get_default_resource()) | |
606 | { } | |
607 | ||
608 | monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept | |
609 | : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource()) | |
610 | { } | |
611 | ||
612 | monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; | |
613 | ||
d574c8aa | 614 | virtual ~monotonic_buffer_resource(); // key function |
dfaa3c47 JW |
615 | |
616 | monotonic_buffer_resource& | |
617 | operator=(const monotonic_buffer_resource&) = delete; | |
618 | ||
619 | void | |
620 | release() noexcept | |
621 | { | |
ea2329d1 JW |
622 | if (_M_head) |
623 | _M_release_buffers(); | |
dfaa3c47 JW |
624 | |
625 | // reset to initial state at contruction: | |
626 | if ((_M_current_buf = _M_orig_buf)) | |
627 | { | |
628 | _M_avail = _M_orig_size; | |
629 | _M_next_bufsiz = _S_next_bufsize(_M_orig_size); | |
630 | } | |
631 | else | |
632 | { | |
633 | _M_avail = 0; | |
634 | _M_next_bufsiz = _M_orig_size; | |
635 | } | |
636 | } | |
637 | ||
638 | memory_resource* | |
639 | upstream_resource() const noexcept | |
640 | __attribute__((__returns_nonnull__)) | |
641 | { return _M_upstream; } | |
642 | ||
643 | protected: | |
644 | void* | |
645 | do_allocate(size_t __bytes, size_t __alignment) override | |
646 | { | |
1e718ec5 | 647 | if (__builtin_expect(__bytes == 0, false)) |
dfaa3c47 JW |
648 | __bytes = 1; // Ensures we don't return the same pointer twice. |
649 | ||
ea2329d1 | 650 | void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail); |
1e718ec5 | 651 | if (__builtin_expect(__p == nullptr, false)) |
dfaa3c47 | 652 | { |
ea2329d1 JW |
653 | _M_new_buffer(__bytes, __alignment); |
654 | __p = _M_current_buf; | |
dfaa3c47 | 655 | } |
ea2329d1 JW |
656 | _M_current_buf = (char*)_M_current_buf + __bytes; |
657 | _M_avail -= __bytes; | |
dfaa3c47 JW |
658 | return __p; |
659 | } | |
660 | ||
661 | void | |
662 | do_deallocate(void*, size_t, size_t) override | |
663 | { } | |
664 | ||
665 | bool | |
666 | do_is_equal(const memory_resource& __other) const noexcept override | |
667 | { return this == &__other; } | |
668 | ||
669 | private: | |
ea2329d1 JW |
670 | // Update _M_current_buf and _M_avail to refer to a new buffer with |
671 | // at least the specified size and alignment, allocated from upstream. | |
672 | void | |
673 | _M_new_buffer(size_t __bytes, size_t __alignment); | |
674 | ||
675 | // Deallocate all buffers obtained from upstream. | |
676 | void | |
677 | _M_release_buffers() noexcept; | |
678 | ||
dfaa3c47 JW |
679 | static size_t |
680 | _S_next_bufsize(size_t __buffer_size) noexcept | |
681 | { | |
1e718ec5 | 682 | if (__builtin_expect(__buffer_size == 0, false)) |
dfaa3c47 JW |
683 | __buffer_size = 1; |
684 | return __buffer_size * _S_growth_factor; | |
685 | } | |
686 | ||
687 | static constexpr size_t _S_init_bufsize = 128 * sizeof(void*); | |
688 | static constexpr float _S_growth_factor = 1.5; | |
689 | ||
690 | void* _M_current_buf = nullptr; | |
691 | size_t _M_avail = 0; | |
692 | size_t _M_next_bufsiz = _S_init_bufsize; | |
693 | ||
694 | // Initial values set at construction and reused by release(): | |
695 | memory_resource* const _M_upstream; | |
696 | void* const _M_orig_buf = nullptr; | |
697 | size_t const _M_orig_size = _M_next_bufsiz; | |
698 | ||
ea2329d1 | 699 | class _Chunk; |
dfaa3c47 JW |
700 | _Chunk* _M_head = nullptr; |
701 | }; | |
702 | ||
703 | } // namespace pmr | |
704 | _GLIBCXX_END_NAMESPACE_VERSION | |
705 | } // namespace std | |
706 | ||
707 | #endif // C++17 | |
708 | #endif // _GLIBCXX_MEMORY_RESOURCE |