diff options
| author | steven-na <noreply.github@stvnc.dev> | 2026-07-28 02:12:54 -0700 |
|---|---|---|
| committer | steven-na <noreply.github@stvnc.dev> | 2026-07-28 02:12:54 -0700 |
| commit | 8bec6205ae1631dc0896fe25795b2946ed414df0 (patch) | |
| tree | a40734bf042ab2236c65254bed08fac23bccc3e5 /src | |
| parent | acea02e9b90a83167d15e62741c8e8bb9f0d4b7c (diff) | |
Arenas and start work on strings
Diffstat (limited to 'src')
| -rw-r--r-- | src/common.h | 29 | ||||
| -rw-r--r-- | src/ez_arena.c | 58 | ||||
| -rw-r--r-- | src/ez_arena.h | 18 | ||||
| -rw-r--r-- | src/smrt_arena.c | 197 | ||||
| -rw-r--r-- | src/smrt_arena.h | 35 | ||||
| -rw-r--r-- | src/string.c | 25 | ||||
| -rw-r--r-- | src/string.h | 18 |
7 files changed, 380 insertions, 0 deletions
diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..1add4db --- /dev/null +++ b/src/common.h @@ -0,0 +1,29 @@ +#pragma once + +#include <stdint.h> +#include <stddef.h> + +#define KiB(n) ((u64)n<<10) +#define MiB(n) ((u64)n<<20) +#define GiB(n) ((u64)n<<30) + +#define MAX(n, m) ((n > m) ? (n) : (m)) +#define MIN(n, m) ((n < m) ? (n) : (m)) +#define ALIGN_UP_POW2(n, m) (((u64)(n) + (u64)(m) - 1) & (~((u64)(m) - 1))) + +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef i8 b8; +typedef i32 b32; + +typedef float f32; +typedef double f64; + +#define ARENA_ALIGN (sizeof(void*)) diff --git a/src/ez_arena.c b/src/ez_arena.c new file mode 100644 index 0000000..e37766e --- /dev/null +++ b/src/ez_arena.c @@ -0,0 +1,58 @@ +#include "ez_arena.h" + +#include <stdlib.h> +#include <string.h> + +ez_arena_t *ez_arena_create(u64 size, b32 zero_out) { + ez_arena_t *alloc = malloc(size + sizeof(ez_arena_t)); + + if (!alloc) { + return NULL; + } + + if (zero_out) { + memset((u8*)alloc+EZ_ARENA_BASE_POS, 0, size); + } + + *alloc = (ez_arena_t){ .alloc_size = size, .pos = EZ_ARENA_BASE_POS }; + + return alloc; +} + +void *ez_arena_alloc(ez_arena_t *arena, u64 alloc_amount) { + u64 pos_aligned = ALIGN_UP_POW2(arena->pos, ARENA_ALIGN); + u64 new_pos = pos_aligned + alloc_amount; + + if (new_pos > arena->alloc_size + sizeof(ez_arena_t)) { return NULL; } + + arena->pos = new_pos; + + u8* out = (u8*)arena + pos_aligned; + + memset(out, 0, alloc_amount); + + return out; +} + +void *ez_arena_alloc_nz(ez_arena_t *arena, u64 alloc_amount) { + u64 pos_aligned = ALIGN_UP_POW2(arena->pos, ARENA_ALIGN); + u64 new_pos = pos_aligned + alloc_amount; + + if (new_pos > arena->alloc_size + sizeof(ez_arena_t)) { return NULL; } + + arena->pos = new_pos; + + return (u8*)arena + pos_aligned; +} + +void ez_arena_clear(ez_arena_t *arena, b32 zero_out) { + if (zero_out) { + memset((u8*)arena+EZ_ARENA_BASE_POS, 0, arena->alloc_size); + } + + arena->pos = EZ_ARENA_BASE_POS; +} + +void ez_arena_destroy(ez_arena_t *arena) { + free(arena); +} diff --git a/src/ez_arena.h b/src/ez_arena.h new file mode 100644 index 0000000..19def60 --- /dev/null +++ b/src/ez_arena.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common.h" + +#define EZ_ARENA_BASE_POS (sizeof(ez_arena_t)) + +typedef struct { + u64 alloc_size; + u64 pos; +} ez_arena_t; + +ez_arena_t *ez_arena_create(u64 size, b32 zero_out); + void *ez_arena_alloc(ez_arena_t *arena, u64 alloc_amount); + void *ez_arena_alloc_nz(ez_arena_t *arena, u64 alloc_amount); + void ez_arena_clear(ez_arena_t *arena, b32 zero_out); + void ez_arena_destroy(ez_arena_t *arena); + +#define EZA_ALLOC_ARRAY(arena, T, n) (T*)ez_arena_alloc(arena, sizeof(T) * (n)) diff --git a/src/smrt_arena.c b/src/smrt_arena.c new file mode 100644 index 0000000..683afcd --- /dev/null +++ b/src/smrt_arena.c @@ -0,0 +1,197 @@ +#if defined(__linux__) +#define _DEFAULT_SOURCE +#endif + +#include "common.h" +#include "smrt_arena.h" + +#include <string.h> + +smrt_arena_t *smrt_arena_create(u64 reserve_size, u64 commit_size, b32 auto_decommit) { + u32 pagesize = plat_get_pagesize(); + + reserve_size = ALIGN_UP_POW2(reserve_size + sizeof(smrt_arena_t), pagesize); + commit_size = ALIGN_UP_POW2( commit_size, pagesize); + + smrt_arena_t *arena = plat_mem_reserve(reserve_size); + + if (!plat_mem_commit(arena, commit_size)) { + return NULL; + } + + arena->reserve_size = reserve_size; + arena->commit_size = commit_size; + arena->commit_pos = commit_size; + arena->pos = SMRT_ARENA_BASE_POS; + arena->mark_pos = 0; + arena->auto_decommit = auto_decommit; + + return arena; + +} + +static void smrt_arena__shrink_commit(smrt_arena_t *arena) { + if (!arena->auto_decommit) { return; } + + u64 target_commit_pos = arena->pos + arena->commit_size - 1; + target_commit_pos -= target_commit_pos % arena->commit_size; + + if (target_commit_pos >= arena->commit_pos) { return; } + + u64 decommit_size = arena->commit_pos - target_commit_pos; + u8 *decommit_start = (u8*)arena + target_commit_pos; + + if (plat_mem_decommit(decommit_start, decommit_size)) { + arena->commit_pos = target_commit_pos; + + if (arena->mark_pos > arena->commit_pos) { + arena->mark_pos = 0; + } + } +} + +void *smrt_arena_push(smrt_arena_t *arena, u64 alloc_amount, b32 zero_out) { + u64 pos_aligned = ALIGN_UP_POW2(arena->pos, ARENA_ALIGN); + u64 new_pos = pos_aligned + alloc_amount; + + if (new_pos > arena->reserve_size) { return NULL; } + + if (new_pos > arena->commit_pos) { + u64 new_commit_pos = new_pos; + new_commit_pos += arena->commit_size - 1; + new_commit_pos -= new_commit_pos % arena->commit_size; + new_commit_pos = MIN(new_commit_pos, arena->reserve_size); + + u8 *mem = (u8*)arena + arena->commit_pos; + u64 commit_size = new_commit_pos - arena->commit_pos; + + if (!plat_mem_commit(mem, commit_size)) { + return NULL; + } + + arena->commit_pos = new_commit_pos; + } + + arena->pos = new_pos; + + u8 *out = (u8*)arena + pos_aligned; + + if (zero_out) { + memset(out, 0, alloc_amount); + } + + return out; +} + +void *smrt_arena_mark_push(smrt_arena_t *arena, u64 alloc_amount, b32 zero_out) { + u64 orig_pos = arena->pos; + + void *mem = smrt_arena_push(arena, alloc_amount, zero_out); + + if (mem) { + arena->mark_pos = orig_pos; + } + + return mem; +} + +void smrt_arena_pop(smrt_arena_t *arena, u64 pop_amount) { + pop_amount = MIN(pop_amount, arena->pos - SMRT_ARENA_BASE_POS); + arena->pos -= pop_amount; + + smrt_arena__shrink_commit(arena); +} + +void smrt_arena_pop_to(smrt_arena_t *arena, u64 pos) { + u64 size = pos < arena->pos ? arena->pos - pos : 0; + smrt_arena_pop(arena, size); +} + +b32 smrt_arena_pop_to_mark(smrt_arena_t *arena) { + if (arena->mark_pos == 0) { + return false; + } + + smrt_arena_pop_to(arena, arena->mark_pos); + + return true; +} + +void smrt_arena_clear(smrt_arena_t *arena, b32 zero_out) { + arena->pos = SMRT_ARENA_BASE_POS; + + if (zero_out) { + memset((u8*)arena + SMRT_ARENA_BASE_POS, 0, arena->commit_size - SMRT_ARENA_BASE_POS); + } + + smrt_arena__shrink_commit(arena); +} + +void smrt_arena_destroy(smrt_arena_t *arena) { + plat_mem_release(arena, arena->reserve_size); +} + +#if defined(_WIN32) + +#include <windows.h> + +u32 plat_get_pagesize(void) { + SYSTEM_INFO sysinfo = { 0 }; + GetSystemInfo(&sysinfo); + + return sysinfo.dwPageSize; +} + +void* plat_mem_reserve(u64 size) { + return VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_READWRITE); +} + +b32 plat_mem_commit(void* ptr, u64 size) { + void* ret = VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE); + return ret != NULL; +} + +b32 plat_mem_decommit(void* ptr, u64 size) { + return VirtualFree(ptr, size, MEM_DECOMMIT); +} + +b32 plat_mem_release(void* ptr, u64 size) { + return VirtualFree(ptr, size, MEM_RELEASE); +} + + +#elif defined(__linux__) + +#include <unistd.h> +#include <sys/mman.h> + +u32 plat_get_pagesize(void) { + return (u32)sysconf(_SC_PAGESIZE); +} + +void* plat_mem_reserve(u64 size) { + void* out = mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (out == MAP_FAILED) { + return NULL; + } + return out; +} + +b32 plat_mem_commit(void* ptr, u64 size) { + i32 ret = mprotect(ptr, size, PROT_READ | PROT_WRITE); + return ret == 0; +} + +b32 plat_mem_decommit(void* ptr, u64 size) { + i32 ret = mprotect(ptr, size, PROT_NONE); + if (ret != 0) return false; + ret = madvise(ptr, size, MADV_DONTNEED); + return ret == 0; +} + +b32 plat_mem_release(void* ptr, u64 size) { + i32 ret = munmap(ptr, size); + return ret == 0; +} + +#endif diff --git a/src/smrt_arena.h b/src/smrt_arena.h new file mode 100644 index 0000000..4e6f592 --- /dev/null +++ b/src/smrt_arena.h @@ -0,0 +1,35 @@ +#pragma once + +#include "common.h" + +#define SMRT_ARENA_BASE_POS (sizeof(smrt_arena_t)) + +typedef struct { + u64 reserve_size; + u64 commit_size; + + u64 mark_pos; + + u64 pos; + u64 commit_pos; + + b32 auto_decommit; +} smrt_arena_t; + +smrt_arena_t *smrt_arena_create(u64 reserve_size, u64 commit_size, b32 auto_decommit); + void *smrt_arena_push(smrt_arena_t *arena, u64 alloc_amount, b32 zero_out); + void *smrt_arena_mark_push(smrt_arena_t *arena, u64 alloc_amount, b32 zero_out); + void smrt_arena_pop(smrt_arena_t *arena, u64 pop_amount); + void smrt_arena_pop_to(smrt_arena_t *arena, u64 location); + b32 smrt_arena_pop_to_mark(smrt_arena_t *arena); + void smrt_arena_clear(smrt_arena_t *arena, b32 zero_out); + void smrt_arena_destroy(smrt_arena_t *arena); + +#define SMRTA_ALLOC_ARRAY(arena, T, n) (T*)smrt_arena_push(arena, sizeof(T) * (n), true) + +u32 plat_get_pagesize(void); + +void *plat_mem_reserve(u64 size); + b32 plat_mem_commit(void *ptr, u64 size); + b32 plat_mem_decommit(void *ptr, u64 size); + b32 plat_mem_release(void *ptr, u64 size); diff --git a/src/string.c b/src/string.c new file mode 100644 index 0000000..be96c63 --- /dev/null +++ b/src/string.c @@ -0,0 +1,25 @@ +#include "common.h" +#include "smrt_arena.h" +#include <string.h> + +#include "string.h" + +strng_t *strng_new(smrt_arena_t *arena, u64 size) { + strng_t *s = smrt_arena_push(arena, sizeof(strng_t) + size, true); + + if (!s) { + return NULL; + } + + s->alloc_size = size; + return s; +} + +strng_t *strng_from(smrt_arena_t *arena, char *c) { + u64 size = strlen(c); + + return strng_new(arena, size); +} + + b32 strng_set(strng_t *string, char *c); + void strng_clear(strng_t *string); diff --git a/src/string.h b/src/string.h new file mode 100644 index 0000000..1b5f136 --- /dev/null +++ b/src/string.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common.h" +#include "smrt_arena.h" + +#define STRNG_BASE_POS (sizeof(ez_arena_t)) + +typedef struct { + u64 alloc_size; + u64 len; +} strng_t; + +strng_t *strng_new(smrt_arena_t *arena, u64 size); +strng_t *strng_from(smrt_arena_t *arena, char *c); + b32 strng_set(strng_t *string, char *c); + void strng_clear(strng_t *string); + +#define STRNG_FMT(s) (int)s->len, (s+STRNG_BASE_POS) |