diff --git a/headers/build/private/kernel/util/BumpAllocator.h b/headers/build/private/kernel/util/BumpAllocator.h new file mode 100644 index 0000000000..614d216e8d --- /dev/null +++ b/headers/build/private/kernel/util/BumpAllocator.h @@ -0,0 +1 @@ +#include <../private/kernel/util/BumpAllocator.h> diff --git a/headers/private/kernel/util/BumpAllocator.h b/headers/private/kernel/util/BumpAllocator.h new file mode 100644 index 0000000000..ad6660e552 --- /dev/null +++ b/headers/private/kernel/util/BumpAllocator.h @@ -0,0 +1,112 @@ +/* + * Copyright 2024, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _BUMP_ALLOCATOR_H +#define _BUMP_ALLOCATOR_H + + +#include + +#include +#include + + +template +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 */