/* 4coder_arena.cpp - Preversioning no warranty implied; use at your own risk This software is in the public domain. Where that dedication is not recognized, you are granted a perpetual, irrevocable license to copy, distribute, and modify this file as you see fit. */ // TOP #if !defined(Migrating__Arena) static Partition make_part(void *memory, i32 size){ Partition part = {}; part.base = (char*)memory; part.pos = 0; part.max = size; return(part); } static void* part_allocate(Partition *data, i32 size){ void *ret = 0; if (size < 0){ size = 0; } if (data->pos + size <= data->max){ ret = data->base + data->pos; data->pos += size; } return(ret); } static void part_reduce(Partition *data, i32 size){ if (size > 0 && size <= data->pos){ data->pos -= size; } } static void part_align(Partition *data, i32 boundary){ i32 p = data->pos; p += boundary - 1; data->pos = p - p%boundary; } static void* part_current(Partition *data){ return(data->base + data->pos); } static i32 part_remaining(Partition *data){ return(data->max - data->pos); } static Partition part_sub_part(Partition *data, i32 size){ Partition result = {}; void *d = part_allocate(data, size); if (d != 0){ result = make_part(d, size); } return(result); } static Temp_Memory begin_temp_memory(Partition *data){ Temp_Memory result = {}; result.part = data; result.pos = data->pos; return(result); } static void end_temp_memory(Temp_Memory temp){ temp.part->pos = temp.pos; } static void* push_allocator_allocate(Partition *part, i32 size){ return(part_allocate(part, size)); } static void push_allocator_align(Partition *part, i32 b){ part_align(part, b); } //////////////////////////////// #if defined(FCODER_CUSTOM_H) static Arena make_arena(Application_Links *app, i32 chunk_size, i32 initial_align){ Arena arena = {}; arena.app = app; arena.chunk_size = chunk_size; arena.align = initial_align; return(arena); } static Arena make_arena(Application_Links *app, i32 chunk_size){ return(make_arena(app, chunk_size, 1)); } static Arena make_arena(Application_Links *app){ return(make_arena(app, 4096, 1)); } static void arena_release_all(Arena *arena){ Application_Links *app = arena->app; for (Partition_Chained *part = arena->part, *prev = 0; part != 0; part = prev){ prev = part->prev; memory_free(app, part, part->part.max); } arena->part = 0; } static void arena_change_chunk_size(Arena *arena, i32 chunk_size){ arena->chunk_size = chunk_size; } static Partition_Chained* arena__new_part(Arena *arena, i32 new_chunk_size){ Application_Links *app = arena->app; i32 memory_size = new_chunk_size + sizeof(Partition_Chained); i32 boundardy = 4096; if (memory_size < boundardy){ memory_size = boundardy; } else{ memory_size = memory_size + boundardy - 1; memory_size = memory_size - memory_size%boundardy; } void *memory = memory_allocate(app, memory_size); Partition_Chained *part = (Partition_Chained*)memory; part->part = make_part(memory, memory_size); part_allocate(&part->part, sizeof(*part)); part->prev = arena->part; arena->part = part; return(part); } static Partition_Chained* arena__new_part(Arena *arena){ return(arena__new_part(arena, arena->chunk_size)); } static void arena__align_inner(Arena *arena, i32 b){ if (arena->align != 1){ Partition_Chained *part = arena->part; if (part == 0){ part = arena__new_part(arena); } part_align(&part->part, b); } } static void* arena_allocate(Arena *arena, i32 size){ void *result = 0; Partition_Chained *part = arena->part; if (part == 0){ part = arena__new_part(arena); } arena__align_inner(arena, arena->align); result = part_allocate(&part->part, size); if (result == 0){ i32 new_chunk_size = arena->chunk_size; if (size > new_chunk_size){ new_chunk_size = size; } part = arena__new_part(arena, new_chunk_size); arena__align_inner(arena, arena->align); result = part_allocate(&part->part, size); } arena->align = 1; return(result); } static void arena_align(Arena *arena, i32 b){ arena__align_inner(arena, b); arena->align = b; } static Partition* arena_use_as_part(Arena *arena, i32 minimum_part_size){ if (minimum_part_size < arena->chunk_size){ minimum_part_size = arena->chunk_size; } Partition_Chained *part = arena->part; if (part == 0){ part = arena__new_part(arena, minimum_part_size); } else{ if (part_remaining(&part->part) < minimum_part_size){ part = arena__new_part(arena, minimum_part_size); } } return(&part->part); } static Temp_Memory_Arena begin_temp_memory(Arena *arena){ Temp_Memory_Arena result = {}; result.arena = arena; result.part = arena->part; if (result.part != 0){ result.pos = result.part->part.pos; } return(result); } static void end_temp_memory(Temp_Memory_Arena temp){ Application_Links *app = temp.arena->app; for (Partition_Chained *part = temp.arena->part, *prev = 0; part != temp.part; part = prev){ prev = part->prev; memory_free(app, part, part->part.max); } temp.arena->part = temp.part; if (temp.part != 0){ temp.part->part.pos = temp.pos; } } static Temp_Memory_Arena_Light temp_memory_light(Temp_Memory_Arena temp){ Temp_Memory_Arena_Light light = {}; light.part = temp.part; light.pos = temp.pos; return(light); } static void end_temp_memory(Arena *arena, Temp_Memory_Arena_Light temp){ Temp_Memory_Arena full_temp = {}; full_temp.arena = arena; full_temp.part = temp.part; full_temp.pos = temp.pos; end_temp_memory(full_temp); } static void* push_allocator_allocate(Arena *arena, i32 size){ return(arena_allocate(arena, size)); } static void push_allocator_align(Arena *arena, i32 b){ arena_align(arena, b); } //////////////////////////////// Scratch_Block::Scratch_Block(Application_Links *app){ scratch = context_get_arena(app); temp = begin_temp_memory(scratch); } Scratch_Block::~Scratch_Block(){ end_temp_memory(temp); } Scratch_Block::operator Arena*(){ return(scratch); } #endif //////////////////////////////// #define push_array(A, T, size) (T*)push_allocator_allocate((A), sizeof(T)*(size)) #define push_align(A, b) push_allocator_align((A), (b)) #define reset_temp_memory end_temp_memory #endif // BOTTOM