Files
Commonwealth-Online-Public/plugin/lib/commonlibf4/include/RE/M/MemoryManager.h
T
2026-05-30 18:33:24 +12:00

272 lines
13 KiB
C++

#pragma once
#include "RE/S/ScrapHeap.h"
namespace RE
{
namespace CompactingStore
{
class Store;
}
class BSSmallBlockAllocator;
class IMemoryHeap;
class MemoryManager
{
public:
class AutoScrapBuffer
{
public:
AutoScrapBuffer() { ctor(); }
~AutoScrapBuffer() { dtor(); }
[[nodiscard]] void* GetPtr() const noexcept { return ptr; }
// members
void* ptr{ nullptr }; // 0
private:
AutoScrapBuffer* ctor()
{
using func_t = decltype(&AutoScrapBuffer::ctor);
static REL::Relocation<func_t> func{ ID::MemoryManager::AutoScrapBuffer::ctor };
return func(this);
}
void dtor()
{
using func_t = decltype(&AutoScrapBuffer::dtor);
static REL::Relocation<func_t> func{ ID::MemoryManager::AutoScrapBuffer::dtor };
return func(this);
}
};
static_assert(sizeof(AutoScrapBuffer) == 0x8);
class ThreadScrapHeap
{
public:
// members
ScrapHeap heap; // 00
ThreadScrapHeap* next{ nullptr }; // 90
std::uint32_t owningThread{ REX::W32::GetCurrentThreadId() }; // 98
};
static_assert(sizeof(ThreadScrapHeap) == 0xA0);
[[nodiscard]] static MemoryManager& GetSingleton()
{
using func_t = decltype(&MemoryManager::GetSingleton);
const REL::Relocation<func_t> func{ ID::MemoryManager::Singleton };
return func();
}
[[nodiscard]] void* Allocate(std::size_t a_size, std::uint32_t a_alignment, bool a_alignmentRequired)
{
using func_t = decltype(&MemoryManager::Allocate);
const REL::Relocation<func_t> func{ ID::MemoryManager::Allocate };
return func(this, a_size, a_alignment, a_alignmentRequired);
}
void Deallocate(void* a_mem, bool a_alignmentRequired)
{
using func_t = decltype(&MemoryManager::Deallocate);
const REL::Relocation<func_t> func{ ID::MemoryManager::Deallocate };
return func(this, a_mem, a_alignmentRequired);
}
[[nodiscard]] ScrapHeap* GetThreadScrapHeap()
{
using func_t = decltype(&MemoryManager::GetThreadScrapHeap);
const REL::Relocation<func_t> func{ ID::MemoryManager::GetThreadScrapHeap };
return func(this);
}
[[nodiscard]] void* Reallocate(void* a_oldMem, std::size_t a_newSize, std::uint32_t a_alignment, bool a_alignmentRequired)
{
using func_t = decltype(&MemoryManager::Reallocate);
const REL::Relocation<func_t> func{ ID::MemoryManager::Reallocate };
return func(this, a_oldMem, a_newSize, a_alignment, a_alignmentRequired);
}
void RegisterMemoryManager()
{
using func_t = decltype(&MemoryManager::RegisterMemoryManager);
const REL::Relocation<func_t> func{ ID::MemoryManager::RegisterMemoryManager };
return func(this);
}
// members
bool initialized{ false }; // 000
std::uint16_t numHeaps{ 0 }; // 002
std::uint16_t numPhysicalHeaps{ 0 }; // 004
IMemoryHeap** heaps{ nullptr }; // 008
bool* allowOtherContextAllocs{ nullptr }; // 010
IMemoryHeap* heapsByContext[127]{ nullptr }; // 018
ThreadScrapHeap* threadScrapHeap{ nullptr }; // 410
IMemoryHeap** physicalHeaps{ nullptr }; // 418
IMemoryHeap* bigAllocHeap{ nullptr }; // 420
IMemoryHeap* emergencyHeap{ nullptr }; // 428
BSSmallBlockAllocator* smallBlockAllocator{ nullptr }; // 430
CompactingStore::Store* compactingStore{ nullptr }; // 438
IMemoryHeap* externalHavokAllocator{ nullptr }; // 440
bool specialHeaps{ false }; // 448
bool allowPoolUse{ true }; // 449
std::uint32_t sysAllocBytes{ 0 }; // 44C
std::uint32_t mallocBytes{ 0 }; // 450
std::uint32_t alignmentForPools{ 4 }; // 454
std::uint32_t mainThreadMemoryProblemPassSignal{ 0 }; // 458
std::size_t failedAllocationSize{ 0 }; // 460
std::uint32_t numMemoryProblemPassesRun{ 0 }; // 468
std::size_t timeOfLastMemoryProblemPass{ 0 }; // 470
IMemoryHeap* defaultHeap{ nullptr }; // 478
};
static_assert(sizeof(MemoryManager) == 0x480);
[[nodiscard]] inline void* malloc(std::size_t a_size)
{
auto& mem = MemoryManager::GetSingleton();
return mem.Allocate(a_size, 0, false);
}
template <class T>
[[nodiscard]] T* malloc()
{
return static_cast<T*>(malloc(sizeof(T)));
}
[[nodiscard]] inline void* aligned_alloc(std::size_t a_alignment, std::size_t a_size)
{
auto& mem = MemoryManager::GetSingleton();
return mem.Allocate(a_size, static_cast<std::uint32_t>(a_alignment), true);
}
template <class T>
[[nodiscard]] T* aligned_alloc()
{
return static_cast<T*>(aligned_alloc(alignof(T), sizeof(T)));
}
[[nodiscard]] inline void* calloc(std::size_t a_num, std::size_t a_size)
{
const auto ret = malloc(a_num * a_size);
if (ret) {
std::memset(ret, 0, a_num * a_size);
}
return ret;
}
template <class T>
[[nodiscard]] T* calloc(std::size_t a_num)
{
return static_cast<T*>(calloc(a_num, sizeof(T)));
}
[[nodiscard]] inline void* realloc(void* a_ptr, std::size_t a_newSize)
{
auto& mem = MemoryManager::GetSingleton();
return mem.Reallocate(a_ptr, a_newSize, 0, false);
}
[[nodiscard]] inline void* aligned_realloc(void* a_ptr, std::size_t a_alignment, std::size_t a_newSize)
{
auto& mem = MemoryManager::GetSingleton();
return mem.Reallocate(a_ptr, a_newSize, static_cast<std::uint32_t>(a_alignment), true);
}
inline void free(void* a_ptr)
{
auto& mem = MemoryManager::GetSingleton();
return mem.Deallocate(a_ptr, false);
}
inline void aligned_free(void* a_ptr)
{
auto& mem = MemoryManager::GetSingleton();
return mem.Deallocate(a_ptr, true);
}
}
#define F4_HEAP_REDEFINE_HELPER(...) \
[[nodiscard]] void* operator new(std::size_t a_count, std::align_val_t a_alignment) \
{ \
const auto mem = RE::aligned_alloc(static_cast<std::size_t>(a_alignment), a_count); \
if (!mem) \
REX::FAIL("out of memory"); \
\
return mem; \
} \
\
[[nodiscard]] void* operator new[](std::size_t a_count, std::align_val_t a_alignment) \
{ \
const auto mem = RE::aligned_alloc(static_cast<std::size_t>(a_alignment), a_count); \
if (!mem) \
REX::FAIL("out of memory"); \
\
return mem; \
} \
\
[[nodiscard]] void* operator new(std::size_t, void* a_ptr) noexcept { return a_ptr; } \
[[nodiscard]] void* operator new[](std::size_t, void* a_ptr) noexcept { return a_ptr; } \
[[nodiscard]] void* operator new(std::size_t, std::align_val_t, void* a_ptr) noexcept { return a_ptr; } \
[[nodiscard]] void* operator new[](std::size_t, std::align_val_t, void* a_ptr) noexcept { return a_ptr; } \
\
void operator delete(void*, void*) noexcept { return; } \
void operator delete[](void*, void*) noexcept { return; } \
\
void operator delete(void* a_ptr, std::align_val_t) { RE::aligned_free(a_ptr); } \
void operator delete[](void* a_ptr, std::align_val_t) { RE::aligned_free(a_ptr); } \
void operator delete(void* a_ptr, std::size_t, std::align_val_t) { RE::aligned_free(a_ptr); } \
void operator delete[](void* a_ptr, std::size_t, std::align_val_t) { RE::aligned_free(a_ptr); }
#define F4_HEAP_REDEFINE_NEW(...) \
[[nodiscard]] void* operator new(std::size_t a_count) \
{ \
const auto mem = RE::malloc(a_count); \
if (!mem) \
REX::FAIL("out of memory"); \
\
return mem; \
} \
\
[[nodiscard]] void* operator new[](std::size_t a_count) \
{ \
const auto mem = RE::malloc(a_count); \
if (!mem) \
REX::FAIL("out of memory"); \
\
return mem; \
} \
\
void operator delete(void* a_ptr) { RE::free(a_ptr); } \
void operator delete[](void* a_ptr) { RE::free(a_ptr); } \
void operator delete(void* a_ptr, std::size_t) { RE::free(a_ptr); } \
void operator delete[](void* a_ptr, std::size_t) { RE::free(a_ptr); } \
\
F4_HEAP_REDEFINE_HELPER(__VA_ARGS__)
#define F4_HEAP_REDEFINE_ALIGNED_NEW(...) \
[[nodiscard]] void* operator new(std::size_t a_count) \
{ \
const auto mem = RE::aligned_alloc(alignof(__VA_ARGS__), a_count); \
if (!mem) \
REX::FAIL("out of memory"); \
\
return mem; \
} \
\
[[nodiscard]] void* operator new[](std::size_t a_count) \
{ \
const auto mem = RE::aligned_alloc(alignof(__VA_ARGS__), a_count); \
if (!mem) \
REX::FAIL("out of memory"); \
\
return mem; \
} \
\
void operator delete(void* a_ptr) { RE::aligned_free(a_ptr); } \
void operator delete[](void* a_ptr) { RE::aligned_free(a_ptr); } \
void operator delete(void* a_ptr, std::size_t) { RE::aligned_free(a_ptr); } \
void operator delete[](void* a_ptr, std::size_t) { RE::aligned_free(a_ptr); } \
\
F4_HEAP_REDEFINE_HELPER(__VA_ARGS__)