VAE - Virtual Audio Engine 1
Small Data Driven Audio Engine
tklb::memory::MemoryPoolStack Class Referencefinal

Stack based pool. More...

#include <TMemoryPoolStack.hpp>

Inheritance diagram for tklb::memory::MemoryPoolStack:
Collaboration diagram for tklb::memory::MemoryPoolStack:

Public Member Functions

 MemoryPoolStack (void *pool, Size size)
 
void * allocate (Size size) override
 
void deallocate (void *ptr) override
 
void * reallocate (void *ptr, size_t size) override
 
- Public Member Functions inherited from tklb::memory::MemoryPool
 MemoryPool (void *pool, Size size)
 Construct a pool from memory provided. More...
 
 ~MemoryPool ()
 
Size getAllocated () const
 
Size getTotalSize () const
 
void * clearallocate (size_t num, size_t size)
 Allocates space for num of structs with size size and clears the memory. More...
 
template<class T , typename ... Args>
T * create (Args &&... args)
 Acts like new. More...
 
template<class T , typename ... Args>
T * createArray (size_t count, Args &&... args)
 
template<class T >
void dispose (T *ptr)
 Acts like delete. More...
 
template<class T >
void disposeArray (size_t count, T *ptr)
 Acts like delete. More...
 
void deallocateAligned (void *ptr)
 
void * allocateAligned (const Size size, const Size align=DEFAULT_ALIGN)
 Allocate aligned if simd is enabled. More...
 

Additional Inherited Members

- Protected Types inherited from tklb::memory::MemoryPool
using Size = uintptr_t
 
using Byte = unsigned char
 
using Mutex = SpinLock
 
using Lock = LockGuard< Mutex >
 
- Protected Attributes inherited from tklb::memory::MemoryPool
SharedPoolmPool
 
- Static Protected Attributes inherited from tklb::memory::MemoryPool
static constexpr Size DEFAULT_ALIGN = xsimd::default_arch::alignment()
 

Detailed Description

Stack based pool.

Definition at line 11 of file TMemoryPoolStack.hpp.

Constructor & Destructor Documentation

◆ MemoryPoolStack()

tklb::memory::MemoryPoolStack::MemoryPoolStack ( void *  pool,
Size  size 
)
inline

Definition at line 13 of file TMemoryPoolStack.hpp.

13 : MemoryPool(pool, size) {
14 if (mPool.allocated == 0) {
15 // first block marks empty space
16 Block& block = *reinterpret_cast<Block*>(mPool.memory);
17 block.size = 0;
18 block.space = mPool.size;
19 }
20 }
MemoryPool(void *pool, Size size)
Construct a pool from memory provided.
Definition: TMemoryPool.hpp:76
Byte * memory
Start of the usable pool space this does not store the pointer, but the location location itself is u...
Definition: TMemoryPool.hpp:65

Member Function Documentation

◆ allocate()

void * tklb::memory::MemoryPoolStack::allocate ( Size  size)
inlineoverridevirtual

Implements tklb::memory::MemoryPool.

Definition at line 22 of file TMemoryPoolStack.hpp.

