vn/code/vn_memory.h

223 lines
5.7 KiB
C
Raw Normal View History

2023-06-17 17:00:55 +00:00
/* 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