v1.2.0 Release
This commit is contained in:
142
arena.h
142
arena.h
@@ -1,4 +1,4 @@
|
||||
// arena.h - v1.1.3 - MIT License
|
||||
// arena.h - v1.2.0 - MIT License
|
||||
// single header library for region-based memory management.
|
||||
//
|
||||
// [License and changelog]
|
||||
@@ -51,6 +51,9 @@
|
||||
//
|
||||
// [Function documentation]
|
||||
//
|
||||
// Note: every function that starts with "arena__" is considered a private
|
||||
// function of this library.
|
||||
//
|
||||
// In this library, arenas are implemented as linked lists of regions. Each
|
||||
// region will contain the allocated buffers. The following are all of the
|
||||
// functions
|
||||
@@ -83,13 +86,29 @@
|
||||
// void *arena_copy(Arena *a, const void *src, size_t size);
|
||||
//
|
||||
// This function allocates a buffer of <size> bytes into the arena and copies
|
||||
// the contents of <src>.
|
||||
// the contents of <src>. Returns the pointer of the new copy.
|
||||
//
|
||||
// char *arena_strdup(Arena *a, const char *s);
|
||||
//
|
||||
// This functions acts like the strdup() function but it instead allocates on
|
||||
// the specified arena. It duplicates a string in the arena.
|
||||
//
|
||||
// char *arena_sprintf(Arena *a, const char *fmt, ...)
|
||||
//
|
||||
// This function internally uses vsnprintf() to store the resulting formatted
|
||||
// string in the specified arena. Returns NULL on error.
|
||||
//
|
||||
// Arena_Marker arena_snapshot(const Arena *a)
|
||||
//
|
||||
// This function creates a snapshot of the current state of the arena and
|
||||
// returns it. This is useful when you only need to allocate memory on the arena
|
||||
// temporarily. To restore the returned state, see arena_rewind().
|
||||
//
|
||||
// void arena_rewind(Arena *a, Arena_Marker marker)
|
||||
//
|
||||
// This function restores the arena to the specified state, invalidating all
|
||||
// previously allocated buffers since the creation of the snapshot.
|
||||
//
|
||||
// [Notes]
|
||||
//
|
||||
// This library is not Thread-safe.
|
||||
@@ -117,8 +136,10 @@ int main(void)
|
||||
#define ARENA_H_
|
||||
|
||||
#include <stdalign.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef ARENA_REGION_CAPACITY
|
||||
@@ -161,6 +182,11 @@ struct Arena_Region {
|
||||
alignas(ARENA_ALIGNMENT) uint8_t data[];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Arena_Region *region;
|
||||
size_t count;
|
||||
} Arena_Marker;
|
||||
|
||||
typedef struct Arena {
|
||||
Arena_Region *head;
|
||||
Arena_Region *tail;
|
||||
@@ -176,6 +202,14 @@ void arena_reset(Arena *a);
|
||||
void *arena_alloc(Arena *a, size_t size);
|
||||
void *arena_copy(Arena *a, const void *src, size_t size);
|
||||
char *arena_strdup(Arena *a, const char *s);
|
||||
char *arena_sprintf(Arena *a, const char *fmt, ...);
|
||||
|
||||
// Snapshot management
|
||||
Arena_Marker arena_snapshot(const Arena *a);
|
||||
void arena_rewind(Arena *a, Arena_Marker marker);
|
||||
|
||||
// Private functions
|
||||
size_t arena__align(size_t n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -236,7 +270,7 @@ void *arena_alloc(Arena *a, size_t size)
|
||||
}
|
||||
|
||||
// Ensure memory alignment of requested size
|
||||
size = (size + (ARENA_ALIGNMENT - 1)) & ~(ARENA_ALIGNMENT - 1);
|
||||
size = arena__align(size);
|
||||
|
||||
// Check for overflow
|
||||
if (size > SIZE_MAX - sizeof(Arena_Region)) {
|
||||
@@ -326,6 +360,106 @@ char *arena_strdup(Arena *a, const char *s)
|
||||
return (char*)arena_copy(a, s, strlen(s) + 1);
|
||||
}
|
||||
|
||||
char *arena_sprintf(Arena *a, const char *fmt, ...)
|
||||
{
|
||||
if (a == NULL || fmt == NULL) {
|
||||
ARENA_ASSERT(false && "Invalid parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
Arena_Region *r = a->tail;
|
||||
char *result = NULL;
|
||||
size_t available = 0;
|
||||
|
||||
if (r != NULL) {
|
||||
available = r->capacity - r->count;
|
||||
if (available > 0) {
|
||||
result = (char*)r->data + r->count;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if result fits inside tail's region available space
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
int n = vsnprintf(result, available, fmt, args_copy);
|
||||
va_end(args_copy);
|
||||
|
||||
if (n < 0) {
|
||||
va_end(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t needed = (size_t)n + 1;
|
||||
|
||||
// If it fits commit and return
|
||||
if (needed <= available) {
|
||||
r->count += arena__align(needed);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Fallback: if it didn't fit, allocate and printf
|
||||
result = (char*)arena_alloc(a, needed);
|
||||
if (result == NULL) {
|
||||
va_end(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = vsnprintf(result, needed, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (n < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Arena_Marker arena_snapshot(const Arena *a)
|
||||
{
|
||||
Arena_Marker marker = {0};
|
||||
|
||||
if (a == NULL) {
|
||||
ARENA_ASSERT(false && "Invalid parameters");
|
||||
return marker;
|
||||
}
|
||||
|
||||
marker.region = a->tail;
|
||||
marker.count = (a->tail != NULL ? a->tail->count : 0);
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
void arena_rewind(Arena *a, Arena_Marker marker)
|
||||
{
|
||||
if (a == NULL) {
|
||||
ARENA_ASSERT(false && "Invalid parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
// If arena was empty reset it
|
||||
if (marker.region == NULL) {
|
||||
arena_reset(a);
|
||||
return;
|
||||
}
|
||||
|
||||
a->tail = marker.region;
|
||||
a->tail->count = marker.count;
|
||||
|
||||
// Clear new regions in case they were appended
|
||||
for (Arena_Region *cur = a->tail->next; cur != NULL; cur = cur->next) {
|
||||
cur->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t arena__align(size_t n)
|
||||
{
|
||||
return (n + (ARENA_ALIGNMENT - 1)) & ~(ARENA_ALIGNMENT - 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
@@ -335,6 +469,8 @@ char *arena_strdup(Arena *a, const char *s)
|
||||
/*
|
||||
* Revision history:
|
||||
*
|
||||
* 1.2.0 (2026-04-08) New helper functions: arena_sprintf(),
|
||||
* arena_snapshot() and arena_rewind()
|
||||
* 1.1.3 (2026-01-14) Align Arena_Region data flexible array member
|
||||
* 1.1.2 (2026-01-10) Minor changes; check result of alloc in arena_copy()
|
||||
* 1.1.1 (2025-11-18) Implement memory alignment; improve docs
|
||||
|
||||
Reference in New Issue
Block a user