/* date = June 19th 2023 10:07 pm */

#ifndef CORE_MEMORY_H
#define CORE_MEMORY_H

/*
The arenas can be used in two modes:
1. Fixed Size:
This is primarily intended for when you need a contigous buffer of memory, it reserves a large chunk
of virtual address space (if applicable) and partitions it to the user.

2. Chaining:
This is the workaround for WASM not supporting memory mapping. It allocates in chunks based on the initial
size requested in the ArenaAlloc call. Internally it just consists of a cyclic doubly linked list.

Potential alternatives:
If you pass in a size of 0 in ArenaAlloc, you get a chaining arena with set chunk size that can extend if
a PushSize call requests more than the prespecified standard. (ex. 4KB chunks, but if you load a file then
that becomes its own chunk)

*/

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

static void Copy(void *Dest, void *Source, umm Count);
static void CopyReverse(void *Dest, void *Source, umm Count);
static void Fill(void *Dest, u8 Value, umm Count);
#define Move(Dest, Source, Count) memmove(Dest, Source, Count)
#define ZeroStruct(Struct) Fill(Struct, 0, sizeof(*(Struct)))

////////////////////////////////
//- sixten: Memory Arena Types

struct arena
{
	u64 Position;
	u64 CommitPosition;
	u64 Size;
	u64 Align;
	b32 Chaining;
	b32 NotFirst;
	arena *Next;
	arena *Prev;
};

struct temp
{
	arena *Arena;
	u64 Position;
};

////////////////////////////////
//~ sixten: Memory Arena Settings
#define MEMORY_ARENA_COMMIT_SIZE        Kilobytes(4)
#define MEMORY_ARENA_DECOMMIT_THRESHOLD Megabytes(64)

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

static arena *ArenaAlloc(u64 Size, b32 Chaining = false);
static void ArenaRelease(arena *Arena);
static void *ArenaPushNoClear(arena *Arena, u64 Size);
static void *ArenaPush(arena *Arena, u64 Size);
static void ArenaPopTo(arena *Arena, u64 Position);
static void ArenaPop(arena *Arena, u64 Amount);
static void ArenaClear(arena *Arena);
static void ArenaSetAlign(arena *Arena, u64 Align);
#define PushArray(Arena, type, Count)        (type *)ArenaPush((Arena), sizeof(type)*(Count))
#define PushArrayNoClear(Arena, type, Count) (type *)ArenaPushNoClear((Arena), sizeof(type)*(Count))
#define PushStruct(Arena, type)              (type *)ArenaPush((Arena), sizeof(type))
#define PushStructNoClear(Arena, type)       (type *)ArenaPushNoClear((Arena), sizeof(type))

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

static temp BeginTemp(arena *Arena);
static void EndTemp(temp Temp);

#endif //CORE_MEMORY_H
