Add arena allocator

This commit is contained in:
2022-11-14 22:33:23 -05:00
parent 6af4e67309
commit a87cab2452
4 changed files with 190 additions and 0 deletions

101
src/arena.c Normal file
View File

@@ -0,0 +1,101 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
struct ucl_arena {
size_t object_size;
size_t capacity;
void *objects;
int *used_map;
};
#define DIV_ROUND_UP(numerator, denominator) \
(((numerator) + (denominator) - 1) / (denominator))
#define INT_BITS (CHAR_BIT * sizeof(int))
struct ucl_arena *ucl_arena_create(size_t object_size, size_t capacity) {
struct ucl_arena *arena = malloc(sizeof(*arena));
size_t used_map_size = DIV_ROUND_UP(capacity, INT_BITS) * sizeof(int);
arena->object_size = object_size;
arena->capacity = capacity;
arena->objects = malloc(capacity * object_size);
arena->used_map = malloc(used_map_size);
memset(arena->used_map, 0, used_map_size);
assert(arena->objects != NULL);
assert(arena->used_map != NULL);
return arena;
}
void ucl_arena_map(struct ucl_arena *arena, void (*map_function)(struct ucl_arena * arena, void *object)) {
size_t used_map_ints = DIV_ROUND_UP(arena->capacity, INT_BITS);
for (int i = 0; i < used_map_ints; i++ ) {
// TODO: Allow for 'put' in map
int map = arena->used_map[i];
while (map) {
int bit_index = __builtin_ffs(map) - 1;
int index = bit_index + INT_BITS * i;
void *obj = arena->objects + (index * arena->object_size);
map_function(arena, obj);
map &= ~(1 << bit_index);
}
}
}
int total_arena_gets = 0;
void *ucl_arena_get(struct ucl_arena *arena) {
int used_map_ints = DIV_ROUND_UP(arena->capacity, INT_BITS);
for (int i = 0; i < used_map_ints; i++ ) {
// TODO: Maybe keep a cache of available used_map_ints
int map = arena->used_map[i];
if (!(~map)) {
continue;
}
int bit_index = __builtin_ffs(~map) - 1;
int index = bit_index + INT_BITS * i;
if (index >= arena->capacity) {
// This might happen in the last used_map_int when (capacity % int_bits != 0)
return NULL;
}
arena->used_map[i] |= 1 << bit_index;
total_arena_gets++;
return arena->objects + (index * arena->object_size);
}
return NULL;
}
int total_arena_puts = 0;
void ucl_arena_put(struct ucl_arena *arena, void *object) {
if (object == NULL) {
return;
}
ptrdiff_t offset = object - arena->objects;
unsigned int index = offset / arena->object_size;
unsigned int int_index = index / INT_BITS;
unsigned int bit_index = index % INT_BITS;
assert(offset % arena->object_size == 0);
assert(index >= 0);
assert(index < arena->capacity);
assert(arena->used_map[int_index] & (1 << bit_index));
//if (arena->used_map[int_index] & (1 << bit_index)) {
total_arena_puts++;
//}
arena->used_map[int_index] &= ~(1 << bit_index);
}

11
src/arena.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef _UCLISP_ARENA_H_
#define _UCLISP_ARENA_H_
#include <stddef.h>
struct ucl_arena *ucl_arena_create(size_t object_size, size_t capacity);
void *ucl_arena_get(struct ucl_arena *arena);
void ucl_arena_put(struct ucl_arena *arena, void *object);
void ucl_arena_map(struct ucl_arena *arena, void (*map_function)(struct ucl_arena *arena, void *object));
#endif