about summary refs log tree commit diff stats
path: root/arena.c
blob: bf78edc857c29e5e8530a51ad79c4a206f231c26 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include "arena.h"

#include <assert.h>
#include <stdlib.h>
#include <string.h>

/*
 * Alignment for largest scalar type. Before max_align_t was added in C11, code
 * like this usually declared a union of several long-ish types, resulting in a
 * suitable sizeof result. Hopefully anyway. This is cleaner.
 */
#define ALIGN (sizeof(max_align_t))

/*
 * We need this property below to round up to multiples of `ALIGN`. (Of course
 * it's almost certainly true anyway.)
 */
static_assert(ALIGN && !(ALIGN & (ALIGN - 1)), "ALIGN not a power of two");

static unsigned char *arena; /* memory allocated for the arena */
static size_t capacity; /* capacity of the arena in bytes */
static size_t used; /* bytes used so far (from beginning) */

/*
 * Round up `minimum` to nearest multiple of ALIGN.
 */
static inline size_t
round_up(size_t minimum)
{
	return (minimum + ALIGN - 1) & ~(ALIGN - 1);
}

int
ar_setup(size_t arena_size)
{
	assert(!arena);

	size_t adjusted = round_up(arena_size);

	void *p = calloc(1, adjusted);
	if (p == NULL) {
		return -1;
	}

	arena = p;
	capacity = adjusted;

	return 0;
}

void *
ar_alloc(size_t object_size)
{
	assert(arena);

	size_t adjusted = round_up(object_size); /* keep `used` aligned */
	if (used + adjusted > capacity) {
		return NULL; /* out of space */
	}

	void *p = arena + used;
	used += adjusted;

	return p;
}

void
ar_free(void)
{
	assert(arena);

	memset(arena, 0, capacity);
	used = 0;
}

void
ar_cleanup(void)
{
	assert(arena);

	free(arena);
	arena = NULL;

	capacity = 0;
	used = 0;
}