
static Arena *
ArenaInit(rawptr buffer, usize size)
{
	Arena *arena = (Arena *)buffer;
	buffer = PtrAdd(buffer, ARENA_HEADER_SIZE);

	arena->buffer = (u8 *)buffer;
	arena->length = size;
	arena->pos = 0;

	return arena;
}

static Arena *
ArenaCreate(usize size)
{
	u8 *mem = (u8 *)pMemAllocZeroed(size);
	return ArenaInit(mem, size);
}

static Arena *
ArenaCreateDebug(usize size, u32 init_line_no)
{
	u8 *mem = (u8 *)pMemAllocZeroed(size);
	return ArenaInitDebug(mem, size, init_line_no);
}

// TODO: investigate overflows when out of memory because something bad is going on
static rawptr 
ArenaAllocAlign(Arena *arena, usize size, usize align)
{
	rawptr ptr = NULL;

	uintptr curr_ptr = (uintptr)arena->buffer + (uintptr)arena->pos;
	uintptr offset = AlignPow2(curr_ptr, align);
	offset -= (uintptr)arena->buffer;

	if (offset+size <= arena->length)
	{
		ptr = &arena->buffer[offset];
		arena->pos = offset+size;
	}
	else
	{
		Printfln("Out of memory: %d", arena->init_line_no);
		Assert(0, "Memory Failure");
	}

	return ptr;
}

static rawptr 
ArenaAlloc(Arena *arena, usize size)
{
	return ArenaAllocAlign(arena, size, DEFAULT_ALIGNMENT);
}

static void 
ArenaFree(Arena *arena)
{
	arena->pos = 0;
}

static void 
ArenaFreeZeroed(Arena *arena)
{
	MemZero(arena->buffer, arena->pos);
	ArenaFree(arena);
}

static void 
DeallocArena(Arena *arena)
{
	pMemFree(arena, arena->length);
}

static Arena * 
ArenaInitDebug(rawptr buffer, usize size, u32 init_line_no)
{
	Arena *arena = ArenaInit(buffer, size);
	arena->init_line_no = init_line_no;
	return arena;
}
