#pragma once

#define GP_ALLOCATOR_TRACK_ALLOCATIONS BUILD_DEBUG
#define GP_ALLOCATOR_VERY_DEBUG BUILD_DEBUG && 0

#if COMPILER_MSVC
    #include <malloc.h>   // _aligned_malloc, _aligned_realloc, _aligned_free (MSVC Only!)
    #if GP_ALLOCATOR_VERY_DEBUG
        #include <crtdbg.h> // required for _dbg variants
        #define Aligned_Alloc(sz, align)                _aligned_malloc_dbg(sz, align, __FILE__, __LINE__)
        #define Aligned_Realloc(old_sz, ptr, sz, align) _aligned_realloc_dbg(ptr, sz, align, __FILE__, __LINE__)
        #define Aligned_Free(ptr)                       _aligned_free_dbg(ptr)
    #else
        #define Aligned_Alloc(sz, align)                _aligned_malloc(sz, align)
        #define Aligned_Realloc(old_sz, ptr, sz, align) _aligned_realloc(ptr, sz, align)
        #define Aligned_Free(ptr)                       _aligned_free(ptr)
    #endif
#else  // Non-MSVC (POSIX / GCC / Clang)
    #include <cstdlib> // std::aligned_alloc
    #define Aligned_Alloc(sz, align)                std::aligned_alloc(align, sz)
    #define Aligned_Realloc(old_sz, ptr, sz, align) gp_aligned_realloc(old_sz, ptr, sz, align)
    #define Aligned_Free(ptr)                       std::free(ptr)
#endif
struct Allocation {
  s64 size;
  void* memory;
  s32 alignment;
};

struct General_Allocator {
  #if GP_ALLOCATOR_TRACK_ALLOCATIONS
    // NOTE: This is VERY slow, a hashmap is better suited here, 
    // but this is just a quick and dirty solution for now.
    Array<Allocation> allocations;
    s64 total_bytes_allocated = 0;
  #endif
};

General_Allocator* get_general_allocator_data();

constexpr u16 default_allocator_Default_Alignment = 16;

Allocator default_allocator ();

void* default_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);

void* default_allocator_new (s64 new_size, s64 alignment=16, bool initialize=true);
void* default_allocator_realloc (s64 old_size, void* old_memory, s64 new_size, s64 alignment=16, bool initialize=true);
void  default_allocator_free (void* memory);

bool default_allocator_Is_This_Yours (void* old_memory);
void default_allocator_Initialize_Allocation_Tracker ();
bool default_allocator_Tracking_Enabled ();

// #TODO: I want to be able to tag any allocations in debug mode.