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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
#ifndef ARENA_H
#define ARENA_H
#include <stdint.h>
#include <stddef.h>
#include <string.h>
typedef struct ArenaPg {
struct ArenaPg *prev, *next;
char *beg, *end;
char data[];
} ArenaPg;
typedef struct {
ArenaPg *pg;
char *beg;
} ArenaMark;
typedef struct {
ArenaPg *cur, *tail;
} Arena;
#define new(a, t)\
(t*)arena_zeroed(arena_alloc(a, sizeof(t), _Alignof(t)), sizeof(t))
#define new_arr(a, t, n)\
arena_alloc(a, sizeof(t) * n, _Alignof(t))
#define resize(a, p, old, new)\
arena_realloc(a, p, (old) * sizeof(*(p)), (new) * sizeof(*(p)),\
_Alignof(__typeof__(*(p))))
void arena_free(Arena *a);
void arena_save(Arena *a, ArenaMark *m);
void arena_load(Arena *a, ArenaMark *m);
void arena_reset(Arena *a);
void arena_reserve(Arena *a, ptrdiff_t n);
void *arena_alloc(Arena *a, ptrdiff_t n, ptrdiff_t align);
void *arena_realloc(Arena *a, void *ptr, ptrdiff_t old, ptrdiff_t new, ptrdiff_t align);
void *arena_zeroed(void *p, size_t n);
#define ARENA_BACKEND_MALLOC 0
#define ARENA_BACKEND_MMAP 1
#ifndef ARENA_BACKEND
#if defined(__linux__)
# define ARENA_BACKEND ARENA_BACKEND_MMAP
#else
# define ARENA_BACKEND ARENA_BACKEND_MALLOC
#endif
#endif
#ifdef ARENA_IMPL
#include <stdio.h>
#include <stdlib.h>
static void arena_pg_alloc_fail(void) {
fprintf(stderr, "failed to allocate arena page\n");
abort();
}
#if ARENA_BACKEND == ARENA_BACKEND_MMAP
#include <sys/mman.h>
#include <unistd.h>
#define ARENA_PG_SIZE sysconf(_SC_PAGESIZE)
static inline void *arena_pg_alloc(ptrdiff_t n) {
void *p = mmap(NULL, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
return p == MAP_FAILED ? NULL : p;
}
static inline void arena_pg_free(void *ptr, ptrdiff_t n) { munmap(ptr, n); }
#elif ARENA_BACKEND == ARENA_BACKEND_MALLOC
#define ARENA_PG_SIZE 8192
static inline void *arena_pg_alloc(ptrdiff_t n) { return malloc(n); }
static inline void arena_pg_free(void *ptr, ptrdiff_t n) { free(ptr); (void)n; }
#endif
void arena_free(Arena *a) {
while (a->tail) {
a->cur = a->tail->prev;
arena_pg_free(a->tail, (uintptr_t)(a->tail->end - (char*)a->tail));
a->tail = a->cur;
}
}
void arena_reserve(Arena *a, ptrdiff_t n) {
while (a->cur && a->cur->beg + n >= a->cur->end) a->cur = a->cur->next;
if (a->cur) return;
ptrdiff_t cap = n + sizeof(ArenaPg);
cap += (uintptr_t)-cap & (ARENA_PG_SIZE - 1);
ArenaPg *p = arena_pg_alloc(cap);
if (!p) arena_pg_alloc_fail();
p->next = NULL;
p->prev = a->tail;
p->beg = p->data;
p->end = (char*)p + cap;
if (a->tail) a->tail->next = p;
a->cur = (a->tail = p);
}
void *arena_alloc(Arena *a, ptrdiff_t n, ptrdiff_t align) {
arena_reserve(a, n + (align - 1));
char *ptr = a->cur->beg + (-(uintptr_t)a->cur->beg & (align - 1));
a->cur->beg = ptr + n;
return ptr;
}
void *arena_realloc(Arena *a, void *ptr, ptrdiff_t old, ptrdiff_t new, ptrdiff_t align) {
if (a->cur && ptr == a->cur->beg - old && (char*)ptr + new < a->cur->end) {
a->cur->beg += new - old;
return ptr;
} else {
void *p = arena_alloc(a, new, align);
if (ptr) memcpy(p, ptr, old);
return p;
}
}
void *arena_zeroed(void *p, size_t n) {
memset(p, 0, n);
return p;
}
void arena_reset(Arena *a) {
if (!a->cur) return;
while (a->cur->prev) {
a->cur->beg = a->cur->data;
a->cur = a->cur->prev;
}
a->cur->beg = a->cur->data;
}
void arena_save(Arena *a, ArenaMark *m) {
m->pg = a->cur;
if (a->cur) m->beg = a->cur->beg;
}
void arena_load(Arena *a, ArenaMark *m) {
while (a->cur && a->cur != m->pg) {
a->cur->beg = a->cur->data;
a->cur = a->cur->prev;
}
if (a->cur) a->cur->beg = m->beg;
}
#endif
#endif
|