Hello. I am writing obj file format parser with using memory arenas. So I need three types of arrays:vertices,textures,normals .Depends on which header I parsed I should push things into storage. When I first time thought how to do that push I wanted implement stretchy buffers. But then at discord I got advice to implement RESERVE/COMMIT style arena where I firstly reserve memory and then commit as I need. So I have some questions. 1) What I should consider when I choose default commit size and need I care about aligning? 2) When I pass 2GB with MEM_RESERVE flag to VirtualAlloc it doesn't allocate memory but when I pass 1GB all is okay. Why? 3) I doubt about correctnes of that way to push things:
push_array(&arena_for_vertices,float,3); vertices[0] = v0; vertices[1] = v1; vertices[2] = v2;
At the end of parsing I push things to "permanent" storage and doing memcpy what seems not good. Thanks for any reply and advice. Code:
int main(int argc, char *argv[]) { void *general_memory = VirtualAlloc(0, MB(512), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); ASSERT(general_memory); MemoryArena arena = {0}; init_arena(&arena, MB(512), general_memory); // TODO(shvayko): doesn't allocate 2GB memory void *memory_for_vertices = VirtualAlloc(0 ,GB(1), MEM_RESERVE,PAGE_READWRITE); ASSERT(memory_for_vertices); void *memory_for_textures = VirtualAlloc(0, GB(1), MEM_RESERVE,PAGE_READWRITE); ASSERT(memory_for_textures); void *memory_for_normals = VirtualAlloc(0, GB(1), MEM_RESERVE,PAGE_READWRITE); ASSERT(memory_for_normals); MemoryArena arena_for_vertices = {0}; MemoryArena arena_for_textures = {0}; MemoryArena arena_for_normals = {0}; init_arena(&arena_for_vertices, GB(1), memory_for_vertices); init_arena(&arena_for_textures, GB(1), memory_for_textures); init_arena(&arena_for_normals, GB(1), memory_for_normals); MeshData *mesh = push_size(&arena, MeshData); for(u32 lines_index = 0; lines_index < lines_total; lines_index++) { LineInfo *line = lines_info + lines_index; u8 *token = line->p; u32 line_length = line->length; u8 *end = token + line_length; while(token != end) { if((token[0] == 'v') && (token[1] == ' ')) { token++; f32 v0 = 0; f32 v1 = 0; f32 v2 = 0; token = ASCII_to_float(&token, &v0); token = ASCII_to_float(&token, &v1); token = ASCII_to_float(&token, &v2); float *vertices = push_array(&arena_for_vertices,float,3); vertices[0] = v0; vertices[1] = v1; vertices[2] = v2; vertices_count++; } } } // END PARSING // pushing into "permanent" storage and freeing "temps arenas" mesh->vertices = push_array(&arena,float, vertices_count); mesh->vertices = memcpy(mesh->vertices, arena_for_vertices.base, vertices_count*3*sizeof(float)); arena_release(&arena_for_vertices); } #define push_size(arena, type) (type*)push_size_(arena, sizeof(type)) #define push_array(arena, type, count) (type*)push_size_(arena, sizeof(type)*count) #define ALIGN_POW_2(x,p) (((x) + (p) - 1)&~((p) - 1)) #define DEFAULT_COMMIT_SIZE (MB(1)) void* push_size_(MemoryArena *arena, size_t size) { void *result = 0; ASSERT((arena->used+size) <= arena->size); result = arena->base + arena->used; arena->used += size; size_t commited = arena->commited; if(arena->used > commited) { size_t new_commited_size = ALIGN_POW_2(arena->used, MAX(size,DEFAULT_COMMIT_SIZE - 1));; VirtualAlloc(arena->base + commited,new_commited_size, MEM_COMMIT, PAGE_READWRITE); arena->commited += new_commited_size; } arena->size -= size; return result; } void arena_release(MemoryArena *arena) { ASSERT(arena); if(arena->base) { VirtualFree(arena->base,0,MEM_RELEASE); } }