solidc
Robust collection of general-purpose cross-platform C libraries and data structures designed for rapid and safe development in C
Loading...
Searching...
No Matches
arena.h
1
21#ifndef ARENA_H
22#define ARENA_H
23
24#include <stdbool.h>
25#include <stddef.h>
26#include <stdint.h>
27#include <string.h>
28
29#if defined(__cplusplus)
30extern "C" {
31#endif
32
33#ifdef _MSC_VER
34#include <intrin.h>
35#define ARENA_INLINE __forceinline
36#define ARENA_PREFETCH(addr) _mm_prefetch((const char*)(addr), _MM_HINT_T0)
37#define ARENA_LIKELY(x) (x)
38#define ARENA_UNLIKELY(x) (x)
39#define ARENA_ALIGNED(n) __declspec(align(n))
40#else
41#define ARENA_INLINE inline __attribute__((always_inline))
42#define ARENA_PREFETCH(addr) __builtin_prefetch((addr), 1, 3)
43#define ARENA_LIKELY(x) __builtin_expect(!!(x), 1)
44#define ARENA_UNLIKELY(x) __builtin_expect(!!(x), 0)
45#define ARENA_ALIGNED(n) __attribute__((aligned(n)))
46#endif
47
49#define ARENA_DEFAULT_ALIGN 16
50
52#define ARENA_MIN_BLOCK_SIZE (64 * 1024)
53
62typedef struct ArenaBlock {
63 struct ArenaBlock* next;
64 char* base;
65 char* end;
68
74typedef struct ARENA_ALIGNED(64) Arena {
75 char* curr;
76 char* end;
77 ArenaBlock* current_block;
78 ArenaBlock* head;
79 size_t page_size;
80 size_t total_committed;
81 bool heap_allocated;
82 ArenaBlock first_block;
83} Arena;
84
95void arena_init(Arena* restrict a, void* restrict buf, size_t size);
96
106Arena* arena_create(size_t reserve_size);
107
113static ARENA_INLINE void arena_reset(Arena* restrict a) {
114 if (!a || !a->head) return;
115 a->current_block = a->head;
116 a->curr = a->head->base;
117 a->end = a->head->end;
118}
119
125void arena_destroy(Arena* restrict arena);
126
128static ARENA_INLINE size_t arena_committed_size(const Arena* restrict a) { return a->total_committed; }
129
135static ARENA_INLINE size_t arena_used_size(const Arena* restrict a) {
136 if (!a || !a->current_block) return 0;
137 size_t block_capacity = (size_t)(a->current_block->end - a->current_block->base);
138 size_t block_used = (size_t)(a->curr - a->current_block->base);
139 return (a->total_committed - block_capacity) + block_used;
140}
141
146void* _arena_alloc_slow(Arena* restrict arena, size_t size, size_t alignment);
147
154static ARENA_INLINE void* arena_alloc_align(Arena* restrict arena, size_t size, size_t alignment) {
155 if (size == 0) return NULL;
156
157 uintptr_t aligned = ((uintptr_t)arena->curr + alignment - 1) & ~(alignment - 1);
158 uintptr_t next = aligned + size;
159
160 if (ARENA_LIKELY(next <= (uintptr_t)arena->end)) {
161 arena->curr = (char*)next;
162 return (void*)aligned;
163 }
164
165 return _arena_alloc_slow(arena, size, alignment);
166}
167
172static ARENA_INLINE void* arena_alloc(Arena* restrict arena, size_t size) {
173 return arena_alloc_align(arena, size, ARENA_DEFAULT_ALIGN);
174}
175
181static ARENA_INLINE void* arena_alloc_unaligned(Arena* restrict arena, size_t size) {
182 if (size == 0) return NULL;
183
184 char* ptr = arena->curr;
185 char* next = ptr + size;
186
187 if (ARENA_LIKELY(next <= arena->end)) {
188 arena->curr = next;
189 return ptr;
190 }
191
192 return _arena_alloc_slow(arena, size, 1);
193}
194
196#define ARENA_ALLOC(arena, type) ((type*)arena_alloc_align((arena), sizeof(type), _Alignof(type)))
197
199#define ARENA_ALLOC_ARRAY(arena, type, count) \
200 ((type*)arena_alloc_align((arena), sizeof(type) * (count), _Alignof(type)))
201
203#define ARENA_ALLOC_ZERO(arena, type) \
204 ({ \
205 type* _ptr = ARENA_ALLOC((arena), type); \
206 (_ptr) ? (type*)memset(_ptr, 0, sizeof(type)) : NULL; \
207 })
208
210#define ARENA_ALLOC_ARRAY_ZERO(arena, type, count) \
211 ({ \
212 type* _ptr = ARENA_ALLOC_ARRAY((arena), type, (count)); \
213 (_ptr) ? (type*)memset(_ptr, 0, sizeof(type) * (count)) : NULL; \
214 })
215
225static ARENA_INLINE bool arena_alloc_batch(Arena* restrict arena, const size_t* restrict sizes, size_t count,
226 void** restrict out_ptrs) {
227 if (!arena || !sizes || !out_ptrs || count == 0) return false;
228
229 const size_t mask = ARENA_DEFAULT_ALIGN - 1;
230 size_t total = 0;
231 for (size_t i = 0; i < count; ++i) {
232 total = (total + mask) & ~mask;
233 total += sizes[i];
234 }
235
236 char* base = (char*)arena_alloc(arena, total);
237 if (!base) return false;
238
239 char* cur = base;
240 for (size_t i = 0; i < count; ++i) {
241 cur = (char*)(((uintptr_t)cur + mask) & ~mask);
242 out_ptrs[i] = cur;
243 cur += sizes[i];
244 }
245
246 return true;
247}
248
253static ARENA_INLINE char* arena_strdup(Arena* restrict arena, const char* restrict str) {
254 if (!arena || !str) return NULL;
255 size_t len = strlen(str);
256 char* dup = (char*)arena_alloc_unaligned(arena, len + 1);
257 if (!dup) return NULL;
258 memcpy(dup, str, len + 1);
259 return dup;
260}
261
267static ARENA_INLINE char* arena_strdupn(Arena* restrict arena, const char* restrict str, size_t length) {
268 if (!arena || !str) return NULL;
269 char* dup = (char*)arena_alloc_unaligned(arena, length + 1);
270 if (!dup) return NULL;
271 memcpy(dup, str, length);
272 dup[length] = '\0';
273 return dup;
274}
275
276#if defined(__cplusplus)
277}
278#endif
279
280#endif // ARENA_H
char * end
Definition arena.h:65
bool is_static
Definition arena.h:66