WPILibC++ 2025.1.1
Loading...
Searching...
No Matches
memory_arena.hpp
Go to the documentation of this file.
1// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
2// SPDX-License-Identifier: Zlib
3
4#ifndef WPI_MEMORY_MEMORY_ARENA_HPP_INCLUDED
5#define WPI_MEMORY_MEMORY_ARENA_HPP_INCLUDED
6
7/// \file
8/// Class \ref wpi::memory::memory_arena and related functionality regarding BlockAllocators.
9
10#include <type_traits>
11
13#include "detail/assert.hpp"
14#include "detail/utility.hpp"
15#include "allocator_traits.hpp"
16#include "config.hpp"
17#include "default_allocator.hpp"
18#include "error.hpp"
19
20namespace wpi
21{
22 namespace memory
23 {
24 /// A memory block.
25 /// It is defined by its starting address and size.
26 /// \ingroup memory_core
28 {
29 void* memory; ///< The address of the memory block (might be \c nullptr).
30 std::size_t size; ///< The size of the memory block (might be \c 0).
31
32 /// \effects Creates an invalid memory block with starting address \c nullptr and size \c 0.
33 memory_block() noexcept : memory_block(nullptr, std::size_t(0)) {}
34
35 /// \effects Creates a memory block from a given starting address and size.
36 memory_block(void* mem, std::size_t s) noexcept : memory(mem), size(s) {}
37
38 /// \effects Creates a memory block from a [begin,end) range.
39 memory_block(void* begin, void* end) noexcept
40 : memory_block(begin, static_cast<std::size_t>(static_cast<char*>(end)
41 - static_cast<char*>(begin)))
42 {
43 }
44
45 /// \returns Whether or not a pointer is inside the memory.
46 bool contains(const void* address) const noexcept
47 {
48 auto mem = static_cast<const char*>(memory);
49 auto addr = static_cast<const char*>(address);
50 return addr >= mem && addr < mem + size;
51 }
52 };
53
54 namespace detail
55 {
56 template <class BlockAllocator>
58 int,
59 WPI_SFINAE(std::declval<memory_block&>() =
60 std::declval<BlockAllocator&>().allocate_block()),
61 WPI_SFINAE(std::declval<std::size_t&>() =
62 std::declval<BlockAllocator&>().next_block_size()),
63 WPI_SFINAE(std::declval<BlockAllocator>().deallocate_block(memory_block{})));
64
65 template <typename T>
66 std::false_type is_block_allocator_impl(short);
67 } // namespace detail
68
69 /// Traits that check whether a type models concept BlockAllocator.
70 /// \ingroup memory_core
71 template <typename T>
72 struct is_block_allocator : decltype(detail::is_block_allocator_impl<T>(0))
73 {
74 };
75
76#if !defined(DOXYGEN)
77 template <class BlockAllocator, bool Cached = true>
78 class memory_arena;
79#endif
80
81 /// @{
82 /// Controls the caching of \ref memory_arena.
83 /// By default, deallocated blocks are put onto a cache, so they can be reused later;
84 /// this tag value enable/disable it..<br>
85 /// This can be useful, e.g. if there will never be blocks available for deallocation.
86 /// The (tiny) overhead for the cache can then be disabled.
87 /// An example is \ref memory_pool.
88 /// \ingroup memory_core
89 constexpr bool cached_arena = true;
90 constexpr bool uncached_arena = false;
91 /// @}
92
93 namespace detail
94 {
95 // stores memory block in an intrusive linked list and allows LIFO access
97 {
98 public:
99 memory_block_stack() noexcept : head_(nullptr) {}
100
102
103 memory_block_stack(memory_block_stack&& other) noexcept : head_(other.head_)
104 {
105 other.head_ = nullptr;
106 }
107
109 {
111 swap(*this, tmp);
112 return *this;
113 }
114
115 friend void swap(memory_block_stack& a, memory_block_stack& b) noexcept
116 {
117 detail::adl_swap(a.head_, b.head_);
118 }
119
120 // the raw allocated block returned from an allocator
122
123 // the inserted block slightly smaller to allow for the fixup value
125
126 // how much an inserted block is smaller
127 static constexpr std::size_t implementation_offset() noexcept
128 {
129 // node size rounded up to the next multiple of max_alignment.
130 return (sizeof(node) / max_alignment + (sizeof(node) % max_alignment != 0))
132 }
133
134 // pushes a memory block
135 void push(allocated_mb block) noexcept;
136
137 // pops a memory block and returns the original block
138 allocated_mb pop() noexcept;
139
140 // steals the top block from another stack
141 void steal_top(memory_block_stack& other) noexcept;
142
143 // returns the last pushed() inserted memory block
144 inserted_mb top() const noexcept
145 {
146 WPI_MEMORY_ASSERT(head_);
147 auto mem = static_cast<void*>(head_);
148 return {static_cast<char*>(mem) + implementation_offset(), head_->usable_size};
149 }
150
151 bool empty() const noexcept
152 {
153 return head_ == nullptr;
154 }
155
156 bool owns(const void* ptr) const noexcept;
157
158 // O(n) size
159 std::size_t size() const noexcept;
160
161 private:
162 struct node
163 {
164 node* prev;
165 std::size_t usable_size;
166
167 node(node* p, std::size_t size) noexcept : prev(p), usable_size(size) {}
168 };
169
170 node* head_;
171 };
172
173 template <bool Cached>
175
176 template <>
178 {
179 protected:
180 bool cache_empty() const noexcept
181 {
182 return cached_.empty();
183 }
184
185 std::size_t cache_size() const noexcept
186 {
187 return cached_.size();
188 }
189
190 std::size_t cached_block_size() const noexcept
191 {
192 return cached_.top().size;
193 }
194
196 {
197 if (cached_.empty())
198 return false;
199 used.steal_top(cached_);
200 return true;
201 }
202
203 template <class BlockAllocator>
204 void do_deallocate_block(BlockAllocator&, detail::memory_block_stack& used) noexcept
205 {
206 cached_.steal_top(used);
207 }
208
209 template <class BlockAllocator>
210 void do_shrink_to_fit(BlockAllocator& alloc) noexcept
211 {
213 // pop from cache and push to temporary stack
214 // this revers order
215 while (!cached_.empty())
216 to_dealloc.steal_top(cached_);
217 // now dealloc everything
218 while (!to_dealloc.empty())
219 alloc.deallocate_block(to_dealloc.pop());
220 }
221
222 private:
224 };
225
226 template <>
228 {
229 protected:
230 bool cache_empty() const noexcept
231 {
232 return true;
233 }
234
235 std::size_t cache_size() const noexcept
236 {
237 return 0u;
238 }
239
240 std::size_t cached_block_size() const noexcept
241 {
242 return 0u;
243 }
244
246 {
247 return false;
248 }
249
250 template <class BlockAllocator>
251 void do_deallocate_block(BlockAllocator& alloc,
252 detail::memory_block_stack& used) noexcept
253 {
254 alloc.deallocate_block(used.pop());
255 }
256
257 template <class BlockAllocator>
258 void do_shrink_to_fit(BlockAllocator&) noexcept
259 {
260 }
261 };
262 } // namespace detail
263
264 /// A memory arena that manages huge memory blocks for a higher-level allocator.
265 /// Some allocators like \ref memory_stack work on huge memory blocks,
266 /// this class manages them fro those allocators.
267 /// It uses a BlockAllocator for the allocation of those blocks.
268 /// The memory blocks in use are put onto a stack like structure, deallocation will pop from the top,
269 /// so it is only possible to deallocate the last allocated block of the arena.
270 /// By default, blocks are not really deallocated but stored in a cache.
271 /// This can be disabled with the second template parameter,
272 /// passing it \ref uncached_arena (or \c false) disables it,
273 /// \ref cached_arena (or \c true) enables it explicitly.
274 /// \ingroup memory_core
275 template <class BlockAllocator, bool Cached /* = true */>
276 class memory_arena : WPI_EBO(BlockAllocator),
277 WPI_EBO(detail::memory_arena_cache<Cached>)
278 {
280 "BlockAllocator is not a BlockAllocator!");
282
283 public:
284 using allocator_type = BlockAllocator;
285 using is_cached = std::integral_constant<bool, Cached>;
286
287 /// \returns The minimum block size required for an arena containing the given amount of memory.
288 /// If an arena is created with the result of `min_block_size(n)`, the resulting capacity will be exactly `n`.
289 /// \requires `byte_size` must be a positive number.
290 static constexpr std::size_t min_block_size(std::size_t byte_size) noexcept
291 {
293 }
294
295 /// \effects Creates it by giving it the size and other arguments for the BlockAllocator.
296 /// It forwards these arguments to its constructor.
297 /// \requires \c block_size must be greater than \c min_block_size(0) and other requirements depending on the BlockAllocator.
298 /// \throws Anything thrown by the constructor of the \c BlockAllocator.
299 template <typename... Args>
300 explicit memory_arena(std::size_t block_size, Args&&... args)
301 : allocator_type(block_size, detail::forward<Args>(args)...)
302 {
303 WPI_MEMORY_ASSERT(block_size > min_block_size(0));
304 }
305
306 /// \effects Deallocates all memory blocks that where requested back to the BlockAllocator.
307 ~memory_arena() noexcept
308 {
309 // clear cache
311 // now deallocate everything
312 while (!used_.empty())
313 allocator_type::deallocate_block(used_.pop());
314 }
315
316 /// @{
317 /// \effects Moves the arena.
318 /// The new arena takes ownership over all the memory blocks from the other arena object,
319 /// which is empty after that.
320 /// This does not invalidate any memory blocks.
321 memory_arena(memory_arena&& other) noexcept
323 cache(detail::move(other)),
324 used_(detail::move(other.used_))
325 {
326 }
327
329 {
330 memory_arena tmp(detail::move(other));
331 swap(*this, tmp);
332 return *this;
333 }
334 /// @}
335
336 /// \effects Swaps to memory arena objects.
337 /// This does not invalidate any memory blocks.
338 friend void swap(memory_arena& a, memory_arena& b) noexcept
339 {
340 detail::adl_swap(static_cast<allocator_type&>(a), static_cast<allocator_type&>(b));
341 detail::adl_swap(static_cast<cache&>(a), static_cast<cache&>(b));
342 detail::adl_swap(a.used_, b.used_);
343 }
344
345 /// \effects Allocates a new memory block.
346 /// It first uses a cache of previously deallocated blocks, if caching is enabled,
347 /// if it is empty, allocates a new one.
348 /// \returns The new \ref memory_block.
349 /// \throws Anything thrown by the BlockAllocator allocation function.
351 {
352 if (!this->take_from_cache(used_))
353 used_.push(allocator_type::allocate_block());
354
355 auto block = used_.top();
356 detail::debug_fill_internal(block.memory, block.size, false);
357 return block;
358 }
359
360 /// \returns The current memory block.
361 /// This is the memory block that will be deallocated by the next call to \ref deallocate_block().
363 {
364 return used_.top();
365 }
366
367 /// \effects Deallocates the current memory block.
368 /// The current memory block is the block on top of the stack of blocks.
369 /// If caching is enabled, it does not really deallocate it but puts it onto a cache for later use,
370 /// use \ref shrink_to_fit() to purge that cache.
371 void deallocate_block() noexcept
372 {
373 auto block = used_.top();
374 detail::debug_fill_internal(block.memory, block.size, true);
375 this->do_deallocate_block(get_allocator(), used_);
376 }
377
378 /// \returns If `ptr` is in memory owned by the arena.
379 bool owns(const void* ptr) const noexcept
380 {
381 return used_.owns(ptr);
382 }
383
384 /// \effects Purges the cache of unused memory blocks by returning them.
385 /// The memory blocks will be deallocated in reversed order of allocation.
386 /// Does nothing if caching is disabled.
387 void shrink_to_fit() noexcept
388 {
389 this->do_shrink_to_fit(get_allocator());
390 }
391
392 /// \returns The capacity of the arena, i.e. how many blocks are used and cached.
393 std::size_t capacity() const noexcept
394 {
395 return size() + cache_size();
396 }
397
398 /// \returns The size of the cache, i.e. how many blocks can be allocated without allocation.
399 std::size_t cache_size() const noexcept
400 {
401 return cache::cache_size();
402 }
403
404 /// \returns The size of the arena, i.e. how many blocks are in use.
405 /// It is always smaller or equal to the \ref capacity().
406 std::size_t size() const noexcept
407 {
408 return used_.size();
409 }
410
411 /// \returns The size of the next memory block,
412 /// i.e. of the next call to \ref allocate_block().
413 /// If there are blocks in the cache, returns size of the next one.
414 /// Otherwise forwards to the BlockAllocator and subtracts an implementation offset.
415 std::size_t next_block_size() const noexcept
416 {
417 return this->cache_empty() ?
418 allocator_type::next_block_size()
420 this->cached_block_size();
421 }
422
423 /// \returns A reference of the BlockAllocator object.
424 /// \requires It is undefined behavior to move this allocator out into another object.
426 {
427 return *this;
428 }
429
430 private:
432 };
433
434#if WPI_MEMORY_EXTERN_TEMPLATE
435 extern template class memory_arena<static_block_allocator, true>;
436 extern template class memory_arena<static_block_allocator, false>;
437 extern template class memory_arena<virtual_block_allocator, true>;
438 extern template class memory_arena<virtual_block_allocator, false>;
439#endif
440
441 /// A BlockAllocator that uses a given RawAllocator for allocating the blocks.
442 /// It calls the \c allocate_array() function with a node of size \c 1 and maximum alignment on the used allocator for the block allocation.
443 /// The size of the next memory block will grow by a given factor after each allocation,
444 /// allowing an amortized constant allocation time in the higher level allocator.
445 /// The factor can be given as rational in the template parameter, default is \c 2.
446 /// \ingroup memory_adapter
447 template <class RawAllocator = default_allocator, unsigned Num = 2, unsigned Den = 1>
450 {
451 static_assert(float(Num) / Den >= 1.0, "invalid growth factor");
452
454
455 public:
457
458 /// \effects Creates it by giving it the initial block size, the allocator object and the growth factor.
459 /// By default, it uses a default-constructed allocator object and a growth factor of \c 2.
460 /// \requires \c block_size must be greater than 0.
461 explicit growing_block_allocator(std::size_t block_size,
462 allocator_type alloc = allocator_type()) noexcept
463 : allocator_type(detail::move(alloc)), block_size_(block_size)
464 {
465 }
466
467 /// \effects Allocates a new memory block and increases the block size for the next allocation.
468 /// \returns The new \ref memory_block.
469 /// \throws Anything thrown by the \c allocate_array() function of the RawAllocator.
471 {
472 auto memory =
473 traits::allocate_array(get_allocator(), block_size_, 1, detail::max_alignment);
474 memory_block block(memory, block_size_);
475 block_size_ = grow_block_size(block_size_);
476 return block;
477 }
478
479 /// \effects Deallocates a previously allocated memory block.
480 /// This does not decrease the block size.
481 /// \requires \c block must be previously returned by a call to \ref allocate_block().
482 void deallocate_block(memory_block block) noexcept
483 {
484 traits::deallocate_array(get_allocator(), block.memory, block.size, 1,
486 }
487
488 /// \returns The size of the memory block returned by the next call to \ref allocate_block().
489 std::size_t next_block_size() const noexcept
490 {
491 return block_size_;
492 }
493
494 /// \returns A reference to the used RawAllocator object.
496 {
497 return *this;
498 }
499
500 /// \returns The growth factor.
501 static float growth_factor() noexcept
502 {
503 static constexpr auto factor = float(Num) / Den;
504 return factor;
505 }
506
507 static std::size_t grow_block_size(std::size_t block_size) noexcept
508 {
509 return block_size * Num / Den;
510 }
511
512 private:
513 std::size_t block_size_;
514 };
515
516#if WPI_MEMORY_EXTERN_TEMPLATE
517 extern template class growing_block_allocator<>;
518 extern template class memory_arena<growing_block_allocator<>, true>;
519 extern template class memory_arena<growing_block_allocator<>, false>;
520#endif
521
522 /// A BlockAllocator that allows only one block allocation.
523 /// It can be used to prevent higher-level allocators from expanding.
524 /// The one block allocation is performed through the \c allocate_array() function of the given RawAllocator.
525 /// \ingroup memory_adapter
526 template <class RawAllocator = default_allocator>
527 class fixed_block_allocator : WPI_EBO(allocator_traits<RawAllocator>::allocator_type)
528 {
530
531 public:
533
534 /// \effects Creates it by passing it the size of the block and the allocator object.
535 /// \requires \c block_size must be greater than 0,
536 explicit fixed_block_allocator(std::size_t block_size,
537 allocator_type alloc = allocator_type()) noexcept
538 : allocator_type(detail::move(alloc)), block_size_(block_size)
539 {
540 }
541
542 /// \effects Allocates a new memory block or throws an exception if there was already one allocation.
543 /// \returns The new \ref memory_block.
544 /// \throws Anything thrown by the \c allocate_array() function of the RawAllocator or \ref out_of_memory if this is not the first call.
546 {
547 if (block_size_)
548 {
549 auto mem = traits::allocate_array(get_allocator(), block_size_, 1,
551 memory_block block(mem, block_size_);
552 block_size_ = 0u;
553 return block;
554 }
555 WPI_THROW(out_of_fixed_memory(info(), block_size_));
556 }
557
558 /// \effects Deallocates the previously allocated memory block.
559 /// It also resets and allows a new call again.
560 void deallocate_block(memory_block block) noexcept
561 {
562 detail::debug_check_pointer([&] { return block_size_ == 0u; }, info(),
563 block.memory);
564 traits::deallocate_array(get_allocator(), block.memory, block.size, 1,
566 block_size_ = block.size;
567 }
568
569 /// \returns The size of the next block which is either the initial size or \c 0.
570 std::size_t next_block_size() const noexcept
571 {
572 return block_size_;
573 }
574
575 /// \returns A reference to the used RawAllocator object.
577 {
578 return *this;
579 }
580
581 private:
582 allocator_info info() noexcept
583 {
584 return {WPI_MEMORY_LOG_PREFIX "::fixed_block_allocator", this};
585 }
586
587 std::size_t block_size_;
588 };
589
590#if WPI_MEMORY_EXTERN_TEMPLATE
591 extern template class fixed_block_allocator<>;
592 extern template class memory_arena<fixed_block_allocator<>, true>;
593 extern template class memory_arena<fixed_block_allocator<>, false>;
594#endif
595
596 namespace detail
597 {
598 template <class RawAlloc>
600
601 template <template <class...> class Wrapper, class BlockAllocator, typename... Args>
602 BlockAllocator make_block_allocator(std::true_type, std::size_t block_size,
603 Args&&... args)
604 {
605 return BlockAllocator(block_size, detail::forward<Args>(args)...);
606 }
607
608 template <template <class...> class Wrapper, class RawAlloc>
609 auto make_block_allocator(std::false_type, std::size_t block_size,
610 RawAlloc alloc = RawAlloc()) -> Wrapper<RawAlloc>
611 {
612 return Wrapper<RawAlloc>(block_size, detail::move(alloc));
613 }
614 } // namespace detail
615
616 /// Takes either a BlockAllocator or a RawAllocator.
617 /// In the first case simply aliases the type unchanged, in the second to \ref growing_block_allocator (or the template in `BlockAllocator`) with the RawAllocator.
618 /// Using this allows passing normal RawAllocators as BlockAllocators.
619 /// \ingroup memory_core
620 template <class BlockOrRawAllocator,
621 template <typename...> class BlockAllocator = detail::default_block_wrapper>
622 using make_block_allocator_t = WPI_IMPL_DEFINED(
623 typename std::conditional<is_block_allocator<BlockOrRawAllocator>::value,
624 BlockOrRawAllocator,
625 BlockAllocator<BlockOrRawAllocator>>::type);
626
627 /// @{
628 /// Helper function make a BlockAllocator.
629 /// \returns A BlockAllocator of the given type created with the given arguments.
630 /// \requires Same requirements as the constructor.
631 /// \ingroup memory_core
632 template <class BlockOrRawAllocator, typename... Args>
634 Args&&... args)
635 {
638 BlockOrRawAllocator>(is_block_allocator<BlockOrRawAllocator>{}, block_size,
639 detail::forward<Args>(args)...);
640 }
641
642 template <template <class...> class BlockAllocator, class BlockOrRawAllocator,
643 typename... Args>
645 std::size_t block_size, Args&&... args)
646 {
648 BlockAllocator, BlockOrRawAllocator>(is_block_allocator<BlockOrRawAllocator>{},
649 block_size, detail::forward<Args>(args)...);
650 }
651 /// @}
652
653 namespace literals
654 {
655 /// Syntax sugar to express sizes with unit prefixes.
656 /// \returns The number of bytes `value` is in the given unit.
657 /// \ingroup memory_core
658 /// @{
659 constexpr std::size_t operator"" _KiB(unsigned long long value) noexcept
660 {
661 return std::size_t(value * 1024);
662 }
663
664 constexpr std::size_t operator"" _KB(unsigned long long value) noexcept
665 {
666 return std::size_t(value * 1000);
667 }
668
669 constexpr std::size_t operator"" _MiB(unsigned long long value) noexcept
670 {
671 return std::size_t(value * 1024 * 1024);
672 }
673
674 constexpr std::size_t operator"" _MB(unsigned long long value) noexcept
675 {
676 return std::size_t(value * 1000 * 1000);
677 }
678
679 constexpr std::size_t operator"" _GiB(unsigned long long value) noexcept
680 {
681 return std::size_t(value * 1024 * 1024 * 1024);
682 }
683
684 constexpr std::size_t operator"" _GB(unsigned long long value) noexcept
685 {
686 return std::size_t(value * 1000 * 1000 * 1000);
687 }
688 } // namespace literals
689 } // namespace memory
690} // namespace wpi
691
692#endif // WPI_MEMORY_MEMORY_ARENA_HPP_INCLUDED
The default specialization of the wpi::memory::allocator_traits.
The default specialization of the allocator_traits for a RawAllocator.
Definition allocator_traits.hpp:292
static void deallocate_array(allocator_type &state, void *array, std::size_t count, std::size_t size, std::size_t alignment) noexcept
Definition allocator_traits.hpp:328
traits_detail::allocator_type< Allocator > allocator_type
Definition allocator_traits.hpp:294
static void * allocate_array(allocator_type &state, std::size_t count, std::size_t size, std::size_t alignment)
Definition allocator_traits.hpp:308
void do_shrink_to_fit(BlockAllocator &alloc) noexcept
Definition memory_arena.hpp:210
std::size_t cache_size() const noexcept
Definition memory_arena.hpp:185
void do_deallocate_block(BlockAllocator &, detail::memory_block_stack &used) noexcept
Definition memory_arena.hpp:204
std::size_t cached_block_size() const noexcept
Definition memory_arena.hpp:190
bool take_from_cache(detail::memory_block_stack &used) noexcept
Definition memory_arena.hpp:195
bool cache_empty() const noexcept
Definition memory_arena.hpp:180
std::size_t cached_block_size() const noexcept
Definition memory_arena.hpp:240
void do_deallocate_block(BlockAllocator &alloc, detail::memory_block_stack &used) noexcept
Definition memory_arena.hpp:251
bool cache_empty() const noexcept
Definition memory_arena.hpp:230
void do_shrink_to_fit(BlockAllocator &) noexcept
Definition memory_arena.hpp:258
bool take_from_cache(detail::memory_block_stack &) noexcept
Definition memory_arena.hpp:245
std::size_t cache_size() const noexcept
Definition memory_arena.hpp:235
Definition memory_arena.hpp:174
Definition memory_arena.hpp:97
memory_block_stack() noexcept
Definition memory_arena.hpp:99
bool empty() const noexcept
Definition memory_arena.hpp:151
friend void swap(memory_block_stack &a, memory_block_stack &b) noexcept
Definition memory_arena.hpp:115
memory_block_stack(memory_block_stack &&other) noexcept
Definition memory_arena.hpp:103
static constexpr std::size_t implementation_offset() noexcept
Definition memory_arena.hpp:127
memory_block_stack & operator=(memory_block_stack &&other) noexcept
Definition memory_arena.hpp:108
void push(allocated_mb block) noexcept
std::size_t size() const noexcept
inserted_mb top() const noexcept
Definition memory_arena.hpp:144
void steal_top(memory_block_stack &other) noexcept
~memory_block_stack() noexcept
Definition memory_arena.hpp:101
bool owns(const void *ptr) const noexcept
A BlockAllocator that allows only one block allocation.
Definition memory_arena.hpp:528
std::size_t next_block_size() const noexcept
Definition memory_arena.hpp:570
allocator_type & get_allocator() noexcept
Definition memory_arena.hpp:576
fixed_block_allocator(std::size_t block_size, allocator_type alloc=allocator_type()) noexcept
Definition memory_arena.hpp:536
memory_block allocate_block()
Definition memory_arena.hpp:545
void deallocate_block(memory_block block) noexcept
Definition memory_arena.hpp:560
typename traits::allocator_type allocator_type
Definition memory_arena.hpp:532
A BlockAllocator that uses a given RawAllocator for allocating the blocks.
Definition memory_arena.hpp:450
static float growth_factor() noexcept
Definition memory_arena.hpp:501
memory_block allocate_block()
Definition memory_arena.hpp:470
std::size_t next_block_size() const noexcept
Definition memory_arena.hpp:489
static std::size_t grow_block_size(std::size_t block_size) noexcept
Definition memory_arena.hpp:507
growing_block_allocator(std::size_t block_size, allocator_type alloc=allocator_type()) noexcept
Definition memory_arena.hpp:461
void deallocate_block(memory_block block) noexcept
Definition memory_arena.hpp:482
typename traits::allocator_type allocator_type
Definition memory_arena.hpp:456
allocator_type & get_allocator() noexcept
Definition memory_arena.hpp:495
A memory arena that manages huge memory blocks for a higher-level allocator.
Definition memory_arena.hpp:278
BlockAllocator allocator_type
Definition memory_arena.hpp:284
memory_arena(memory_arena &&other) noexcept
Definition memory_arena.hpp:321
void shrink_to_fit() noexcept
Definition memory_arena.hpp:387
friend void swap(memory_arena &a, memory_arena &b) noexcept
Definition memory_arena.hpp:338
memory_block allocate_block()
Definition memory_arena.hpp:350
std::integral_constant< bool, Cached > is_cached
Definition memory_arena.hpp:285
std::size_t cache_size() const noexcept
Definition memory_arena.hpp:399
memory_block current_block() const noexcept
Definition memory_arena.hpp:362
std::size_t next_block_size() const noexcept
Definition memory_arena.hpp:415
allocator_type & get_allocator() noexcept
Definition memory_arena.hpp:425
std::size_t capacity() const noexcept
Definition memory_arena.hpp:393
void deallocate_block() noexcept
Definition memory_arena.hpp:371
static constexpr std::size_t min_block_size(std::size_t byte_size) noexcept
Definition memory_arena.hpp:290
~memory_arena() noexcept
Definition memory_arena.hpp:307
bool owns(const void *ptr) const noexcept
Definition memory_arena.hpp:379
memory_arena & operator=(memory_arena &&other) noexcept
Definition memory_arena.hpp:328
std::size_t size() const noexcept
Definition memory_arena.hpp:406
memory_arena(std::size_t block_size, Args &&... args)
Definition memory_arena.hpp:300
A special case of out_of_memory errors thrown when a low-level allocator with a fixed size runs out o...
Definition error.hpp:121
Configuration macros.
#define WPI_MEMORY_LOG_PREFIX
Definition config.hpp:46
#define WPI_THROW(Ex)
Definition config.hpp:33
The typedef wpi::memory::default_allocator.
The exception classes.
auto ptr(T p) -> const void *
Converts p to const void* for pointer formatting.
Definition format.h:3821
implementation_defined make_block_allocator_t
Takes either a BlockAllocator or a RawAllocator.
Definition memory_arena.hpp:622
constexpr bool cached_arena
Definition memory_arena.hpp:89
make_block_allocator_t< BlockOrRawAllocator > make_block_allocator(std::size_t block_size, Args &&... args)
Definition memory_arena.hpp:633
constexpr bool uncached_arena
Definition memory_arena.hpp:90
detail namespace with internal helper functions
Definition input_adapters.h:32
Definition json.h:5183
Implement std::hash so that hash_code can be used in STL containers.
Definition PointerIntPair.h:280
BlockAllocator make_block_allocator(std::true_type, std::size_t block_size, Args &&... args)
Definition memory_arena.hpp:602
void adl_swap(T &a, T &b) noexcept
Definition utility.hpp:60
growing_block_allocator< RawAlloc > default_block_wrapper
Definition memory_arena.hpp:599
T && forward(typename std::remove_reference< T >::type &t) noexcept
Definition utility.hpp:31
constexpr std::size_t max_alignment
Definition align.hpp:42
std::remove_reference< T >::type && move(T &&arg) noexcept
Definition utility.hpp:25
std::true_type is_block_allocator_impl(int,,,)
void debug_check_pointer(Functor condition, const allocator_info &info, void *ptr)
Definition debug_helpers.hpp:71
void debug_fill_internal(void *, std::size_t, bool) noexcept
Definition debug_helpers.hpp:62
Memory namespace.
Definition heap_allocator.hpp:20
Foonathan namespace.
Definition ntcore_cpp.h:26
Contains information about an allocator.
Definition error.hpp:23
Traits that check whether a type models concept BlockAllocator.
Definition memory_arena.hpp:73
A memory block.
Definition memory_arena.hpp:28
memory_block(void *mem, std::size_t s) noexcept
Definition memory_arena.hpp:36
memory_block(void *begin, void *end) noexcept
Definition memory_arena.hpp:39
std::size_t size
The size of the memory block (might be 0).
Definition memory_arena.hpp:30
memory_block() noexcept
Definition memory_arena.hpp:33
void * memory
The address of the memory block (might be nullptr).
Definition memory_arena.hpp:29
bool contains(const void *address) const noexcept
Definition memory_arena.hpp:46
#define WPI_SFINAE(Expr)
Definition utility.hpp:85
#define WPI_MEMORY_ASSERT(Expr)
Definition assert.hpp:46