Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/c++/15/memory_resource
1 // <memory_resource> -*- C++ -*- 2 3 // Copyright (C) 2018-2025 Free Software Foundation, Inc. 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 * This header declares the @ref pmr (std::pmr) memory resources. 29 * @ingroup pmr 30 */ 31 32 #ifndef _GLIBCXX_MEMORY_RESOURCE 33 #define _GLIBCXX_MEMORY_RESOURCE 1 34 35 #ifdef _GLIBCXX_SYSHDR 36 #pragma GCC system_header 37 #endif 38 39 #include <bits/requires_hosted.h> // polymorphic allocation 40 41 #define __glibcxx_want_polymorphic_allocator 42 #define __glibcxx_want_memory_resource 43 #include <bits/version.h> 44 45 #if __cplusplus >= 201703L 46 47 /** 48 * @defgroup pmr Polymorphic memory resources 49 * 50 * @anchor pmr 51 * @ingroup memory 52 * @since C++17 53 * 54 * Memory resources are classes that implement the `std::pmr::memory_resource` 55 * interface for allocating and deallocating memory. Unlike traditional C++ 56 * allocators, memory resources are not value types and are used via pointers 57 * to the abstract base class. They are only responsible for allocating and 58 * deallocating, not for construction and destruction of objects. As a result, 59 * memory resources just allocate raw memory as type `void*` and are not 60 * templates that allocate/deallocate and construct/destroy a specific type. 61 * 62 * The class template `std::pmr::polymorphic_allocator` is an allocator that 63 * uses a memory resource for its allocations. 64 */ 65 66 #include <bits/memory_resource.h> 67 #include <vector> // vector 68 #include <shared_mutex> // shared_mutex 69 #include <bits/align.h> // align 70 #include <debug/assertions.h> 71 72 namespace std _GLIBCXX_VISIBILITY(default) 73 { 74 _GLIBCXX_BEGIN_NAMESPACE_VERSION 75 namespace pmr 76 { 77 78 #ifdef __cpp_lib_polymorphic_allocator // C++ >= 20 && HOSTED 79 template<typename _Tp = std::byte> 80 class polymorphic_allocator; 81 #endif 82 83 // Global memory resources 84 85 /// A pmr::memory_resource that uses `new` to allocate memory 86 /** 87 * @ingroup pmr 88 * @headerfile memory_resource 89 * @since C++17 90 */ 91 [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]] 92 memory_resource* 93 new_delete_resource() noexcept; 94 95 /// A pmr::memory_resource that always throws `bad_alloc` 96 [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]] 97 memory_resource* 98 null_memory_resource() noexcept; 99 100 /// Replace the default memory resource pointer 101 [[__gnu__::__returns_nonnull__]] 102 memory_resource* 103 set_default_resource(memory_resource* __r) noexcept; 104 105 /// Get the current default memory resource pointer 106 [[__gnu__::__returns_nonnull__]] 107 memory_resource* 108 get_default_resource() noexcept; 109 110 // Pool resource classes 111 struct pool_options; 112 #if __cpp_lib_memory_resource >= 201603L // C++ >= 17 && hosted && gthread 113 class synchronized_pool_resource; 114 #endif 115 class unsynchronized_pool_resource; 116 class monotonic_buffer_resource; 117 118 /// Parameters for tuning a pool resource's behaviour. 119 /** 120 * @ingroup pmr 121 * @headerfile memory_resource 122 * @since C++17 123 */ 124 struct pool_options 125 { 126 /** @brief Upper limit on number of blocks in a chunk. 127 * 128 * A lower value prevents allocating huge chunks that could remain mostly 129 * unused, but means pools will need to replenished more frequently. 130 */ 131 size_t max_blocks_per_chunk = 0; 132 133 /* @brief Largest block size (in bytes) that should be served from pools. 134 * 135 * Larger allocations will be served directly by the upstream resource, 136 * not from one of the pools managed by the pool resource. 137 */ 138 size_t largest_required_pool_block = 0; 139 }; 140 141 // Common implementation details for un-/synchronized pool resources. 142 class __pool_resource 143 { 144 friend class synchronized_pool_resource; 145 friend class unsynchronized_pool_resource; 146 147 __pool_resource(const pool_options& __opts, memory_resource* __upstream); 148 149 ~__pool_resource(); 150 151 __pool_resource(const __pool_resource&) = delete; 152 __pool_resource& operator=(const __pool_resource&) = delete; 153 154 // Allocate a large unpooled block. 155 void* 156 allocate(size_t __bytes, size_t __alignment); 157 158 // Deallocate a large unpooled block. 159 void 160 deallocate(void* __p, size_t __bytes, size_t __alignment); 161 162 163 // Deallocate unpooled memory. 164 void release() noexcept; 165 166 memory_resource* resource() const noexcept 167 { return _M_unpooled.get_allocator().resource(); } 168 169 struct _Pool; 170 171 _Pool* _M_alloc_pools(); 172 173 const pool_options _M_opts; 174 175 struct _BigBlock; 176 // Collection of blocks too big for any pool, sorted by address. 177 // This also stores the only copy of the upstream memory resource pointer. 178 _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled; 179 180 const int _M_npools; 181 }; 182 183 #if __cpp_lib_memory_resource >= 201603L // C++ >= 17 && hosted && gthread 184 /// A thread-safe memory resource that manages pools of fixed-size blocks. 185 /** 186 * @ingroup pmr 187 * @headerfile memory_resource 188 * @since C++17 189 */ 190 class synchronized_pool_resource : public memory_resource 191 { 192 public: 193 synchronized_pool_resource(const pool_options& __opts, 194 memory_resource* __upstream) 195 __attribute__((__nonnull__)); 196 197 synchronized_pool_resource() 198 : synchronized_pool_resource(pool_options(), get_default_resource()) 199 { } 200 201 explicit 202 synchronized_pool_resource(memory_resource* __upstream) 203 __attribute__((__nonnull__)) 204 : synchronized_pool_resource(pool_options(), __upstream) 205 { } 206 207 explicit 208 synchronized_pool_resource(const pool_options& __opts) 209 : synchronized_pool_resource(__opts, get_default_resource()) { } 210 211 synchronized_pool_resource(const synchronized_pool_resource&) = delete; 212 213 virtual ~synchronized_pool_resource(); 214 215 synchronized_pool_resource& 216 operator=(const synchronized_pool_resource&) = delete; 217 218 void release(); 219 220 memory_resource* 221 upstream_resource() const noexcept 222 __attribute__((__returns_nonnull__)) 223 { return _M_impl.resource(); } 224 225 pool_options options() const noexcept { return _M_impl._M_opts; } 226 227 protected: 228 void* 229 do_allocate(size_t __bytes, size_t __alignment) override; 230 231 void 232 do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; 233 234 bool 235 do_is_equal(const memory_resource& __other) const noexcept override 236 { return this == &__other; } 237 238 public: 239 // Thread-specific pools (only public for access by implementation details) 240 struct _TPools; 241 242 private: 243 _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&); 244 _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&); 245 auto _M_thread_specific_pools() noexcept; 246 247 __pool_resource _M_impl; 248 __gthread_key_t _M_key; 249 // Linked list of thread-specific pools. All threads share _M_tpools[0]. 250 _TPools* _M_tpools = nullptr; 251 mutable shared_mutex _M_mx; 252 }; 253 #endif // __cpp_lib_memory_resource >= 201603L 254 255 /// A non-thread-safe memory resource that manages pools of fixed-size blocks. 256 /** 257 * @ingroup pmr 258 * @headerfile memory_resource 259 * @since C++17 260 */ 261 class unsynchronized_pool_resource : public memory_resource 262 { 263 public: 264 [[__gnu__::__nonnull__]] 265 unsynchronized_pool_resource(const pool_options& __opts, 266 memory_resource* __upstream); 267 268 unsynchronized_pool_resource() 269 : unsynchronized_pool_resource(pool_options(), get_default_resource()) 270 { } 271 272 [[__gnu__::__nonnull__]] 273 explicit 274 unsynchronized_pool_resource(memory_resource* __upstream) 275 : unsynchronized_pool_resource(pool_options(), __upstream) 276 { } 277 278 explicit 279 unsynchronized_pool_resource(const pool_options& __opts) 280 : unsynchronized_pool_resource(__opts, get_default_resource()) { } 281 282 unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; 283 284 virtual ~unsynchronized_pool_resource(); 285 286 unsynchronized_pool_resource& 287 operator=(const unsynchronized_pool_resource&) = delete; 288 289 void release(); 290 291 [[__gnu__::__returns_nonnull__]] 292 memory_resource* 293 upstream_resource() const noexcept 294 { return _M_impl.resource(); } 295 296 pool_options options() const noexcept { return _M_impl._M_opts; } 297 298 protected: 299 void* 300 do_allocate(size_t __bytes, size_t __alignment) override; 301 302 void 303 do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; 304 305 bool 306 do_is_equal(const memory_resource& __other) const noexcept override 307 { return this == &__other; } 308 309 private: 310 using _Pool = __pool_resource::_Pool; 311 312 auto _M_find_pool(size_t) noexcept; 313 314 __pool_resource _M_impl; 315 _Pool* _M_pools = nullptr; 316 }; 317 318 /// A memory resource that allocates from a fixed-size buffer. 319 /** 320 * The main feature of a `pmr::monotonic_buffer_resource` is that its 321 * `do_deallocate` does nothing. This makes it very fast because there is no 322 * need to manage a free list, and every allocation simply returns a new 323 * block of memory, rather than searching for a suitably-sized free block. 324 * Because deallocating is a no-op, the amount of memory used by the resource 325 * only grows until `release()` (or the destructor) is called to return all 326 * memory to upstream. 327 * 328 * A `monotonic_buffer_resource` can be initialized with a buffer that 329 * will be used to satisfy all allocation requests, until the buffer is full. 330 * After that a new buffer will be allocated from the upstream resource. 331 * By using a stack buffer and `pmr::null_memory_resource()` as the upstream 332 * you can get a memory resource that only uses the stack and never 333 * dynamically allocates. 334 * 335 * @ingroup pmr 336 * @headerfile memory_resource 337 * @since C++17 338 */ 339 class monotonic_buffer_resource : public memory_resource 340 { 341 public: 342 explicit 343 monotonic_buffer_resource(memory_resource* __upstream) noexcept 344 __attribute__((__nonnull__)) 345 : _M_upstream(__upstream) 346 { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); } 347 348 monotonic_buffer_resource(size_t __initial_size, 349 memory_resource* __upstream) noexcept 350 __attribute__((__nonnull__)) 351 : _M_next_bufsiz(__initial_size), 352 _M_upstream(__upstream) 353 { 354 _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); 355 _GLIBCXX_DEBUG_ASSERT(__initial_size > 0); 356 } 357 358 monotonic_buffer_resource(void* __buffer, size_t __buffer_size, 359 memory_resource* __upstream) noexcept 360 __attribute__((__nonnull__(4))) 361 : _M_current_buf(__buffer), _M_avail(__buffer_size), 362 _M_next_bufsiz(_S_next_bufsize(__buffer_size)), 363 _M_upstream(__upstream), 364 _M_orig_buf(__buffer), _M_orig_size(__buffer_size) 365 { 366 _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); 367 _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0); 368 } 369 370 monotonic_buffer_resource() noexcept 371 : monotonic_buffer_resource(get_default_resource()) 372 { } 373 374 explicit 375 monotonic_buffer_resource(size_t __initial_size) noexcept 376 : monotonic_buffer_resource(__initial_size, get_default_resource()) 377 { } 378 379 monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept 380 : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource()) 381 { } 382 383 monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; 384 385 virtual ~monotonic_buffer_resource(); // key function 386 387 monotonic_buffer_resource& 388 operator=(const monotonic_buffer_resource&) = delete; 389 390 void 391 release() noexcept 392 { 393 if (_M_head) 394 _M_release_buffers(); 395 396 // reset to initial state at contruction: 397 if ((_M_current_buf = _M_orig_buf)) 398 { 399 _M_avail = _M_orig_size; 400 _M_next_bufsiz = _S_next_bufsize(_M_orig_size); 401 } 402 else 403 { 404 _M_avail = 0; 405 _M_next_bufsiz = _M_orig_size; 406 } 407 } 408 409 memory_resource* 410 upstream_resource() const noexcept 411 __attribute__((__returns_nonnull__)) 412 { return _M_upstream; } 413 414 protected: 415 void* 416 do_allocate(size_t __bytes, size_t __alignment) override 417 { 418 if (__builtin_expect(__bytes == 0, false)) 419 __bytes = 1; // Ensures we don't return the same pointer twice. 420 421 void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail); 422 if (__builtin_expect(__p == nullptr, false)) 423 { 424 _M_new_buffer(__bytes, __alignment); 425 __p = _M_current_buf; 426 } 427 _M_current_buf = (char*)_M_current_buf + __bytes; 428 _M_avail -= __bytes; 429 return __p; 430 } 431 432 void 433 do_deallocate(void*, size_t, size_t) override 434 { } 435 436 bool 437 do_is_equal(const memory_resource& __other) const noexcept override 438 { return this == &__other; } 439 440 private: 441 // Update _M_current_buf and _M_avail to refer to a new buffer with 442 // at least the specified size and alignment, allocated from upstream. 443 void 444 _M_new_buffer(size_t __bytes, size_t __alignment); 445 446 // Deallocate all buffers obtained from upstream. 447 void 448 _M_release_buffers() noexcept; 449 450 static size_t 451 _S_next_bufsize(size_t __buffer_size) noexcept 452 { 453 if (__builtin_expect(__buffer_size == 0, false)) 454 __buffer_size = 1; 455 return __buffer_size * _S_growth_factor; 456 } 457 458 static constexpr size_t _S_init_bufsize = 128 * sizeof(void*); 459 static constexpr float _S_growth_factor = 1.5; 460 461 void* _M_current_buf = nullptr; 462 size_t _M_avail = 0; 463 size_t _M_next_bufsiz = _S_init_bufsize; 464 465 // Initial values set at construction and reused by release(): 466 memory_resource* const _M_upstream; 467 void* const _M_orig_buf = nullptr; 468 size_t const _M_orig_size = _M_next_bufsiz; 469 470 class _Chunk; 471 _Chunk* _M_head = nullptr; 472 }; 473 474 } // namespace pmr 475 _GLIBCXX_END_NAMESPACE_VERSION 476 } // namespace std 477 478 #endif // C++17 479 #endif // _GLIBCXX_MEMORY_RESOURCE