1414
1515#include " ../Macros.h"
1616
17+ /* *
18+ * A shorthand macro for making deallocations easier to manage.
19+ */
1720#define FREE (ptr ) Deallocate((void **) &ptr)
1821
1922namespace Siege
@@ -23,32 +26,55 @@ class TlsfAllocator
2326{
2427public:
2528
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+ */
2633 enum HeaderFlags
2734 {
2835 FULL = 0 ,
2936 FREE = 1 ,
3037 PREV_IS_FREE = 2
3138 };
3239
40+ /* *
41+ * @brief linked list nodes for representing free memory blocks
42+ */
3343 struct FreeBlockNode
3444 {
3545 FreeBlockNode* next {nullptr };
3646 FreeBlockNode* prev {nullptr };
3747 };
3848
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+ */
3953 struct BlockHeader
4054 {
4155 T sizeAndFlags {0 };
4256 };
4357
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+ */
4462 struct BlockFooter
4563 {
4664 T totalBlockSize {0 };
4765 };
4866
4967 // S'tructors
5068
69+ /* *
70+ * @brief Empty constructor Initialises the constructor and size to 0 (null)
71+ */
5172 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+ */
5278 TlsfAllocator (const T size);
5379
5480 // Deleted copy and move constructors
@@ -58,69 +84,279 @@ class TlsfAllocator
5884
5985 // Other functions
6086
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);
6593
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+ */
6799 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+ */
68108 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+ */
69114 bool IsFull ();
70- bool PrevBlockIsFree (BlockHeader* header);
71- T CalculateFreeBlockIndices (T size, OUT T& fl, OUT T& sl);
72115
73116 // Buffer manipulation Functions
74117
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+ */
75123 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+ */
76131 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+ */
77138 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+ */
78145 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+ */
79152 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+ */
80159 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+ */
81167 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+ */
82174 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+ */
83181 BlockHeader* GetNextHeader (BlockHeader* header);
84182
85183 // Allocate/Deallocate
86184
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+ */
87191 void * Allocate (const T& size);
88- void Deallocate (void ** ptr);
89192
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);
94198
95199 // Getters
96200
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+ */
98206 const T GetHeaderSize (BlockHeader* header);
207+
208+ /* *
209+ * Returns the maximum capacity of the allocator
210+ * @return the allocator's capacity in bytes
211+ */
99212 const T Capacity ();
213+
214+ /* *
215+ * Returns the number of unpadded bytes remaining
216+ * @return the number of bytes remaining in the allocator
217+ */
100218 const T BytesRemaining ();
219+
220+ /* *
221+ * Returns the total bytes remaining with padding
222+ * @return the total bytes remaining with padding
223+ */
101224 const T TotalBytesRemaining ()
102225 {
103226 return totalBytesRemaining;
104227 }
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+ */
105233 const T TotalSize ()
106234 {
107235 return totalSize;
108236 }
237+
238+ /* *
239+ * Returns the data buffer held by the allocator
240+ * @return the data buffer held by the allocator
241+ */
109242 const uint8_t * Data ()
110243 {
111244 return data;
112245 }
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+ */
113251 const T FlBitmask ()
114252 {
115253 return flBitmask;
116254 }
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+ */
117261 const uint16_t & SlBitmask (const T fl)
118262 {
119263 return slBitmasks[fl];
120264 }
121265
122266private:
123267
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+
124360 static uint8_t MIN_SIZE_INDEX;
125361
126362 T totalSize {0 };
@@ -137,11 +373,22 @@ class TlsfAllocator
137373 uint16_t * slBitmasks {nullptr };
138374};
139375
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+ */
141380typedef 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+ */
143386typedef 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+ */
145392typedef TlsfAllocator<uint64_t > LargeTlsfAllocator;
146393} // namespace Siege
147394
0 commit comments