100 lines
3.1 KiB
C
100 lines
3.1 KiB
C
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), alignof(T), 0, __FILE__, __LINE__))
|
|
#define arena_make(A, C, T) cast(T*, A(arena__alloc, sizeof(T) * (C), alignof(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 $
|