commit 73387bb7a63549b795780413252c37cdaed46f64 Author: seajee Date: Tue Jul 22 17:12:24 2025 +0200 Initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bfa2314 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 seajee + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1cd4d09 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ + +test: test.c arena.h + cc -Wall -Wextra -DDEBUG -o test test.c + +clean: + rm -rf test diff --git a/README.md b/README.md new file mode 100644 index 0000000..0fde199 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# arena.h + +A single header library that implements +[https://en.wikipedia.org/wiki/Region-based_memory_management](region-based memory management) in C. + +## Example + +```c +#define ARENA_IMPLEMENTATION +#include "arena.h" + +int main(void) +{ + Arena a = {0}; + + int *x = arena_alloc(&a, sizeof(*x) * 69); + float *y = arena_alloc(&a, sizeof(*y) * 420); + + arena_free(&a); + return 0; +} +``` diff --git a/arena.h b/arena.h new file mode 100644 index 0000000..d5821e0 --- /dev/null +++ b/arena.h @@ -0,0 +1,113 @@ +#ifndef ARENA_H_ +#define ARENA_H_ + +#include +#include +#include +#include + +#ifndef ARENA_MIN_CAPACITY +#define ARENA_MIN_CAPACITY 4096 +#endif // ARENA_MIN_CAPACITY + +typedef struct Arena_Region Arena_Region; + +struct Arena_Region { + size_t count; + size_t capacity; + Arena_Region *next; + uint8_t data[]; +}; + +typedef struct { + Arena_Region *head; + Arena_Region *tail; +} Arena; + +void *arena_alloc(Arena *a, size_t bytes); +void arena_free(Arena *a); +void arena_reset(Arena *a); + +#endif // ARENA_H_ + +#ifdef ARENA_IMPLEMENTATION + +void *arena_alloc(Arena *a, size_t bytes) +{ + if (a == NULL) { + return NULL; + } + + // Empty a + if (a->head == NULL) { + size_t size = (bytes > ARENA_MIN_CAPACITY ? bytes : ARENA_MIN_CAPACITY); + a->head = malloc(sizeof(*a->head) + size); + if (a->head == NULL) { + return NULL; + } + memset(a->head, 0, sizeof(*a->head)); + a->head->count = bytes; + a->head->capacity = size; + a->tail = a->head; + return a->head->data; + } + + // Not enough capacity + if (bytes > a->tail->capacity - a->tail->count) { + // Find first suitable region + while (a->tail->next != NULL && bytes > a->tail->capacity - a->tail->count) { + a->tail = a->tail->next; + } + + // If found allocate on that region + if (bytes <= a->tail->capacity - a->tail->count) { + a->tail->count += bytes; + return a->tail->data + a->tail->count; + } + + // If not create a new region + a->tail->next = malloc(sizeof(*a->tail) + bytes); + if (a->tail->next == NULL) { + return NULL; + } + a->tail = a->tail->next; + memset(a->tail, 0, sizeof(*a->tail)); + a->tail->count = bytes; + a->tail->capacity = bytes; + return a->tail->data; + } + + a->tail->count += bytes; + return a->tail->data + a->tail->count; +} + +void arena_free(Arena *a) +{ + if (a == NULL) { + return; + } + + Arena_Region *cur = a->head; + while (cur != NULL) { + Arena_Region *next = cur->next; + free(cur); + cur = next; + } + + memset(a, 0, sizeof(*a)); +} + +void arena_reset(Arena *a) +{ + if (a == NULL) { + return; + } + + for (Arena_Region *cur = a->head; cur != NULL; cur = cur->next) { + cur->count = 0; + } + + a->tail = a->head; +} + +#endif // ARENA_IMPLEMENTATION diff --git a/test.c b/test.c new file mode 100644 index 0000000..ef4f04d --- /dev/null +++ b/test.c @@ -0,0 +1,61 @@ +#include +#include + +#ifdef DEBUG +#define malloc(n) (printf("%s:%d:%s: malloc(%ld)\n",\ + __FILE__, __LINE__, __func__, (n)), malloc((n))); +#define free(p) (printf("%s:%d:%s: free(%p)\n",\ + __FILE__, __LINE__, __func__, (p)), free((p))); +#endif // DEBUG + +#define ARENA_MIN_CAPACITY 400 +#define ARENA_IMPLEMENTATION +#include "arena.h" + +void arena_print(Arena arena) +{ + int i = 0; + for (Arena_Region *cur = arena.head; cur != NULL; cur = cur->next) { + printf("Arena_Region #%d:\n", ++i); + printf(" count = %ld\n", cur->count); + printf(" capacity = %ld\n", cur->capacity); + printf(" next = %p\n", cur->next); + printf(" data = %p\n", cur->data); + } +} + +int main(void) +{ + Arena a = {0}; + + printf("------ small alloc ------\n"); + + arena_alloc(&a, 100); + arena_alloc(&a, 100); + arena_alloc(&a, 100); + arena_alloc(&a, 100); + arena_print(a); + + printf("\n=========================================================\n\n"); + printf("------ big alloc ------\n"); + + arena_alloc(&a, 8000); + arena_print(a); + + printf("\n=========================================================\n\n"); + printf("------ reset ------\n"); + + arena_reset(&a); + arena_print(a); + + printf("\n=========================================================\n\n"); + printf("------ allocs after reset ------\n"); + + arena_alloc(&a, 300); + arena_alloc(&a, 400); + arena_alloc(&a, 9000); + arena_print(a); + + arena_free(&a); + return 0; +}