global const SizeU default_reserve_size = gib(4); global const SizeU default_alignment = 8; global const SizeU additional_commit_size = mib(1); function SizeU align_up(SizeU size, SizeU align); function void memory_copy(void *dst, void *src, SizeU size){ U8 *d = (U8*)dst; U8 *s = (U8*)src; for(SizeU i = 0; i < size; i++){ d[i] = s[i]; } } function void memory_zero(void *p, SizeU size){ U8 *pp = (U8 *)p; for(SizeU i = 0; i < size; i++) pp[i] = 0; } function int max_int(int a, int b){ if(a>b) return a; return b; } 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_push_copy(Arena *a, void *pointer, SizeU size){ void *result = arena_push_size(a, size); memory_copy(result, pointer, size); return result; } function SizeU clamp_top_sizeu(SizeU val, SizeU max){ if(val>max)return max; return val; } 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); S64 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; String res = {(U8 *)result, len}; return res; } #define STRING_FMT(arena, str, result) \ va_list args1; \ va_start(args1, str); \ String result = string_fmtv(arena, str, args1); \ va_end(args1) function String string_fmt(Arena *arena, const char *str, ...) { STRING_FMT(arena, str, result); return result; } function void string_listf(Arena *arena, String_List *list, const char *str, ...){ STRING_FMT(arena, str, string); String_Node *node = arena_push_struct(arena, String_Node); node->string = string; SLLQueuePush(list->first, list->last, node); list->char_count += node->string.len; list->node_count += 1; } function String string_list_flatten(Arena *arena, String_List *list){ String result = {(U8 *)arena_push_size(arena, list->char_count + 1)}; for(String_Node *node = list->first; node; node=node->next){ memory_copy(result.str+result.len, node->str, node->len); result.len += node->len; } return result; }