MULE
0.0.1
Multi-Use Library Essentials
Toggle main menu visibility
Loading...
Searching...
No Matches
mem.h
1
#pragma once
2
/**
3
* @defgroup mod_mem Mem
4
* @brief The allocator interface, and an arena that frees everything at once.
5
*
6
* ## Allocators
7
*
8
* An Allocator is one realloc-shaped function and a context pointer. Every
9
* module that allocates takes a `const Allocator *`, and null means the libc
10
* heap. A Str or an Arr keeps the pointer in its `alloc` field, so the
11
* caller picks where its bytes live once and the rest of the code does not
12
* care.
13
*
14
* All allocation in the library goes through mem_realloc(). Only this module
15
* calls malloc, realloc and free.
16
*
17
* ## Arenas
18
*
19
* An Arena hands out memory from large blocks and frees all of it in one
20
* call. Use one for data that lives and dies together, such as everything
21
* built while handling one request or parsing one file.
22
*
23
* - A zero-initialised Arena (`Arena a = { 0 };`) is valid and owns nothing.
24
* The first allocation creates a block of at least #MEM_ARENA_BLOCK
25
* bytes.
26
* - arena_alloc() hands out raw aligned bytes. arena_allocator() wraps the
27
* arena in an Allocator, for a Str or an Arr to grow inside.
28
* - Growing the most recent allocation happens in place when the block has
29
* room, so a Str growing in an arena does not leave a copy behind at
30
* every doubling. Freeing the most recent allocation gives its bytes
31
* back. Older allocations stay until arena_reset() or arena_free().
32
*
33
* @snippet{trimleft} test_mem.c arena
34
*
35
* @warning An Arena must stay where it is once arena_allocator() has been
36
* called. The Allocator's context points at it, so copying or moving the
37
* Arena leaves every Str that uses it pointing at the old address.
38
* @{
39
*/
40
41
#include "base/base.h"
42
43
/* Callers pass alignof(T) to arena_alloc. */
44
#include <stdalign.h>
45
46
/** @name Allocators
47
* The interface every allocating module takes.
48
* @{ */
49
50
/** Allocate, resize or free, depending on @p old and @p new_size. It has
51
* the same contract as mem_realloc(), with @p ctx from the Allocator. */
52
typedef
void
*
AllocatorFn
(
void
*ctx,
void
*old,
size_t
old_size,
53
size_t
new_size);
54
55
/** Where a module gets its memory. */
56
typedef
struct
Allocator
{
57
AllocatorFn
*
fn
;
/**< Called with `ctx` and the mem_realloc arguments. */
58
void
*
ctx
;
/**< Passed to `fn` unchanged. */
59
}
Allocator
;
60
61
/** Resize @p old from @p old_size to @p new_size bytes through @p a.
62
* @param a The allocator, or null for the libc heap.
63
* @param old The block to resize, or null to allocate a new one.
64
* @param old_size The size @p old was allocated with. Ignored when @p old
65
* is null.
66
* @param new_size The size wanted. Zero frees @p old.
67
* @return The new block, or null on failure with @p old untouched. A free
68
* returns null too, so `p = mem_realloc(a, p, n, 0);` frees and clears. */
69
MULE_NODISCARD
void
*
mem_realloc
(
const
Allocator
*a,
void
*old,
size_t
old_size,
70
size_t
new_size);
71
72
/** @} */
73
74
/** @name Arenas
75
* Bump allocation from blocks that are freed together.
76
* @{ */
77
78
/** Bytes in a regular arena block. Larger requests get a block of their own. */
79
#define MEM_ARENA_BLOCK ((size_t)64 * 1024)
80
81
/** One block of an arena. Defined in mem.c. */
82
typedef
struct
ArenaBlock
ArenaBlock
;
83
84
/** Bump allocator over a chain of blocks. Do not copy or move an Arena once
85
* arena_allocator() has been called on it. */
86
typedef
struct
Arena
{
87
ArenaBlock
*
head
;
/**< Newest block. Older blocks chain behind it. */
88
void
*
last
;
/**< Most recent allocation, for in-place growth. */
89
Allocator
allocator
;
/**< Filled by arena_allocator(). */
90
}
Arena
;
91
92
/** Hand out @p size bytes from @p a.
93
* @param a The arena.
94
* @param size Bytes wanted.
95
* @param align A power of two, usually `alignof(T)`. An assert checks it.
96
* @return The bytes, or null when a new block cannot be allocated or the
97
* size overflows. */
98
MULE_NODISCARD
void
*
arena_alloc
(
Arena
*a,
size_t
size,
size_t
align);
99
/** An Allocator that draws from @p a. It lives as long as @p a.
100
* @warning @p a must not move after this call.
101
* @par Example
102
* @snippet{trimleft} test_mem.c allocator */
103
MULE_NODISCARD
const
Allocator
*
arena_allocator
(
Arena
*a);
104
/** Forget every allocation and keep the newest block for reuse. Memory
105
* handed out before is invalid afterwards. */
106
void
arena_reset
(
Arena
*a);
107
/** Release every block. Safe to call twice, and @p a stays usable. Its
108
* Allocator still works, so a Str that points at it can allocate again. */
109
void
arena_free
(
Arena
*a);
110
111
/** @} */
112
113
/** @} */
Allocator::fn
AllocatorFn * fn
Called with ctx and the mem_realloc arguments.
Definition
mem.h:57
Arena::allocator
Allocator allocator
Filled by arena_allocator().
Definition
mem.h:89
Allocator::ctx
void * ctx
Passed to fn unchanged.
Definition
mem.h:58
Arena::head
ArenaBlock * head
Newest block.
Definition
mem.h:87
Arena::last
void * last
Most recent allocation, for in-place growth.
Definition
mem.h:88
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.
Definition
mem.c:14
arena_reset
void arena_reset(Arena *a)
Forget every allocation and keep the newest block for reuse.
Definition
mem.c:100
arena_allocator
const Allocator * arena_allocator(Arena *a)
An Allocator that draws from a.
Definition
mem.c:95
arena_alloc
void * arena_alloc(Arena *a, size_t size, size_t align)
Hand out size bytes from a.
Definition
mem.c:48
arena_free
void arena_free(Arena *a)
Release every block.
Definition
mem.c:112
AllocatorFn
void * AllocatorFn(void *ctx, void *old, size_t old_size, size_t new_size)
Allocate, resize or free, depending on old and new_size.
Definition
mem.h:52
Allocator
Where a module gets its memory.
Definition
mem.h:56
Arena
Bump allocator over a chain of blocks.
Definition
mem.h:86
ArenaBlock
One block of an arena.
Definition
mem.c:7
src
mem
mem.h
Generated by
1.18.0