arena.c (2268B)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "arena.h"
#include "check.h"
// not thread safe
struct Arena {
uint8_t* buf;
size_t cap;
size_t pos;
};
Arena* arena_init(size_t bytes)
{
Arena* a;
if (!bytes || bytes == 0) {
bytes = 1024;
}
a = malloc(sizeof(Arena));
if (!a) {
fprintf(stderr, "arena_init failed to alloc\n");
return NULL;
}
a->buf = malloc(bytes);
if (!a->buf) {
free(a);
fprintf(stderr, "arena_init: failed to allocate buffer\n");
return NULL;
}
a->cap = bytes;
a->pos = 0;
return a;
}
static size_t align_to(size_t offset, size_t align)
{
// align to a power of 2
return (offset + align - 1) & ~(align - 1);
}
void* arena_alloc(Arena* a, size_t size, size_t align)
{
size_t pos, new_cap;
void* ptr;
uint8_t* p;
if (!a) {
fprintf(stderr, "arena: no arena given to alloc to\n");
return NULL;
}
if (!size) {
fprintf(stderr, "arena: no arena size given to alloc to\n");
return NULL;
}
if (!align) {
fprintf(stderr, "arena: no arena alignment given to alloc to\n");
return NULL;
}
if ((align & (align - 1)) != 0) { /* not power of two */
fprintf(stderr, "arena: alignment must be a power of two\n");
return NULL;
}
pos = align_to(a->pos, align);
if (SIZE_MAX - pos < size) {
fprintf(stderr, "arena_alloc: too large for available memory\n");
free(a->buf);
return NULL;
}
if (pos + size > a->cap) {
new_cap = a->cap == 0 ? 1024 : a->cap * 2;
check(new_cap <= a->cap || new_cap > SIZE_MAX / sizeof(uint8_t), "arena: could not reallocate arena, underflow or overflow\n");
p = realloc(a->buf, new_cap);
if (!p) {
fprintf(stderr, "arena: could not reallocate double its size!\n");
free(a->buf);
return NULL;
}
a->buf = p;
a->cap = new_cap;
}
ptr = a->buf + pos;
a->pos = pos + size;
return (void*)ptr;
}
void arena_reset(Arena* a)
{
if (!a) return;
a->pos = 0;
}
void arena_destroy(Arena* a)
{
if (!a) return;
free(a->buf);
free(a);
}