// vim:fileencoding=utf-8:foldmethod=marker

#include "mem_arena_allocator.h"
#include "mem_arena.h"
#include "../../mem/mem_os.h"
#include "../../../common/aliases/aliases.h"
#include "../../../common/assert/assert.h"

wp_intern void initialise_arena_allocator(WpAllocator *allocator);
wp_intern void *mem_arena_alloc(u64 size, void *alloc_obj);
wp_intern void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj);
wp_intern void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
wp_intern void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
                                            void *alloc_obj);

WpAllocator wpMemArenaAllocatorInitWithBuffer(u8 *buffer, u64 buffer_size) {
	WpAllocator allocator = {0};
	b8 initialised = wpMemArenaInitBuffer((WpArena **)(&allocator.obj), buffer, buffer_size);
	if (!initialised) {
		return allocator;
	}

	initialise_arena_allocator(&allocator);

	return allocator;
}

WpAllocator wpMemArenaAllocatorInitCustom(u64 base_capacity, WpMemAllocFlags flags, b8 zero_buffer) {
	WpAllocator allocator = {0};
	b8 initialised = wpMemArenaInitAllocatedCustom((WpArena **)(&allocator.obj), base_capacity, flags, zero_buffer);
	if (!initialised) {
		return allocator;
	}

	initialise_arena_allocator(&allocator);

	return allocator;
}

void wpMemArenaAllocatorTempBegin(const WpAllocator *allocator) {
	wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
	wpMemArenaTempBegin((WpArena *)(allocator->obj));
}

void wpMemArenaAllocatorTempEnd(const WpAllocator *allocator) {
	wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
	wpMemArenaTempEnd((WpArena *)(allocator->obj));
}

void wpMemArenaAllocatorClear(WpAllocator *allocator) {
	wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
	wpMemArenaClear((WpArena *)(allocator->obj));
}

void wpMemArenaAllocatorDestroy(WpAllocator *allocator) {
	wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
	wpMemArenaDestroy((WpArena **)(&(allocator->obj)));
	*allocator = (WpAllocator){0};
}

wp_intern void initialise_arena_allocator(WpAllocator *allocator) {
	allocator->alloc           = mem_arena_alloc;
	allocator->alloc_aligned   = mem_arena_alloc_aligned;
	allocator->realloc         = mem_arena_realloc;
	allocator->realloc_aligned = mem_arena_realloc_aligned;
}

wp_intern void *mem_arena_alloc(u64 size, void *alloc_obj) {
	WpArena *arena = (WpArena *)alloc_obj;
	return wpMemArenaAlloc(arena, size);
}

wp_intern void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj) {
	WpArena *arena = (WpArena *)alloc_obj;
	return wpMemArenaAllocAligned(arena, size, alignment);
}

wp_intern void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj) {
	WpArena *arena = (WpArena *)alloc_obj;
	return wpMemArenaRealloc(arena, ptr, old_size, new_size);
}

wp_intern void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
                                            void *alloc_obj) {
	WpArena *arena = (WpArena *)alloc_obj;
	return wpMemArenaReallocAligned(arena, ptr, old_size, new_size, alignment);
}
