#pragma once struct LocationTrace { char *file; int line; }; #if DEBUG_BUILD thread_local LocationTrace LocationTraceO; #define LOCATION_TRACE (LocationTraceO.file = __FILE__, LocationTraceO.line = __LINE__) #else #define LOCATION_TRACE #endif const int AllocatorKind_Allocate = 1; const int AllocatorKind_Deallocate = 2; struct Allocator { void *(*proc)(void *object, int kind, void *p, size_t size); void *object; }; #define AllocType(alo, Type) (Type *)AllocSize(alo, sizeof(Type)) #define AllocArray(alo, Type, count) (Type *)AllocSize(alo, sizeof(Type) * (count)) #define AllocSize(alo, size) (LOCATION_TRACE, _AllocSize_(alo, size)) API void *_AllocSize_(Allocator alo, size_t size); inline void Dealloc(Allocator alo, void *p) { if (p) (alo).proc((alo).object, AllocatorKind_Deallocate, (p), 0); } API Allocator GetSystemAllocator(); API void TrackingAllocatorCheck(); API Allocator GetTrackingAllocator(); #define MemoryZero(x, size) memset(x, 0, size) #define MemoryZeroStruct(x) memset(x, 0, sizeof(*x)) #define MemoryCopy(dst, src, size) memcpy(dst, src, size) #define MemoryMove(dst, src, size) memmove(dst, src, size) /////////////////// // Block Arena /////////////////// API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size); struct BlockArenaNode { BlockArenaNode *next; U8 *end; U8 start[0]; }; struct BlockArena { U8 *start; U8 *end; BlockArenaNode *blocks; Allocator allocator; operator Allocator() { return {BlockArenaAllocatorProc, this}; } }; API void *PushSize(BlockArena *arena, size_t size); API void Release(BlockArena *arena); API void Unwind(BlockArena *arena, U8 *pos); /////////////////// // Virtual Arena /////////////////// struct VirtualArena { uint8_t *data; size_t len; size_t base_len; // to prevent self deleting the arena size_t reserve; size_t commit; size_t align; operator Allocator() { void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size); return {ArenaAllocatorProc, this}; } }; inline void SetLen(VirtualArena *arena, size_t len) { arena->len = Clamp(len, arena->base_len, arena->len); } inline void Pop(VirtualArena *arena, size_t size) { SetLen(arena, arena->len - size); } inline void Clear(VirtualArena *arena) { SetLen(arena, 0); } API void *VReserve(size_t size); API bool VCommit(void *p, size_t size); API bool VRelease(void *p, size_t size); API bool VDecommit(void *p, size_t size); API void InitArena(VirtualArena *arena, size_t reserve = MiB(256)); API VirtualArena *AllocArena(size_t reserve = MiB(256)); API VirtualArena *AllocArena(Allocator allocator, size_t size); API void *PushSize(VirtualArena *arena, size_t size); API void Release(VirtualArena *arena); /////////////////////////////// // Scratch struct Scratch { BlockArena arena = {}; Scratch() {} Scratch(BlockArena *conflict) {} Scratch(BlockArena *c1, BlockArena *c2) {} Scratch(Allocator conflict) {} Scratch(Allocator c1, Allocator c2) {} ~Scratch() { Release(&arena); } operator BlockArena *() { return &arena; } operator Allocator() { return arena; } private: // @Note: Disable copy constructors, cause its error prone Scratch(Scratch &arena); Scratch(Scratch &arena, Scratch &a2); }; const int PAGE_SIZE = 4096; const int DEFAULT_ALIGNMENT = sizeof(void *);