#ifndef ARENA_H #define ARENA_H #include #include #include typedef struct ArenaBlock { struct ArenaBlock* next; size_t used; size_t capacity; max_align_t data[]; } ArenaBlock; typedef struct { ArenaBlock* first; ArenaBlock* current; size_t block_size; } Arena; static inline Arena arena_create(void) { return (Arena){.block_size = 4096}; } static inline void* arena_alloc_aligned(Arena* arena, size_t size, size_t alignment) { if (alignment == 0 || (alignment & (alignment - 1)) != 0) { return NULL; } if (size == 0) { size = 1; } ArenaBlock* block = arena->current; size_t offset = 0; while (block != NULL) { uintptr_t address = (uintptr_t)block->data + block->used; size_t padding = (size_t)(-(uintptr_t)address & (alignment - 1)); if (padding <= SIZE_MAX - block->used) { offset = block->used + padding; if (offset <= block->capacity && size <= block->capacity - offset) { break; } } block = block->next; } if (block == NULL) { size_t capacity = arena->block_size == 0 ? 4096 : arena->block_size; if (size > SIZE_MAX - alignment) { return NULL; } if (capacity < size + alignment) { capacity = size + alignment; } if (capacity > SIZE_MAX - sizeof(ArenaBlock)) { return NULL; } ArenaBlock* new_block = malloc(sizeof(*new_block) + capacity); if (new_block == NULL) { return NULL; } *new_block = (ArenaBlock){.capacity = capacity}; ArenaBlock* previous = arena->current; if (previous == NULL) { arena->first = new_block; } else { while (previous->next != NULL) { previous = previous->next; } previous->next = new_block; } arena->current = new_block; block = new_block; uintptr_t address = (uintptr_t)block->data; offset = (size_t)(-(uintptr_t)address & (alignment - 1)); } else { arena->current = block; } void* result = (unsigned char* )block->data + offset; block->used = offset + size; return result; } static inline void* arena_alloc(Arena* arena, size_t size) { return arena_alloc_aligned(arena, size, _Alignof(max_align_t)); } static inline void arena_reset(Arena* arena) { for (ArenaBlock* block = arena->first; block != NULL; block = block->next) { block->used = 0; } arena->current = arena->first; } static inline void arena_destroy(Arena* arena) { ArenaBlock* block = arena->first; while (block != NULL) { ArenaBlock* next = block->next; free(block); block = next; } *arena = (Arena){0}; } #endif