global const SizeU default_reserve_size = gib(4); global const SizeU default_alignment = 8; global const SizeU additional_commit_size = mib(1); function void memory_copy(U8 *dst, U8 *src, SizeU size){ for(SizeU i = 0; i < size; i++){ dst[i] = src[i]; } } function void memory_zero(void *p, SizeU size){ U8 *pp = p; for(SizeU i = 0; i < size; i++) pp[i] = 0; } function void arena_init(Arena *a){ a->memory = os_reserve(default_reserve_size); a->alignment = default_alignment; } function void * arena_push_size(Arena *a, SizeU size){ SizeU generous_size = size; if(a->memory.commit+generous_size>a->memory.commit){ if(a->memory.reserve == 0){ arena_init(a); } os_commit(&a->memory, generous_size+additional_commit_size); } a->len = align_up(a->len, a->alignment); void *result = (U8*)a->memory.data + a->len; a->len += size; memory_zero(result, size); return result; } function void arena_pop_pos(Arena *arena, SizeU pos){ pos = clamp_top_sizeu(pos, arena->len); arena->len = pos; } function Arena_Checkpoint arena_checkpoint(Arena *arena){ Arena_Checkpoint result = {arena, arena->len}; return result; } function void arena_restore(Arena_Checkpoint checkpoint){ arena_pop_pos(checkpoint.arena, checkpoint.pos); } function String arena_push_string_copy(Arena *arena, String string){ U8 *copy = arena_push_array(arena, U8, string.len+1); memory_copy(copy, string.str, string.len); copy[string.len] = 0; return (String){copy, string.len}; } function String string_fmtv(Arena *arena, const char *str, va_list args1) { va_list args2; va_copy(args2, args1); U64 len = vsnprintf(0, 0, str, args2); va_end(args2); char *result = (char *)arena_push_size(arena, len + 1); vsnprintf(result, len + 1, str, args1); if (arena->len > 0) arena->len -= 1; return (String){(U8 *)result, len}; } function String string_fmt(Arena *arena, const char *str, ...) { va_list args1; va_start(args1, str); String result = string_fmtv(arena, str, args1); va_end(args1); return result; }