diff options
Diffstat (limited to 'src/un_memory.c')
-rw-r--r-- | src/un_memory.c | 282 |
1 files changed, 94 insertions, 188 deletions
diff --git a/src/un_memory.c b/src/un_memory.c index 178fcbc..dd1bc87 100644 --- a/src/un_memory.c +++ b/src/un_memory.c @@ -2,267 +2,173 @@ /// -------- 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); + return alloc.proc(NULL, size, UN_DEFAULT_ALIGN, UN_ALLOC_MSG_ALLOCATE, alloc.data); } -void un_memory_free(void *ptr, Allocator alloc) { +void *un_memory_alloc_align(u64 size, u32 align, Allocator alloc) { assert(alloc.proc != NULL); - alloc.proc(ptr, 0, UN_ALLOC_MSG_FREE, alloc.data); + return alloc.proc(NULL, size, align, UN_ALLOC_MSG_ALLOCATE, 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); +void un_memory_free(void *ptr, Allocator alloc) { + assert(alloc.proc != NULL); + alloc.proc(ptr, 0, 0, UN_ALLOC_MSG_FREE, alloc.data); } -/// -------- Stdlib allocator +/// -------- Std allocator #if defined(OS_WINDOWS) -#include "un_mem_win_x64.c" - +# include "un_mem_win_x64.c" #elif defined(OS_LINUX) -#include "un_mem_linux_x64.c" - +# include "un_mem_linux_x64.c" #else -#include "un_mem_std.c" - +# include "un_mem_std.c" #endif -Allocator un_allocator_get_standard(void) { +Allocator un_alloc_std_get(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; -} +/// Arena allocator -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(); - } +typedef struct Arena { + u8 *buffer; + u64 size, curr_offset, prev_offset; +} Arena; - if ((_temp.index + size) > UN_TEMP_SIZE) { - return NULL; - } +static Arena __temp_arena; - void *ptr = (u8*)_temp.data + _temp.index; - _temp.index += size; - un_memory_set(ptr, 0x00, size); +static Arena arena_create(u64 size) { + Allocator alloc; + Arena arena; - return ptr; -} + UN_CLEAR(arena); -static ALLOCATOR_PROC_SIGNATURE(un_temp_alloc_proc) { - UNUSED(data); - UNUSED(p); + alloc = un_alloc_std_get(); + arena.buffer = un_memory_alloc(size, alloc); - switch (message) { - case UN_ALLOC_MSG_ALLOCATE: - return temp_alloc(size); - case UN_ALLOC_MSG_FREE: - break; - case UN_ALLOC_MSG_SELF_DELETE: break; + if (arena.buffer == NULL) { + return arena; } - return NULL; + arena.size = size; + return arena; } -Allocator un_allocator_get_temporary(void) { - return CLITERAL(Allocator) { .proc = un_temp_alloc_proc }; -} +// special thanks to ginger bill: https://www.gingerbill.org/article/2019/02/08/memory-allocation-strategies-002/ +static uintptr_t align_forward(uintptr_t ptr, u32 align) { + uintptr_t p, a, modulo; -/// Arena allocator + assert(UN_POW_OF2(align)); -typedef struct Arena { - u64 size; - u64 occupied; - struct Arena *next; - u8 data[1]; -} Arena; + p = ptr; + a = (uintptr_t)align; + modulo = p & (a-1); -static Arena *arena_create(u64 size) { - Allocator alloc; - Arena *arena; + if (modulo != 0) { + p += a - modulo; + } - alloc = un_allocator_get_standard(); - arena = CLITERAL(Arena*)un_memory_alloc(size, alloc); + return p; +} - if (!arena) { - return NULL; - } +static void* arena_allocate_align(Arena *arena, u32 align, u64 size) { + uintptr_t curr_ptr, offset; + u8 *ptr; - UN_CLEAR(*arena); - arena->size = size - sizeof(Arena); - return arena; -} + assert(arena != NULL); -static void arena_delete(Arena *arena) { - if (arena->next != NULL) { - arena_delete(arena->next); + curr_ptr = (uintptr_t)arena->buffer + arena->curr_offset; + offset = align_forward(curr_ptr, align); + offset -= (uintptr_t)arena->buffer; + + if ((offset + size) <= arena->size) { + ptr = (u8*)(arena->buffer + offset); + arena->prev_offset = offset; + arena->curr_offset = offset + size; + memset(ptr, 0, size); + } else { + ptr = NULL; } - Allocator alloc = un_allocator_get_standard(); - un_memory_free(arena, alloc); + return ptr; } -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; - } +static void arena_free_memory(Arena *arena) { + if (arena == &__temp_arena) return; - if (!arena->next) { - arena->next = arena_create((arena->size + sizeof(Arena)) * 2LL); - } + assert(arena != NULL); - return arena_allocate(size, arena->next); + if (arena->buffer != NULL) { + un_memory_free(arena->buffer, un_alloc_std_get()); + } } 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); + return arena_allocate_align((Arena*)data, align, size); case UN_ALLOC_MSG_FREE: break; case UN_ALLOC_MSG_SELF_DELETE: - arena_delete((Arena*)data); + arena_free_memory((Arena*)data); break; } return NULL; } -Allocator un_allocator_create_arena(u64 size) { - Allocator alloc = { 0 }; +Allocator un_alloc_arena_create(u64 byte_size) { + Allocator alloc, std; + Arena arena; + UN_CLEAR(alloc); + std = un_alloc_std_get(); alloc.proc = un_arena_alloc_proc; - alloc.data = arena_create(size); - - return alloc; -} + arena = arena_create(byte_size); -/// Wrapping allocator + if(arena.buffer == NULL) { + UN_CLEAR(alloc); + } + alloc.data = un_memory_alloc(sizeof(arena), std); // yeah, it allocs 4kb for 32 bytes... -typedef struct Allocation_Info { - void *p; - u64 size; -} Allocation_Info; + if(alloc.data == NULL) { + arena_free_memory(&arena); + UN_CLEAR(alloc); + return alloc; + } -typedef struct Wrapper { - // we need to create hashmap and add all allocations in here - // List allocations; - Allocator target; -} Wrapper; + *((Arena *)alloc.data) = arena; + return alloc; +} -static Wrapper *wrapper_create(Allocator target) { - Wrapper *wrapper = (Wrapper *)un_memory_alloc(sizeof(Wrapper), un_allocator_get_standard()); +void un_alloc_arena_destroy(Allocator *alloc) { + arena_free_memory((Arena*)alloc->data); - un_memory_set((void*)wrapper, 0, sizeof(Wrapper)); - wrapper->target = target; + un_memory_free(alloc->data, un_alloc_std_get()); - return wrapper; + UN_CLEAR(*alloc); } -static void wrapper_destroy(Wrapper *wrapper) { - assert(wrapper != NULL); - un_memory_free(wrapper, un_allocator_get_standard()); +void un_alloc_temp_init(u64 byte_size) { + __temp_arena = arena_create(byte_size); } -static ALLOCATOR_PROC_SIGNATURE(un_wrapper_alloc_proc) { - assert(data != NULL); +void un_alloc_temp_reset(void) { + __temp_arena.curr_offset = 0; + __temp_arena.prev_offset = 0; +} - 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; - } +Allocator un_alloc_temp_get(void) { + assert(__temp_arena.buffer != NULL); - return NULL; + return CLITERAL(Allocator) { un_arena_alloc_proc, &__temp_arena }; } -Allocator un_allocator_create_wrapper(Allocator target) { - Allocator alloc = { 0 }; - - alloc.proc = un_wrapper_alloc_proc; - alloc.data = wrapper_create(target); - return alloc; -} |