#include #include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE c_bool_t is_power_of_two(c_size_t x) { return (x & (x-1)) == 0; } C_STATIC_FORCE_INLINE c_uintptr_t align_forward(c_uintptr_t ptr, c_size_t align) { c_uintptr_t p; c_uintptr_t a; c_uintptr_t modulo; assert(is_power_of_two(align)); p = ptr; a = (uintptr_t)align; // Same as (p % a) but faster as 'a' is a power of two modulo = p & (a-1); if (modulo != 0) { // If 'p' address is not aligned, push the address to the // next value which is aligned p += a - modulo; } return p; } C_STATIC_FORCE_INLINE void *arena_alloc_align(c_Arena_t *a, c_size_t size, c_size_t align) { // Align 'curr_offset' forward to the specified alignment c_uintptr_t curr_ptr = (c_uintptr_t)a->buf + (c_uintptr_t)a->curr_offset; c_uintptr_t offset = align_forward(curr_ptr, align); offset -= (c_uintptr_t)a->buf; // Change to relative offset // Check to see if the backing memory has space left if (offset+size <= a->buf_len) { void *ptr = &a->buf[offset]; a->prev_offset = offset; a->curr_offset = offset+size; // Zero new memory by default memset(ptr, 0, size); return ptr; } // Return NULL if the arena is out of memory (or handle differently) return NULL; } C_STATIC_FORCE_INLINE void *arena_resize_align(c_Arena_t *a, void *old_memory, c_size_t old_size, c_size_t new_size, c_size_t align) { uint8_t* old_mem = (uint8_t*)old_memory; assert(is_power_of_two(align)); if (old_mem == NULL || old_size == 0) { return 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 = arena_alloc_align(a, new_size, align); c_size_t copy_size = old_size < new_size ? old_size : new_size; // Copy across old memory to the new memory 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 c_Arena_Init(c_Arena_t* a, void* buf, c_size_t buf_len) { a->buf = buf; a->buf_len = buf_len; a->prev_offset = 0; a->curr_offset = 0; } void *c_Arena_Alloc(c_Arena_t *a, c_size_t size) { return arena_alloc_align(a, size, C_ALIGN_SIZE); } void *c_Arena_Resize(c_Arena_t *a, void *old_memory, c_size_t old_size, c_size_t new_size) { return arena_resize_align(a, old_memory, old_size, new_size, C_ALIGN_SIZE); }