// vim:fileencoding=utf-8:foldmethod=marker #include "mem_arena.h" #include "../utils/mem_utils.h" #include "../../../common/aliases/aliases.h" #include "../../../common/assert/assert.h" #include "../../../common/misc/misc_utils.h" #include "../../os/mem/mem_os.h" #include #include #include #ifndef DEFAULT_ALIGNMENT // Why 2 * sizeof(void *) instead of sizeof(void *) // https://handmade.network/forums/t/6860-alignment_arena_allocator #define DEFAULT_ALIGNMENT (2 * sizeof(void *)) #endif /* ifndef DEFAULT_ALIGNMENT */ #define ARENA_MINIMUM_CAPACITY KB(16) // Allocate minimum of 4 pages struct arena { u8 *buf; u8 *offset; u64 capacity; bool committed; #ifdef WAPP_PLATFORM_WINDOWS wapp_misc_utils_padding_size(sizeof(u8 *) * 2 + sizeof(u64) + sizeof(bool)); #endif // ifdef WAPP_PLATFORM_WINDOWS }; bool wapp_mem_arena_init_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, bool zero_buffer) { if (!arena || *arena || base_capacity == 0) { return false; } *arena = (Arena *)calloc(1, sizeof(Arena)); Arena *arena_ptr = *arena; if (!arena_ptr) { return false; } u64 arena_capacity = wapp_misc_utils_u64_round_up_pow2( base_capacity >= ARENA_MINIMUM_CAPACITY ? base_capacity : ARENA_MINIMUM_CAPACITY ); arena_ptr->buf = (u8 *)wapp_mem_util_alloc(NULL, arena_capacity, WAPP_MEM_ACCESS_READ_WRITE, flags, zero_buffer ? WAPP_MEM_INIT_INITIALISED : WAPP_MEM_INIT_UNINITIALISED); if (!(arena_ptr->buf)) { wapp_mem_arena_destroy(arena); return false; } arena_ptr->capacity = arena_capacity; arena_ptr->offset = arena_ptr->buf; arena_ptr->committed = (flags & WAPP_MEM_ALLOC_COMMIT) == WAPP_MEM_ALLOC_COMMIT; return true; } void *wapp_mem_arena_alloc(Arena *arena, u64 size) { return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT); } void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) { wapp_debug_assert(arena != NULL, "`arena` should not be NULL"); u8 *alloc_start = arena->offset; u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment); if (output + size >= arena->buf + arena->capacity) { return NULL; } arena->offset = output + size; #ifdef WAPP_PLATFORM_WINDOWS if (!(arena->committed)) { wapp_mem_util_alloc(alloc_start, (uptr)(arena->offset) - (uptr)(alloc_start), WAPP_MEM_ACCESS_READ_WRITE, WAPP_MEM_ALLOC_COMMIT, WAPP_MEM_INIT_UNINITIALISED); } #endif // ifdef WAPP_PLATFORM_WINDOWS memset(output, 0, size); return (void *)output; } void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 old_size, u64 new_size) { if ((u8*)ptr < arena->buf || (u8*)ptr > arena->offset || arena->offset + new_size >= arena->buf + arena->capacity) { return NULL; } void *new_ptr = wapp_mem_arena_alloc(arena, new_size); if (!new_ptr) { return NULL; } u64 copy_size = new_size <= old_size ? new_size : old_size; memcpy(new_ptr, ptr, copy_size); return new_ptr; } void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 old_size, u64 new_size, u64 alignment) { if ((u8*)ptr < arena->buf || (u8*)ptr > arena->offset || arena->offset + new_size >= arena->buf + arena->capacity) { return NULL; } void *new_ptr = wapp_mem_arena_alloc_aligned(arena, new_size, alignment); if (!new_ptr) { return NULL; } u64 copy_size = new_size <= old_size ? new_size : old_size; memcpy(new_ptr, ptr, copy_size); return new_ptr; } void wapp_mem_arena_clear(Arena *arena) { wapp_debug_assert(arena != NULL, "`arena` should not be NULL"); memset(arena->buf, 0, arena->offset - arena->buf); arena->offset = arena->buf; } void wapp_mem_arena_destroy(Arena **arena) { wapp_debug_assert(arena != NULL && (*arena) != NULL, "`arena` double pointer is not valid"); Arena *arena_ptr = *arena; if (arena_ptr->buf) { wapp_mem_util_free(arena_ptr->buf, arena_ptr->capacity); } arena_ptr->buf = arena_ptr->offset = NULL; arena_ptr->capacity = 0; free(*arena); *arena = NULL; }