summaryrefslogtreecommitdiff
path: root/src/arena.c
diff options
context:
space:
mode:
author@syxhe <https://t.me/syxhe>2025-03-23 22:11:15 -0500
committer@syxhe <https://t.me/syxhe>2025-03-23 22:11:15 -0500
commitb3bd3df103a5a75d267b2b79e85558768b1dc4bb (patch)
treeee3ad753b2db679295db846e7d80363e9b6552e7 /src/arena.c
parentc1b188af8c51e29c96a0422b79516d95696869e7 (diff)
Fix a whole bunch of shit, create an arena implementation
Diffstat (limited to 'src/arena.c')
-rw-r--r--src/arena.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/arena.c b/src/arena.c
new file mode 100644
index 0000000..d340f3a
--- /dev/null
+++ b/src/arena.c
@@ -0,0 +1,183 @@
1#include "arena.h"
2#include "shared.h"
3
4#include <stddef.h>
5#include <stdint.h>
6#include <stdlib.h>
7#include <errno.h>
8#include <error.h>
9
10typedef struct an {
11 void *membase;
12 void *memcur;
13 size_t allocated;
14 size_t used;
15
16 struct an *next;
17} arenanode;
18
19typedef struct arena {
20 arenanode *start;
21 arenanode *current;
22
23 // For keeping track of the largest possible thing that can be allocated to one node
24 size_t node_memspace;
25} arena;
26
27int arenanode_init(arenanode **an, size_t bytes) {
28 (*an) = xcalloc(1, sizeof(**an));
29 if(!(*an))
30 return -1;
31
32 (*an)->allocated = bytes;
33 (*an)->used = 0;
34 (*an)->next = NULL;
35
36 void *mem = xcalloc(bytes, 1);
37 if(!mem) {
38 free((*an));
39 (*an) = NULL;
40 return -1;
41 }
42
43 (*an)->membase = mem;
44 (*an)->memcur = mem;
45
46 return 0;
47}
48
49int arena_init(arena **a, size_t bytes) {
50 if(!ISPOWOF2(MEM_ALIGN_BYTES))
51 XALLOC_EXIT("<arena_init> \"MEM_ALIGN_BYTES\" is not a power of 2. Refusing to create a new arena");
52
53 (*a) = xcalloc(1, sizeof(**a));
54 if(!(*a))
55 return -1;
56 (*a)->start = NULL;
57 (*a)->current = NULL;
58 (*a)->node_memspace = bytes;
59
60 arenanode *base;
61 if(arenanode_init(&base, bytes) < 0) {
62 free(*a);
63 (*a) = NULL;
64 return -1;
65 }
66
67 (*a)->start = base;
68 (*a)->current = base;
69
70 return 0;
71}
72
73void* arena_alloc(arena * const arena, size_t bytes) {
74 if(!arena) {
75 errno = EINVAL;
76 return NULL;
77 }
78 if(bytes > arena->node_memspace) {
79 errno = ENOMEM;
80 return NULL;
81 }
82 if(!ISPOWOF2(MEM_ALIGN_BYTES))
83 XALLOC_EXIT("<arena_alloc> \"MEM_ALIGN_BYTES\" is not a power of 2. Refusing to allocate any memory");
84
85 if(bytes > ((arena->current)->allocated - (arena->current)->used)) {
86 arenanode *new;
87 if(arenanode_init(&new, arena->node_memspace) < 0)
88 return NULL;
89
90 arena->current->next = new;
91 arena->current = new;
92 }
93
94 size_t alignment = MEM_ALIGN(bytes);
95 size_t offset = bytes + alignment;
96
97 void *mem = arena->current->memcur;
98 arena->current->memcur = (void*)(((uint8_t*)arena->current->memcur) + offset);
99
100 arena->current->used += offset;
101
102 return mem;
103
104 // Note: This implementation assumes that malloc provides already-aligned memory. If it
105 // doesn't, that sucks and blows everything up
106}
107
108int arena_free(arena **arena) {
109 if(!arena) {
110 errno = EINVAL;
111 return -1;
112 }
113 if(!(*arena)) {
114 errno = EINVAL;
115 return -1;
116 }
117
118 (*arena)->current = (*arena)->start;
119 for(arenanode *n; (*arena)->current != NULL;) {
120 n = (*arena)->current->next;
121
122 free((*arena)->current->membase);
123 free((*arena)->current);
124
125 (*arena)->current = n;
126 }
127 free((*arena));
128 (*arena) = NULL;
129
130 return 0;
131}
132
133int arena_clear(arena **arena) {
134 if(!arena) {
135 errno = EINVAL;
136 return -1;
137 }
138 if(!(*arena)) {
139 errno = EINVAL;
140 return -1;
141 }
142
143 size_t bytes = (*arena)->node_memspace;
144
145 int ret = 0;
146 if((ret = arena_free(arena)) < 0)
147 return ret;
148 return arena_init(arena, bytes);
149}
150
151
152
153// Simple Arena is an arena that can't expand whenever allocating memory, meaning what you originally allocated is what you get
154
155typedef arena simplearena;
156
157int simplearena_init(simplearena **a, size_t bytes) {
158 return arena_init(a, bytes);
159}
160
161void* simplearena_alloc(simplearena * const a, size_t bytes) {
162 // The criteria to allocate new memory in arena_alloc is 'bytes > ((a->current)->allocated - (a->current)->used)', so if this
163 // is true, just return NULL & set errno
164
165 if(!a) {
166 errno = EINVAL;
167 return NULL;
168 }
169 if(bytes > ((a->current)->allocated - (a->current)->used)) {
170 errno = ENOMEM;
171 return NULL;
172 }
173
174 return arena_alloc(a, bytes);
175}
176
177int simplearena_free(simplearena **a) {
178 return arena_free(a);
179}
180
181int simplearena_clear(simplearena **a) {
182 return arena_clear(a);
183} \ No newline at end of file