]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/include/std/memory_resource
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / include / std / memory_resource
CommitLineData
dfaa3c47
JW
1// <memory_resource> -*- C++ -*-
2
83ffe9cd 3// Copyright (C) 2018-2023 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
18f176d0
AA
34#include <bits/requires_hosted.h> // polymorphic allocation
35
dfaa3c47
JW
36#if __cplusplus >= 201703L
37
8ccdc7ce 38#include <bits/memory_resource.h>
852a971c 39#include <vector> // vector
c5be6481 40#include <shared_mutex> // shared_mutex
b1e7c6fc 41#include <bits/align.h> // align
dfaa3c47
JW
42#include <debug/assertions.h>
43
44namespace std _GLIBCXX_VISIBILITY(default)
45{
46_GLIBCXX_BEGIN_NAMESPACE_VERSION
47namespace pmr
48{
c5be6481
JW
49#ifdef _GLIBCXX_HAS_GTHREADS
50 // Header and all contents are present.
b1e7c6fc 51# define __cpp_lib_memory_resource 201603L
c5be6481
JW
52#else
53 // The pmr::synchronized_pool_resource type is missing.
54# define __cpp_lib_memory_resource 1
55#endif
dfaa3c47 56
8ccdc7ce 57#if __cplusplus >= 202002L
56772f62 58# define __cpp_lib_polymorphic_allocator 201902L
0e318273
JW
59 template<typename _Tp = std::byte>
60 class polymorphic_allocator;
61#endif
dfaa3c47
JW
62
63 // Global memory resources
5c2d703e
JW
64
65 /// A pmr::memory_resource that uses `new` to allocate memory
66 [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]]
67 memory_resource*
68 new_delete_resource() noexcept;
69
70 /// A pmr::memory_resource that always throws `bad_alloc`
71 [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]]
72 memory_resource*
73 null_memory_resource() noexcept;
74
75 /// Replace the default memory resource pointer
76 [[__gnu__::__returns_nonnull__]]
77 memory_resource*
78 set_default_resource(memory_resource* __r) noexcept;
79
80 /// Get the current default memory resource pointer
81 [[__gnu__::__returns_nonnull__]]
82 memory_resource*
83 get_default_resource() noexcept;
dfaa3c47
JW
84
85 // Pool resource classes
86 struct pool_options;
c5be6481 87#ifdef _GLIBCXX_HAS_GTHREADS
dfaa3c47 88 class synchronized_pool_resource;
c5be6481 89#endif
dfaa3c47
JW
90 class unsynchronized_pool_resource;
91 class monotonic_buffer_resource;
92
36d2acbd 93 /// Parameters for tuning a pool resource's behaviour.
dfaa3c47
JW
94 struct pool_options
95 {
36d2acbd
JW
96 /** @brief Upper limit on number of blocks in a chunk.
97 *
98 * A lower value prevents allocating huge chunks that could remain mostly
99 * unused, but means pools will need to replenished more frequently.
100 */
dfaa3c47 101 size_t max_blocks_per_chunk = 0;
36d2acbd
JW
102
103 /* @brief Largest block size (in bytes) that should be served from pools.
104 *
105 * Larger allocations will be served directly by the upstream resource,
106 * not from one of the pools managed by the pool resource.
107 */
dfaa3c47
JW
108 size_t largest_required_pool_block = 0;
109 };
110
36d2acbd 111 // Common implementation details for un-/synchronized pool resources.
852a971c
JW
112 class __pool_resource
113 {
114 friend class synchronized_pool_resource;
115 friend class unsynchronized_pool_resource;
116
117 __pool_resource(const pool_options& __opts, memory_resource* __upstream);
118
119 ~__pool_resource();
120
121 __pool_resource(const __pool_resource&) = delete;
122 __pool_resource& operator=(const __pool_resource&) = delete;
123
124 // Allocate a large unpooled block.
125 void*
126 allocate(size_t __bytes, size_t __alignment);
127
128 // Deallocate a large unpooled block.
129 void
130 deallocate(void* __p, size_t __bytes, size_t __alignment);
131
132
133 // Deallocate unpooled memory.
134 void release() noexcept;
135
136 memory_resource* resource() const noexcept
137 { return _M_unpooled.get_allocator().resource(); }
138
139 struct _Pool;
140
141 _Pool* _M_alloc_pools();
142
143 const pool_options _M_opts;
144
145 struct _BigBlock;
146 // Collection of blocks too big for any pool, sorted by address.
147 // This also stores the only copy of the upstream memory resource pointer.
1f48525d 148 _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled;
852a971c
JW
149
150 const int _M_npools;
151 };
152
c5be6481
JW
153#ifdef _GLIBCXX_HAS_GTHREADS
154 /// A thread-safe memory resource that manages pools of fixed-size blocks.
155 class synchronized_pool_resource : public memory_resource
156 {
157 public:
158 synchronized_pool_resource(const pool_options& __opts,
159 memory_resource* __upstream)
160 __attribute__((__nonnull__));
161
162 synchronized_pool_resource()
163 : synchronized_pool_resource(pool_options(), get_default_resource())
164 { }
165
166 explicit
167 synchronized_pool_resource(memory_resource* __upstream)
168 __attribute__((__nonnull__))
169 : synchronized_pool_resource(pool_options(), __upstream)
170 { }
171
172 explicit
173 synchronized_pool_resource(const pool_options& __opts)
174 : synchronized_pool_resource(__opts, get_default_resource()) { }
175
176 synchronized_pool_resource(const synchronized_pool_resource&) = delete;
177
178 virtual ~synchronized_pool_resource();
179
180 synchronized_pool_resource&
181 operator=(const synchronized_pool_resource&) = delete;
182
183 void release();
184
185 memory_resource*
186 upstream_resource() const noexcept
187 __attribute__((__returns_nonnull__))
188 { return _M_impl.resource(); }
189
190 pool_options options() const noexcept { return _M_impl._M_opts; }
191
192 protected:
193 void*
194 do_allocate(size_t __bytes, size_t __alignment) override;
195
196 void
197 do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
198
199 bool
200 do_is_equal(const memory_resource& __other) const noexcept override
201 { return this == &__other; }
202
203 public:
204 // Thread-specific pools (only public for access by implementation details)
205 struct _TPools;
206
207 private:
208 _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&);
209 _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&);
210 auto _M_thread_specific_pools() noexcept;
211
212 __pool_resource _M_impl;
213 __gthread_key_t _M_key;
214 // Linked list of thread-specific pools. All threads share _M_tpools[0].
215 _TPools* _M_tpools = nullptr;
216 mutable shared_mutex _M_mx;
217 };
218#endif
852a971c
JW
219
220 /// A non-thread-safe memory resource that manages pools of fixed-size blocks.
221 class unsynchronized_pool_resource : public memory_resource
222 {
223 public:
224 [[__gnu__::__nonnull__]]
225 unsynchronized_pool_resource(const pool_options& __opts,
226 memory_resource* __upstream);
227
228 unsynchronized_pool_resource()
229 : unsynchronized_pool_resource(pool_options(), get_default_resource())
230 { }
231
232 [[__gnu__::__nonnull__]]
233 explicit
234 unsynchronized_pool_resource(memory_resource* __upstream)
235 : unsynchronized_pool_resource(pool_options(), __upstream)
236 { }
237
238 explicit
239 unsynchronized_pool_resource(const pool_options& __opts)
240 : unsynchronized_pool_resource(__opts, get_default_resource()) { }
241
242 unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
243
244 virtual ~unsynchronized_pool_resource();
245
246 unsynchronized_pool_resource&
247 operator=(const unsynchronized_pool_resource&) = delete;
248
249 void release();
250
251 [[__gnu__::__returns_nonnull__]]
252 memory_resource*
253 upstream_resource() const noexcept
254 { return _M_impl.resource(); }
255
256 pool_options options() const noexcept { return _M_impl._M_opts; }
257
258 protected:
259 void*
260 do_allocate(size_t __bytes, size_t __alignment) override;
261
262 void
263 do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
264
265 bool
266 do_is_equal(const memory_resource& __other) const noexcept override
267 { return this == &__other; }
268
269 private:
270 using _Pool = __pool_resource::_Pool;
271
272 auto _M_find_pool(size_t) noexcept;
273
274 __pool_resource _M_impl;
275 _Pool* _M_pools = nullptr;
276 };
dfaa3c47
JW
277
278 class monotonic_buffer_resource : public memory_resource
279 {
280 public:
281 explicit
282 monotonic_buffer_resource(memory_resource* __upstream) noexcept
283 __attribute__((__nonnull__))
284 : _M_upstream(__upstream)
285 { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); }
286
287 monotonic_buffer_resource(size_t __initial_size,
288 memory_resource* __upstream) noexcept
289 __attribute__((__nonnull__))
290 : _M_next_bufsiz(__initial_size),
291 _M_upstream(__upstream)
292 {
293 _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
294 _GLIBCXX_DEBUG_ASSERT(__initial_size > 0);
295 }
296
297 monotonic_buffer_resource(void* __buffer, size_t __buffer_size,
298 memory_resource* __upstream) noexcept
299 __attribute__((__nonnull__(4)))
300 : _M_current_buf(__buffer), _M_avail(__buffer_size),
301 _M_next_bufsiz(_S_next_bufsize(__buffer_size)),
302 _M_upstream(__upstream),
303 _M_orig_buf(__buffer), _M_orig_size(__buffer_size)
304 {
305 _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
306 _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0);
307 }
308
309 monotonic_buffer_resource() noexcept
310 : monotonic_buffer_resource(get_default_resource())
311 { }
312
313 explicit
314 monotonic_buffer_resource(size_t __initial_size) noexcept
315 : monotonic_buffer_resource(__initial_size, get_default_resource())
316 { }
317
318 monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept
319 : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource())
320 { }
321
322 monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
323
d574c8aa 324 virtual ~monotonic_buffer_resource(); // key function
dfaa3c47
JW
325
326 monotonic_buffer_resource&
327 operator=(const monotonic_buffer_resource&) = delete;
328
329 void
330 release() noexcept
331 {
ea2329d1
JW
332 if (_M_head)
333 _M_release_buffers();
dfaa3c47
JW
334
335 // reset to initial state at contruction:
336 if ((_M_current_buf = _M_orig_buf))
337 {
338 _M_avail = _M_orig_size;
339 _M_next_bufsiz = _S_next_bufsize(_M_orig_size);
340 }
341 else
342 {
343 _M_avail = 0;
344 _M_next_bufsiz = _M_orig_size;
345 }
346 }
347
348 memory_resource*
349 upstream_resource() const noexcept
350 __attribute__((__returns_nonnull__))
351 { return _M_upstream; }
352
353 protected:
354 void*
355 do_allocate(size_t __bytes, size_t __alignment) override
356 {
1e718ec5 357 if (__builtin_expect(__bytes == 0, false))
dfaa3c47
JW
358 __bytes = 1; // Ensures we don't return the same pointer twice.
359
ea2329d1 360 void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
1e718ec5 361 if (__builtin_expect(__p == nullptr, false))
dfaa3c47 362 {
ea2329d1
JW
363 _M_new_buffer(__bytes, __alignment);
364 __p = _M_current_buf;
dfaa3c47 365 }
ea2329d1
JW
366 _M_current_buf = (char*)_M_current_buf + __bytes;
367 _M_avail -= __bytes;
dfaa3c47
JW
368 return __p;
369 }
370
371 void
372 do_deallocate(void*, size_t, size_t) override
373 { }
374
375 bool
376 do_is_equal(const memory_resource& __other) const noexcept override
377 { return this == &__other; }
378
379 private:
ea2329d1
JW
380 // Update _M_current_buf and _M_avail to refer to a new buffer with
381 // at least the specified size and alignment, allocated from upstream.
382 void
383 _M_new_buffer(size_t __bytes, size_t __alignment);
384
385 // Deallocate all buffers obtained from upstream.
386 void
387 _M_release_buffers() noexcept;
388
dfaa3c47
JW
389 static size_t
390 _S_next_bufsize(size_t __buffer_size) noexcept
391 {
1e718ec5 392 if (__builtin_expect(__buffer_size == 0, false))
dfaa3c47
JW
393 __buffer_size = 1;
394 return __buffer_size * _S_growth_factor;
395 }
396
397 static constexpr size_t _S_init_bufsize = 128 * sizeof(void*);
398 static constexpr float _S_growth_factor = 1.5;
399
400 void* _M_current_buf = nullptr;
401 size_t _M_avail = 0;
402 size_t _M_next_bufsiz = _S_init_bufsize;
403
404 // Initial values set at construction and reused by release():
405 memory_resource* const _M_upstream;
406 void* const _M_orig_buf = nullptr;
407 size_t const _M_orig_size = _M_next_bufsiz;
408
ea2329d1 409 class _Chunk;
dfaa3c47
JW
410 _Chunk* _M_head = nullptr;
411 };
412
413} // namespace pmr
414_GLIBCXX_END_NAMESPACE_VERSION
415} // namespace std
416
417#endif // C++17
418#endif // _GLIBCXX_MEMORY_RESOURCE