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.
|
// single header library for region-based memory management.
|
||||||
//
|
//
|
||||||
// [License and changelog]
|
// [License and changelog]
|
||||||
@@ -51,6 +51,9 @@
|
|||||||
//
|
//
|
||||||
// [Function documentation]
|
// [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
|
// In this library, arenas are implemented as linked lists of regions. Each
|
||||||
// region will contain the allocated buffers. The following are all of the
|
// region will contain the allocated buffers. The following are all of the
|
||||||
// functions
|
// functions
|
||||||
@@ -83,13 +86,29 @@
|
|||||||
// void *arena_copy(Arena *a, const void *src, size_t size);
|
// void *arena_copy(Arena *a, const void *src, size_t size);
|
||||||
//
|
//
|
||||||
// This function allocates a buffer of <size> bytes into the arena and copies
|
// 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);
|
// char *arena_strdup(Arena *a, const char *s);
|
||||||
//
|
//
|
||||||
// This functions acts like the strdup() function but it instead allocates on
|
// This functions acts like the strdup() function but it instead allocates on
|
||||||
// the specified arena. It duplicates a string in the arena.
|
// 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]
|
// [Notes]
|
||||||
//
|
//
|
||||||
// This library is not Thread-safe.
|
// This library is not Thread-safe.
|
||||||
@@ -117,8 +136,10 @@ int main(void)
|
|||||||
#define ARENA_H_
|
#define ARENA_H_
|
||||||
|
|
||||||
#include <stdalign.h>
|
#include <stdalign.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef ARENA_REGION_CAPACITY
|
#ifndef ARENA_REGION_CAPACITY
|
||||||
@@ -161,6 +182,11 @@ struct Arena_Region {
|
|||||||
alignas(ARENA_ALIGNMENT) uint8_t data[];
|
alignas(ARENA_ALIGNMENT) uint8_t data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Arena_Region *region;
|
||||||
|
size_t count;
|
||||||
|
} Arena_Marker;
|
||||||
|
|
||||||
typedef struct Arena {
|
typedef struct Arena {
|
||||||
Arena_Region *head;
|
Arena_Region *head;
|
||||||
Arena_Region *tail;
|
Arena_Region *tail;
|
||||||
@@ -176,6 +202,14 @@ void arena_reset(Arena *a);
|
|||||||
void *arena_alloc(Arena *a, size_t size);
|
void *arena_alloc(Arena *a, size_t size);
|
||||||
void *arena_copy(Arena *a, const void *src, size_t size);
|
void *arena_copy(Arena *a, const void *src, size_t size);
|
||||||
char *arena_strdup(Arena *a, const char *s);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@@ -236,7 +270,7 @@ void *arena_alloc(Arena *a, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure memory alignment of requested size
|
// Ensure memory alignment of requested size
|
||||||
size = (size + (ARENA_ALIGNMENT - 1)) & ~(ARENA_ALIGNMENT - 1);
|
size = arena__align(size);
|
||||||
|
|
||||||
// Check for overflow
|
// Check for overflow
|
||||||
if (size > SIZE_MAX - sizeof(Arena_Region)) {
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
@@ -335,6 +469,8 @@ char *arena_strdup(Arena *a, const char *s)
|
|||||||
/*
|
/*
|
||||||
* Revision history:
|
* 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.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.2 (2026-01-10) Minor changes; check result of alloc in arena_copy()
|
||||||
* 1.1.1 (2025-11-18) Implement memory alignment; improve docs
|
* 1.1.1 (2025-11-18) Implement memory alignment; improve docs
|
||||||
|
|||||||
Reference in New Issue
Block a user