Skip to content

Instantly share code, notes, and snippets.

@Magicalbat
Last active May 3, 2026 23:53
Show Gist options
  • Select an option

  • Save Magicalbat/4e085cadeed46c7b6f917ea9e9220d6a to your computer and use it in GitHub Desktop.

Select an option

Save Magicalbat/4e085cadeed46c7b6f917ea9e9220d6a to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
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;
#define KiB(n) ((u64)(n) << 10)
#define MiB(n) ((u64)(n) << 20)
#define GiB(n) ((u64)(n) << 30)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define ALIGN_UP_POW2(n, p) (((u64)(n) + ((u64)(p) - 1)) & (~((u64)(p) - 1)))
#define ARENA_BASE_POS (sizeof(mem_arena))
#define ARENA_ALIGN (sizeof(void*))
typedef struct {
u64 reserve_size;
u64 commit_size;
u64 pos;
u64 commit_pos;
} mem_arena;
mem_arena* arena_create(u64 reserve_size, u64 commit_size);
void arena_destroy(mem_arena* arena);
void* arena_push(mem_arena* arena, u64 size, b32 non_zero);
void arena_pop(mem_arena* arena, u64 size);
void arena_pop_to(mem_arena* arena, u64 pos);
void arena_clear(mem_arena* arena);
#define PUSH_STRUCT(arena, T) (T*)arena_push((arena), sizeof(T), false)
#define PUSH_STRUCT_NZ(arena, T) (T*)arena_push((arena), sizeof(T), true)
#define PUSH_ARRAY(arena, T, n) (T*)arena_push((arena), sizeof(T) * (n), false)
#define PUSH_ARRAY_NZ(arena, T, n) (T*)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);
int main(void) {
mem_arena* perm_arena = arena_create(GiB(1), MiB(1));
while (1) {
arena_push(perm_arena, MiB(16), false);
getc(stdin);
}
arena_destroy(perm_arena);
return 0;
}
mem_arena* arena_create(u64 reserve_size, u64 commit_size) {
u32 pagesize = plat_get_pagesize();
reserve_size = ALIGN_UP_POW2(reserve_size, pagesize);
commit_size = ALIGN_UP_POW2(commit_size, pagesize);
mem_arena* 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->pos = ARENA_BASE_POS;
arena->commit_pos = commit_size;
return arena;
}
void arena_destroy(mem_arena* arena) {
plat_mem_release(arena, arena->reserve_size);
}
void* arena_push(mem_arena* arena, u64 size, b32 non_zero) {
u64 pos_aligned = ALIGN_UP_POW2(arena->pos, ARENA_ALIGN);
u64 new_pos = pos_aligned + size;
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 (!non_zero) {
memset(out, 0, size);
}
return out;
}
void arena_pop(mem_arena* arena, u64 size) {
size = MIN(size, arena->pos - ARENA_BASE_POS);
arena->pos -= size;
}
void arena_pop_to(mem_arena* arena, u64 pos) {
u64 size = pos < arena->pos ? arena->pos - pos : 0;
arena_pop(arena, size);
}
void arena_clear(mem_arena* arena) {
arena_pop_to(arena, ARENA_BASE_POS);
}
#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__)
#define _DEFAULT_SOURCE
#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
@isGavri
Copy link
Copy Markdown

isGavri commented Apr 8, 2026

having a PUSH_ARRAY_NO_ZERO version could save a lot of CPU cycles when the data is going to be immediately overwritten anyway.

It does have a PUSH_ARRAY_NZ.

#define PUSH_STRUCT(arena, T) (T*)arena_push((arena), sizeof(T), false)
#define PUSH_STRUCT_NZ(arena, T) (T*)arena_push((arena), sizeof(T), true)
#define PUSH_ARRAY(arena, T, n) (T*)arena_push((arena), sizeof(T) * (n), false)
#define PUSH_ARRAY_NZ(arena, T, n) (T*)arena_push((arena), sizeof(T) * (n), true)

And inside arena_push

    if (!non_zero) {
        memset(out, 0, size);
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment