summaryrefslogtreecommitdiff
path: root/src/arena.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arena.c')
-rw-r--r--src/arena.c284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/arena.c b/src/arena.c
new file mode 100644
index 0000000..bd93eeb
--- /dev/null
+++ b/src/arena.c
@@ -0,0 +1,284 @@
1#include <stdint.h>
2#include <string.h>
3
4#define CMMM__ARENA__STRIP_VENDOR
5#include "cmmm/arena.h"
6
7#ifndef ASSERT
8#include <assert.h>
9#define ASSERT assert
10#endif
11
12#ifndef MALLOC
13#include <stdlib.h>
14#define MALLOC malloc
15#define FREE free
16#endif
17
18#define MAX(A, B) ((A) > (B) ? (A) : (B))
19
20static size_t
21chunk_size (struct arena__chunk *chunk)
22{
23 return chunk->end - chunk->data;
24}
25
26static struct arena__chunk *
27new_chunk (size_t size)
28{
29 struct arena__chunk *chunk = MALLOC (sizeof (struct arena__chunk) + size);
30
31 chunk->next = NULL;
32 chunk->free = chunk->data;
33 chunk->end = chunk->data + size;
34
35 return chunk;
36}
37
38static struct arena__chunk *
39append_chunk (struct cmmm__arena *arena, size_t size)
40{
41 size = arena->tail != NULL
42 ? MAX (ARENA__CHUNK_GROWTH_FACTOR*chunk_size (arena->tail), size)
43 : MAX (ARENA__FIRST_CHUNK_SIZE, size);
44
45 struct arena__chunk *chunk = new_chunk (size);
46
47 if (arena->tail) {
48 arena->tail->next = chunk;
49 arena->tail = chunk;
50 } else {
51 arena->head = chunk;
52 arena->tail = chunk;
53 }
54
55 return chunk;
56}
57
58static void *
59alignto (void *ptr, size_t alignment)
60{
61 return ptr + (uintptr_t) ptr % alignment;
62}
63
64void *
65arena__reserve (struct cmmm__arena *arena, size_t size, size_t alignment)
66{
67 ASSERT (arena != NULL);
68
69 if (arena->tail != NULL) {
70 char *aligned_free = alignto (arena->tail->free, alignment);
71 ASSERT (aligned_free - arena->tail->end >= 0);
72 if ((size_t) (aligned_free - arena->tail->end) >= size)
73 return aligned_free;
74 }
75
76 append_chunk (arena, size);
77 return arena->tail->free;
78}
79
80void *
81arena__allocate (struct cmmm__arena *arena, size_t size, size_t alignment)
82{
83 ASSERT (arena != NULL);
84
85 void *ptr = arena__reserve (arena, size, alignment);
86 arena->tail->free += size;
87 return ptr;
88}
89
90void *
91arena__allocate_fast (struct cmmm__arena *arena, size_t size, size_t alignment)
92{
93 ASSERT (arena != NULL);
94
95 return arena->tail->free = alignto (arena->tail->free, alignment) + size;
96}
97
98size_t
99arena__room (const struct cmmm__arena *arena, size_t alignment)
100{
101 ASSERT (arena != NULL);
102
103 char *aligned_free = alignto (arena->tail->free, alignment);
104 return arena->tail->end - aligned_free;
105}
106
107void *
108arena__next_free (const struct cmmm__arena *arena, size_t alignment)
109{
110 ASSERT (arena != NULL);
111
112 char *aligned_free = alignto (arena->tail->free, alignment);
113 return aligned_free;
114}
115
116void *
117arena__copy (struct cmmm__arena *arena, const void *from,
118 size_t size, size_t alignment)
119{
120 ASSERT (arena != NULL);
121
122 void *ptr = arena__allocate (arena, size, alignment);
123 memcpy (ptr, from, size);
124 return ptr;
125}
126
127char *
128arena__copy_cstr (struct cmmm__arena *arena, const char *cstr)
129{
130 ASSERT (arena != NULL);
131
132 size_t size = strlen (cstr) + 1;
133 return arena__copy (arena, cstr, size, 1);
134}
135
136void
137arena__reset (struct cmmm__arena *arena)
138{
139 ASSERT (arena != NULL);
140
141 if (arena->head == NULL)
142 return;
143
144 arena->tail = arena->head;
145 arena->head->free = arena->head->data;
146}
147
148struct arena__checkpoint
149arena__checkpoint (struct cmmm__arena *arena)
150{
151 ASSERT (arena != NULL);
152
153 if (arena->tail == NULL)
154 arena__reserve (arena, 0, 1);
155
156 return (struct arena__checkpoint) {
157 .tail = arena->tail,
158 .free = arena->tail->free,
159 };
160}
161
162void
163arena__rollback_to (ARENA arena, struct arena__checkpoint checkpoint)
164{
165 ASSERT (arena != NULL);
166
167 arena->tail = checkpoint.tail;
168 arena->tail->free = checkpoint.free;
169}
170
171size_t
172arena__checkpoint__size_from (struct arena__checkpoint checkpoint)
173{
174 size_t size = checkpoint.tail->free - checkpoint.free;
175 for (struct arena__chunk *chunk = checkpoint.tail; chunk; chunk = chunk->next)
176 size += chunk_size (chunk);
177 return size;
178}
179
180void *
181arena__coalesce_from (ARENA arena, struct arena__checkpoint checkpoint)
182{
183 ASSERT (arena != NULL);
184
185 if (arena->tail == checkpoint.tail) // already coalesced
186 return checkpoint.free;
187
188 size_t size = arena__checkpoint__size_from (checkpoint);
189 return arena__coalesce_from_fast (arena, checkpoint, size);
190}
191
192void *
193arena__coalesce_from_fast (ARENA arena, struct arena__checkpoint checkpoint,
194 size_t size)
195{
196 ASSERT (arena != NULL);
197
198 if (arena->tail == checkpoint.tail) // already coalesced
199 return checkpoint.free;
200
201 // make new chunk, add old chunks after it
202 struct arena__chunk *chunk = new_chunk (size);
203 chunk->next = checkpoint.free == checkpoint.tail->data
204 ? checkpoint.tail
205 : checkpoint.tail->next;
206
207 // copy old chunks into new chunk
208 size_t other_size = checkpoint.tail->free - checkpoint.free;
209 memcpy (chunk->free, checkpoint.free, other_size);
210 chunk->free += other_size;
211 for (struct arena__chunk *other_chunk = checkpoint.tail->next;
212 other_chunk; other_chunk = other_chunk->next) {
213 other_size = chunk_size (other_chunk);
214 memcpy (chunk->free, other_chunk->data, other_size);
215 chunk->free += other_size;
216 }
217
218 // link in new chunk
219 checkpoint.tail->next = chunk;
220
221 return chunk->data;
222}
223
224void
225arena__trim (ARENA arena)
226{
227 ASSERT (arena != NULL);
228
229 if (arena->tail == NULL)
230 return;
231
232 struct arena__chunk *chunk = arena->tail->next;
233 while (chunk) {
234 struct arena__chunk *next = chunk->next;
235 FREE (chunk);
236 chunk = next;
237 }
238}
239
240void
241arena__free (ARENA arena)
242{
243 ASSERT (arena != NULL);
244
245 struct arena__chunk *chunk = arena->head;
246 while (chunk) {
247 struct arena__chunk *next = chunk->next;
248 FREE (chunk);
249 chunk = next;
250 }
251
252 arena->head = NULL;
253 arena->tail = NULL;
254}
255
256#ifndef ARENA__NO_STDIO
257#include <stdio.h>
258
259char *
260arena__printf (ARENA arena, const char *format, ...)
261{
262 va_list ap;
263 va_start (ap, format);
264 char *cstr = arena__vprintf (arena, format, ap);
265 va_end (ap);
266
267 return cstr;
268}
269
270char *
271arena__vprintf (ARENA arena, const char *format, va_list ap)
272{
273 va_list ap_copy;
274 va_copy (ap_copy, ap);
275 int len = vsnprintf (NULL, 0, format, ap_copy);
276 va_end (ap_copy);
277
278 ASSERT (len >= 0);
279 char *cstr = ARENA__ALLOCATE_ARRAY (arena, len + 1, char);
280 vsnprintf (cstr, len + 1, format, ap);
281
282 return cstr;
283}
284#endif