commit - afccd2672f33f8db43d1d7290f7c0c25daaecef2
commit + 1a06caead69676af14aec4f145173cd819caf17d
blob - af1bf32c978a6307eeb41f46b079b5affe93f477
blob + a1a15aebc088f0eccd463e74c523616e8a1a64d6
--- include/lfmemory.h
+++ include/lfmemory.h
#define LF_DEFAULT_ALIGNMENT (2*sizeof(void*))
#endif // LF_DEFAULT_ALIGNMENT
+#ifndef LF_ARENA_MAX_SAVE_POINTS
+#define LF_ARENA_MAX_SAVE_POINTS 32
+#endif
+
typedef struct {
unsigned char* buf;
size_t buf_sz;
size_t offset_cur;
size_t offset_prev;
+
+ size_t save_stack[LF_ARENA_MAX_SAVE_POINTS];
+ size_t save_count;
} ArenaAllocator;
void arena_init(ArenaAllocator *allocator, size_t buf_sz);
void arena_resize_buf(ArenaAllocator *allocator, size_t new_sz);
void *arena_resize(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz);
void arena_clear(ArenaAllocator *allocator);
+int arena_save(ArenaAllocator *allocator);
+void arena_restore(ArenaAllocator *allocator);
typedef struct {
unsigned char *buf;
blob - 83289bdda46e17a6c8bf99a1fbcdf72cef59c53c
blob + 627dbf52c50beebcc40de79d911dd68f39120235
--- src/memory.c
+++ src/memory.c
allocator->buf_sz = buf_sz;
allocator->offset_cur = 0;
allocator->offset_prev = 0;
+ allocator->save_count = 0;
}
void arena_free(ArenaAllocator *allocator) {
allocator->buf_sz = 0;
allocator->offset_cur = 0;
allocator->offset_prev = 0;
+ allocator->save_count = 0;
}
void arena_clear(ArenaAllocator *allocator) {
allocator->offset_cur = 0;
allocator->offset_prev = 0;
+ allocator->save_count = 0;
}
+int arena_save(ArenaAllocator *allocator) {
+ if (allocator->save_count >= LF_ARENA_MAX_SAVE_POINTS) {
+ return -1;
+ }
+ allocator->save_stack[allocator->save_count++] = allocator->offset_cur;
+ return 0;
+}
+
+void arena_restore(ArenaAllocator *allocator) {
+ if (allocator->save_count == 0) {
+ return;
+ }
+ allocator->offset_cur = allocator->save_stack[--allocator->save_count];
+ allocator->offset_prev = allocator->offset_cur;
+}
+
static uintptr_t align_forward(const uintptr_t ptr, const uintptr_t align) {
if (!is_power_of_two(align)) {
return 0;
blob - 11d06ce65252457ffd479c6d1f893f96c1b21ca5
blob + 6fc0580bc98896e1b56234a8c7a163f12e7c9289
--- tests/test_memory.c
+++ tests/test_memory.c
pool_destroy(pool);
+ /* arena save/restore */
+ ArenaAllocator save_arena;
+ arena_init(&save_arena, 512);
+
+ int *perm1 = arena_malloc(&save_arena, sizeof(int));
+ *perm1 = 100;
+ int *perm2 = arena_malloc(&save_arena, sizeof(int));
+ *perm2 = 200;
+
+ /* save, do temp work, restore */
+ ASSERT_EQ(arena_save(&save_arena), 0);
+ size_t saved_offset = save_arena.offset_cur;
+
+ int *tmp1 = arena_malloc(&save_arena, sizeof(int));
+ *tmp1 = 999;
+ int *tmp2 = arena_malloc(&save_arena, sizeof(int));
+ *tmp2 = 888;
+ ASSERT_TRUE(save_arena.offset_cur > saved_offset);
+
+ arena_restore(&save_arena);
+ ASSERT_EQ(save_arena.offset_cur, saved_offset);
+
+ /* permanent data still intact */
+ ASSERT_EQ(*perm1, 100);
+ ASSERT_EQ(*perm2, 200);
+
+ /* new alloc reuses temp space */
+ int *perm3 = arena_malloc(&save_arena, sizeof(int));
+ *perm3 = 300;
+ ASSERT_NOT_NULL(perm3);
+
+ /* nested save/restore */
+ arena_clear(&save_arena);
+ int *outer = arena_malloc(&save_arena, sizeof(int));
+ *outer = 1;
+
+ ASSERT_EQ(arena_save(&save_arena), 0);
+ size_t outer_offset = save_arena.offset_cur;
+
+ int *mid = arena_malloc(&save_arena, sizeof(int));
+ *mid = 2;
+
+ ASSERT_EQ(arena_save(&save_arena), 0);
+ size_t inner_offset = save_arena.offset_cur;
+
+ int *inner = arena_malloc(&save_arena, sizeof(int));
+ *inner = 3;
+
+ arena_restore(&save_arena);
+ ASSERT_EQ(save_arena.offset_cur, inner_offset);
+
+ arena_restore(&save_arena);
+ ASSERT_EQ(save_arena.offset_cur, outer_offset);
+
+ ASSERT_EQ(*outer, 1);
+
+ /* restore on empty stack is a no-op */
+ arena_restore(&save_arena);
+ ASSERT_EQ(save_arena.offset_cur, outer_offset);
+
+ arena_free(&save_arena);
+
TEST_REPORT();
}