Compare commits
3 Commits
c7e3ac32b4
...
49023da0c1
Author | SHA1 | Date |
---|---|---|
_Redstone_c_ | 49023da0c1 | |
_Redstone_c_ | d8543421a0 | |
_Redstone_c_ | d825285a4a |
|
@ -1,6 +1,8 @@
|
|||
#include "Memory/Memory.h"
|
||||
|
||||
#include "Memory/Alignment.h"
|
||||
#include "Templates/Atomic.h"
|
||||
#include "Templates/ScopeHelper.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
@ -13,26 +15,72 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
|||
|
||||
NAMESPACE_BEGIN(Memory)
|
||||
|
||||
#if DO_CHECK
|
||||
|
||||
class FMemoryLeakChecker
|
||||
{
|
||||
private:
|
||||
|
||||
TAtomic<size_t> MemoryAllocationCount;
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr FMemoryLeakChecker()
|
||||
: MemoryAllocationCount(0)
|
||||
{ }
|
||||
|
||||
FORCEINLINE ~FMemoryLeakChecker()
|
||||
{
|
||||
checkf(MemoryAllocationCount.Load() == 0, TEXT("There is unfree memory. Please check for memory leaks."));
|
||||
}
|
||||
|
||||
FORCEINLINE void AddMemoryAllocationCount()
|
||||
{
|
||||
MemoryAllocationCount.FetchAdd(1, EMemoryOrder::Relaxed);
|
||||
}
|
||||
|
||||
FORCEINLINE void ReleaseMemoryAllocationCount()
|
||||
{
|
||||
MemoryAllocationCount.FetchSub(1, EMemoryOrder::Relaxed);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
FMemoryLeakChecker MemoryLeakChecker;
|
||||
|
||||
#endif
|
||||
|
||||
void* Malloc(size_t Count, size_t Alignment)
|
||||
{
|
||||
checkf(IsValidAlignment(Alignment), TEXT("The alignment value must be an integer power of 2."));
|
||||
|
||||
Count = Count != 0 ? Count : 1; // Treat zero-byte allocation as one-byte allocation.
|
||||
|
||||
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)
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
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;
|
||||
Result = _aligned_malloc(Count, Alignment);
|
||||
}
|
||||
#endif
|
||||
# else
|
||||
{
|
||||
void* Ptr = SystemMalloc(Count + Alignment + sizeof(void*) + sizeof(size_t));
|
||||
|
||||
if (Ptr != nullptr)
|
||||
{
|
||||
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
|
||||
|
||||
check(Result != nullptr);
|
||||
|
||||
check_code({ MemoryLeakChecker.AddMemoryAllocationCount(); });
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
@ -41,39 +89,55 @@ void* Realloc(void* Ptr, size_t Count, size_t Alignment)
|
|||
{
|
||||
checkf(IsValidAlignment(Alignment), TEXT("The alignment value must be an integer power of 2."));
|
||||
|
||||
Count = Count != 0 ? Count : 1; // Treat zero-byte allocation as one-byte allocation.
|
||||
|
||||
const size_t MinimumAlignment = Count >= 16 ? 16 : 8;
|
||||
Alignment = MinimumAlignment > Alignment ? MinimumAlignment : Alignment;
|
||||
|
||||
if (Ptr && Count)
|
||||
void* Result = nullptr;
|
||||
|
||||
if (Ptr != nullptr)
|
||||
{
|
||||
#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);
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
Result = _aligned_realloc(Ptr, Count, Alignment);
|
||||
}
|
||||
# else
|
||||
{
|
||||
Result = Malloc(Count, Alignment);
|
||||
|
||||
if (Result != nullptr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Free(Ptr);
|
||||
return nullptr;
|
||||
Result = Malloc(Count, Alignment);
|
||||
}
|
||||
|
||||
check(Result != nullptr);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void Free(void* Ptr)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
_aligned_free(Ptr);
|
||||
#else
|
||||
SystemFree(*reinterpret_cast<void**>(reinterpret_cast<uint8*>(Ptr) - sizeof(void*)));
|
||||
#endif
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
_aligned_free(Ptr);
|
||||
}
|
||||
# else
|
||||
{
|
||||
SystemFree(*reinterpret_cast<void**>(reinterpret_cast<uint8*>(Ptr) - sizeof(void*)));
|
||||
}
|
||||
# endif
|
||||
|
||||
check_code({ if (Ptr != nullptr) MemoryLeakChecker.ReleaseMemoryAllocationCount(); });
|
||||
}
|
||||
|
||||
size_t QuantizeSize(size_t Count, size_t Alignment)
|
||||
|
|
|
@ -148,6 +148,7 @@ void TestMemoryMalloc()
|
|||
always_check(PtrC->A == 0x01234567);
|
||||
delete [] PtrC;
|
||||
|
||||
Memory::Free(Memory::Realloc(Memory::Malloc(0), 0));
|
||||
}
|
||||
|
||||
NAMESPACE_UNNAMED_BEGIN
|
||||
|
|
|
@ -322,6 +322,10 @@ void TestTypeTraits()
|
|||
always_check(!(CConvertibleTo<FTestStructE*, FTestStructH*>));
|
||||
always_check((CConvertibleTo<FTestStructW, FTestStructV>));
|
||||
|
||||
always_check(!(CDerivedFrom<FTestStructD, FTestStructH>));
|
||||
always_check(!(CDerivedFrom<FTestStructE, FTestStructH>));
|
||||
always_check((CDerivedFrom<FTestStructH, FTestStructE>));
|
||||
|
||||
always_check((CSameAs<int32, TRemoveConst<int32>>));
|
||||
always_check(!(CSameAs<int32, TRemoveConst<int32*>>));
|
||||
always_check(!(CSameAs<int32, TRemoveConst<int32&>>));
|
||||
|
|
|
@ -255,6 +255,7 @@ NODISCARD REDCRAFTUTILITY_API void* Malloc(size_t Count, size_t Alignment = Defa
|
|||
|
||||
/**
|
||||
* Reallocates the given area of memory. It must be previously allocated by Malloc() or Realloc().
|
||||
* If 'Ptr' is a nullptr, effectively the same as calling Malloc().
|
||||
*
|
||||
* @param Ptr - The pointer to the memory area to be reallocated.
|
||||
* @param Count - The number of bytes to allocate.
|
||||
|
|
|
@ -30,38 +30,48 @@ private:
|
|||
|
||||
};
|
||||
|
||||
#define RS_CHECK_IMPL(InExpr) assert(InExpr)
|
||||
#define RS_CHECK_F_IMPL(InExpr, InFormat, ...) assert((InFormat, InExpr))
|
||||
#define RS_CHECK_IMPL(InExpr) assert(InExpr)
|
||||
#define RS_CHECK_F_IMPL(InExpr, InFormat, ...) assert((InFormat, InExpr))
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
#define always_check(InExpr) RS_CHECK_IMPL(InExpr)
|
||||
#define always_checkf(InExpr, InFormat, ...) RS_CHECK_F_IMPL(InExpr, InFormat, ##__VA_ARGS__)
|
||||
#define always_check_no_entry() always_checkf(false, "Enclosing block should never be called.")
|
||||
#define always_check_no_reentry() { static bool PREPROCESSOR_JOIN(bBeenHere, __LINE__) = false; always_checkf(!PREPROCESSOR_JOIN(bBeenHere, __LINE__), "Enclosing block was called more than once."); PREPROCESSOR_JOIN(bBeenHere, __LINE__) = true; }
|
||||
#define always_check_no_recursion() static uint8 PREPROCESSOR_JOIN(RecursionCounter, __LINE__) = 0; always_checkf(PREPROCESSOR_JOIN(RecursionCounter, __LINE__) == 0, "Enclosing block was entered recursively."); const NAMESPACE_REDCRAFT::NAMESPACE_PRIVATE::FRecursionScopeMarker PREPROCESSOR_JOIN(ScopeMarker, __LINE__)(PREPROCESSOR_JOIN(RecursionCounter, __LINE__))
|
||||
#define always_unimplemented() always_checkf(false, "Unimplemented function called.")
|
||||
|
||||
#if BUILD_DEBUG || BUILD_DEVELOPMENT
|
||||
# define DO_CHECK 1
|
||||
#else
|
||||
# define DO_CHECK 0
|
||||
#endif
|
||||
|
||||
# define check(InExpr) always_check(InExpr)
|
||||
# define checkf(InExpr, InFormat, ...) always_checkf(InExpr, InFormat, ##__VA_ARGS__)
|
||||
# define check_no_entry() always_check_no_entry()
|
||||
# define check_no_reentry() always_check_no_reentry()
|
||||
# define check_no_recursion() always_check_no_recursion()
|
||||
# define verify(InExpr) always_check(InExpr)
|
||||
# define verifyf(InExpr, InFormat, ...) always_checkf(InExpr, InFormat, ##__VA_ARGS__)
|
||||
# define unimplemented() always_unimplemented()
|
||||
#define always_check(InExpr) RS_CHECK_IMPL(InExpr)
|
||||
#define always_checkf(InExpr, InFormat, ...) RS_CHECK_F_IMPL(InExpr, InFormat, ##__VA_ARGS__)
|
||||
#define always_check_no_entry() always_checkf(false, "Enclosing block should never be called.")
|
||||
#define always_check_no_reentry() { static bool PREPROCESSOR_JOIN(bBeenHere, __LINE__) = false; always_checkf(!PREPROCESSOR_JOIN(bBeenHere, __LINE__), "Enclosing block was called more than once."); PREPROCESSOR_JOIN(bBeenHere, __LINE__) = true; }
|
||||
#define always_check_no_recursion() static uint8 PREPROCESSOR_JOIN(RecursionCounter, __LINE__) = 0; always_checkf(PREPROCESSOR_JOIN(RecursionCounter, __LINE__) == 0, "Enclosing block was entered recursively."); const NAMESPACE_REDCRAFT::NAMESPACE_PRIVATE::FRecursionScopeMarker PREPROCESSOR_JOIN(ScopeMarker, __LINE__)(PREPROCESSOR_JOIN(RecursionCounter, __LINE__))
|
||||
#define always_unimplemented() always_checkf(false, "Unimplemented function called.")
|
||||
|
||||
#if DO_CHECK
|
||||
|
||||
# define check_code(InCode) do InCode while(false)
|
||||
|
||||
# define check(InExpr) check_code({ always_check(InExpr); })
|
||||
# define checkf(InExpr, InFormat, ...) always_checkf(InExpr, InFormat, ##__VA_ARGS__)
|
||||
# define check_no_entry() always_check_no_entry()
|
||||
# define check_no_reentry() always_check_no_reentry()
|
||||
# define check_no_recursion() always_check_no_recursion()
|
||||
# define verify(InExpr) always_check(InExpr)
|
||||
# define verifyf(InExpr, InFormat, ...) always_checkf(InExpr, InFormat, ##__VA_ARGS__)
|
||||
# define unimplemented() always_unimplemented()
|
||||
|
||||
#else
|
||||
|
||||
# define check_code(InCode)
|
||||
|
||||
# define check(InExpr)
|
||||
# define checkf(InExpr, InFormat, ...)
|
||||
# define check_no_entry()
|
||||
# define check_no_reentry()
|
||||
# define check_no_recursion()
|
||||
# define verify(InExpr) { if(InExpr) { } }
|
||||
# define verifyf(InExpr, InFormat, ...) { if(InExpr) { } }
|
||||
# define verify(InExpr) { if(InExpr) { } }
|
||||
# define verifyf(InExpr, InFormat, ...) { if(InExpr) { } }
|
||||
# define unimplemented()
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,6 +31,7 @@ template <typename T, size_t I = 0> inline constexpr size_t TExtent = NAMESPACE
|
|||
template <typename T, typename U> concept CSameAs = NAMESPACE_STD::is_same_v<T, U>;
|
||||
template <typename T, typename U> concept CBaseOf = NAMESPACE_STD::is_base_of_v<T, U>;
|
||||
template <typename T, typename U> concept CConvertibleTo = NAMESPACE_STD::is_convertible_v<T, U>;
|
||||
template <typename T, typename U> concept CDerivedFrom = CBaseOf<U, T> && CConvertibleTo<const volatile T*, const volatile U*>;
|
||||
|
||||
template <typename T> using TRemoveConst = NAMESPACE_STD::remove_const_t<T>;
|
||||
template <typename T> using TRemoveVolatile = NAMESPACE_STD::remove_volatile_t<T>;
|
||||
|
|
Loading…
Reference in New Issue