diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f51cef5..bd0a5a9 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ { "label": "build", "type": "shell", - "command": "${workspaceFolder}/build.sh && ./a.out", + "command": "${workspaceFolder}/build.sh && ./a.out 2>&1", "group": { "kind": "build", "isDefault": true diff --git a/src/arena.c b/src/arena.c index d18afed..81ec05a 100644 --- a/src/arena.c +++ b/src/arena.c @@ -13,6 +13,12 @@ static void memory_release(void *mem) free(mem); } +static INLINE U32 arena_absolute_pos(const Arena *arena) +{ + const Arena *current = arena->current; + return current->base_pos + current->pos; +} + Arena *arena_alloc_(const ArenaParams *params) { Assert(params->size > ARENA_HEADER_SZ); @@ -27,6 +33,7 @@ Arena *arena_alloc_(const ArenaParams *params) arena->current = arena; arena->size = params->size; arena->pos = ARENA_HEADER_SZ; + arena->base_pos = 0; arena->prev = NULL; return arena; @@ -35,10 +42,9 @@ Arena *arena_alloc_(const ArenaParams *params) void arena_free(Arena *arena) { Arena *it = arena->current; - Arena *prev = NULL; while (it != NULL) { - prev = it->prev; + Arena *prev = it->prev; memory_release(it); it = prev; } @@ -49,11 +55,11 @@ void *arena_push(Arena *arena, U32 size, U32 align) Assert(size < (U32_Max - align - ARENA_HEADER_SZ - 1)); Assert(IsPow2(align)); Arena *current = arena->current; - U32 start_pos = AlignUpPow2(arena->pos, align); + U32 start_pos = AlignUpPow2(current->pos, align); U32 available = arena_available(current); if (available < size) { - U32 new_size = current->size; + U32 new_size = arena->size; // original user requeted size if (new_size < size) { new_size = AlignUpPow2(size + ARENA_HEADER_SZ,align); } @@ -62,18 +68,57 @@ void *arena_push(Arena *arena, U32 size, U32 align) new_params.flags = current->flags; new_params.size = new_size; - Arena *new_arena = arena_alloc_(&new_params); - new_arena->prev = current; - current->current = new_arena; - current = new_arena; - start_pos = AlignUpPow2(current->pos, align); + Arena *new_arena = arena_alloc_(&new_params); + new_arena->base_pos = current->base_pos + current->size; + new_arena->prev = current; + arena->current = new_arena; + current = new_arena; + start_pos = AlignUpPow2(current->pos, align); } U32 end_pos = start_pos + size; Assert(end_pos <= current->size); U8 *mem = ¤t->base[start_pos]; - arena->pos = start_pos + size; + current->pos = end_pos; return mem; } + +void arena_pop_to(Arena *arena, U32 abs_pos) +{ + Arena *current = arena->current; + abs_pos = Max(ARENA_HEADER_SZ, abs_pos); + while (current) { + Arena *prev = current->prev; + + if (current->base_pos >= abs_pos) { + memory_release(current->base); + arena->current = prev; + } else { + U32 new_pos = abs_pos - current->base_pos; + // Note, when doing commit/release, new_pos <= current->pos + // is the right thing . shouldn't be able to pop to larger than what's already commited + Assert(new_pos <= current->size); + current->pos = new_pos; + break; + } + + current = prev; + } +} + +ArenaCheckPoint arena_temp_begin(Arena *arena) +{ + ArenaCheckPoint checkpoint = {}; + checkpoint.arena = arena; + checkpoint.absolute_pos = arena_absolute_pos(arena); + + return checkpoint; +} + +void arena_temp_end(ArenaCheckPoint *checkpoint) +{ + Arena *arena = checkpoint->arena; + arena_pop_to(arena, checkpoint->absolute_pos); +} diff --git a/src/arena.h b/src/arena.h index 33ab094..d196913 100644 --- a/src/arena.h +++ b/src/arena.h @@ -17,21 +17,31 @@ struct Arena { Arena *current; U8 *base; U32 size; - U32 pos; + U32 pos; // start of next allocation + U32 base_pos; // absolute position of base relative to the first linked arena ArenaFlags flags; Arena *prev; }; +typedef struct ArenaCheckPoint ArenaCheckPoint; +struct ArenaCheckPoint { + Arena *arena; + U32 absolute_pos; +}; + StaticAssert(sizeof(Arena) <= 64); -#define ARENA_HEADER_SZ 64 +#define ARENA_HEADER_SZ 64u -INLINE U32 arena_available(const Arena *arena) +static INLINE U32 arena_available(const Arena *arena) { return arena->size - arena->pos; } - Arena *arena_alloc_(const ArenaParams *params); void arena_free(Arena *arena); void *arena_push(Arena *arena, U32 size, U32 align); + +ArenaCheckPoint arena_temp_begin(Arena *arena); +void arena_temp_end(ArenaCheckPoint *checkpoint); +void arena_pop_to(Arena *arena, U32 abs_pos); diff --git a/src/main.c b/src/main.c index d20c6cf..03e30d0 100644 --- a/src/main.c +++ b/src/main.c @@ -9,16 +9,16 @@ void arena_dump(const Arena *arena) puts("@@@@@@@@@@"); while (arena) { puts("-----Arena-----"); - printf("base: %p\n", arena->base); - printf("size: %u\n", arena->size); - printf("pos: %u\n", arena->pos); + printf("base: %p\n", arena->base); + printf("size: %u\n", arena->size); + printf("pos: %u\n", arena->pos); + printf("base_pos: %u\n", arena->base_pos); printf("prev: %p\n", arena->prev); puts("-----Arena end-"); arena = arena->prev; } } - -int main(int argc, char *argv[]) +static void arena_test_1(void) { ArenaParams arena_params = {}; arena_params.size = 1024+ARENA_HEADER_SZ; @@ -39,3 +39,37 @@ int main(int argc, char *argv[]) arena_dump(arena); arena_free(arena); } +static void arena_test_2(void) +{ + ArenaParams arena_params = {}; + arena_params.size = 1024+ARENA_HEADER_SZ; + Arena *arena = arena_alloc_(&arena_params); + + void *ptr; + ptr = arena_push(arena, 1024, 8); + printf("Allocated ptr %p\n", ptr); + + arena_dump(arena); + ArenaCheckPoint checkpoint = arena_temp_begin(arena); + ptr = arena_push(arena, 4096, 8); + ptr = arena_push(arena, 4096, 8); + + ArenaCheckPoint checkpoint2 = arena_temp_begin(arena); + ptr = arena_push(arena, 64, 8); + arena_temp_end(&checkpoint2); + + arena_temp_end(&checkpoint); + arena_pop_to(arena, 1088); + arena_dump(arena); + ptr = arena_push(arena, 1, 1); + ptr = arena_push(arena, 1, 1); + arena_pop_to(arena, 1089); + arena_dump(arena); + + arena_free(arena); +} + +int main(int argc, char *argv[]) +{ + arena_test_2(); +}