22 {
23 if (size == 0) { return nullptr; }
24 if (size < sizeof(Size)) {
25 // min block size since the space will be used when it's free
26 // to store the distance to the next block
27 size = sizeof(Size);
28 }
29
30 size += sizeof(Size); // add space for the size
31
32 // This needs to be enough for the Block struct
33 static_assert(sizeof(Block) <= 2 * sizeof(Size), "Not enough space to store spare block!");
34
35 // Make sure the size is aligned
36 size += sizeof(uintptr_t) - (size % sizeof(uintptr_t));
37
38 Lock lock(mPool.mutex);
39 for (Size i = 0; i < mPool.size;) {
40 Block& block = *reinterpret_cast<Block*>(mPool.memory + i);
41 if (block.size == 0) {
42 // block is free
43 if (size <= block.space) {
44 // block has space
45 const Size oldSize = block.space;
46 if (oldSize <= size + sizeof(Size)) {
47 // not enough space to mark a spare block
48 // after, so just take the space of the old block
49 size = oldSize;
50 } else {
51 // Enough space to mark a new block
52 Block& freeBlock = *reinterpret_cast<Block*>(
53 reinterpret_cast<Byte*>(&block) + size
54 );
55 freeBlock.size = 0;
56 // Mark the size of the new free block
57 freeBlock.space = oldSize - size;
58 }
59 block.size = size;
60 mPool.allocated += size;
61 return &block.space; // * Found free spot
62 } else {
63 // Step over the free area which is too small
64 if (block.space == 0) {
65 // this means the previous block has overrun this one
66 // and we can't continue
67 TKLB_ASSERT(false)
68 return nullptr; // ! Block was overrun
69 }
70 i += block.space;
71 }
72 } else {
73 if (block.size == 0) {
74 // same as above
75 TKLB_ASSERT(false)
76 return nullptr; // ! Block was overrun
77 }
78 i += block.size; // Step over the already allocated area
79 }
80 }
81 TKLB_ASSERT(false)
82 return nullptr; // ! No memory left
83 }
#define TKLB_ASSERT(condition)
Wrap assertions.
Definition: TAssert.h:18
LockGuard< Mutex > Lock
Definition: TMemoryPool.hpp:30
else() add_library(tklb STATIC $
Here is the caller graph for this function:

◆ deallocate()

void tklb::memory::MemoryPoolStack::deallocate ( void *  ptr)
inlineoverridevirtual

Implements tklb::memory::MemoryPool.

Definition at line 85 of file TMemoryPoolStack.hpp.

85 {
86 if (ptr == nullptr) { return; }
87
88 // Check if pointer is in memory range
89 TKLB_ASSERT((uintptr_t) mPool.memory <= (uintptr_t) ptr)
90 TKLB_ASSERT((uintptr_t) ptr < (uintptr_t) mPool.memory + (uintptr_t)mPool.memory)
91
92 Block& block = *reinterpret_cast<Block*>(
93 reinterpret_cast<Byte*>(ptr) - sizeof(Size)
94 );
95
96 // blocks can never be less than 2 * sizeof(Size)
97 TKLB_ASSERT(sizeof(Size) < block.size)
98
99 #ifdef TKLB_MEM_TRACE
100 Size* data = reinterpret_cast<Size*>(&block);
101 const Size end = block.size / sizeof(Size);
102 // Set the freed memory to a pattern
103 // skip the first 8 bytes since they are 0 indicating the block is free
104 for (Size i = 2; i < end; i++) {
105 data[i] = 123;
106 }
107 data[end - 1] = 666; // end of free block
108 #endif
109
110 Lock lock(mPool.mutex);
111 // Save how large is the gap in memory will be
112 // TODO tklb check if the next block is free too
113 // These blocks should be merged or fragmentation gets worse
114 block.space = block.size;
115 mPool.allocated -= block.size;
116 block.size = 0; // Mark the block as unallocated
117 }
Here is the caller graph for this function:

◆ reallocate()

void * tklb::memory::MemoryPoolStack::reallocate ( void *  ptr,
size_t  size 
)
inlineoverridevirtual

Implements tklb::memory::MemoryPool.

Definition at line 119 of file TMemoryPoolStack.hpp.

119 {
120 // Act like malloc when ptr is nullptr
121 if (ptr == nullptr) { return allocate(size); }
122
123 Block& block = *reinterpret_cast<Block*>(
124 reinterpret_cast<Byte*>(ptr) - sizeof(Size)
125 );
126 const Size oldSize = block.size;
127 Size newSize = size + sizeof(Size);
128 // Make sure the size is aligned
129 newSize += sizeof(uintptr_t) - (newSize % sizeof(uintptr_t));
130
131 if (newSize <= oldSize) {
132 // Down size
133 if (oldSize <= newSize + sizeof(Size)) {
134 // Don't do anything since there's not enough
135 // space beeing freed to mark a spare block
136 return ptr; // * return same block
137 }
138
139 // Enough space for new spare block
140 block.size = newSize; // down size current block
141 Block& freeBlock = *reinterpret_cast<Block*>(
142 reinterpret_cast<Byte*>(&block) + newSize
143 );
144 freeBlock.size = 0; // Mark the start of a new block
145 freeBlock.space = oldSize - newSize; // Mark the size of the new free block
146 return ptr; // * return same block
147 }
148
149 void* newPtr = allocate(size);
150 if (newPtr == nullptr) { return nullptr; }
151 const Size bytes = oldSize - sizeof(Size);
152 copy(ptr, newPtr, bytes);
153 deallocate(ptr);
154 return newPtr;
155 };
void deallocate(void *ptr) override
void * allocate(Size size) override
static void copy(void *dst, const void *src, const size_t size)
memcpy wrapper
Definition: TMemoryUtil.hpp:14
Here is the call graph for this function:

The documentation for this class was generated from the following file: