// ::Allocator::Arena::Start::

static Arena *CreateArena(rawptr buffer, isize length)
{
	Arena *arena = (Arena *)buffer;
	buffer = PtrAdd(buffer, ARENA_HEADER_SIZE);

	arena->buffer = buffer;
	arena->length = length;
	arena->pos = 0;

	return arena;
}

static rawptr ArenaAllocAlign(Arena *arena, isize size, isize 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, isize 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)
{
	MemFree(arena, arena->length);
}

static Arena * CreateArenaDebug(rawptr buffer, isize length, u32 init_line_no)
{
	Arena *arena = CreateArena(buffer, length);
	arena->init_line_no = init_line_no;
	return arena;
}

// ::Allocator::Arena::End::

// ::Allocator::FreeList::Start::

static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size)
{
	isize size = init_size + sizeof(FreeListAlloc) + sizeof(FreeListBuffer) + sizeof(rawptr) + sizeof(FLNode);
	u8 *mem = (u8 *)MemAllocZeroed(size);
	FreeListAlloc *fl_alloc = (FreeListAlloc *)mem;

	u8 *pre_mem = mem;
	mem = (u8 *)PtrAdd(mem, sizeof(FreeListAlloc));
	isize rem_size = (size) - (pre_mem - mem);

	fl_alloc->buf_len = 1;
	fl_alloc->grow_size = grow_size;
	fl_alloc->buffers = (FreeListBuffer *)mem;

	pre_mem = mem;
	mem = (u8 *)PtrAdd(mem, sizeof(FreeListBuffer));
	rem_size -= pre_mem - mem;

	fl_alloc->nil = (FLNode *)mem;

	pre_mem = mem;
	mem = (u8 *)PtrAdd(mem, sizeof(FLNode));
	rem_size -= pre_mem - mem;

	fl_alloc->buffers[0].buf = mem;
	fl_alloc->buffers[0].size = (u32)size;
	fl_alloc->buffers[0].free_size = (u32)rem_size;

	return fl_alloc;
}

static void DeallocFreeListAlloc(FreeListAlloc *alloc)
{
	for (u8 i = alloc->buf_len-1; i >= 0; i--)
	{
		if (i == 0)
			MemFree(alloc, alloc->buffers[i].size);
		else
			MemFree(alloc->buffers[i].buf, alloc->buffers[i].size);
	}
}

// ::Allocator::FreeList::End::
