A no-dependency shunting arena allocator for C with global and local APIs.
I reach for arenas whenever I want deterministic lifetimes without the bookkeeping of individual frees. While building ReMem I pulled the arena into its own library so I could reuse it across interpreters, CLI tools, and coursework projects. The goal: small enough to drop straight into a source tree without adding build complexity, yet complete enough to cover the allocation patterns that come up in real projects.
The library ships with both global and local APIs. The global functions (arenaInit, arenaAlloc, arenaReset, arenaDestroy) hide everything behind static state — painless for single-threaded prototypes. Each function has a counterpart that accepts an explicit Arena * so more advanced projects can juggle multiple arenas or manage lifetimes manually.
Allocations pull from a configurable BUFF_SIZE block (1 MB by default). Two pointers march forward: one tracks the current block, one tracks placement. When a request would overflow the block, the arena allocates a fresh chunk, links it, and continues. Resetting rewinds the pointers and frees any extra blocks — cleanup is trivial and predictable.
// Global API — simplest case
arenaInit();
char *buf = arenaAlloc(256);
// ... use buf ...
arenaReset(); // rewind, keep buffer
arenaDestroy(); // free everything
// Local API — multiple arenas
Arena a;
arenaInitLocal(&a);
Node *node = arenaAllocLocal(&a, sizeof(Node));
arenaResetLocal(&a);
arenaDestroyLocal(&a);
malloc calls that already clean up in one place — hit arenaReset instead of repeatedly destroying and reinitializing.arenaInit() — just call arenaAlloc() and arenaDestroy()If you tweak BUFF_SIZE, powers of two generally perform best since the arena aligns to the requested size. For threaded use, spin up one arena per worker — this keeps the data structure lock-free and requires minimal extra code. The entire implementation fits in two files and is intentionally short enough to read in one sitting.