119 lines
3.0 KiB
C++
119 lines
3.0 KiB
C++
#pragma once
|
|
|
|
#include "Base.h"
|
|
|
|
#define ALLOCATOR_DEBUG_MODE 1
|
|
#define ALLOCATOR_POISON_MEMORY_ON_ALLOCATION \
|
|
(BUILD_DEBUG && ALLOCATOR_DEBUG_MODE)
|
|
|
|
#if ALLOCATOR_POISON_MEMORY_ON_ALLOCATION
|
|
#define ALLOCATOR_INIT_VALUE 0xCD
|
|
#else
|
|
#define ALLOCATOR_INIT_VALUE 0
|
|
#endif
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
// 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 <typename T> force_inline void Initialize (T* memory) { (*memory) = T(); }
|
|
|
|
template <typename T> 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 <typename T> T* New (bool initialize=true) {
|
|
auto memory = (T*)internal_alloc(sizeof(T));
|
|
|
|
if (initialize) {
|
|
(*memory) = T();
|
|
}
|
|
|
|
return memory;
|
|
}
|
|
|
|
// For raw-pointer arrays.
|
|
template <typename T> 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 <typename T> 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 <typename T> 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 <typename T> void reset_struct (T* src) {
|
|
(*src) = T();
|
|
}
|
|
|
|
template <typename T> void zero_struct(T* src) {
|
|
memset(src, 0, sizeof(T));
|
|
}
|
|
|
|
template <typename T> void poison_struct(T* src) {
|
|
memset(src, 0xCD, sizeof(T));
|
|
}
|
|
|
|
template <typename T> T* copy_struct(T* src) {
|
|
T* dst = New<T>(false);
|
|
memcpy(dst, src, sizeof(T));
|
|
}
|
|
|