7
7
// https://opensource.org/licenses/Zlib
8
8
//
9
9
10
- #include " TlsfAllocator.h"
11
-
10
+ #include " Tlsf.h"
12
11
#include < memory>
13
-
14
- #include " Logging.h"
12
+ #include " ../Logging.h"
15
13
16
14
#define TO_BYTES (val ) reinterpret_cast <uint8_t *>(val)
17
15
#define TO_HEADER (val ) reinterpret_cast <BlockHeader*>(val)
24
22
#define METADATA_OVERHEAD HEADER_SIZE + FOOTER_SIZE
25
23
#define PAD_SIZE (size ) size + METADATA_OVERHEAD
26
24
27
- #define FL_MIN_INDEX 4
28
25
#define MAX_SL_BUCKETS 16
29
26
#define FL (size ) 63 - __builtin_clzll(size)
30
- #define SL (size, fl ) (size >> fl) & ((1 << FL_MIN_INDEX ) - 1 );
27
+ #define SL (size, fl ) (size >> fl) & ((1 << MIN_SIZE_INDEX ) - 1 );
31
28
#define FLAG_OFFSET 3
32
- #define MIN_ALLOCATION 16
33
- #define INVALID_INDEX UINT64_MAX
29
+ #define INVALID_INDEX ( T ) std::numeric_limits<T>::max()
30
+ #define MIN_ALLOCATION_SIZE 16
34
31
35
32
namespace Siege
36
33
{
34
+ template <typename T>
35
+ uint8_t TlsfAllocator<T>::MIN_SIZE_INDEX = sizeof (T) < 4 ? 4 : sizeof (T);
37
36
38
- TlsfAllocator::TlsfAllocator () {}
37
+ template <typename T>
38
+ TlsfAllocator<T>::TlsfAllocator() {}
39
39
40
- TlsfAllocator::TlsfAllocator (const uint64_t size)
40
+ template <typename T>
41
+ TlsfAllocator<T>::TlsfAllocator(const uint64_t size)
41
42
{
42
43
uint64_t paddedSize = PAD_SIZE (size);
43
- if (size == 0 || size < MIN_ALLOCATION || size > (UINT64_MAX - METADATA_OVERHEAD) ||
44
+ if (size == 0 || size < MIN_ALLOCATION_SIZE || size > (INVALID_INDEX (T) - METADATA_OVERHEAD) ||
44
45
paddedSize < size)
45
46
return ;
46
47
47
- uint64_t maxBuckets = (FL (size) - FL_MIN_INDEX ) + 1 ;
48
+ uint64_t maxBuckets = (FL (size) - MIN_SIZE_INDEX ) + 1 ;
48
49
49
50
uint64_t slBucketSize = sizeof (uint16_t ) * maxBuckets;
50
51
uint64_t freeListSize = maxBuckets * MAX_SL_BUCKETS * sizeof (FreeBlockNode*);
@@ -71,18 +72,20 @@ TlsfAllocator::TlsfAllocator(const uint64_t size)
71
72
AddNewBlock (paddedSize, TO_HEADER (data));
72
73
}
73
74
74
- void TlsfAllocator::CreateHeader (uint8_t * ptr, const uint64_t size, HeaderFlags flags)
75
+ template <typename T>
76
+ void TlsfAllocator<T>::CreateHeader(uint8_t * ptr, const uint64_t size, HeaderFlags flags)
75
77
{
76
78
if (!ptr) return ;
77
79
BlockHeader* header = TO_HEADER (ptr);
78
80
header->sizeAndFlags = (size << FLAG_OFFSET) | flags;
79
81
}
80
82
81
- void * TlsfAllocator::Allocate (const uint64_t & size)
83
+ template <typename T>
84
+ void * TlsfAllocator<T>::Allocate(const uint64_t & size)
82
85
{
83
86
uint64_t requiredSize = sizeof (BlockHeader) + size + sizeof (BlockFooter);
84
87
if (!data || capacity == 0 || size == 0 || requiredSize < size ||
85
- requiredSize > totalBytesRemaining || size < MIN_ALLOCATION )
88
+ requiredSize > totalBytesRemaining || size < MIN_ALLOCATION_SIZE )
86
89
return nullptr ;
87
90
88
91
FreeBlockNode* block = FindFreeBlock (requiredSize);
@@ -100,7 +103,43 @@ void* TlsfAllocator::Allocate(const uint64_t& size)
100
103
return ptr;
101
104
}
102
105
103
- TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock (TlsfAllocator::FreeBlockNode* node,
106
+ template <typename T>
107
+ void TlsfAllocator<T>::Deallocate(void ** ptr)
108
+ {
109
+ uint8_t * raw = (uint8_t *) *ptr;
110
+ if (!raw) return ;
111
+ if (raw < data || raw >= (data + capacity)) return ;
112
+
113
+ BlockHeader* header = GetHeader (raw);
114
+
115
+ if (IsFree (header)) return ;
116
+
117
+ uint64_t blockSize = GetHeaderSize (header);
118
+
119
+ uint64_t totalBlockSize = blockSize;
120
+ header = TryCoalesce (header, totalBlockSize);
121
+ BlockFooter* footer = GetFooter (header);
122
+
123
+ header->sizeAndFlags = (totalBlockSize << 3 ) | (header->sizeAndFlags & PREV_IS_FREE) | FREE;
124
+ footer->totalBlockSize = totalBlockSize;
125
+
126
+ BlockHeader* nextHeader = GetNextHeader (header);
127
+
128
+ if (nextHeader && ((uint8_t *) nextHeader < (data + capacity)))
129
+ {
130
+ nextHeader->sizeAndFlags |= PREV_IS_FREE;
131
+ }
132
+
133
+ AddNewBlock (totalBlockSize, header);
134
+
135
+ bytesRemaining += blockSize - sizeof (BlockHeader) - sizeof (BlockFooter);
136
+ totalBytesRemaining += blockSize;
137
+
138
+ *ptr = nullptr ;
139
+ }
140
+
141
+ template <typename T>
142
+ typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::TrySplitBlock(TlsfAllocator<T>::FreeBlockNode* node,
104
143
uint64_t & allocatedSize)
105
144
{
106
145
if (!node) return nullptr ;
@@ -125,7 +164,8 @@ TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock(TlsfAllocator::FreeBloc
125
164
return header;
126
165
}
127
166
128
- void TlsfAllocator::AddNewBlock (const uint64_t size, BlockHeader* header)
167
+ template <typename T>
168
+ void TlsfAllocator<T>::AddNewBlock(const uint64_t size, BlockHeader* header)
129
169
{
130
170
uint64_t fl = 0 , sl = 0 , index;
131
171
index = CalculateFreeBlockIndices (size, fl, sl);
@@ -141,7 +181,8 @@ void TlsfAllocator::AddNewBlock(const uint64_t size, BlockHeader* header)
141
181
slBitmasks[fl] |= (1 << sl);
142
182
}
143
183
144
- TlsfAllocator::BlockHeader* TlsfAllocator::TryCoalesce (BlockHeader* header, OUT uint64_t & size)
184
+ template <typename T>
185
+ typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::TryCoalesce(BlockHeader* header, OUT uint64_t & size)
145
186
{
146
187
BlockHeader* start = header;
147
188
BlockHeader* prev = GetPrevHeader (start);
@@ -163,7 +204,8 @@ TlsfAllocator::BlockHeader* TlsfAllocator::TryCoalesce(BlockHeader* header, OUT
163
204
return start;
164
205
}
165
206
166
- bool TlsfAllocator::RemoveFreeBlock (TlsfAllocator::FreeBlockNode* node)
207
+ template <typename T>
208
+ bool TlsfAllocator<T>::RemoveFreeBlock(TlsfAllocator::FreeBlockNode* node)
167
209
{
168
210
BlockHeader* header = GetHeader (node);
169
211
@@ -189,19 +231,21 @@ bool TlsfAllocator::RemoveFreeBlock(TlsfAllocator::FreeBlockNode* node)
189
231
return true ;
190
232
}
191
233
192
- TlsfAllocator::FreeBlockNode* TlsfAllocator::FindFreeBlock (const uint64_t & size)
234
+ template <typename T>
235
+ typename TlsfAllocator<T>::FreeBlockNode* TlsfAllocator<T>::FindFreeBlock(const uint64_t & size)
193
236
{
194
237
uint64_t fl, sl, index;
195
238
// 1000 0000 0000 1000
196
239
index = CalculateFreeBlockIndices (size, fl, sl);
197
240
198
241
if (!IsFree (fl, sl)) index = GetNextFreeSlotIndex (fl, sl);
199
- if (index == INVALID_INDEX) return nullptr ;
242
+ if (index == INVALID_INDEX (T) ) return nullptr ;
200
243
201
244
return freeList[index];
202
245
}
203
246
204
- const uint64_t TlsfAllocator::GetNextFreeSlotIndex (uint64_t & fl, uint64_t & sl)
247
+ template <typename T>
248
+ const uint64_t TlsfAllocator<T>::GetNextFreeSlotIndex(uint64_t & fl, uint64_t & sl)
205
249
{
206
250
sl = __builtin_ctz (slBitmasks[fl] & ~(((1 << (sl + 1 )) - 1 )));
207
251
@@ -210,7 +254,7 @@ const uint64_t TlsfAllocator::GetNextFreeSlotIndex(uint64_t& fl, uint64_t& sl)
210
254
211
255
fl = flBitmask & ~(((1ULL << (fl + 1 )) - 1 ));
212
256
213
- if (!fl) return INVALID_INDEX;
257
+ if (!fl) return INVALID_INDEX (T) ;
214
258
215
259
fl = __builtin_ctzll (fl);
216
260
CC_ASSERT (slBitmasks[fl] > 0 ,
@@ -222,38 +266,43 @@ const uint64_t TlsfAllocator::GetNextFreeSlotIndex(uint64_t& fl, uint64_t& sl)
222
266
return fl * MAX_SL_BUCKETS + sl;
223
267
}
224
268
225
- uint64_t TlsfAllocator::CalculateFreeBlockIndices (uint64_t size, OUT uint64_t & fl, OUT uint64_t & sl)
269
+ template <typename T>
270
+ uint64_t TlsfAllocator<T>::CalculateFreeBlockIndices(uint64_t size, OUT uint64_t & fl, OUT uint64_t & sl)
226
271
{
227
272
uint64_t rawFl = FL (size);
228
- fl = rawFl - FL_MIN_INDEX ;
273
+ fl = rawFl - MIN_SIZE_INDEX ;
229
274
sl = SL (size, fl);
230
275
return fl * MAX_SL_BUCKETS + sl;
231
276
}
232
277
233
- void TlsfAllocator::CreateFooter (uint8_t * ptr, const uint64_t size)
278
+ template <typename T>
279
+ void TlsfAllocator<T>::CreateFooter(uint8_t * ptr, const uint64_t size)
234
280
{
235
281
if (!ptr) return ;
236
282
BlockFooter* footer = TO_FOOTER (ptr);
237
283
footer->totalBlockSize = size;
238
284
}
239
285
240
- TlsfAllocator::BlockHeader* TlsfAllocator::GetHeader (TlsfAllocator::FreeBlockNode* node)
286
+ template <typename T>
287
+ typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::GetHeader(TlsfAllocator::FreeBlockNode* node)
241
288
{
242
289
if (!node) return nullptr ;
243
290
uint8_t * rawHeader = TO_BYTES (node) - HEADER_SIZE;
244
291
if (!IsValid (rawHeader)) return nullptr ;
245
292
return TO_HEADER (rawHeader);
246
293
}
247
294
248
- TlsfAllocator::BlockHeader* TlsfAllocator::GetHeader (uint8_t * ptr)
295
+ template <typename T>
296
+ typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::GetHeader(uint8_t * ptr)
249
297
{
250
298
if (!ptr) return nullptr ;
251
299
uint8_t * rawHeader = ptr - HEADER_SIZE;
252
300
if (!IsValid (rawHeader)) return nullptr ;
253
301
return TO_HEADER (rawHeader);
254
302
}
255
303
256
- TlsfAllocator::BlockHeader* TlsfAllocator::GetPrevHeader (TlsfAllocator::BlockHeader* header)
304
+ template <typename T>
305
+ typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::GetPrevHeader(TlsfAllocator::BlockHeader* header)
257
306
{
258
307
if (!header) return nullptr ;
259
308
uint8_t * rawPrevFooter = TO_BYTES (GetPrevFooter (header));
@@ -263,7 +312,8 @@ TlsfAllocator::BlockHeader* TlsfAllocator::GetPrevHeader(TlsfAllocator::BlockHea
263
312
return TO_HEADER (prevHeader);
264
313
}
265
314
266
- TlsfAllocator::BlockHeader* TlsfAllocator::GetNextHeader (TlsfAllocator::BlockHeader* header)
315
+ template <typename T>
316
+ typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::GetNextHeader(TlsfAllocator::BlockHeader* header)
267
317
{
268
318
if (!header) return nullptr ;
269
319
uint8_t * rawHeader = TO_BYTES (header);
@@ -272,7 +322,8 @@ TlsfAllocator::BlockHeader* TlsfAllocator::GetNextHeader(TlsfAllocator::BlockHea
272
322
return TO_HEADER (next);
273
323
}
274
324
275
- TlsfAllocator::FreeBlockNode* TlsfAllocator::CreateFreeBlock (uint8_t * ptr,
325
+ template <typename T>
326
+ typename TlsfAllocator<T>::FreeBlockNode* TlsfAllocator<T>::CreateFreeBlock(uint8_t * ptr,
276
327
TlsfAllocator::FreeBlockNode* prev,
277
328
TlsfAllocator::FreeBlockNode* next)
278
329
{
@@ -284,20 +335,23 @@ TlsfAllocator::FreeBlockNode* TlsfAllocator::CreateFreeBlock(uint8_t* ptr,
284
335
return node;
285
336
}
286
337
287
- TlsfAllocator::FreeBlockNode* TlsfAllocator::GetFreeBlock (BlockHeader* header)
338
+ template <typename T>
339
+ typename TlsfAllocator<T>::FreeBlockNode* TlsfAllocator<T>::GetFreeBlock(BlockHeader* header)
288
340
{
289
341
if (!header || !IsFree (header)) return nullptr ;
290
342
uint8_t * rawBlock = TO_BYTES (header) + HEADER_SIZE;
291
343
if (!IsValid (rawBlock)) return nullptr ;
292
344
return TO_FREE_BLOCK (rawBlock);
293
345
}
294
346
295
- TlsfAllocator::FreeBlockNode* TlsfAllocator::GetFreeBlock (const uint64_t fl, const uint64_t sl)
347
+ template <typename T>
348
+ typename TlsfAllocator<T>::FreeBlockNode* TlsfAllocator<T>::GetFreeBlock(const uint64_t fl, const uint64_t sl)
296
349
{
297
350
return freeList[fl * MAX_SL_BUCKETS + sl];
298
351
}
299
352
300
- TlsfAllocator::BlockFooter* TlsfAllocator::GetFooter (TlsfAllocator::BlockHeader* header)
353
+ template <typename T>
354
+ typename TlsfAllocator<T>::BlockFooter* TlsfAllocator<T>::GetFooter(TlsfAllocator::BlockHeader* header)
301
355
{
302
356
if (!header) return nullptr ;
303
357
uint64_t size = GetHeaderSize (header);
@@ -306,35 +360,41 @@ TlsfAllocator::BlockFooter* TlsfAllocator::GetFooter(TlsfAllocator::BlockHeader*
306
360
return TO_FOOTER (rawFooter);
307
361
}
308
362
309
- TlsfAllocator::BlockFooter* TlsfAllocator::GetPrevFooter (TlsfAllocator::BlockHeader* header)
363
+ template <typename T>
364
+ typename TlsfAllocator<T>::BlockFooter* TlsfAllocator<T>::GetPrevFooter(TlsfAllocator::BlockHeader* header)
310
365
{
311
366
if (!header) return nullptr ;
312
367
uint8_t * rawFooter = TO_BYTES (header) - FOOTER_SIZE;
313
368
if (!IsValid (rawFooter)) return nullptr ;
314
369
return TO_FOOTER (rawFooter);
315
370
}
316
371
317
- uint8_t * TlsfAllocator::GetBlockData (TlsfAllocator::BlockHeader* header)
372
+ template <typename T>
373
+ uint8_t * TlsfAllocator<T>::GetBlockData(TlsfAllocator::BlockHeader* header)
318
374
{
319
375
return TO_BYTES (header) + HEADER_SIZE;
320
376
}
321
377
322
- const uint64_t TlsfAllocator::GetHeaderSize (BlockHeader* header)
378
+ template <typename T>
379
+ const uint64_t TlsfAllocator<T>::GetHeaderSize(BlockHeader* header)
323
380
{
324
381
return header->sizeAndFlags >> FLAG_OFFSET;
325
382
}
326
383
327
- bool TlsfAllocator::IsFree (BlockHeader* header)
384
+ template <typename T>
385
+ bool TlsfAllocator<T>::IsFree(BlockHeader* header)
328
386
{
329
387
return header->sizeAndFlags & FREE;
330
388
}
331
389
332
- bool TlsfAllocator::IsFree (uint64_t fl, uint64_t sl)
390
+ template <typename T>
391
+ bool TlsfAllocator<T>::IsFree(uint64_t fl, uint64_t sl)
333
392
{
334
393
return slBitmasks[fl] & (1 << sl);
335
394
}
336
395
337
- bool TlsfAllocator::PrevBlockIsFree (BlockHeader* header)
396
+ template <typename T>
397
+ bool TlsfAllocator<T>::PrevBlockIsFree(BlockHeader* header)
338
398
{
339
399
uint8_t * raw = TO_BYTES (header);
340
400
if (raw == data) return false ;
@@ -348,19 +408,26 @@ bool TlsfAllocator::PrevBlockIsFree(BlockHeader* header)
348
408
return IsFree (TO_HEADER (rawPrevHeader));
349
409
}
350
410
351
- bool TlsfAllocator::IsValid (uint8_t * ptr)
411
+ template <typename T>
412
+ bool TlsfAllocator<T>::IsValid(uint8_t * ptr)
352
413
{
353
414
return ptr && ptr >= data && ptr < (data + (capacity + HEADER_SIZE + FOOTER_SIZE));
354
415
}
355
416
356
- const uint64_t TlsfAllocator::Capacity ()
417
+ template <typename T>
418
+ const uint64_t TlsfAllocator<T>::Capacity()
357
419
{
358
420
return capacity;
359
421
}
360
422
361
- const uint64_t TlsfAllocator::BytesRemaining ()
423
+ template <typename T>
424
+ const uint64_t TlsfAllocator<T>::BytesRemaining()
362
425
{
363
426
return bytesRemaining;
364
427
}
365
428
366
- } // namespace Siege
429
+ template class TlsfAllocator <uint16_t >;
430
+ template class TlsfAllocator <uint32_t >;
431
+ template class TlsfAllocator <uint64_t >;
432
+ }
433
+
0 commit comments