data-structures-c
Loading...
Searching...
No Matches
arena_template.h
Go to the documentation of this file.
1// Copyright (c) 2026 abxh
2// SPDX-License-Identifier: MIT
3
11
16
21
22#ifdef __cplusplus
23#ifdef __GNUC__
24#define restrict __restrict__
25#else
26#define restrict
27#endif
28extern "C" {
29#endif
30
31#include <stddef.h>
32
33// macro definitions: {{{
34
39#ifndef PASTE
40#define PASTE(a, b) a##b
41#endif
42
47#ifndef XPASTE
48#define XPASTE(a, b) PASTE(a, b)
49#endif
50
55#ifndef JOIN
56#define JOIN(a, b) XPASTE(a, XPASTE(_, b))
57#endif
58
66#ifndef IS_POW2
67#define IS_POW2(X) ((X) != 0 && ((X) & ((X) - 1)) == 0)
68#endif
69
77#ifndef NAME
78#error "Must define NAME."
79#define FUNCTION_DEFINITIONS
80#define TYPE_DEFINITIONS
81#else
82#define ARENA_NAME NAME
83#endif
84
89#ifndef FUNCTION_LINKAGE
90#define FUNCTION_LINKAGE
91#endif
92
94#define ARENA_TYPE struct ARENA_NAME
95#define ARENA_STATE_TYPE struct JOIN(ARENA_NAME, state)
97
98// }}}
99
100// type definitions: {{{
101
102struct ARENA_NAME;
103struct JOIN(ARENA_NAME, state);
104
109#ifdef TYPE_DEFINITIONS
110
114struct ARENA_NAME {
115 size_t buf_len;
116 size_t prev_offset;
117 size_t curr_offset;
118 unsigned char *buf_ptr;
119};
120
124struct JOIN(ARENA_NAME, state) {
125 ARENA_TYPE *arena_ptr;
126 size_t prev_offset;
127 size_t curr_offset;
128};
129
130#endif
131
132// }}}
133
134// function declarations: {{{
135
141FUNCTION_LINKAGE ARENA_STATE_TYPE JOIN(ARENA_NAME, state_save)(ARENA_TYPE *arena_ptr);
142
148FUNCTION_LINKAGE void JOIN(ARENA_NAME, state_restore)(ARENA_STATE_TYPE prev_state);
149
157FUNCTION_LINKAGE void JOIN(ARENA_NAME, init)(void *self_, const size_t len, unsigned char *backing_buf);
158
164FUNCTION_LINKAGE void JOIN(ARENA_NAME, deallocate_all)(void *self_);
165
171FUNCTION_LINKAGE void JOIN(ARENA_NAME, deallocate)(void *self_, void *mem);
172
183FUNCTION_LINKAGE void *JOIN(ARENA_NAME, allocate_aligned)(void *self_, const size_t alignment, const size_t size);
184
194FUNCTION_LINKAGE void *JOIN(ARENA_NAME, allocate)(void *self_, const size_t size);
195
210FUNCTION_LINKAGE void *JOIN(ARENA_NAME, reallocate_aligned)(void *self_, void *old_ptr_, const size_t alignment,
211 const size_t old_size, const size_t new_size);
212
225FUNCTION_LINKAGE void *JOIN(ARENA_NAME, reallocate)(void *self_, void *old_ptr, const size_t old_size,
226 const size_t new_size);
227
228// }}}
229
230// function definitions: {{{
231
236#ifdef FUNCTION_DEFINITIONS
237
238#include "align.h" // align, calc_alignment_padding
239
240#include <assert.h>
241#include <stdalign.h>
242#include <stdbool.h>
243#include <stdint.h>
244#include <stdlib.h>
245#include <string.h>
246
247FUNCTION_LINKAGE ARENA_STATE_TYPE JOIN(ARENA_NAME, state_save)(ARENA_TYPE *arena_ptr)
248{
249 ARENA_STATE_TYPE curr_state;
250 curr_state.arena_ptr = arena_ptr;
251 curr_state.prev_offset = arena_ptr->prev_offset;
252 curr_state.curr_offset = arena_ptr->curr_offset;
253 return curr_state;
254}
255
256FUNCTION_LINKAGE void JOIN(ARENA_NAME, state_restore)(ARENA_STATE_TYPE prev_state)
257{
258 prev_state.arena_ptr->prev_offset = prev_state.prev_offset;
259 prev_state.arena_ptr->curr_offset = prev_state.curr_offset;
260}
261
262FUNCTION_LINKAGE void JOIN(ARENA_NAME, init)(void *self_, const size_t len, unsigned char *backing_buf)
263{
264 assert(self_);
265 assert(backing_buf);
266
267 ARENA_TYPE *self = (ARENA_TYPE *)self_;
268
269 const uintptr_t padding = calc_alignment_padding(alignof(max_align_t), (uintptr_t)backing_buf);
270
271 assert(len >= padding);
272
273 self->buf_ptr = &backing_buf[padding];
274 self->buf_len = len - padding;
275 self->curr_offset = 0;
276 self->prev_offset = 0;
277}
278
279FUNCTION_LINKAGE void JOIN(ARENA_NAME, deallocate_all)(void *self_)
280{
281 assert(self_);
282
283 ARENA_TYPE *self = (ARENA_TYPE *)self_;
284
285 self->curr_offset = 0;
286 self->prev_offset = 0;
287}
288
289FUNCTION_LINKAGE void JOIN(ARENA_NAME, deallocate)(void *self_, void *mem)
290{
291 assert(self_);
292
293 (void)self_;
294 (void)mem;
295}
296
297FUNCTION_LINKAGE void *JOIN(ARENA_NAME, allocate_aligned)(void *self_, const size_t alignment, const size_t size)
298{
299 assert(self_);
300
301 ARENA_TYPE *self = (ARENA_TYPE *)self_;
302
303 void *ptr = (void *)&self->buf_ptr[self->curr_offset];
304
305 size_t space_left = self->buf_len - (size_t)self->curr_offset;
306
307 const bool has_space_left = align(alignment, size, &ptr, &space_left);
308 if (!has_space_left) {
309 return NULL;
310 }
311
312 const uintptr_t relative_offset = (uintptr_t)((unsigned char *)ptr - &self->buf_ptr[0]);
313
314 self->prev_offset = relative_offset;
315 self->curr_offset = relative_offset + size;
316
317 memset(ptr, 0, size);
318
319 return ptr;
320}
321
322FUNCTION_LINKAGE void *JOIN(ARENA_NAME, allocate)(void *self_, const size_t size)
323{
324 assert(self_);
325
326 return JOIN(ARENA_NAME, allocate_aligned)(self_, alignof(max_align_t), size);
327}
328
330static inline void *JOIN(JOIN(internal, ARENA_NAME),
331 try_optimizing_w_prev_offset)(ARENA_TYPE *self, unsigned char *old_ptr, const size_t old_size,
332 const size_t new_size)
333{
334 if (&self->buf_ptr[self->prev_offset] != old_ptr) {
335 return NULL;
336 }
337
338 self->curr_offset = self->prev_offset + new_size;
339
340 if (new_size > old_size) {
341 const size_t diff = new_size - old_size;
342
343 memset(&self->buf_ptr[self->curr_offset], 0, diff);
344 }
345
346 return old_ptr;
347}
349
350FUNCTION_LINKAGE void *JOIN(ARENA_NAME, reallocate_aligned)(void *self_, void *old_ptr_, const size_t alignment,
351 const size_t old_size, const size_t new_size)
352{
353 assert(self_);
354 assert(IS_POW2(alignment));
355
356 ARENA_TYPE *self = (ARENA_TYPE *)self_;
357 unsigned char *old_ptr = (unsigned char *)old_ptr_;
358
359 const bool misc_input = old_ptr == NULL || old_size == 0 || new_size == 0;
360 const bool inside_arena_buf = &self->buf_ptr[0] <= old_ptr && old_ptr <= &self->buf_ptr[self->buf_len - 1];
361 if (misc_input || !inside_arena_buf) {
362 return NULL;
363 }
364
365 const bool has_optimized_w_prev_buf =
366 JOIN(JOIN(internal, ARENA_NAME), try_optimizing_w_prev_offset)(self, old_ptr, old_size, new_size);
367 if (has_optimized_w_prev_buf) {
368 return old_ptr;
369 }
370
371 const size_t copy_size = old_size < new_size ? old_size : new_size;
372
373 void *new_mem = JOIN(ARENA_NAME, allocate_aligned)(self, alignment, new_size);
374
375 memmove(new_mem, old_ptr, copy_size);
376
377 return new_mem;
378}
379
380FUNCTION_LINKAGE void *JOIN(ARENA_NAME, reallocate)(void *self_, void *old_ptr, const size_t old_size,
381 const size_t new_size)
382{
383 assert(self_);
384
385 return JOIN(ARENA_NAME, reallocate_aligned)(self_, old_ptr, alignof(max_align_t), old_size, new_size);
386}
387
388#endif
389
390// }}}
391
392// macro undefs: {{{
393
394#undef NAME
395#undef FUNCTION_LINKAGE
396#undef FUNCTION_DEFINITIONS
397#undef TYPE_DEFINITIONS
398
399#undef ARENA_NAME
400#undef ARENA_TYPE
401#undef ARENA_STATE_TYPE
402
403// }}}
404
405#ifdef __cplusplus
406}
407#endif
408
409// vim: ft=c fdm=marker
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition arena_template.h:56
#define IS_POW2(X)
Macro to check if a number is a power of two.
Definition arena_template.h:67
#define FUNCTION_LINKAGE
Specify function linkage e.g. static inline.
Definition fstack_template.h:145
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition fstack_template.h:50
size_t curr_offset
Arena curr offset.
Definition arena_template.h:127
size_t prev_offset
Arena prev offset.
Definition arena_template.h:126
arena_type * arena_ptr
Arena pointer.
Definition arena_template.h:125
unsigned char * buf_ptr
Underlying buffer pointer.
Definition arena_template.h:118
size_t prev_offset
Previous offset relative to buf_ptr.
Definition arena_template.h:116
size_t buf_len
Underlying buffer length.
Definition arena_template.h:115
size_t curr_offset
Current offset relative to buf_ptr.
Definition arena_template.h:117