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
4/* arena_template.h
5 *
6 * Copyright (C) 2023 abxh
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 * See the file LICENSE included with this distribution for more
13 * information. */
14
22
27
32
33#ifdef __cplusplus
34#ifdef __GNUC__
35#define restrict __restrict__
36#else
37#define restrict
38#endif
39extern "C" {
40#endif
41
42#include <stddef.h>
43
44// macro definitions: {{{
45
50#ifndef FUNCTION_LINKAGE
51#define FUNCTION_LINKAGE
52#endif
53
61#ifndef IS_POW2
62#define IS_POW2(X) ((X) != 0 && ((X) & ((X) - 1)) == 0)
63#endif
64
65// }}}
66
67// type definitions: {{{
68
69struct arena;
70struct arena_state;
71
76#ifdef TYPE_DEFINITIONS
77
81struct arena {
82 size_t buf_len;
83 size_t prev_offset;
84 size_t curr_offset;
85 unsigned char *buf_ptr;
86};
87
91struct arena_state {
92 struct arena *arena_ptr;
93 size_t prev_offset;
94 size_t curr_offset;
95};
96
97#endif
98
99// }}}
100
101// function declarations: {{{
102
108FUNCTION_LINKAGE struct arena_state arena_state_save(struct arena *arena_ptr);
109
115FUNCTION_LINKAGE void arena_state_restore(struct arena_state prev_state);
116
124FUNCTION_LINKAGE void arena_init(void *self_, const size_t len, unsigned char *backing_buf);
125
132
138FUNCTION_LINKAGE void arena_deallocate(void *self_, void *mem);
139
150FUNCTION_LINKAGE void *arena_allocate_aligned(void *self_, const size_t alignment, const size_t size);
151
161FUNCTION_LINKAGE void *arena_allocate(void *self_, const size_t size);
162
177FUNCTION_LINKAGE void *arena_reallocate_aligned(void *self_, void *old_ptr_, const size_t alignment,
178 const size_t old_size, const size_t new_size);
179
192FUNCTION_LINKAGE void *arena_reallocate(void *self_, void *old_ptr, const size_t old_size, const size_t new_size);
193
194// }}}
195
196// function definitions: {{{
197
202#ifdef FUNCTION_DEFINITIONS
203
204#include "align.h" // align, calc_alignment_padding
205
206#include <assert.h>
207#include <stdalign.h>
208#include <stdbool.h>
209#include <stdint.h>
210#include <stdlib.h>
211#include <string.h>
212
213FUNCTION_LINKAGE struct arena_state arena_state_save(struct arena *arena_ptr)
214{
215 struct arena_state curr_state;
216 curr_state.arena_ptr = arena_ptr;
217 curr_state.prev_offset = arena_ptr->prev_offset;
218 curr_state.curr_offset = arena_ptr->curr_offset;
219 return curr_state;
220}
221
222FUNCTION_LINKAGE void arena_state_restore(struct arena_state prev_state)
223{
224 prev_state.arena_ptr->prev_offset = prev_state.prev_offset;
225 prev_state.arena_ptr->curr_offset = prev_state.curr_offset;
226}
227
228FUNCTION_LINKAGE void arena_init(void *self_, const size_t len, unsigned char *backing_buf)
229{
230 assert(self_);
231 assert(backing_buf);
232
233 struct arena *self = (struct arena *)self_;
234
235 const uintptr_t padding = calc_alignment_padding(alignof(max_align_t), (uintptr_t)backing_buf);
236
237 assert(len >= padding);
238
239 self->buf_ptr = &backing_buf[padding];
240 self->buf_len = len - padding;
241 self->curr_offset = 0;
242 self->prev_offset = 0;
243}
244
246{
247 assert(self_);
248
249 struct arena *self = (struct arena *)self_;
250
251 self->curr_offset = 0;
252 self->prev_offset = 0;
253}
254
255FUNCTION_LINKAGE void arena_deallocate(void *self_, void *mem)
256{
257 assert(self_);
258
259 (void)self_;
260 (void)mem;
261}
262
263FUNCTION_LINKAGE void *arena_allocate_aligned(void *self_, const size_t alignment, const size_t size)
264{
265 assert(self_);
266
267 struct arena *self = (struct arena *)self_;
268
269 void *ptr = (void *)&self->buf_ptr[self->curr_offset];
270
271 size_t space_left = self->buf_len - (size_t)self->curr_offset;
272
273 const bool has_space_left = align(alignment, size, &ptr, &space_left);
274 if (!has_space_left) {
275 return NULL;
276 }
277
278 const uintptr_t relative_offset = (uintptr_t)((unsigned char *)ptr - &self->buf_ptr[0]);
279
280 self->prev_offset = relative_offset;
281 self->curr_offset = relative_offset + size;
282
283 memset(ptr, 0, size);
284
285 return ptr;
286}
287
288FUNCTION_LINKAGE void *arena_allocate(void *self_, const size_t size)
289{
290 assert(self_);
291
292 return arena_allocate_aligned(self_, alignof(max_align_t), size);
293}
294
296static inline void *internal_arena_try_optimizing_w_prev_offset(struct arena *self, unsigned char *old_ptr,
297 const size_t old_size, const size_t new_size)
298{
299 if (&self->buf_ptr[self->prev_offset] != old_ptr) {
300 return NULL;
301 }
302
303 self->curr_offset = self->prev_offset + new_size;
304
305 if (new_size > old_size) {
306 const size_t diff = new_size - old_size;
307
308 memset(&self->buf_ptr[self->curr_offset], 0, diff);
309 }
310
311 return old_ptr;
312}
314
315FUNCTION_LINKAGE void *arena_reallocate_aligned(void *self_, void *old_ptr_, const size_t alignment,
316 const size_t old_size, const size_t new_size)
317{
318 assert(self_);
319 assert(IS_POW2(alignment));
320
321 struct arena *self = (struct arena *)self_;
322 unsigned char *old_ptr = (unsigned char *)old_ptr_;
323
324 const bool misc_input = old_ptr == NULL || old_size == 0 || new_size == 0;
325 const bool inside_arena_buf = &self->buf_ptr[0] <= old_ptr && old_ptr <= &self->buf_ptr[self->buf_len - 1];
326 if (misc_input || !inside_arena_buf) {
327 return NULL;
328 }
329
330 const bool has_optimized_w_prev_buf =
331 internal_arena_try_optimizing_w_prev_offset(self, old_ptr, old_size, new_size);
332 if (has_optimized_w_prev_buf) {
333 return old_ptr;
334 }
335
336 const size_t copy_size = old_size < new_size ? old_size : new_size;
337
338 void *new_mem = arena_allocate_aligned(self, alignment, new_size);
339
340 memmove(new_mem, old_ptr, copy_size);
341
342 return new_mem;
343}
344
345FUNCTION_LINKAGE void *arena_reallocate(void *self_, void *old_ptr, const size_t old_size, const size_t new_size)
346{
347 assert(self_);
348
349 return arena_reallocate_aligned(self_, old_ptr, alignof(max_align_t), old_size, new_size);
350}
351
352#endif
353
354// }}}
355
356// macro undefs: {{{
357
358#undef FUNCTION_LINKAGE
359#undef FUNCTION_DEFINITIONS
360#undef TYPE_DEFINITIONS
361
362// }}}
363
364#ifdef __cplusplus
365}
366#endif
367
368// vim: ft=c fdm=marker
void arena_deallocate(void *self_, void *mem)
Dummy no-op deallocate function.
#define IS_POW2(X)
Macro to check if a number is a power of two.
Definition arena_template.h:62
struct arena_state arena_state_save(struct arena *arena_ptr)
Save the arena state temporarily.
void arena_state_restore(struct arena_state prev_state)
Restore the arena state.
void * arena_allocate(void *self_, const size_t size)
Get the pointer to a chunk of the arena.
void * arena_allocate_aligned(void *self_, const size_t alignment, const size_t size)
Get the pointer to a chunk of the arena. With specific alignment.
void arena_init(void *self_, const size_t len, unsigned char *backing_buf)
Initialize the arena.
void * arena_reallocate_aligned(void *self_, void *old_ptr_, const size_t alignment, const size_t old_size, const size_t new_size)
Reallocate a previously allocated chunk in the arena. With specific aligment.
void * arena_reallocate(void *self_, void *old_ptr, const size_t old_size, const size_t new_size)
Reallocate a previously allocated chunk in the arena.
void arena_deallocate_all(void *self_)
Deallocate all allocations in the arena.
#define FUNCTION_LINKAGE
Specify function linkage e.g. static inline.
Definition fstack_template.h:146