14
14
15
15
#include " ../Macros.h"
16
16
17
+ /* *
18
+ * A shorthand macro for making deallocations easier to manage.
19
+ */
17
20
#define FREE (ptr ) Deallocate((void **) &ptr)
18
21
19
22
namespace Siege
@@ -23,32 +26,55 @@ class TlsfAllocator
23
26
{
24
27
public:
25
28
29
+ /* *
30
+ * @brief Flags for determining the state of a memory block. Every header has a flag where the
31
+ * first three bits are dedicated to keeping track of the block's state
32
+ */
26
33
enum HeaderFlags
27
34
{
28
35
FULL = 0 ,
29
36
FREE = 1 ,
30
37
PREV_IS_FREE = 2
31
38
};
32
39
40
+ /* *
41
+ * @brief linked list nodes for representing free memory blocks
42
+ */
33
43
struct FreeBlockNode
34
44
{
35
45
FreeBlockNode* next {nullptr };
36
46
FreeBlockNode* prev {nullptr };
37
47
};
38
48
49
+ /* *
50
+ * @brief A struct representing the header for each memory block in the allocator. This struct
51
+ * stores the size of the entire block alongside the state of the block
52
+ */
39
53
struct BlockHeader
40
54
{
41
55
T sizeAndFlags {0 };
42
56
};
43
57
58
+ /* *
59
+ * @brief a struct which stores the size of the the entire memory block. Used to navigate the
60
+ * allocator and find the block's header
61
+ */
44
62
struct BlockFooter
45
63
{
46
64
T totalBlockSize {0 };
47
65
};
48
66
49
67
// S'tructors
50
68
69
+ /* *
70
+ * @brief Empty constructor Initialises the constructor and size to 0 (null)
71
+ */
51
72
TlsfAllocator ();
73
+ /* *
74
+ * @brief Size initialiser. Accepts a number representing the number of bytes to allocate to
75
+ * the allocator's memory buffer
76
+ * @param size the number of bytes to allocate, cannot be less than 16
77
+ */
52
78
TlsfAllocator (const T size);
53
79
54
80
// Deleted copy and move constructors
@@ -58,69 +84,279 @@ class TlsfAllocator
58
84
59
85
// Other functions
60
86
61
- void CreateHeader (uint8_t * ptr, const T size, HeaderFlags flags);
62
- void CreateFooter (uint8_t * ptr, const T size);
63
- FreeBlockNode* CreateFreeBlock (uint8_t * ptr, FreeBlockNode* prev, FreeBlockNode* next);
64
- FreeBlockNode* FindFreeBlock (const T& size);
87
+ /* *
88
+ * @brief Checks if a block's preceding neighbour is free (the block that comes before it)
89
+ * @param header the current header
90
+ * @return true if the previous block is free, otherwise false
91
+ */
92
+ bool PrevBlockIsFree (BlockHeader* header);
65
93
66
- const T GetNextFreeSlotIndex (T& fl, T& sl);
94
+ /* *
95
+ * @brief Checks if a block is free for allocation
96
+ * @param header the header to check for free space
97
+ * @return true if the free flag is set, otherwise false
98
+ */
67
99
bool IsFree (BlockHeader* header);
100
+
101
+ /* *
102
+ * @brief Checks if an entry exists in the FreeList for a specific combination of first and
103
+ * second level indices
104
+ * @param fl the index to search the first level bitmask with
105
+ * @param sl the index to search the second level bitmask with
106
+ * @return true if a free block exists, false otherwise
107
+ */
68
108
bool IsFree (T fl, T sl);
109
+
110
+ /* *
111
+ * @brief Checks if the allocator is full
112
+ * @return true if there are no bytes left in the allocator, otherwise false
113
+ */
69
114
bool IsFull ();
70
- bool PrevBlockIsFree (BlockHeader* header);
71
- T CalculateFreeBlockIndices (T size, OUT T& fl, OUT T& sl);
72
115
73
116
// Buffer manipulation Functions
74
117
118
+ /* *
119
+ * @brief Retrieves a free block from a header if possible
120
+ * @param header the header from which to get a FreeBlock
121
+ * @return a FreeBlock if applicable, otherwise a nullptr
122
+ */
75
123
FreeBlockNode* GetFreeBlock (BlockHeader* header);
124
+
125
+ /* *
126
+ * @brief Retrieves a free block using first and second level indices
127
+ * @param fl the first level index to be calculated
128
+ * @param sl the second level index to be calculated
129
+ * @return the FreeBlock at the specified first and second level indices
130
+ */
76
131
FreeBlockNode* GetFreeBlock (const T fl, const T sl);
132
+
133
+ /* *
134
+ * @brief Retrieves the raw allocated data stored within the memory block
135
+ * @param header the header to extrapolate the data from
136
+ * @return a pointer to the data stored by the memory block
137
+ */
77
138
uint8_t * GetBlockData (BlockHeader* header);
139
+
140
+ /* *
141
+ * @brief Gets the footer for a memory block
142
+ * @param header the header of the memory block
143
+ * @return the footer associated with the memory block or nullptr if out of bounds
144
+ */
78
145
BlockFooter* GetFooter (BlockHeader* header);
146
+
147
+ /* *
148
+ * @brief Returns the footer of the previous memory block
149
+ * @param header the current header
150
+ * @return the previous footer or nullptr if it doesnt exist
151
+ */
79
152
BlockFooter* GetPrevFooter (BlockHeader* header);
153
+
154
+ /* *
155
+ * @brief Returns the header associated with a FreeBlock
156
+ * @param node the FreeBlock to search
157
+ * @return the BlockHeader associated with the free block
158
+ */
80
159
BlockHeader* GetHeader (FreeBlockNode* node);
160
+
161
+ /* *
162
+ * @brief Returns the header of a data pointer. Assumes that the data is pointing to the start
163
+ * of the data pointer
164
+ * @param ptr the raw data pointer
165
+ * @return a BlockHeader if one exists
166
+ */
81
167
BlockHeader* GetHeader (uint8_t * ptr);
168
+
169
+ /* *
170
+ * @brief Returns the header of the previous data block if within the allocator's range
171
+ * @param header the current header
172
+ * @return the header of the previous block or nullptr if none exist
173
+ */
82
174
BlockHeader* GetPrevHeader (BlockHeader* header);
175
+
176
+ /* *
177
+ * @brief Returns the header of the next memory block if within the allocator's range
178
+ * @param header the current header
179
+ * @return the header of the next memory block or nullptr if out of bounds
180
+ */
83
181
BlockHeader* GetNextHeader (BlockHeader* header);
84
182
85
183
// Allocate/Deallocate
86
184
185
+ /* *
186
+ * @brief Allocates a memory block and returns a pointer to the allocator's buffer
187
+ * @param size the size in bytes to allocate. The minimum allocatable chunk of memory is 16
188
+ * bytes
189
+ * @return a pointer to the memory block
190
+ */
87
191
void * Allocate (const T& size);
88
- void Deallocate (void ** ptr);
89
192
90
- BlockHeader* TrySplitBlock (FreeBlockNode* node, T& allocatedSize);
91
- bool RemoveFreeBlock (FreeBlockNode* node);
92
- void AddNewBlock (const T size, BlockHeader* currentNode);
93
- BlockHeader* TryCoalesce (BlockHeader* header, OUT T& size);
193
+ /* *
194
+ * @brief Deallocates a memory block and returns the memory to the allocator's pool
195
+ * @param ptr the pointer to deallocate
196
+ */
197
+ void Deallocate (void ** ptr);
94
198
95
199
// Getters
96
200
97
- bool IsValid (uint8_t * ptr);
201
+ /* *
202
+ * @brief Returns the size of a memory block from its header
203
+ * @param header the header of the memory block
204
+ * @return the fully padded size of the memory block
205
+ */
98
206
const T GetHeaderSize (BlockHeader* header);
207
+
208
+ /* *
209
+ * Returns the maximum capacity of the allocator
210
+ * @return the allocator's capacity in bytes
211
+ */
99
212
const T Capacity ();
213
+
214
+ /* *
215
+ * Returns the number of unpadded bytes remaining
216
+ * @return the number of bytes remaining in the allocator
217
+ */
100
218
const T BytesRemaining ();
219
+
220
+ /* *
221
+ * Returns the total bytes remaining with padding
222
+ * @return the total bytes remaining with padding
223
+ */
101
224
const T TotalBytesRemaining ()
102
225
{
103
226
return totalBytesRemaining;
104
227
}
228
+
229
+ /* *
230
+ * Returns the total size of allocated memory by the allocator with padding
231
+ * @return the total size of allocated memory by the allocator with padding
232
+ */
105
233
const T TotalSize ()
106
234
{
107
235
return totalSize;
108
236
}
237
+
238
+ /* *
239
+ * Returns the data buffer held by the allocator
240
+ * @return the data buffer held by the allocator
241
+ */
109
242
const uint8_t * Data ()
110
243
{
111
244
return data;
112
245
}
246
+
247
+ /* *
248
+ * Returns the bitmask representing the first level of size classes
249
+ * @return the bitmask representing the first level of size classes
250
+ */
113
251
const T FlBitmask ()
114
252
{
115
253
return flBitmask;
116
254
}
255
+
256
+ /* *
257
+ * Returns the second level bitmask stored by the allocator
258
+ * @param fl the first level index to search over
259
+ * @return the value of the second level bitmask
260
+ */
117
261
const uint16_t & SlBitmask (const T fl)
118
262
{
119
263
return slBitmasks[fl];
120
264
}
121
265
122
266
private:
123
267
268
+ /* *
269
+ * @brief Calculates the FreeList, first level, and second level indices for a given size
270
+ * @param size the size class to search for in the allocator
271
+ * @param fl the first level index to be calculated
272
+ * @param sl the second level index to be calculated
273
+ * @return the FreeList index
274
+ */
275
+ T CalculateFreeBlockIndices (T size, OUT T& fl, OUT T& sl);
276
+
277
+ /* *
278
+ * @brief Creates and initialises a header at a specified memory location
279
+ * @param ptr the memory location, represented as a pointer to a set of bytes
280
+ * @param size the size to allocate to the memory block. Size must have metadata sizes factored
281
+ * into its calculation
282
+ * @param flags The state flags for header (see HeaderFlags)
283
+ */
284
+ void CreateHeader (uint8_t * ptr, const T size, HeaderFlags flags);
285
+
286
+ /* *
287
+ * @brief Creates a footer at a specified memory location. Footers store the size of the entire
288
+ * memory block (including metadata padding)
289
+ * @param ptr the memory location to allocate the footer to (represented as a byte pointer)
290
+ * @param size the size to assign the footer (should be the full block size)
291
+ */
292
+ void CreateFooter (uint8_t * ptr, const T size);
293
+
294
+ /* *
295
+ * @brief Creates a FreeBlockNode at a specified memory location and positions it within the
296
+ * FreeList
297
+ * @param ptr the memory location to initialise the block to
298
+ * @param prev the FreeBlock that precedes this block
299
+ * @param next the FreeBlock that follows this block
300
+ * @return a pointer to the new FreeBlock
301
+ */
302
+ FreeBlockNode* CreateFreeBlock (uint8_t * ptr, FreeBlockNode* prev, FreeBlockNode* next);
303
+
304
+ /* *
305
+ * @brief Finds a free block for a specified size. If none exist, will attempt to find the next
306
+ * available block
307
+ * @param size the minimum size of the free block
308
+ * @return a pointer to a FreeBlockNode if one exists, otherwise nullptr
309
+ */
310
+ FreeBlockNode* FindFreeBlock (const T& size);
311
+
312
+ /* *
313
+ * @brief Returns the next available free block (if any exist)
314
+ * @param fl the index to search the first level bitmask with
315
+ * @param sl the index to search the second level bitmask with
316
+ * @return the index to the FreeList where the block exists
317
+ */
318
+ const T GetNextFreeSlotIndex (T& fl, T& sl);
319
+
320
+ /* *
321
+ * Attempts to split a block in two, prioritising splitting the block into the requested size
322
+ * first and allocating the remainder to a second block. If an attempted split results in too
323
+ * few bytes remaining, the block will allocate the full free block
324
+ * @param node the node to try and split
325
+ * @param allocatedSize the size to allocate to the first split block
326
+ * @return a BlockHeader representing the split block
327
+ */
328
+ BlockHeader* TrySplitBlock (FreeBlockNode* node, T& allocatedSize);
329
+
330
+ /* *
331
+ * Removes a free block from the FreeList, unlinking it from its class linked list
332
+ * @param node the node to remove
333
+ * @return true if successfully removed, otherwise false
334
+ */
335
+ bool RemoveFreeBlock (FreeBlockNode* node);
336
+
337
+ /* *
338
+ * Adds a new free block to the allocator
339
+ * @param size the size in bytes of the new FreeBlock
340
+ * @param currentNode the header of the FreeNode you wish to add
341
+ */
342
+ void AddNewBlock (const T size, BlockHeader* currentNode);
343
+
344
+ /* *
345
+ * Attempts to combine a FreeBlock with its neighbours and updates the size of the header if
346
+ * memory blocks were successfully combined
347
+ * @param header the header to attempt to coalesce
348
+ * @param size the size in bytes of the combined new memory block
349
+ * @return the BlockHeader of the combined memory block (if combined)
350
+ */
351
+ BlockHeader* TryCoalesce (BlockHeader* header, OUT T& size);
352
+
353
+ /* *
354
+ * Tests if a pointer is valid within the allocator
355
+ * @param ptr the pointer to test
356
+ * @return true if the pointer is valid, otherwise false
357
+ */
358
+ bool IsValid (uint8_t * ptr);
359
+
124
360
static uint8_t MIN_SIZE_INDEX;
125
361
126
362
T totalSize {0 };
@@ -137,11 +373,22 @@ class TlsfAllocator
137
373
uint16_t * slBitmasks {nullptr };
138
374
};
139
375
140
- // Maximum buffer possible here is around 8KB.
376
+ /* *
377
+ * @brief A TLSF allocator capable of storing up to 8KB of memory. Each allocation has a overhead of
378
+ * 4 bytes and can only allocate a minimum of 16 bytes
379
+ */
141
380
typedef TlsfAllocator<uint16_t > SmallTlsfAllocator;
142
- // Maximum buffer possible here is around 512MB.
381
+
382
+ /* *
383
+ * A TLSF allocator capable of storing up to 512MB of memory. Each allocation has a overhead of
384
+ * 8 bytes and can only allocate a minimum of 16 bytes
385
+ */
143
386
typedef TlsfAllocator<uint32_t > MediumTlsfAllocator;
144
- // Maximum buffer possible here is around 2,147,483.6GB.
387
+
388
+ /* *
389
+ * A TLSF allocator capable of storing up to 8GB of memory. Each allocation has a overhead of
390
+ * 16 bytes and can only allocate a minimum of 16 bytes
391
+ */
145
392
typedef TlsfAllocator<uint64_t > LargeTlsfAllocator;
146
393
} // namespace Siege
147
394
0 commit comments