typedef enum { arena__alloc, arena__reset, arena__save, arena__restore, arena__release } arena__action; typedef closure(void*, arena__action, uword, uword, void*, const char*, sword) Arena; #define arena_new(A, T) cast(T*, A(arena__alloc, sizeof(T), ualign_of(T), 0, __FILE__, __LINE__)) #define arena_make(A, C, T) cast(T*, A(arena__alloc, sizeof(T) * (C), ualign_of(T), 0, __FILE__, __LINE__)) #define arena_reset(A) A(arena__reset, 0, 0, 0, __FILE__, __LINE__) #define arena_release(A) A(arena__release, 0, 0, 0, __FILE__, __LINE__) #define arena_save(A, SP) A(arena__save, 0, 0, (SP), __FILE__, __LINE__) #define arena_restore(A, SP) A(arena__restore, 0, 0, (SP), __FILE__, __LINE__) // tiny macro to make arenas easier to declare #define $(a1, a2, a3, a4, a5, a6) ^void* (arena__action a1, uword a2, uword a3, void* a4, const char* a5, sword a6) static Arena Static(u8* data, uword count) { memset(data, 0, count); capture uword offset = 0; return persist($(action, size, align, savepoint, _2, _3) { switch (action) { default: { } break; case arena__alloc: { offset = (offset + align - 1) & ~(align - 1); if (offset + size > count) { return 0; } void* ptr = data + offset; offset += size; return ptr; } break; case arena__reset: { offset = 0; } break; case arena__save: { assert(savepoint != NULL && "Static: savepoint was null"); *cast(uword*, savepoint) = offset; } break; case arena__restore: { assert(savepoint != NULL && "Static: savepoint was null"); offset = *cast(uword*, savepoint); } break; } return 0; }); } static Arena Linear(uword max_memory) { void* ptr = malloc(max_memory); Arena backing = Static(ptr, max_memory); return persist($(action, size, align, savepoint, file, line) { if (action == arena__release) { free(ptr); return 0; } return backing(action, size, align, savepoint, file, line); }); } static Arena Logger(Arena arena) { return persist($(action, size, align, savepoint, file, line) { char* action_str = "unknown"; switch (action) { case arena__alloc: action_str = "alloc"; break; case arena__reset: action_str = "reset"; break; case arena__release: action_str = "release"; break; case arena__save: action_str = "save"; break; case arena__restore: action_str = "restore"; break; } printf("[ARENA] %s:%d: %s (%d, %d)\n", file, cast(int, line), action_str, cast(int, size), cast(int, align)); return arena(action, size, align, savepoint, file, line); }); } static Arena Region(Arena arena) { capture uword savepoint = 0; arena_save(arena, &savepoint); return persist($(action, size, align, _, file, line) { if (action == arena__reset || action == arena__restore) { return arena(arena__restore, size, align, &savepoint, file, line); } return arena(action, size, align, &savepoint, file, line); }); } #undef $