223 lines
5.7 KiB
C
223 lines
5.7 KiB
C
/* 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
|