#include /// -------- Basic functions void un_memory_set(u8 *buffer, u8 value, u64 size) { if (size == 0) return; assert(buffer != NULL); while (size-- > 0) { *buffer++ = value; } } void un_memory_copy(u8 *dest, u8 *source, u64 size) { if (size == 0) return; assert(dest != NULL); assert(source != NULL); #ifdef DEBUG if (dest < source) { assert(((ptrdiff_t)source - (ptrdiff_t)dest) >= (ptrdiff_t)size); } else { assert(((ptrdiff_t)dest - (ptrdiff_t)source) >= (ptrdiff_t)size); } #endif // DEBUG while (size-- > 0) { *dest++ = *source++; } } s32 un_memory_compare(u8 *left, u8 *right, u64 size) { while (size-- > 0) { if (*left++ == *right++) continue; return left[-1] > right[-1] ? 1 : -1; } return 0; } void un_memory_move(u8 *dest, u8 *src, u64 size) { Allocator talloc = un_allocator_get_temporary(); void *temp = un_memory_alloc(size, talloc); un_memory_copy(temp, src, size); un_memory_copy(dest, temp, size); } void *un_memory_alloc(u64 size, Allocator alloc) { assert(alloc.proc != NULL); return alloc.proc(NULL, size, UN_ALLOC_MSG_ALLOCATE, alloc.data); } void un_memory_free(void *ptr, Allocator alloc) { assert(alloc.proc != NULL); alloc.proc(ptr, 0, UN_ALLOC_MSG_FREE, alloc.data); } void un_memory_destroy(Allocator *alloc) { assert(alloc != NULL); assert(alloc->proc != NULL); alloc->proc(NULL, 0, UN_ALLOC_MSG_SELF_DELETE, alloc->data); UN_CLEAR(*alloc); } /// -------- Stdlib allocator #if defined(OS_WINDOWS) #include "un_mem_win_x64.c" #elif defined(OS_LINUX) #include "un_mem_linux_x64.c" #else #include "un_mem_std.c" #endif Allocator un_allocator_get_standard(void) { return CLITERAL(Allocator) { .proc = un_std_alloc_proc }; } /// -------- Temp allocator static struct { u64 index; u8 data[UN_TEMP_SIZE]; } _temp; static void temp_reset(void) { _temp.index = 0; } static void *temp_alloc(u64 size) { if ((_temp.index + size) > UN_TEMP_SIZE) { // @todo: Decice what is the best behaviour for wrapping assert(false); temp_reset(); } if ((_temp.index + size) > UN_TEMP_SIZE) { return NULL; } void *ptr = (u8*)_temp.data + _temp.index; _temp.index += size; un_memory_set(ptr, 0x00, size); return ptr; } static ALLOCATOR_PROC_SIGNATURE(un_temp_alloc_proc) { UNUSED(data); UNUSED(p); switch (message) { case UN_ALLOC_MSG_ALLOCATE: return temp_alloc(size); case UN_ALLOC_MSG_FREE: break; case UN_ALLOC_MSG_SELF_DELETE: break; } return NULL; } Allocator un_allocator_get_temporary(void) { return CLITERAL(Allocator) { .proc = un_temp_alloc_proc }; } /// Arena allocator typedef struct Arena { u64 size; u64 occupied; struct Arena *next; u8 data[1]; } Arena; static Arena *arena_create(u64 size) { Allocator alloc; Arena *arena; alloc = un_allocator_get_standard(); arena = CLITERAL(Arena*)un_memory_alloc(size, alloc); if (!arena) { return NULL; } UN_CLEAR(*arena); arena->size = size - sizeof(Arena); return arena; } static void arena_delete(Arena *arena) { if (arena->next != NULL) { arena_delete(arena->next); } Allocator alloc = un_allocator_get_standard(); un_memory_free(arena, alloc); } static void *arena_allocate(u64 size, Arena *arena) { u8* pos; if (size <= (arena->size - arena->occupied)) { pos = arena->data + arena->occupied; arena->occupied += size; return (void*)pos; } if (!arena->next) { arena->next = arena_create((arena->size + sizeof(Arena)) * 2LL); } return arena_allocate(size, arena->next); } static ALLOCATOR_PROC_SIGNATURE(un_arena_alloc_proc) { assert(data != NULL); UNUSED(p); switch (message) { case UN_ALLOC_MSG_ALLOCATE: return arena_allocate(size, (Arena*)data); case UN_ALLOC_MSG_FREE: break; case UN_ALLOC_MSG_SELF_DELETE: arena_delete((Arena*)data); break; } return NULL; } Allocator un_allocator_create_arena(u64 size) { Allocator alloc = { 0 }; alloc.proc = un_arena_alloc_proc; alloc.data = arena_create(size); return alloc; } /// Wrapping allocator typedef struct Allocation_Info { void *p; u64 size; } Allocation_Info; typedef struct Wrapper { // we need to create hashmap and add all allocations in here // List allocations; Allocator target; } Wrapper; static Wrapper *wrapper_create(Allocator target) { Wrapper *wrapper = (Wrapper *)un_memory_alloc(sizeof(Wrapper), un_allocator_get_standard()); un_memory_set((void*)wrapper, 0, sizeof(Wrapper)); wrapper->target = target; return wrapper; } static void wrapper_destroy(Wrapper *wrapper) { assert(wrapper != NULL); un_memory_free(wrapper, un_allocator_get_standard()); } static ALLOCATOR_PROC_SIGNATURE(un_wrapper_alloc_proc) { assert(data != NULL); switch (message) { case UN_ALLOC_MSG_ALLOCATE: return un_memory_alloc(size, ((Wrapper*)data)->target); case UN_ALLOC_MSG_FREE: un_memory_free(p, ((Wrapper*)data)->target); break; case UN_ALLOC_MSG_SELF_DELETE: un_memory_destroy(&((Wrapper*)data)->target); wrapper_destroy((Wrapper*)data); break; } return NULL; } Allocator un_allocator_create_wrapper(Allocator target) { Allocator alloc = { 0 }; alloc.proc = un_wrapper_alloc_proc; alloc.data = wrapper_create(target); return alloc; }