#include "amr_memory.h" bool amr_IsPowerOfTwo(uintptr_t x) { return (x & (x-1)) == 0; } uintptr_t amr_AlignForward(uintptr_t ptr, size_t align) { uintptr_t p, a, modulo; assert(amr_IsPowerOfTwo(align)); p = ptr; a = (uintptr_t)align; modulo = p & (a-1); if (modulo != 0) { p += a - modulo; } return p; } void *amr_ArenaAllocAlign(amr_DebugArena *Alloc, size_t Size, size_t Align) { uintptr_t CurrOffset = (uintptr_t)Alloc->Buffer + (uintptr_t)Alloc->CurrOffset; uintptr_t AlignedOffset = amr_AlignForward(CurrOffset, Align); AlignedOffset -= (uintptr_t)(Alloc->Buffer); if (AlignedOffset + Size < Alloc->Size) { void *Ptr = &Alloc->Buffer[AlignedOffset]; Alloc->PrevOffset = AlignedOffset; Alloc->CurrOffset = AlignedOffset + Size; PlatformZeroMemory(Ptr, Size); return Ptr; } return NULL; } void amr_ArenaInit(amr_DebugArena *Alloc, void* BackingBuffer, size_t Size) { Alloc->Buffer = (u8 *)BackingBuffer; Alloc->Size = Size; Alloc->CurrOffset = 0; Alloc->PrevOffset = 0; } void *amr_ArenaAlloc(amr_DebugArena *Alloc, size_t Size) { return amr_ArenaAllocAlign(Alloc, Size, DEFAULT_ALIGNMENT); } void amr_ArenaFree(amr_DebugArena *Alloc, void *Ptr) { // @note: Arenas do not support freeing memory // this is here to let me know I have not forgotten to implement it return; } void *amr_ArenaResizeAlign(amr_DebugArena *Alloc, void *OldMem, size_t OldSize, size_t NewSize, size_t Align) { assert(amr_IsPowerOfTwo(Align)); if (OldMem == NULL || OldSize == 0) { return amr_ArenaAllocAlign(Alloc, NewSize, Align); } else if (Alloc->Buffer < OldMem && OldMem < Alloc->Buffer + Alloc->Size) { // check if old_memory falls on prev_offset if (Alloc->Buffer + Alloc->PrevOffset == OldMem) { // re-use prev_offset and resize from there size_t _CurrOffset = Alloc->CurrOffset; Alloc->CurrOffset = Alloc->PrevOffset + NewSize; if (NewSize > OldSize) { PlatformZeroMemory(&Alloc->Buffer[_CurrOffset], NewSize - OldSize); } return OldMem; } else { // generate new memory // will have some fragmentation void *NewMem = amr_ArenaAllocAlign(Alloc, NewSize, Align); size_t CopySize = OldSize < NewSize ? OldSize : NewSize; // copy old memory to new memory location PlatformCopyMemory(NewMem, OldMem, CopySize); return NewMem; } } else { assert(0 && "Memory is out of bounds of the buffer in this arena"); return NULL; } } void *amr_ArenaResize(amr_DebugArena *Alloc, void *OldMem, size_t OldSize, size_t NewSize) { return amr_ArenaResizeAlign(Alloc, OldMem, OldSize, NewSize, DEFAULT_ALIGNMENT); } void amr_ArenaFreeAll(amr_DebugArena *Alloc) { Alloc->CurrOffset = 0; Alloc->PrevOffset = 0; }