// A non-thread-safe expandable table of memory pools
#include "pistachio.h"
#define POOLS_PER_STAND 16
char **pools = NULL;
int n_pools = 0;
int table_len = 0;
void find_next_pool(Arena *a) {
while (a->pool < table_len && pools[a->pool])
a->pool++;
if (a->pool >= table_len) {
pools = realloc(pools, (table_len + POOLS_PER_STAND) * sizeof(char*));
memset(&pools[table_len], 0, POOLS_PER_STAND * sizeof(char*));
table_len += POOLS_PER_STAND;
}
if (a->pool >= n_pools)
n_pools = a->pool + 1;
}
void make_arena(int pool_size, Arena *a) {
if (!pools) {
pools = calloc(POOLS_PER_STAND, sizeof(char*));
table_len = POOLS_PER_STAND;
}
*a = (Arena) {
.pool_size = pool_size,
.pool = 0,
.idx = 0,
.allow_overflow = true,
.initialized = true
};
find_next_pool(a);
pools[a->pool] = malloc(a->pool_size);
}
void *allocate(Arena *a, int size) {
if (a->idx + size > a->pool_size) {
if (!a->allow_overflow)
return NULL;
a->idx = 0;
find_next_pool(a);
// if the allocation request is too large for a pool, make it its own pool
if (size > a->pool_size) {
pools[a->pool] = malloc(size);
void *ptr = (void*)pools[a->pool];
find_next_pool(a);
return ptr;
}
if (!pools[a->pool])
pools[a->pool] = malloc(a->pool_size);
}
void *ptr = (void*)&pools[a->pool][a->idx];
a->idx += size;
return ptr;
}
void destroy_all_arenas() {
if (!pools)
return;
for (int i = 0; i < table_len; i++) {
if (pools[i])
free(pools[i]);
}
free(pools);
pools = NULL;
}
void defer_arena_destruction() {
atexit(destroy_all_arenas);
}