data-structures-c
Loading...
Searching...
No Matches
arena.h
Go to the documentation of this file.
1/* arena.h
2 *
3 * Copyright (C) 2023 abxh
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 * See the file LICENSE included with this distribution for more
10 * information. */
11
20#pragma once
21
22#include "align.h" // align, calc_alignment_padding
23#include "is_pow2.h" // is_pow2
24
25#include <assert.h>
26#include <stdalign.h>
27#include <stdbool.h>
28#include <stddef.h>
29#include <stdint.h>
30#include <stdlib.h>
31#include <string.h>
32
36struct arena {
37 size_t buf_len;
38 size_t prev_offset;
39 size_t curr_offset;
40 unsigned char *buf_ptr;
41};
42
47 struct arena *arena_ptr;
48 size_t prev_offset;
49 size_t curr_offset;
50};
51
59static inline void arena_init(struct arena *self, const size_t len, unsigned char *backing_buf)
60{
61 assert(self);
62 assert(backing_buf);
63
64 const uintptr_t padding = calc_alignment_padding(alignof(max_align_t), (uintptr_t)backing_buf);
65
66 assert(len >= padding);
67
68 self->buf_ptr = &backing_buf[padding];
69 self->buf_len = len - padding;
70 self->curr_offset = 0;
71 self->prev_offset = 0;
72}
73
79static inline void arena_deallocate_all(struct arena *self)
80{
81 assert(self);
82
83 self->curr_offset = 0;
84 self->prev_offset = 0;
85}
86
97static inline void *arena_allocate_aligned(struct arena *self, const size_t alignment, const size_t size)
98{
99 assert(self);
100
101 void *ptr = (void *)&self->buf_ptr[self->curr_offset];
102
103 size_t space_left = self->buf_len - (size_t)self->curr_offset;
104
105 const bool has_space_left = align(alignment, size, &ptr, &space_left);
106 if (!has_space_left) {
107 return NULL;
108 }
109
110 const uintptr_t relative_offset = (uintptr_t)((unsigned char *)ptr - &self->buf_ptr[0]);
111
112 self->prev_offset = relative_offset;
113 self->curr_offset = relative_offset + size;
114
115 memset(ptr, 0, size);
116
117 return ptr;
118}
119
129static inline void *arena_allocate(struct arena *self, const size_t size)
130{
131 assert(self);
132
133 return arena_allocate_aligned(self, alignof(max_align_t), size);
134}
135
137static inline void *internal_arena_try_optimizing_w_prev_offset(struct arena *self, unsigned char *old_ptr,
138 const size_t old_size, const size_t new_size)
139{
140 if (&self->buf_ptr[self->prev_offset] != old_ptr) {
141 return NULL;
142 }
143
144 self->curr_offset = self->prev_offset + new_size;
145
146 if (new_size > old_size) {
147 const size_t diff = new_size - old_size;
148
149 memset(&self->buf_ptr[self->curr_offset], 0, diff);
150 }
151
152 return old_ptr;
153}
155
170static inline void *arena_reallocate_aligned(struct arena *self, void *old_ptr_, const size_t alignment,
171 const size_t old_size, const size_t new_size)
172{
173 assert(self);
174 assert(is_pow2(alignment));
175
176 unsigned char *old_ptr = (unsigned char *)old_ptr_;
177
178 const bool misc_input = old_ptr == NULL || old_size == 0 || new_size == 0;
179 const bool inside_arena_buf = &self->buf_ptr[0] <= old_ptr && old_ptr <= &self->buf_ptr[self->buf_len - 1];
180 if (misc_input || !inside_arena_buf) {
181 return NULL;
182 }
183
184 const bool has_optimized_w_prev_buf =
185 internal_arena_try_optimizing_w_prev_offset(self, old_ptr, old_size, new_size);
186 if (has_optimized_w_prev_buf) {
187 return old_ptr;
188 }
189
190 const size_t copy_size = old_size < new_size ? old_size : new_size;
191
192 void *new_mem = arena_allocate_aligned(self, alignment, new_size);
193
194 memmove(new_mem, old_ptr, copy_size);
195
196 return new_mem;
197}
198
211static inline void *arena_reallocate(struct arena *self, void *old_ptr, const size_t old_size, const size_t new_size)
212{
213 assert(self);
214
215 return arena_reallocate_aligned(self, old_ptr, alignof(max_align_t), old_size, new_size);
216}
217
224{
225 struct temp_arena_state curr_state;
226 curr_state.arena_ptr = arena_ptr;
227 curr_state.prev_offset = arena_ptr->prev_offset;
228 curr_state.curr_offset = arena_ptr->curr_offset;
229 return curr_state;
230}
231
237static inline void temp_arena_state_restore(struct temp_arena_state prev_state)
238{
239 prev_state.arena_ptr->prev_offset = prev_state.prev_offset;
240 prev_state.arena_ptr->curr_offset = prev_state.curr_offset;
241}
Align memory.
static uintptr_t calc_alignment_padding(const size_t alignment, const uintptr_t ptr)
Calculate the alignment padding required to align a pointer.
Definition align.h:91
static void * align(const size_t alignment, const size_t size, void **ptr_ptr, size_t *space_ptr)
Align pointer to the next alignment boundary.
Definition align.h:43
static void arena_deallocate_all(struct arena *self)
Deallocate all allocations in the arena.
Definition arena.h:79
static void * arena_reallocate(struct arena *self, void *old_ptr, const size_t old_size, const size_t new_size)
Reallocate a previously allocated chunk in the arena.
Definition arena.h:211
static void * arena_allocate_aligned(struct arena *self, const size_t alignment, const size_t size)
Get the pointer to a chunk of the arena. With specific alignment.
Definition arena.h:97
static void * arena_reallocate_aligned(struct arena *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.
Definition arena.h:170
static void arena_init(struct arena *self, const size_t len, unsigned char *backing_buf)
Initialize the arena.
Definition arena.h:59
static void temp_arena_state_restore(struct temp_arena_state prev_state)
Restore the arena state.
Definition arena.h:237
static struct temp_arena_state temp_arena_state_save(struct arena *arena_ptr)
Save the arena state temporarily.
Definition arena.h:223
static void * arena_allocate(struct arena *self, const size_t size)
Get the pointer to a chunk of the arena.
Definition arena.h:129
Check if a number is a power of two.
static size_t is_pow2(const size_t x)
Check if a number is a power of two.
Definition is_pow2.h:34
Arena data struct.
Definition arena.h:36
unsigned char * buf_ptr
Underlying buffer pointer.
Definition arena.h:40
size_t prev_offset
Previous offset relative to buf_ptr.
Definition arena.h:38
size_t buf_len
Underlying buffer length.
Definition arena.h:37
size_t curr_offset
Current offset relative to buf_ptr.
Definition arena.h:39
Tempory arena state struct.
Definition arena.h:46
size_t curr_offset
Arena curr offset.
Definition arena.h:49
struct arena * arena_ptr
Arena pointer.
Definition arena.h:47
size_t prev_offset
Arena prev offset.
Definition arena.h:48