#include #include #include #include #include "wv_mem.h" #include "wv_err.h" #define WV_ALIGNMENT alignof(max_align_t) #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) err(1, "malloc arena struct"); arena->buf = malloc(n); if (!arena->buf) err(1, "malloc arena buffer"); arena->size = n; arena->offset = WV_ARENA_RESERVED; return arena; } wv_ref wv_arena_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) 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) return; memset(arena->buf, 0, arena->offset); arena->offset = WV_ARENA_RESERVED; } void wv_arena_destroy(struct wv_arena *arena) { if (!arena) return; free(arena->buf); free(arena); } wv_ref wv_arena_push_string(struct wv_arena *arena, const char *src, size_t len) { wv_ref ref = wv_arena_alloc(arena, len + 1); char *dst = (char *)WV_ADDR(arena, ref); memcpy(dst, src, len); dst[len] = '\0'; return ref; }