#pragma once
#include "core/error/error_macros.h"
#include "core/templates/safe_refcount.h"
#include <new>
#include <type_traits>
class Memory {
#ifdef DEBUG_ENABLED
static SafeNumeric<uint64_t> mem_usage;
static SafeNumeric<uint64_t> max_usage;
#endif
public:
static constexpr size_t SIZE_OFFSET = 0;
static constexpr size_t ELEMENT_OFFSET = ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t) == 0) ? (SIZE_OFFSET + sizeof(uint64_t)) : ((SIZE_OFFSET + sizeof(uint64_t)) + alignof(uint64_t) - ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t)));
static constexpr size_t DATA_OFFSET = ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t) == 0) ? (ELEMENT_OFFSET + sizeof(uint64_t)) : ((ELEMENT_OFFSET + sizeof(uint64_t)) + alignof(max_align_t) - ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t)));
template <bool p_ensure_zero = false>
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
_FORCE_INLINE_ static void *alloc_static_zeroed(size_t p_bytes, bool p_pad_align = false) { return alloc_static<true>(p_bytes, p_pad_align); }
static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
static void free_static(void *p_ptr, bool p_pad_align = false);
static void *alloc_aligned_static(size_t p_bytes, size_t p_alignment);
static void *realloc_aligned_static(void *p_memory, size_t p_bytes, size_t p_prev_bytes, size_t p_alignment);
static void free_aligned_static(void *p_memory);
static uint64_t get_mem_available();
static uint64_t get_mem_usage();
static uint64_t get_mem_max_usage();
};
class DefaultAllocator {
public:
_FORCE_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory, false); }
_FORCE_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr, false); }
};
void *operator new(size_t p_size, const char *p_description);
void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size));
void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description);
#ifdef _MSC_VER
void operator delete(void *p_mem, const char *p_description);
void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size));
void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description);
#endif
#define memalloc(m_size) Memory::alloc_static(m_size)
#define memalloc_zeroed(m_size) Memory::alloc_static_zeroed(m_size)
#define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size)
#define memfree(m_mem) Memory::free_static(m_mem)
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
template <typename T>
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
postinitialize_handler(p_obj);
return p_obj;
}
#define memnew(m_class) _post_initialize(::new ("") m_class)
#define memnew_allocator(m_class, m_allocator) _post_initialize(::new (m_allocator::alloc) m_class)
#define memnew_placement(m_placement, m_class) _post_initialize(::new (m_placement) m_class)
_ALWAYS_INLINE_ bool predelete_handler(void *) {
return true;
}
template <typename T>
void memdelete(T *p_class) {
if (!predelete_handler(p_class)) {
return;
}
if constexpr (!std::is_trivially_destructible_v<T>) {
p_class->~T();
}
Memory::free_static(p_class, false);
}
template <typename T, typename A>
void memdelete_allocator(T *p_class) {
if (!predelete_handler(p_class)) {
return;
}
if constexpr (!std::is_trivially_destructible_v<T>) {
p_class->~T();
}
A::free(p_class);
}
#define memdelete_notnull(m_v) \
{ \
if (m_v) { \
memdelete(m_v); \
} \
}
#define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
_FORCE_INLINE_ uint64_t *_get_element_count_ptr(uint8_t *p_ptr) {
return (uint64_t *)(p_ptr - Memory::DATA_OFFSET + Memory::ELEMENT_OFFSET);
}
template <typename T>
T *memnew_arr_template(size_t p_elements) {
if (p_elements == 0) {
return nullptr;
}
size_t len = sizeof(T) * p_elements;
uint8_t *mem = (uint8_t *)Memory::alloc_static(len, true);
T *failptr = nullptr;
ERR_FAIL_NULL_V(mem, failptr);
uint64_t *_elem_count_ptr = _get_element_count_ptr(mem);
*(_elem_count_ptr) = p_elements;
if constexpr (!std::is_trivially_constructible_v<T>) {
T *elems = (T *)mem;
for (size_t i = 0; i < p_elements; i++) {
::new (&elems[i]) T;
}
}
return (T *)mem;
}
template <typename T>
_FORCE_INLINE_ void memnew_arr_placement(T *p_start, size_t p_num) {
if constexpr (is_zero_constructible_v<T>) {
memset(static_cast<void *>(p_start), 0, p_num * sizeof(T));
} else {
for (size_t i = 0; i < p_num; i++) {
memnew_placement(p_start + i, T());
}
}
}
template <typename T>
size_t memarr_len(const T *p_class) {
uint8_t *ptr = (uint8_t *)p_class;
uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
return *(_elem_count_ptr);
}
template <typename T>
void memdelete_arr(T *p_class) {
uint8_t *ptr = (uint8_t *)p_class;
if constexpr (!std::is_trivially_destructible_v<T>) {
uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
uint64_t elem_count = *(_elem_count_ptr);
for (uint64_t i = 0; i < elem_count; i++) {
p_class[i].~T();
}
}
Memory::free_static(ptr, true);
}
struct _GlobalNil {
int color = 1;
_GlobalNil *right = nullptr;
_GlobalNil *left = nullptr;
_GlobalNil *parent = nullptr;
_GlobalNil();
};
struct _GlobalNilClass {
static _GlobalNil _nil;
};
template <typename T>
class DefaultTypedAllocator {
public:
template <typename... Args>
_FORCE_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
_FORCE_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
};