169 lines
5.3 KiB
C++
169 lines
5.3 KiB
C++
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
|
global General_Allocator gAllocator; // @Shared
|
|
global Mutex allocator_mutex;
|
|
#endif
|
|
|
|
#if !COMPILER_MSVC
|
|
// Note: There is *no* std::aligned_realloc. Must implement manually if needed.
|
|
force_inline void* gp_aligned_realloc(u64 old_size, void* ptr, u64 new_size, u64 alignment) {
|
|
if (!ptr || old_size == 0) return std::aligned_alloc(alignment, new_size);
|
|
if (new_size == 0) { std::free(ptr); return nullptr; }
|
|
|
|
// Allocate new block
|
|
void* new_ptr = std::aligned_alloc(alignment, new_size);
|
|
if (!new_ptr) return nullptr;
|
|
|
|
u64 copy_size = old_size < new_size ? old_size : new_size;
|
|
memcpy(new_ptr, ptr, copy_size);
|
|
|
|
std::free(ptr);
|
|
return new_ptr;
|
|
}
|
|
#endif
|
|
|
|
|
|
General_Allocator* get_general_allocator_data() {
|
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
|
return &gAllocator;
|
|
#else
|
|
return (General_Allocator*)nullptr;
|
|
#endif
|
|
}
|
|
|
|
constexpr s64 Allocation_Tracking_Is_Enabled = GP_ALLOCATOR_TRACK_ALLOCATIONS;
|
|
|
|
bool GPAllocator_Tracking_Enabled () {
|
|
return Allocation_Tracking_Is_Enabled != 0;
|
|
}
|
|
|
|
void GPAllocator_Initialize_Allocation_Tracker () {
|
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
|
mutex_init(&allocator_mutex);
|
|
constexpr s64 alignment = 64;
|
|
s64 item_count_max = 64 * 4096;
|
|
s64 total_allocation_size = item_count_max * sizeof(Allocation);
|
|
auto memory = Aligned_Alloc(total_allocation_size, alignment); // @MemoryLeak (intentional)
|
|
gAllocator.allocations = Array<Allocation>(item_count_max, memory, item_count_max, GPAllocator());
|
|
gAllocator.allocations.count = 0; // Init to zero.
|
|
#endif
|
|
}
|
|
|
|
bool GPAllocator_Is_This_Yours (void* old_memory) {
|
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
|
lock_guard(&allocator_mutex);
|
|
|
|
s64 old_size = 0;
|
|
for (s64 i = 0; i < gAllocator.allocations.count; i += 1) {
|
|
if (gAllocator.allocations[i].memory != old_memory)
|
|
continue;
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void Add_Allocation(s64 new_size, void* new_memory_address, s32 alignment) {
|
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
|
if (new_memory_address == nullptr) return;
|
|
|
|
lock_guard(&allocator_mutex);
|
|
Allocation allocation = {new_size, new_memory_address, alignment};
|
|
array_add(gAllocator.allocations, allocation);
|
|
|
|
gAllocator.total_bytes_allocated += new_size;
|
|
#endif
|
|
}
|
|
|
|
void Remove_Allocation(void* old_memory) {
|
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
|
lock_guard(&allocator_mutex);
|
|
|
|
s64 old_size = 0;
|
|
for (s64 i = 0; i < gAllocator.allocations.count; i += 1) {
|
|
if (gAllocator.allocations[i].memory != old_memory)
|
|
continue;
|
|
old_size = gAllocator.allocations[i].size;
|
|
array_unordered_remove_by_index(gAllocator.allocations, i);
|
|
|
|
gAllocator.total_bytes_allocated -= old_size;
|
|
return;
|
|
}
|
|
|
|
Assert(false); // "Did not find allocation in Array"
|
|
#endif
|
|
}
|
|
|
|
void* GPAllocator_New (s64 new_size, s64 alignment, bool initialize) {
|
|
// Fallback allocator: _aligned_malloc, which is MSVC's version of std::aligned_alloc
|
|
|
|
auto memory = Aligned_Alloc(new_size, alignment);
|
|
// _aligned_malloc does not zero memory, so we can zero it here
|
|
if (initialize && memory) { memset(memory, ALLOCATOR_INIT_VALUE, new_size); }
|
|
Add_Allocation(new_size, memory, (s32)alignment);
|
|
|
|
// printf("[GP] Allocating memory %p of size %llu\n", memory, new_size);
|
|
|
|
return memory;
|
|
}
|
|
|
|
void* GPAllocator_Resize (s64 old_size, void* old_memory, s64 new_size, s64 alignment, bool initialize) {
|
|
Assert((alignment % 8) == 0 && (alignment != 0));
|
|
|
|
if (old_memory == nullptr) {
|
|
return GPAllocator_New(new_size, alignment);
|
|
}
|
|
|
|
// Debug version: _aligned_realloc_dbg
|
|
auto new_memory_address = Aligned_Realloc(old_size, old_memory, new_size, alignment);
|
|
|
|
if (initialize && new_memory_address && new_size > old_size) {
|
|
memset((u8*)new_memory_address + old_size, ALLOCATOR_INIT_VALUE, new_size - old_size);
|
|
}
|
|
Remove_Allocation(old_memory);
|
|
Add_Allocation(new_size, new_memory_address, (s32)alignment);
|
|
|
|
// printf("[GP] Rellocating memory %p of size %llu\n", new_memory_address, new_size);
|
|
|
|
return new_memory_address;
|
|
}
|
|
|
|
void GPAllocator_Delete (void* memory) {
|
|
if (memory == nullptr) return;
|
|
Aligned_Free(memory);
|
|
Remove_Allocation(memory);
|
|
|
|
// printf("[GP] Deleting memory %p\n", memory);
|
|
}
|
|
|
|
Allocator GPAllocator () {
|
|
return { GPAllocator_Proc, nullptr };
|
|
}
|
|
|
|
void* GPAllocator_Proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data) {
|
|
u16 alignment = 16; // default alignment
|
|
|
|
Thread_Context* context = thread_context();
|
|
if (context) alignment = context->GPAllocator_alignment;
|
|
|
|
switch (mode) {
|
|
case Allocator_Mode::ALLOCATE: {
|
|
return GPAllocator_New(requested_size, alignment);
|
|
} break;
|
|
case Allocator_Mode::RESIZE: {
|
|
void* result = GPAllocator_Resize(old_size, old_memory, requested_size, alignment);
|
|
// NOTE: The _aligned_realloc function already copies the old memory, so there's
|
|
// no need to copy the old memory block here.
|
|
return result;
|
|
} break;
|
|
case Allocator_Mode::DEALLOCATE: {
|
|
GPAllocator_Delete(old_memory); // unused
|
|
} break;
|
|
case Allocator_Mode::DETAILS: {
|
|
Assert(allocator_data == nullptr);
|
|
return "GPAllocator";
|
|
} break;
|
|
}
|
|
|
|
return nullptr;
|
|
} |