BlockArena, a bit of allocator rework
This commit is contained in:
@@ -1,5 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
struct LocationTrace {
|
||||
char *file;
|
||||
int line;
|
||||
};
|
||||
|
||||
#if DEBUG_BUILD
|
||||
thread_local LocationTrace LocationTraceO;
|
||||
#define LOCATION_TRACE (LocationTraceO.file = __FILE__, LocationTraceO.line = __LINE__)
|
||||
#else
|
||||
#define LOCATION_TRACE
|
||||
#endif
|
||||
|
||||
const int AllocatorKind_Allocate = 1;
|
||||
const int AllocatorKind_Deallocate = 2;
|
||||
|
||||
@@ -10,29 +22,47 @@ struct Allocator {
|
||||
|
||||
#define AllocType(alo, Type) (Type *)AllocSize(alo, sizeof(Type))
|
||||
#define AllocArray(alo, Type, count) (Type *)AllocSize(alo, sizeof(Type) * (count))
|
||||
inline void *AllocSize(Allocator alo, size_t size) {
|
||||
void *result = alo.proc(alo.object, AllocatorKind_Allocate, NULL, size);
|
||||
memset(result, 0, size);
|
||||
return result;
|
||||
}
|
||||
#define AllocSize(alo, size) (LOCATION_TRACE, _AllocSize_(alo, size))
|
||||
API void *_AllocSize_(Allocator alo, size_t size);
|
||||
inline void Dealloc(Allocator alo, void *p) { if (p) (alo).proc((alo).object, AllocatorKind_Deallocate, (p), 0); }
|
||||
|
||||
template <class T>
|
||||
void Dealloc(Allocator alo, T **p) {
|
||||
if (*p == NULL) return;
|
||||
alo.proc(alo.object, AllocatorKind_Deallocate, *p, 0);
|
||||
*p = NULL;
|
||||
}
|
||||
#define DeallocEx(alo, p) (alo).proc((alo).object, AllocatorKind_Deallocate, (p), 0);
|
||||
API Allocator GetSystemAllocator();
|
||||
API void TrackingAllocatorCheck();
|
||||
API Allocator GetTrackingAllocator();
|
||||
|
||||
Allocator GetSystemAllocator();
|
||||
#define MemoryZero(x, size) memset(x, 0, size)
|
||||
#define MemoryCopy(dst, src, size) memcpy(dst, src, size)
|
||||
#define MemoryMove(dst, src, size) memmove(dst, src, size)
|
||||
|
||||
const int PAGE_SIZE = 4096;
|
||||
const int DEFAULT_ALIGNMENT = sizeof(void *);
|
||||
///////////////////
|
||||
// Block Arena
|
||||
///////////////////
|
||||
API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size);
|
||||
|
||||
struct Arena {
|
||||
struct BlockArenaNode {
|
||||
BlockArenaNode *next;
|
||||
U8 *end;
|
||||
U8 start[0];
|
||||
};
|
||||
|
||||
struct BlockArena {
|
||||
U8 *start;
|
||||
U8 *end;
|
||||
BlockArenaNode *blocks;
|
||||
Allocator allocator;
|
||||
|
||||
operator Allocator() { return {BlockArenaAllocatorProc, this}; }
|
||||
};
|
||||
|
||||
API void *PushSize(BlockArena *arena, size_t size);
|
||||
API void Release(BlockArena *arena);
|
||||
API void Unwind(BlockArena *arena, U8 *pos);
|
||||
|
||||
///////////////////
|
||||
// Virtual Arena
|
||||
///////////////////
|
||||
|
||||
struct VirtualArena {
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
size_t base_len; // to prevent self deleting the arena
|
||||
@@ -46,50 +76,40 @@ struct Arena {
|
||||
}
|
||||
};
|
||||
|
||||
struct TempArena {
|
||||
Arena *arena;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
inline void SetLen(Arena *arena, size_t len) { arena->len = Clamp(len, arena->base_len, arena->len); }
|
||||
inline void Pop(Arena *arena, size_t size) { SetLen(arena, arena->len - size); }
|
||||
inline TempArena BeginTemp(Arena *arena) { return {arena, arena->len}; }
|
||||
inline void EndTemp(TempArena temp) { SetLen(temp.arena, temp.len); }
|
||||
inline void Clear(Arena *arena) { SetLen(arena, 0); }
|
||||
inline void SetLen(VirtualArena *arena, size_t len) { arena->len = Clamp(len, arena->base_len, arena->len); }
|
||||
inline void Pop(VirtualArena *arena, size_t size) { SetLen(arena, arena->len - size); }
|
||||
inline void Clear(VirtualArena *arena) { SetLen(arena, 0); }
|
||||
|
||||
void *VReserve(size_t size);
|
||||
bool VCommit(void *p, size_t size);
|
||||
bool VRelease(void *p, size_t size);
|
||||
bool VDecommit(void *p, size_t size);
|
||||
API void *VReserve(size_t size);
|
||||
API bool VCommit(void *p, size_t size);
|
||||
API bool VRelease(void *p, size_t size);
|
||||
API bool VDecommit(void *p, size_t size);
|
||||
|
||||
void InitArena(Arena *arena, size_t reserve = MiB(256));
|
||||
Arena *AllocArena(size_t reserve = MiB(256));
|
||||
Arena *AllocArena(Allocator allocator, size_t size);
|
||||
void *PushSize(Arena *arena, size_t size);
|
||||
void Release(Arena *arena);
|
||||
void InitScratch();
|
||||
TempArena GetScratchEx(Arena **conflicts, int conflict_count);
|
||||
API void InitArena(VirtualArena *arena, size_t reserve = MiB(256));
|
||||
API VirtualArena *AllocArena(size_t reserve = MiB(256));
|
||||
API VirtualArena *AllocArena(Allocator allocator, size_t size);
|
||||
API void *PushSize(VirtualArena *arena, size_t size);
|
||||
API void Release(VirtualArena *arena);
|
||||
|
||||
inline TempArena GetScratch(Arena *c1 = NULL, Arena *c2 = NULL) {
|
||||
int count = c1 ? 1 : 0;
|
||||
count += c2 ? 1 : 0;
|
||||
Arena *conflicts[] = {c1, c2};
|
||||
return GetScratchEx(conflicts, count);
|
||||
}
|
||||
///////////////////////////////
|
||||
// Scratch
|
||||
|
||||
struct Scratch {
|
||||
TempArena checkpoint;
|
||||
Scratch() { this->checkpoint = GetScratch(); }
|
||||
|
||||
Scratch(Arena *conflict) { this->checkpoint = GetScratch(conflict); }
|
||||
Scratch(Arena *c1, Arena *c2) { this->checkpoint = GetScratch(c1, c2); }
|
||||
Scratch(Allocator conflict) { this->checkpoint = GetScratch((Arena *)conflict.object); }
|
||||
Scratch(Allocator c1, Allocator c2) { this->checkpoint = GetScratch((Arena *)c1.object, (Arena *)c2.object); }
|
||||
~Scratch() { EndTemp(checkpoint); }
|
||||
operator Arena *() { return checkpoint.arena; }
|
||||
operator Allocator() { return *checkpoint.arena; }
|
||||
BlockArena arena = {};
|
||||
Scratch() {}
|
||||
Scratch(BlockArena *conflict) {}
|
||||
Scratch(BlockArena *c1, BlockArena *c2) {}
|
||||
Scratch(Allocator conflict) {}
|
||||
Scratch(Allocator c1, Allocator c2) {}
|
||||
~Scratch() { Release(&arena); }
|
||||
operator BlockArena *() { return &arena; }
|
||||
operator Allocator() { return arena; }
|
||||
|
||||
private: // @Note: Disable copy constructors, cause its error prone
|
||||
Scratch(Scratch &arena);
|
||||
Scratch(Scratch &arena, Scratch &a2);
|
||||
};
|
||||
};
|
||||
|
||||
const int PAGE_SIZE = 4096;
|
||||
const int DEFAULT_ALIGNMENT = sizeof(void *);
|
||||
Reference in New Issue
Block a user