MULE 0.0.1
Multi-Use Library Essentials
Loading...
Searching...
No Matches
Mem

Overview

The allocator interface, and an arena that frees everything at once.

Allocators

An Allocator is one realloc-shaped function and a context pointer. Every module that allocates takes a const Allocator *, and null means the libc heap. A Str or an Arr keeps the pointer in its alloc field, so the caller picks where its bytes live once and the rest of the code does not care.

All allocation in the library goes through mem_realloc(). Only this module calls malloc, realloc and free.

Arenas

An Arena hands out memory from large blocks and frees all of it in one call. Use one for data that lives and dies together, such as everything built while handling one request or parsing one file.

  • A zero-initialised Arena (Arena a = { 0 };) is valid and owns nothing. The first allocation creates a block of at least MEM_ARENA_BLOCK bytes.
  • arena_alloc() hands out raw aligned bytes. arena_allocator() wraps the arena in an Allocator, for a Str or an Arr to grow inside.
  • Growing the most recent allocation happens in place when the block has room, so a Str growing in an arena does not leave a copy behind at every doubling. Freeing the most recent allocation gives its bytes back. Older allocations stay until arena_reset() or arena_free().
Arena arena = { 0 };
int *squares = arena_alloc(&arena, 100 * sizeof *squares, alignof(int));
REQUIRE(squares != NULL);
for (int i = 0; i < 100; i++) squares[i] = i * i;
CHECK_EQ_INT(squares[99], 9801);
arena_free(&arena); /* one call releases every allocation */
Warning
An Arena must stay where it is once arena_allocator() has been called. The Allocator's context points at it, so copying or moving the Arena leaves every Str that uses it pointing at the old address.

Data Structures

struct  Allocator
 Where a module gets its memory. More...
struct  Arena
 Bump allocator over a chain of blocks. More...

Allocators

The interface every allocating module takes.

typedef void * AllocatorFn(void *ctx, void *old, size_t old_size, size_t new_size)
 Allocate, resize or free, depending on old and new_size.
void * mem_realloc (const Allocator *a, void *old, size_t old_size, size_t new_size)
 Resize old from old_size to new_size bytes through a.

Arenas

Bump allocation from blocks that are freed together.

void * arena_alloc (Arena *a, size_t size, size_t align)
 Hand out size bytes from a.
const Allocator * arena_allocator (Arena *a)
 An Allocator that draws from a.
void arena_reset (Arena *a)
 Forget every allocation and keep the newest block for reuse.
void arena_free (Arena *a)
 Release every block.
#define MEM_ARENA_BLOCK   ((size_t)64 * 1024)
 Bytes in a regular arena block.

Data Structure Documentation

◆ Allocator

struct Allocator

Where a module gets its memory.

Definition at line 56 of file mem.h.

Data Fields
AllocatorFn * fn Called with ctx and the mem_realloc arguments.
void * ctx Passed to fn unchanged.

◆ Arena

struct Arena

Bump allocator over a chain of blocks.

Do not copy or move an Arena once arena_allocator() has been called on it.

Examples
main.c.

Definition at line 86 of file mem.h.

Data Fields
ArenaBlock * head Newest block.

Older blocks chain behind it.

void * last Most recent allocation, for in-place growth.
Allocator allocator Filled by arena_allocator().

Macro Definition Documentation

◆ MEM_ARENA_BLOCK

#define MEM_ARENA_BLOCK   ((size_t)64 * 1024)

Bytes in a regular arena block.

Larger requests get a block of their own.

Definition at line 79 of file mem.h.

Typedef Documentation

◆ AllocatorFn

typedef void * AllocatorFn(void *ctx, void *old, size_t old_size, size_t new_size)

Allocate, resize or free, depending on old and new_size.

It has the same contract as mem_realloc(), with ctx from the Allocator.

Definition at line 52 of file mem.h.

Function Documentation

◆ mem_realloc()

void * mem_realloc ( const Allocator * a,
void * old,
size_t old_size,
size_t new_size )

Resize old from old_size to new_size bytes through a.

Parameters
aThe allocator, or null for the libc heap.
oldThe block to resize, or null to allocate a new one.
old_sizeThe size old was allocated with. Ignored when old is null.
new_sizeThe size wanted. Zero frees old.
Returns
The new block, or null on failure with old untouched. A free returns null too, so p = mem_realloc(a, p, n, 0); frees and clears.

Definition at line 14 of file mem.c.

◆ arena_alloc()

void * arena_alloc ( Arena * a,
size_t size,
size_t align )

Hand out size bytes from a.

Parameters
aThe arena.
sizeBytes wanted.
alignA power of two, usually alignof(T). An assert checks it.
Returns
The bytes, or null when a new block cannot be allocated or the size overflows.

Definition at line 48 of file mem.c.

◆ arena_allocator()

const Allocator * arena_allocator ( Arena * a)

An Allocator that draws from a.

It lives as long as a.

Warning
a must not move after this call.
Example
Arena arena = { 0 };
const Allocator *al = arena_allocator(&arena);
char *p = mem_realloc(al, NULL, 0, 16);
REQUIRE(p != NULL);
memcpy(p, "grow me", 8);
char *q = mem_realloc(al, p, 16, 1000); /* newest, so it grows in place */
CHECK(q == p);
arena_free(&arena);

Definition at line 95 of file mem.c.

◆ arena_reset()

void arena_reset ( Arena * a)

Forget every allocation and keep the newest block for reuse.

Memory handed out before is invalid afterwards.

Definition at line 100 of file mem.c.

◆ arena_free()

void arena_free ( Arena * a)

Release every block.

Safe to call twice, and a stays usable. Its Allocator still works, so a Str that points at it can allocate again.

Definition at line 112 of file mem.c.