From 7bae84d126c775ae2b5fd0c81da665f73b30863e Mon Sep 17 00:00:00 2001 From: Shanti Chellaram Date: Mon, 12 Jul 2021 22:28:33 -0400 Subject: [PATCH] Add arena headers An arena is a data structure that makes memory management a fair bit simpler. This is an arena type that doesn't do anything fancy; it simply maintains a linked list of blocks from which it doles out memory. It's probably not even that efficient! Future directions for this work include adding more options and implementation details: * custom allocators * object destructors * strcpy instead of just strncpy support * large-block allocation support * block data structure that is more concurrency safe --- src/arena.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/arena.h | 14 ++++++ 2 files changed, 135 insertions(+) create mode 100644 src/arena.c create mode 100644 src/arena.h diff --git a/src/arena.c b/src/arena.c new file mode 100644 index 0000000..2522d66 --- /dev/null +++ b/src/arena.c @@ -0,0 +1,121 @@ +#include +#include + +#include "arena.h" + +struct arena_block { + struct arena_block *next; + size_t used; + char data[]; +}; + +struct arena { + size_t block_size; /* size of blocks to allocate */ + struct arena_block *head, *last; +}; + +struct arena *arena_create(size_t block_size) { + // allocate an initial block + struct arena * result = (struct arena *) malloc(sizeof(struct arena) + sizeof(struct arena_block) + block_size); + if (result == NULL) { + return NULL; + } + result->block_size = block_size; + result->head = (struct arena_block *) (result + 1); + result->head->next = NULL; + result->head->used = 0; + result->last = result->head; + + return result; +} + +void arena_destroy(struct arena *arena) { + if (arena == NULL) { + return; // error? + } + struct arena_block *blk = arena->head->next; + while (blk != NULL) { + struct arena_block *tmp = blk->next; + free(blk); + blk = tmp; + }; + free(arena); +} + +void *arena_malloc(struct arena *arena, size_t size) { + struct arena_block *block; + if (size > arena->block_size) { + return NULL; + } else if (size < arena->block_size - arena->last->used) { + block = arena->last; + } else { + block = (struct arena_block *) malloc(sizeof(struct arena_block) + arena->block_size); + if (block == NULL) { + return NULL; + } + block->next = NULL; + block->used = 0; + arena->last->next = block; + arena->last = block; + } + void *ret = block->data + block->used; + block->used += size; + return ret; +} + +void *arena_calloc(struct arena *arena, size_t count, size_t size) { + return arena_malloc(arena, count * size); +} + +void *arena_copy_alloc(struct arena *arena, const void *src, size_t len) { + void *dst = arena_malloc(arena, len); + if (dst == NULL) { + return NULL; + } + return memcpy(dst, src, len); +} + +void *arena_strcpy_alloc(struct arena *arena, const void *src, size_t len) { + if (arena == NULL) { + return NULL; + } + size_t true_len = strnlen(src, len) + 1; + void *dst = arena_malloc(arena, true_len); + if (dst == NULL) { + return NULL; + } + memcpy(dst, src, true_len - 1); + ((char *)dst)[true_len - 1] = '\0'; + return dst; +} + +size_t arena_used(struct arena *arena) { + size_t total = 0; + if (arena != NULL) { + for (struct arena_block *block = arena->head; block != NULL; block = block->next) { + total += block->used; + } + } + return total; +} + +size_t arena_overhead(struct arena *arena) { + size_t total = 0; + if (arena != NULL) { + total += sizeof(struct arena); + for (struct arena_block *block = arena->head; block != NULL; block = block->next) { + total += sizeof(struct arena_block); + } + } + return total; +} + +size_t arena_total_capacity(struct arena *arena) { + size_t total = 0; + if (arena != NULL) { + for (struct arena_block *block = arena->head; block != NULL; block = block->next) { + total += arena->block_size; + } + } + return total; +} diff --git a/src/arena.h b/src/arena.h new file mode 100644 index 0000000..6456107 --- /dev/null +++ b/src/arena.h @@ -0,0 +1,14 @@ + +struct arena; + +struct arena *arena_create(size_t block_size); +void arena_destroy(struct arena *); + +void *arena_malloc(struct arena *, size_t size); +void *arena_calloc(struct arena *, size_t count, size_t size); +void *arena_copy_alloc(struct arena *, const void *src, size_t len); +void *arena_strcpy_alloc(struct arena *, const void *src, size_t len); + +size_t arena_used(struct arena *); +size_t arena_overhead(struct arena *); +size_t arena_total_capacity(struct arena *);