#pragma once #include "Base.h" #include "error-codes.h" enum class Allocator_Mode: s32 { ALLOCATE = 0, RESIZE = 1, DEALLOCATE = 2, // IS_THIS_YOURS = 3, // DETAILS = 4, }; typedef void* (*Allocator_Proc)(Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data); struct Allocator { Allocator_Proc proc; void* data; bool operator ! () { return (proc == nullptr && data == nullptr); } }; // Public Allocator API: // Note that alignment is handled on a per-allocator basis. void* internal_alloc (s64 size); void internal_free (void* memory); void* internal_realloc (void* memory, s64 size, s64 old_size); template force_inline void Initialize (T* memory) { (*memory) = T(); } template T* New (Allocator allocator, bool initialize=true) { auto memory = (T*)allocator.proc(Allocator_Mode::ALLOCATE, sizeof(T), 0, nullptr, allocator.data); if (initialize) { (*memory) = T(); } return memory; } template T* New (bool initialize=true) { auto memory = (T*)internal_alloc(sizeof(T)); if (initialize) { (*memory) = T(); } return memory; } // For raw-pointer arrays. template T* NewArray (Allocator allocator, s64 count, bool initialize=true) { auto memory = (T*)allocator.proc(Allocator_Mode::ALLOCATE, count * sizeof(T), 0, nullptr, allocator.data); if (initialize) { for (s64 i = 0; i < count; i += 1) { memory[i] = T(); } } return memory; } template T* NewArray (s64 count, bool initialize=true) { auto memory = (T*)internal_alloc(count * sizeof(T)); if (initialize) { for (s64 i = 0; i < count; i += 1) { memory[i] = T(); } } return memory; } // Likely will rarely be used, if ever. See: internal_realloc template force_inline T* Resize (Allocator allocator, void* memory, s64 size, s64 old_size, bool initialize=true) { void* result = allocator.proc(Allocator_Mode::RESIZE, size, old_size, memory, allocator.data); return result; } // There's not really any reason for this to be a template force_inline void Delete (Allocator allocator, void* memory) { allocator.proc(Allocator_Mode::DEALLOCATE, 0, 0, memory, allocator.data); } // We use internal functions when we assume the user just wants to use the // current allocator on the context. // For Resizes and Deletes, use internal_realloc and internal_free. template void reset_struct (T* src) { (*src) = T(); } template void zero_struct(T* src) { memset(src, 0, sizeof(T)); } template T* copy_struct(T* src) { T* dst = New(false); memcpy(dst, src, sizeof(T)); }