Files
cig/arena_allocator.c
T
2025-11-24 22:59:18 +01:00

134 lines
4.1 KiB
C

#include "cig.h"
#include <assert.h>
#include <stdbool.h>
void *arena_allocator_alloc_func(
arena_allocator_t *this,
size_t bytes,
const char *file,
int line
) {
buffer_allocator_t ba = (buffer_allocator_t) {
.size=dyn_array_length(this->bytes),
.capacity=dyn_array_capacity(this->bytes),
.data=this->bytes
};
void *allocated = buffer_allocator_alloc(&ba, bytes);
if (allocated != NULL) {
return allocated;
}
allocated = borrow_allocator_alloc_func(&this->borrow_allocator, bytes, file, line);
if (allocated != NULL) {
this->total_allocated += bytes;
return allocated;
}
return NULL;
}
void arena_allocator_reset(arena_allocator_t *this, const char *file, int line) {
borrow_allocator_free_all(&this->borrow_allocator);
if (this->bytes == NULL) {
this->bytes = dyn_array_create_non_crashing_func(
(dyn_array_create_non_crashing_func_args_t) {
.allocator=allocator_stdlib(),
.itemsize=sizeof(uint8_t),
.initial_capacity=this->total_allocated,
.file=file,
.line=line,
}
);
}
if (this->bytes == NULL) {
return;
}
if (dyn_array_capacity(this->bytes) < this->total_allocated) {
size_t needed_bytes = this->total_allocated - dyn_array_length(this->bytes);
uint8_t *new_bytes = dyn_array_grow_non_crashing_func(
this->bytes,
needed_bytes,
file,
line
);
if (new_bytes == NULL) {
dyn_array_shrink_func(
this->bytes,
dyn_array_length(this->bytes),
file,
line
);
return;
} else {
this->bytes = new_bytes;
}
}
if (this->bytes == NULL) {
return;
}
dyn_array_shrink_func(this->bytes, dyn_array_length(this->bytes), file, line);
return;
}
void arena_allocator_destroy(arena_allocator_t *this) {
borrow_allocator_free_all(&this->borrow_allocator);
dyn_array_destroy(this->bytes);
}
static void *arena_allocator_alloc_impl(void *this, size_t bytes, const char *file, int line) {
return arena_allocator_alloc_func(
(arena_allocator_t*) this,
bytes,
file,
line
);
}
static void *arena_allocator_resize_impl(void *this, void *old_ptr, size_t bytes, const char *file, int line) {
(void)this;
(void)file;
(void)line;
assert(false && "TODO: This is fucky. I need to see whether the allocation "
"is in the buffer, if not then it is one of the borrow "
"allocator nodes. I need an actual implementation here.");
arena_allocator_t *t = (arena_allocator_t*) this;
if (
(size_t)t->bytes <= (size_t)old_ptr &&
(size_t)old_ptr < (size_t)t->bytes + dyn_array_length(t->bytes)
) {
assert(false &&
"TODO: make new arena allocator implementation and copy from the "
"start of the old pointer until either the new size or until the "
"end of the bytes buffer. whichever is shorter.");
} else {
borrow_allocator_resize_func(&t->borrow_allocator, old_ptr, bytes, file, line);
// The bytes added to total_allocated is just an educated guess. If
// calling realloc, you are often allocating twice what you got from the
// last malloc/realloc call.
t->total_allocated += bytes/2;
}
return realloc(old_ptr, bytes);
return arena_allocator_alloc_func(
(arena_allocator_t*) this,
bytes,
file,
line
);
}
static void arena_allocator_free_impl(void *this, void *ptr, const char *file, int line) {
(void)this;
(void)file;
(void)line;
free(ptr);
}
static const allocator_vtbl_t arena_allocator_vtbl = {
.alloc = arena_allocator_alloc_impl,
.resize = arena_allocator_resize_impl,
.free = arena_allocator_free_impl,
};
allocator_t arena_allocator_interface(arena_allocator_t *this) {
assert(false && "TODO: implement this");
}