summaryrefslogtreecommitdiff
path: root/src/arena.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arena.c')
-rw-r--r--src/arena.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/arena.c b/src/arena.c
new file mode 100644
index 0000000..8822fdd
--- /dev/null
+++ b/src/arena.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <assert.h>
+#include <obe/arena.h>
+#include <stdlib.h>
+#include <string.h>
+
+void*
+obe_arena_alloc(obe_arena_t* arena, size_t size)
+{
+ if (arena->end == NULL) {
+ assert(arena->begin == NULL);
+ size_t capacity = OBE_ARENA_REGION_DEFAULT_CAPACITY;
+ if (capacity < OBE_ARENA_PADDING(size))
+ capacity = size + OBE_ARENA_PADDING(size);
+ arena->end = obe_arena_region_new(capacity);
+ arena->begin = arena->end;
+ }
+
+ while (arena->end->offset + size > arena->end->capacity &&
+ arena->end->next != NULL) {
+ arena->end = arena->end->next;
+ }
+
+ if (arena->end->offset + size > arena->end->capacity) {
+ assert(arena->end->next == NULL);
+ size_t capacity = OBE_ARENA_REGION_DEFAULT_CAPACITY;
+ if (capacity < size)
+ capacity = size + OBE_ARENA_PADDING(size);
+ arena->end->next = obe_arena_region_new(capacity);
+ arena->end = arena->end->next;
+ }
+
+ void* ptr = arena->end->data + arena->end->offset;
+ arena->end->offset += size + OBE_ARENA_PADDING(size);
+ return ptr;
+}
+
+void*
+obe_arena_realloc(obe_arena_t* arena,
+ void* old_ptr,
+ size_t old_size,
+ size_t new_size)
+{
+ if (new_size <= old_size)
+ return old_ptr;
+ void* new_ptr = obe_arena_alloc(arena, new_size);
+ return memcpy(new_ptr, old_ptr, old_size);
+}
+
+void
+obe_arena_release(obe_arena_t* arena)
+{
+ for (obe_arena_region_t* r = arena->begin; r != NULL; r = r->next) {
+ r->offset = 0;
+ }
+ arena->end = arena->begin;
+}
+
+void
+obe_arena_free(obe_arena_t* arena)
+{
+ obe_arena_region_t* r = arena->begin;
+ while (r) {
+ obe_arena_region_t* r_tmp = r;
+ r = r->next;
+ obe_arena_region_free(r_tmp);
+ }
+ arena->begin = NULL;
+ arena->end = NULL;
+}
+
+obe_arena_region_t*
+obe_arena_region_new(size_t capacity)
+{
+ size_t size = sizeof(obe_arena_region_t) + sizeof(uint8_t) * capacity;
+ obe_arena_region_t* r = (obe_arena_region_t*)malloc(size);
+ assert(r);
+ r->next = NULL;
+ r->offset = 0;
+ r->capacity = capacity;
+ r->data = (uint8_t*)(r + 1);
+ return r;
+}
+
+void
+obe_arena_region_free(obe_arena_region_t* r)
+{
+ free(r);
+}
+
+char*
+obe_arena_strdup(obe_arena_t* arena, char* s)
+{
+ size_t slen = strlen(s);
+ char* d = obe_arena_alloc(arena, sizeof(char) * (slen + 1));
+ assert(d);
+
+ for (size_t i = 0; i <= slen; ++i)
+ d[i] = s[i];
+
+ return d;
+}