feat(memory): complete low-level memory management utilities
This commit is contained in:
85
Redcraft.Utility/Source/Private/Memory/Memory.cpp
Normal file
85
Redcraft.Utility/Source/Private/Memory/Memory.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "Memory/Memory.h"
|
||||
|
||||
#include "Memory/Alignment.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <corecrt_malloc.h>
|
||||
#endif
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Memory)
|
||||
|
||||
void* Malloc(size_t Count, size_t Alignment)
|
||||
{
|
||||
const size_t MinimumAlignment = Count >= 16 ? 16 : 8;
|
||||
Alignment = MinimumAlignment > Alignment ? MinimumAlignment : Alignment;
|
||||
|
||||
void* Result = nullptr;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
if (Count != 0) Result = _aligned_malloc(Count, Alignment);
|
||||
#else
|
||||
void* Ptr = SystemMalloc(Count + Alignment + sizeof(void*) + sizeof(size_t));
|
||||
if (Ptr)
|
||||
{
|
||||
Result = Align(reinterpret_cast<uint8*>(Ptr) + sizeof(void*) + sizeof(size_t), Alignment);
|
||||
*reinterpret_cast<void**>(reinterpret_cast<uint8*>(Result) - sizeof(void*)) = Ptr;
|
||||
*reinterpret_cast<size_t*>(reinterpret_cast<uint8*>(Result) - sizeof(void*) - sizeof(size_t)) = Count;
|
||||
}
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void* Realloc(void* Ptr, size_t Count, size_t Alignment)
|
||||
{
|
||||
const size_t MinimumAlignment = Count >= 16 ? 16 : 8;
|
||||
Alignment = MinimumAlignment > Alignment ? MinimumAlignment : Alignment;
|
||||
|
||||
if (Ptr && Count)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
return _aligned_realloc(Ptr, Count, Alignment);
|
||||
#else
|
||||
void* Result = Malloc(Count, Alignment);
|
||||
size_t PtrSize = *reinterpret_cast<size_t*>(reinterpret_cast<uint8*>(Ptr) - sizeof(void*) - sizeof(size_t));
|
||||
Memcpy(Result, Ptr, Count < PtrSize ? Count : PtrSize);
|
||||
Free(Ptr);
|
||||
return Result;
|
||||
#endif
|
||||
}
|
||||
else if (Ptr == nullptr)
|
||||
{
|
||||
return Malloc(Count, Alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
Free(Ptr);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Free(void* Ptr)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
_aligned_free(Ptr);
|
||||
#else
|
||||
SystemFree(*reinterpret_cast<void**>(reinterpret_cast<uint8*>(Ptr) - sizeof(void*)));
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t QuantizeSize(size_t Count, size_t Alignment)
|
||||
{
|
||||
return Count;
|
||||
}
|
||||
|
||||
NAMESPACE_END(Memory)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
||||
|
||||
REPLACEMENT_OPERATOR_NEW_AND_DELETE
|
142
Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp
Normal file
142
Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include "Testing/MemoryTesting.h"
|
||||
|
||||
#include "Memory/Memory.h"
|
||||
#include "Memory/Alignment.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
void TestMemory()
|
||||
{
|
||||
TestAlignment();
|
||||
TestMemoryBuffer();
|
||||
TestMemoryMalloc();
|
||||
}
|
||||
|
||||
void TestAlignment()
|
||||
{
|
||||
int32 Unaligned = 0xAAAA;
|
||||
|
||||
int32 Aligned8 = Memory::Align(Unaligned, 8);
|
||||
int32 Aligned16 = Memory::Align(Unaligned, 16);
|
||||
int32 Aligned32 = Memory::Align(Unaligned, 32);
|
||||
int32 Aligned64 = Memory::Align(Unaligned, 64);
|
||||
|
||||
int32 AlignedDown8 = Memory::AlignDown(Unaligned, 8);
|
||||
int32 AlignedDown16 = Memory::AlignDown(Unaligned, 16);
|
||||
int32 AlignedDown32 = Memory::AlignDown(Unaligned, 32);
|
||||
int32 AlignedDown64 = Memory::AlignDown(Unaligned, 64);
|
||||
|
||||
int32 AlignedArbitrary8 = Memory::AlignArbitrary(Unaligned, 8);
|
||||
int32 AlignedArbitrary16 = Memory::AlignArbitrary(Unaligned, 16);
|
||||
int32 AlignedArbitrary32 = Memory::AlignArbitrary(Unaligned, 32);
|
||||
int32 AlignedArbitrary64 = Memory::AlignArbitrary(Unaligned, 64);
|
||||
|
||||
always_check((Memory::IsAligned(Aligned8, 8) && Aligned8 > Unaligned));
|
||||
always_check((Memory::IsAligned(Aligned16, 16) && Aligned16 > Unaligned));
|
||||
always_check((Memory::IsAligned(Aligned32, 32) && Aligned32 > Unaligned));
|
||||
always_check((Memory::IsAligned(Aligned64, 64) && Aligned64 > Unaligned));
|
||||
|
||||
always_check((Memory::IsAligned(Aligned8, 8) && AlignedDown8 < Unaligned));
|
||||
always_check((Memory::IsAligned(Aligned16, 16) && AlignedDown16 < Unaligned));
|
||||
always_check((Memory::IsAligned(Aligned32, 32) && AlignedDown32 < Unaligned));
|
||||
always_check((Memory::IsAligned(Aligned64, 64) && AlignedDown64 < Unaligned));
|
||||
|
||||
always_check((Memory::IsAligned(AlignedArbitrary8, 8)));
|
||||
always_check((Memory::IsAligned(AlignedArbitrary16, 16)));
|
||||
always_check((Memory::IsAligned(AlignedArbitrary32, 32)));
|
||||
always_check((Memory::IsAligned(AlignedArbitrary64, 64)));
|
||||
|
||||
}
|
||||
|
||||
void TestMemoryBuffer()
|
||||
{
|
||||
int64 TempA;
|
||||
int64 TempB;
|
||||
int64 TempC;
|
||||
int64 TempD;
|
||||
uint8* PtrA = reinterpret_cast<uint8*>(&TempA);
|
||||
uint8* PtrB = reinterpret_cast<uint8*>(&TempB);
|
||||
uint8* PtrC = reinterpret_cast<uint8*>(&TempC);
|
||||
uint8* PtrD = reinterpret_cast<uint8*>(&TempD);
|
||||
|
||||
TempA = 0x0123456789ABCDEF;
|
||||
TempB = 0x0123456789AB0000;
|
||||
Memory::Memmove(PtrA, PtrA + 2, 6);
|
||||
always_check((TempA << 16) == TempB);
|
||||
|
||||
TempA = 1004;
|
||||
TempB = 1005;
|
||||
TempC = 1005;
|
||||
TempD = 1006;
|
||||
int32 ResultA = Memory::Memcmp(PtrA, PtrB, sizeof(int64));
|
||||
int32 ResultB = Memory::Memcmp(PtrB, PtrC, sizeof(int64));
|
||||
int32 ResultC = Memory::Memcmp(PtrC, PtrD, sizeof(int64));
|
||||
always_check((ResultA < 0) != (ResultB < 0));
|
||||
always_check(ResultB == 0);
|
||||
|
||||
Memory::Memset(PtrA, 0x3F, sizeof(int64));
|
||||
always_check(TempA == 0x3F3F3F3F3F3F3F3F);
|
||||
Memory::Memset(TempB, 0x3F);
|
||||
always_check(TempB == 0x3F3F3F3F3F3F3F3F);
|
||||
|
||||
Memory::Memzero(PtrA, sizeof(int64));
|
||||
always_check(TempA == 0);
|
||||
Memory::Memzero(TempB);
|
||||
always_check(TempB == 0);
|
||||
|
||||
TempA = 0x0123456789ABCDEF;
|
||||
Memory::Memcpy(PtrC, PtrA, sizeof(int64));
|
||||
always_check(TempA == TempC);
|
||||
TempB = 0xDEDCBA9876543210;
|
||||
Memory::Memcpy(TempD, TempB);
|
||||
always_check(TempB == TempD);
|
||||
|
||||
}
|
||||
|
||||
void TestMemoryMalloc()
|
||||
{
|
||||
int32* PtrA;
|
||||
int64* PtrB;
|
||||
|
||||
PtrA = reinterpret_cast<int32*>(Memory::SystemMalloc(sizeof(int32)));
|
||||
*PtrA = 0x01234567;
|
||||
always_check(*PtrA == 0x01234567);
|
||||
PtrB = reinterpret_cast<int64*>(Memory::SystemRealloc(PtrA, sizeof(int64)));
|
||||
*PtrB = 0x0123456789ABCDEF;
|
||||
always_check(*PtrB == 0x0123456789ABCDEF);
|
||||
Memory::SystemFree(PtrB);
|
||||
|
||||
PtrA = reinterpret_cast<int32*>(Memory::Malloc(sizeof(int32), 1024));
|
||||
always_check(Memory::IsAligned(PtrA, 1024));
|
||||
*PtrA = 0x01234567;
|
||||
always_check(*PtrA == 0x01234567);
|
||||
PtrB = reinterpret_cast<int64*>(Memory::Realloc(PtrA, sizeof(int64), 1024));
|
||||
always_check(Memory::IsAligned(PtrB, 1024));
|
||||
*PtrB = 0x0123456789ABCDEF;
|
||||
always_check(*PtrB == 0x0123456789ABCDEF);
|
||||
Memory::Free(PtrB);
|
||||
|
||||
PtrA = new int32;
|
||||
PtrB = new int64;
|
||||
*PtrA = 0x01234567;
|
||||
always_check(*PtrA == 0x01234567);
|
||||
*PtrB = 0x0123456789ABCDEF;
|
||||
always_check(*PtrB == 0x0123456789ABCDEF);
|
||||
delete PtrA;
|
||||
delete PtrB;
|
||||
|
||||
struct alignas(1024) FTest { int32 A; };
|
||||
FTest* PtrC = new FTest[4];
|
||||
always_check(Memory::IsAligned(PtrC, 1024));
|
||||
PtrC->A = 0x01234567;
|
||||
always_check(PtrC->A == 0x01234567);
|
||||
delete[] PtrC;
|
||||
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
Reference in New Issue
Block a user