/* date = April 26th 2023 10:11 pm */ #ifndef VN_MEMORY_H #define VN_MEMORY_H struct memory_arena { platform_memory_block *CurrentBlock; umm MinimumBlockSize; s32 TemporaryMemoryCount; }; struct temporary_memory { memory_arena *Arena; platform_memory_block *Block; umm Used; }; inline temporary_memory BeginTemporaryMemory(memory_arena *Arena) { temporary_memory Result; Result.Arena = Arena; Result.Block = Arena->CurrentBlock; Result.Used = Arena->CurrentBlock ? Arena->CurrentBlock->Used : 0; ++Arena->TemporaryMemoryCount; return(Result); } inline void EndTemporaryMemory(temporary_memory Temp) { memory_arena *Arena = Temp.Arena; while(Arena->CurrentBlock != Temp.Block) { platform_memory_block *MemoryBlock = Arena->CurrentBlock; Arena->CurrentBlock = MemoryBlock->ArenaPrev; Platform.DeallocateMemory(MemoryBlock); } if(Arena->CurrentBlock) { Assert(Arena->CurrentBlock->Used >= Temp.Used); Arena->CurrentBlock->Used = Temp.Used; } Assert(Arena->TemporaryMemoryCount > 0); --Arena->TemporaryMemoryCount; } static void Release(memory_arena *Arena) { while(Arena->CurrentBlock != 0) { platform_memory_block *MemoryBlock = Arena->CurrentBlock; b32 IsLastBlock = MemoryBlock->ArenaPrev == 0; Arena->CurrentBlock = MemoryBlock->ArenaPrev; Platform.DeallocateMemory(MemoryBlock); if(IsLastBlock) { break; } } } enum arena_push_flag { ArenaFlag_ClearToZero = 0x1, }; struct arena_push_params { u32 Flags; u32 Alignment; }; inline arena_push_params DefaultArenaParams(void) { arena_push_params Params = {}; Params.Flags = ArenaFlag_ClearToZero; Params.Alignment = 4; return(Params); } inline arena_push_params NoClear(void) { arena_push_params Params = DefaultArenaParams(); Params.Flags &= ~ArenaFlag_ClearToZero; return(Params); } inline umm GetAlignmentOffset(memory_arena *Arena, umm Alignment) { umm AlignmentOffset = 0; umm ResultPointer = (umm)Arena->CurrentBlock + Arena->CurrentBlock->Used; umm AlignmentMask = Alignment - 1; if(ResultPointer & AlignmentMask) { AlignmentOffset = Alignment - (ResultPointer & AlignmentMask); } return(AlignmentOffset); } inline umm GetEffectiveSizeFor(memory_arena *Arena, umm InitialSize, arena_push_params Params) { umm Size = InitialSize; umm AlignmentOffset = GetAlignmentOffset(Arena, Params.Alignment); Size += AlignmentOffset; return(Size); } #define PushSize(Arena, InitialSize, ...) PushSize_(Arena, InitialSize, __VA_ARGS__) #define PushStruct(Arena, type, ...) (type *)PushSize_(Arena, sizeof(type), __VA_ARGS__) #define PushArray(Arena, type, Count, ...) (type *)PushSize_(Arena, sizeof(type)*Count, __VA_ARGS__) inline void *PushSize_(memory_arena *Arena, umm InitialSize, arena_push_params Params = DefaultArenaParams()) { void *Result = 0; umm Size = 0; if(Arena->CurrentBlock) { Size = GetEffectiveSizeFor(Arena, InitialSize, Params); } if(!Arena->CurrentBlock || ((Arena->CurrentBlock->Used + Size) > Arena->CurrentBlock->Size)) { Size = InitialSize; if(!Arena->MinimumBlockSize) { Arena->MinimumBlockSize = 1024*1024; } umm BlockSize = Maximum(Size, Arena->MinimumBlockSize); platform_memory_block *NewBlock = Platform.AllocateMemory(BlockSize); NewBlock->ArenaPrev = Arena->CurrentBlock; Arena->CurrentBlock = NewBlock; } Assert((Arena->CurrentBlock->Used + Size) <= Arena->CurrentBlock->Size); umm AlignmentOffset = GetAlignmentOffset(Arena, Params.Alignment); umm OffsetInBlock = Arena->CurrentBlock->Used + AlignmentOffset; Result = Arena->CurrentBlock->Base + OffsetInBlock; Arena->CurrentBlock->Used += Size; Assert(Size >= InitialSize); Assert(Arena->CurrentBlock->Used <= Arena->CurrentBlock->Size); if(Params.Flags & ArenaFlag_ClearToZero) { ZeroSize(Result, InitialSize); } return(Result); } static void *BootstrapPushSize(umm Size, umm OffsetToArena) { memory_arena Arena = {}; void *Result = PushSize(&Arena, Size); *(memory_arena *)((u8 *)Result + OffsetToArena) = Arena; return(Result); } #define BootstrapPushStruct(type, Member) (type *)BootstrapPushSize(sizeof(type), OffsetOf(type, Member)) static string PushString(memory_arena *Arena, string String) { string Result = MakeString(PushArray(Arena, char, String.Count + 1), String.Count); Copy(Result.Data, String.Data, String.Count); Result.Data[Result.Count] = 0; return(Result); } static string PushFormatVariadic(memory_arena *Arena, char *Format, va_list Arguments) { va_list ArgumentsCopy; va_copy(ArgumentsCopy, Arguments); string Result; Result.Count = stbsp_vsnprintf(0, 0, Format, ArgumentsCopy); Result.Data = (u8 *)PushSize(Arena, Result.Count + 1, NoClear()); Result.Data[Result.Count] = 0; stbsp_vsnprintf((char *)Result.Data, (s32)Result.Count + 1, Format, Arguments); return(Result); } inline string PushFormat(memory_arena *Arena, char *Format, ...) { va_list Arguments; va_start(Arguments, Format); string Result = PushFormatVariadic(Arena, Format, Arguments); va_end(Arguments); return(Result); } inline string PushCString(memory_arena *Arena, char *CString) { string Result; Result.Count = StringLength(CString); Result.Data = PushArray(Arena, u8, Result.Count); Copy(Result.Data, CString, Result.Count); return(Result); } #endif //VN_MEMORY_H