* Copyright 2024, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _BUMP_ALLOCATOR_H
#define _BUMP_ALLOCATOR_H
#include <stdlib.h>
#include <OS.h>
#include <SupportDefs.h>
template<size_t InlineDataSize = (16 * sizeof(void*)), size_t SlabSize = 4096>
class BumpAllocator {
public:
BumpAllocator()
:
fCurrentSlab((Slab*)fInlineData)
{
fCurrentSlab->previous = NULL;
fCurrentSlab->total = sizeof(fInlineData) - sizeof(Slab);
fCurrentSlab->remaining = fCurrentSlab->total;
}
~BumpAllocator()
{
if (fCurrentSlab != (Slab*)fInlineData)
Free(NULL);
if (!IsEmpty())
debugger("BumpAllocator: deleted with allocations still active!");
}
bool IsEmpty() const
{
return fCurrentSlab == (Slab*)fInlineData
&& fCurrentSlab->remaining == fCurrentSlab->total;
}
void* Allocate(size_t _size)
{
const size_t size = _size + sizeof(Allocation);
if (size > SlabSize)
debugger("BumpAllocator: can't allocate larger than the slab size");
if (fCurrentSlab->remaining < size) {
Slab* newSlab = (Slab*)malloc(SlabSize);
if (newSlab == NULL)
return NULL;
newSlab->previous = fCurrentSlab;
newSlab->total = SlabSize - sizeof(Slab);
newSlab->remaining = newSlab->total;
fCurrentSlab = newSlab;
}
fCurrentSlab->remaining -= size;
uint8* pointer = fCurrentSlab->data + fCurrentSlab->remaining;
Allocation* allocation = (Allocation*)pointer;
allocation->size = size;
return allocation->data;
}
void Free(void* _pointer)
{
if (fCurrentSlab->remaining == fCurrentSlab->total) {
Slab* previous = fCurrentSlab->previous;
free(fCurrentSlab);
fCurrentSlab = previous;
}
if (_pointer == NULL)
return;
Allocation* allocation = (((Allocation*)_pointer) - 1);
uint8* last = fCurrentSlab->data + fCurrentSlab->remaining;
if ((uint8*)allocation != last) {
debugger("BumpAllocator: out-of-order free");
return;
}
fCurrentSlab->remaining += allocation->size;
}
private:
#if __cplusplus >= 201103L
# define FLA_SIZE
#else
# define FLA_SIZE 0
#endif
struct Slab {
Slab* previous;
uint32 total;
uint32 remaining;
uint8 data[FLA_SIZE];
};
struct Allocation {
uint32 size;
uint32 _pad;
uint8 data[FLA_SIZE];
#undef FLA_SIZE
};
Slab* fCurrentSlab;
uint8 fInlineData[InlineDataSize - sizeof(Slab*)];
};
#endif