////////////////////////////////
//- sixten: Common Memory Functions

static void Copy(void *Dest, void *Source, umm Count)
{
    if(Count <= S64_Max)
    {
        u8 *Dest8 = (u8 *)Dest;
        u8 *Source8 = (u8 *)Source;
        
        while(Count--)
        {
            *Dest8++ = *Source8++;
        }
    }
}

static void CopyReverse(void *Dest, void *Source, umm Count)
{
    if(Count <= S64_Max)
    {
        u8 *Dest8 = (u8 *)Dest + Count;
        u8 *Source8 = (u8 *)Source + Count;
        
        while(Count--)
        {
            *--Dest8 = *--Source8;
        }
    }
}

static void Fill(void *Dest, u8 Value, umm Count)
{
    if(Count <= S64_Max)
    {
        u8 *Dest8 = (u8 *)Dest;
        
        while(Count--)
        {
            *Dest8++ = Value;
        }
    }
}

////////////////////////////////
//- sixten: Memory Arena Functions

static memory_arena *ArenaAllocate(u64 Size)
{
    u64 RoundedSize = Size+Megabytes(64)-1;
    RoundedSize -= RoundedSize&Megabytes(64);
    void *Memory = Platform.Reserve(RoundedSize);
    u64 InitialCommitSize = MEMORY_ARENA_COMMIT_SIZE;
    Platform.Commit(Memory, InitialCommitSize);
    memory_arena *Arena = (memory_arena *)Memory;
    Arena->Position = sizeof(memory_arena);
    Arena->CommitPosition = InitialCommitSize;
    Arena->Size = Size;
    Arena->Align = 8;
    return(Arena);
}

static void ArenaRelease(memory_arena *Arena)
{
    Platform.Release(Arena);
}

static void *ArenaPushNoClear(memory_arena *Arena, u64 Size)
{
    void *Result = 0;
    if(Arena->Position + Size <= Arena->Size)
    {
        u8 *Base = (u8 *)Arena;
        u64 PostAlignPos = (Arena->Position+Arena->Align-1);
        PostAlignPos -= PostAlignPos%Arena->Align;
        u64 Align = PostAlignPos - Arena->Position;
        Result = Base + Arena->Position + Align;
        Arena->Position += Size + Align;
        if(Arena->CommitPosition < Arena->Position)
        {
            u64 ToCommit = Arena->Position - Arena->CommitPosition;
            ToCommit += MEMORY_ARENA_COMMIT_SIZE - 1;
            ToCommit -= ToCommit%MEMORY_ARENA_COMMIT_SIZE;
            Platform.Commit(Base + Arena->CommitPosition, ToCommit);
            Arena->CommitPosition += ToCommit;
        }
    }
    else
    {
        InvalidCodepath;
    }
    return(Result);
}

static void *ArenaPush(memory_arena *Arena, u64 Size)
{
    void *Result = ArenaPushNoClear(Arena, Size);
    Fill(Result, 0, Size);
    return(Result);
}

static void ArenaPopTo(memory_arena *Arena, u64 Position)
{
    u64 MinPosition = sizeof(*Arena);
    u64 NewPosition = Maximum(MinPosition, Position);
    Arena->Position = NewPosition;
    u64 CommitAlignedPosition = Arena->Position+MEMORY_ARENA_COMMIT_SIZE-1;
    CommitAlignedPosition -= CommitAlignedPosition%MEMORY_ARENA_COMMIT_SIZE;
    if(CommitAlignedPosition + MEMORY_ARENA_DECOMMIT_THRESHOLD <= Arena->CommitPosition)
    {
        u8 *Base = (u8 *)Arena;
        u64 ToDecommit = Arena->CommitPosition-CommitAlignedPosition;
        Platform.Decommit(Base+CommitAlignedPosition, ToDecommit);
        Arena->CommitPosition -= ToDecommit;
    }
}

static void ArenaPop(memory_arena *Arena, u64 Amount)
{
    ArenaPopTo(Arena, Max(Arena->Position-Amount, (s64)sizeof(memory_arena)));
}

static void ArenaClear(memory_arena *Arena)
{
    ArenaPopTo(Arena, sizeof(*Arena));
}

static void ArenaSetAlign(memory_arena *Arena, u64 Align)
{
    Arena->Align = Align;
}

////////////////////////////////
//- sixten: Temporary Memory Functions

static temporary_memory BeginTemporaryMemory(memory_arena *Arena)
{
    temporary_memory Temp;
    Temp.Arena = Arena;
    Temp.Position = Arena->Position;
    return(Temp);
}

static void EndTemporaryMemory(temporary_memory Temp)
{
    ArenaPopTo(Temp.Arena, Temp.Position);
}