mirror of
https://review.haiku-os.org/haiku
synced 2025-01-31 18:56:49 +01:00
3be79a33b0
A basic bump allocator that can handle arbitrary amounts of allocations, so long as all are allocated and freed in a "stack"-like manner. (Actually it could be extended to support non-stack-like operation, but that would require more logic that isn't needed at the moment.) Change-Id: I47077146ea282600130778d312f7d86bd8c032e0 Reviewed-on: https://review.haiku-os.org/c/haiku/+/8238 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: waddlesplash <waddlesplash@gmail.com> Reviewed-by: Michael Lotz <mmlr@mlotz.ch>
113 lines
2.5 KiB
C++
113 lines
2.5 KiB
C++
/*
|
|
* 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) {
|
|
// We need a new slab.
|
|
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) {
|
|
// Free the current slab.
|
|
Slab* previous = fCurrentSlab->previous;
|
|
free(fCurrentSlab);
|
|
fCurrentSlab = previous;
|
|
}
|
|
if (_pointer == NULL)
|
|
return;
|
|
|
|
Allocation* allocation = (((Allocation*)_pointer) - 1);
|
|
|
|
// This needs to be the last thing allocated.
|
|
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; /*!< includes sizeof(Allocation) */
|
|
uint32 _pad;
|
|
uint8 data[FLA_SIZE];
|
|
#undef FLA_SIZE
|
|
};
|
|
Slab* fCurrentSlab;
|
|
uint8 fInlineData[InlineDataSize - sizeof(Slab*)];
|
|
};
|
|
|
|
#endif /* _BUMP_ALLOCATOR_H */
|