summaryrefslogtreecommitdiffstats
path: root/wv_mem.c
diff options
context:
space:
mode:
authorSadeep Madurange <sadeep@asciimx.com>2026-05-04 12:58:31 +0800
committerSadeep Madurange <sadeep@asciimx.com>2026-05-04 17:42:39 +0800
commite786c2e12add1aa3078cba4c367764e4252748e9 (patch)
tree07461ccfd8cab329ce779d989bc712a2300da537 /wv_mem.c
downloadweb-view-e786c2e12add1aa3078cba4c367764e4252748e9.tar.gz
Defined arena for memory management.
Diffstat (limited to 'wv_mem.c')
-rw-r--r--wv_mem.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/wv_mem.c b/wv_mem.c
new file mode 100644
index 0000000..0bb32dc
--- /dev/null
+++ b/wv_mem.c
@@ -0,0 +1,94 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "wv_mem.h"
+#include "wv_err.h"
+
+/* Detect alignment pre-C11 */
+union wv_max_align { long l; double d; void *p; };
+
+#define WV_ALIGNOF(type) offsetof(struct { char c; type member; }, member)
+#define WV_ALIGNMENT WV_ALIGNOF(union wv_max_align)
+#define WV_ALIGN_MASK (WV_ALIGNMENT - 1)
+
+#define WV_ARENA_MIN_SIZE (256 * 1024)
+#define WV_ARENA_RESERVED WV_ALIGNMENT /* Reserve 0 as the sentinel "null" ref */
+
+struct wv_arena *wv_arena_create(size_t n)
+{
+ struct wv_arena *arena;
+
+ if (n < WV_ARENA_MIN_SIZE)
+ n = WV_ARENA_MIN_SIZE;
+
+ arena = malloc(sizeof(struct wv_arena));
+ if (arena == NULL)
+ err(1, "malloc arena struct");
+
+ arena->buf = malloc(n);
+ if (arena->buf == NULL)
+ err(1, "malloc arena buffer");
+
+ arena->size = n;
+ arena->offset = WV_ARENA_RESERVED;
+
+ return arena;
+}
+
+wv_ref wv_alloc(struct wv_arena *arena, size_t n)
+{
+ wv_ref ref;
+ unsigned char *new_buf;
+ size_t aligned_n, new_size;
+
+ if (n == 0)
+ errx(1, "wv_alloc: zero-size allocation");
+
+ if (n > SIZE_MAX - WV_ALIGN_MASK)
+ errx(1, "wv_alloc: allocation size overflow");
+
+ aligned_n = (n + WV_ALIGN_MASK) & ~WV_ALIGN_MASK;
+
+ if (aligned_n > SIZE_MAX - arena->offset)
+ errx(1, "wv_alloc: arena offset overflow");
+
+ if (arena->offset + aligned_n > arena->size) {
+ new_size = arena->size;
+ while (new_size < arena->offset + aligned_n) {
+ if (new_size > SIZE_MAX / 2)
+ errx(1, "wv_alloc: arena growth overflow");
+ new_size *= 2;
+ }
+
+ new_buf = realloc(arena->buf, new_size);
+ if (new_buf == NULL)
+ err(1, "realloc arena failed at %zu bytes", new_size);
+
+ arena->buf = new_buf;
+ arena->size = new_size;
+ }
+
+ ref = (wv_ref)arena->offset;
+ arena->offset += aligned_n;
+ return ref;
+}
+
+void wv_arena_reset(struct wv_arena *arena)
+{
+ if (arena == NULL)
+ return;
+
+ memset(arena->buf, 0, arena->offset);
+ arena->offset = WV_ARENA_RESERVED;
+}
+
+void wv_arena_destroy(struct wv_arena *arena)
+{
+ if (arena == NULL)
+ return;
+
+ free(arena->buf);
+ free(arena);
+}
+