#include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE bool is_power_of_two(uintptr_t x) { return (x & (x-1)) == 0; } C_STATIC_FORCE_INLINE uintptr_t align_forward(uintptr_t ptr, size_t align) { uintptr_t p, a, 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, size_t size, 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+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, size_t old_size, size_t new_size, size_t align) { unsigned char *old_mem = (unsigned char *)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); 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_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, size_t old_size, size_t new_size) { return arena_resize_align(a, old_memory, old_size, new_size, C_ALIGN_SIZE); }