From dc96fcd771bea09d726a760266739906e95c09a6 Mon Sep 17 00:00:00 2001 From: Vasco Date: Sun, 23 Aug 2026 02:25:33 +0100 Subject: Peak 0.1.1 --- Fuse/allocators.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 Fuse/allocators.c (limited to 'Fuse/allocators.c') diff --git a/Fuse/allocators.c b/Fuse/allocators.c new file mode 100644 index 0000000..f2c6a67 --- /dev/null +++ b/Fuse/allocators.c @@ -0,0 +1,303 @@ +#pragma once + +#include "allocators.h" + +static inline bool is_power_of_two(uintptr_t x) { + return (x & (x-1)) == 0; +} + +static inline uintptr_t align_forward(uintptr_t ptr, size_t align) { + uintptr_t p, a, remainder; + assert(is_power_of_two(align)); + + p = ptr; + a = (uintptr_t)align; + remainder = p & (a-1); + + return (remainder != 0) ? p + a - remainder : p; +} + + +void +al_arena_create(Arena *a, void *backing_buffer, size_t backing_buffer_length) +{ + a->buf = (unsigned char *)backing_buffer; + a->buf_len = backing_buffer_length; + a->curr_offset = 0; + a->prev_offset = 0; +} + +void* +al_arena_alloc_align(Arena *a, size_t s, size_t align) +{ + + // Align 'curr_offset' forward to the specified alignment + uintptr_t curr_ptr = (uintptr_t)a->buf + (uintptr_t)a->curr_offset; + uintptr_t offset = align_forward(curr_ptr, align); + offset -= (uintptr_t)a->buf; // Change to relative offset + + // Check to see if the backing memory has space left + if (offset+s <= a->buf_len) { + void *ptr = &a->buf[offset]; + a->prev_offset = offset; + a->curr_offset = offset+s; + + memset(ptr, 0, s); + return ptr; + } + + return NULL; +} + +void* +al_arena_alloc(Arena *a, size_t s) { + return al_arena_alloc_align(a, s, DEFAULT_ALIGNMENT); +} + +void* +al_arena_resize_align(Arena *a, void *old_memory, size_t old_size, size_t new_size, size_t align) +{ + assert(is_power_of_two(align)); + unsigned char *old_mem = (unsigned char *)old_memory; + + if (old_mem == NULL || old_size == 0) { + return al_arena_alloc_align(a, new_size, align); + } else if (a->buf <= old_mem && old_mem < a->buf+a->buf_len) { + if (a->buf+a->prev_offset == old_mem) { + a->curr_offset = a->prev_offset + new_size; + if (new_size > old_size) { + // Zero the new memory by default + memset(&a->buf[a->curr_offset], 0, new_size-old_size); + } + return old_memory; + } else { + void *new_memory = al_arena_alloc_align(a, new_size, align); + size_t copy_size = old_size < new_size ? old_size : new_size; + memmove(new_memory, old_memory, copy_size); + return new_memory; + } + + } else { + assert(0 && "Memory is out of bounds of the buffer in this arena"); + return NULL; + } +} + +void* +al_arena_resize(Arena *a, void *old_memory, size_t old_size, size_t new_size) +{ + return al_arena_resize_align(a, old_memory, old_size, new_size, DEFAULT_ALIGNMENT); +} + +void +al_arena_free_all(Arena *a) +{ + a->curr_offset = 0; + a->prev_offset = 0; +} + +void +al_arena_destroy(Arena* a) +{ + a->buf_len = 0; + a->curr_offset = 0; + a->prev_offset = 0; +} + +void +al_stack_create(Stack *s, void *backing_buffer, size_t backing_buffer_length) +{ + s->buf = (unsigned char*) backing_buffer; + s->buf_len = backing_buffer_length; + s->offset = 0; +} + +size_t +al_calc_padding_with_header(uintptr_t ptr, uintptr_t alignment, size_t header_size) +{ + uintptr_t p, a, modulo, padding, needed_space; + + assert(is_power_of_two(alignment)); + + p = ptr; + a = alignment; + modulo = p & (a-1); // (p % a) as it assumes alignment is a power of two + + padding = 0; + needed_space = 0; + + if (modulo != 0) { // Same logic as 'align_forward' + padding = a - modulo; + } + + needed_space = (uintptr_t)header_size; + + if (padding < needed_space) { + needed_space -= padding; + + if ((needed_space & (a-1)) != 0) { + padding += a * (1+(needed_space/a)); + } else { + padding += a * (needed_space/a); + } + } + + return (size_t)padding; +} + +void* +al_stack_alloc(Stack *s, size_t len, size_t alignment) +{ + uintptr_t curr_addr, next_addr; + size_t padding; + Stack_Allocation_Header *header; + + assert(is_power_of_two(alignment)); + + if (alignment > 128) { + // As the padding is 8 bits (1 byte), the largest alignment that can + // be used is 128 bytes + alignment = 128; + } + + curr_addr = (uintptr_t)s->buf + (uintptr_t)s->offset; + padding = al_calc_padding_with_header(curr_addr, (uintptr_t)alignment, sizeof(Stack_Allocation_Header)); + if (s->offset + padding + len > s->buf_len) { + // Stack allocator is out of memory + return NULL; + } + s->offset += padding; + + next_addr = curr_addr + (uintptr_t)padding; + header = (Stack_Allocation_Header *)(next_addr - sizeof(Stack_Allocation_Header)); + header->padding = (uint8_t)padding; + + s->offset += len; + + return memset((void *)next_addr, 0, len); +} + +void +al_stack_free(Stack *s, void *ptr) +{ + if (ptr != NULL) { + uintptr_t start, end, curr_addr; + Stack_Allocation_Header *header; + size_t prev_offset; + + start = (uintptr_t)s->buf; + end = start + (uintptr_t)s->buf_len; + curr_addr = (uintptr_t)ptr; + + if (!(start <= curr_addr && curr_addr < end)) { + assert(0 && "Out of bounds memory address passed to stack allocator (free)"); + return; + } + + if (curr_addr >= start+(uintptr_t)s->offset) { + // Allow double frees + return; + } + + header = (Stack_Allocation_Header *)(curr_addr - sizeof(Stack_Allocation_Header)); + prev_offset = (size_t)(curr_addr - (uintptr_t)header->padding - start); + + s->offset = prev_offset; + } +} + +void +al_stack_free_all(Stack* s) +{ + s->offset = 0; +} + +void +al_stack_destroy(Stack* s) +{ + s->buf = 0; + s->buf_len = 0; + s->offset = 0; +} + +void +al_pool_create(Pool *p, void *buf, size_t buf_len, size_t chunk_size, size_t chunk_align) +{ + /* align start */ + uintptr_t start = (uintptr_t) buf; + uintptr_t aligned = align_forward(start, chunk_align); + buf_len -= (aligned - start); + + /* align chunk size_t */ + chunk_size = (size_t) align_forward(chunk_size, chunk_align); + + assert(chunk_size >= sizeof(Pool_Free_Node) && "Chunk size_t is too small"); + assert(buf_len >= chunk_size && "Backing buffer length is smaller than the chunk size"); + + p->buf = (unsigned char *) buf; + p->pool_size = buf_len; + p->chunk_size = chunk_size; + p->head = NULL; + + al_pool_free_all(p); +} + +void* +al_pool_alloc(Pool *p) +{ + Pool_Free_Node *node = p->head; + + assert(node != NULL && "Pool allocator has no free memory"); + + p->head = p->head->next; + + return memset(node, 0 , p->chunk_size); +} + +void +al_pool_free(Pool *p, void *ptr) +{ + Pool_Free_Node *node; + + void *start = p->buf; + void *end = &p->buf[p->pool_size]; + + if (ptr == NULL) { + return; + } + + if (!(start <= ptr && ptr < end)) { + assert(0 && "Memory is out of bounds of the buffer in this pool"); + return; + } + + node = (Pool_Free_Node *)ptr; + node->next = p->head; + p->head = node; +} + +void +al_pool_free_all(Pool *p) +{ + size_t chunk_count = p->pool_size / p->chunk_size; + size_t i; + + for (i = 0; i < chunk_count; i++) { + void *ptr = &p->buf[i * p->chunk_size]; + Pool_Free_Node *node = (Pool_Free_Node *)ptr; + + // Push free node onto thte free list + node->next = p->head; + p->head = node; + } +} + +void +al_pool_destroy(Pool *p) +{ + p->buf = NULL; + p->pool_size = 0; + p->chunk_size = 0; + p->head = NULL; +} + -- cgit v1.3.1