feat(memory): add ToAddress and refactor the code with it

This commit is contained in:
Redstone1024 2024-11-01 15:11:45 +08:00
parent 1cfa252779
commit 9785326b18
12 changed files with 170 additions and 131 deletions

View File

@ -18,6 +18,7 @@ NAMESPACE_BEGIN(Testing)
void TestMemory() void TestMemory()
{ {
TestAddress();
TestAlignment(); TestAlignment();
TestMemoryBuffer(); TestMemoryBuffer();
TestMemoryMalloc(); TestMemoryMalloc();
@ -29,6 +30,41 @@ void TestMemory()
TestInOutPointer(); TestInOutPointer();
} }
NAMESPACE_UNNAMED_BEGIN
template <typename T>
struct TTestStructA
{
T* Pad;
T* Data;
TTestStructA(T* InData) : Pad(nullptr), Data(InData) { }
~TTestStructA() { delete Data; }
T** operator&() { return &Data; }
};
template <typename T>
int32 TestFunctionB(TTestStructA<T>*)
{
return 0;
}
template <typename T>
int32 TestFunctionB(T**)
{
return 1;
}
NAMESPACE_UNNAMED_END
void TestAddress()
{
TTestStructA<int32> ObjectA(new int32(3));
always_check(TestFunctionB(&ObjectA) == 1);
always_check(TestFunctionB(AddressOf(ObjectA)) == 0);
always_check(AddressOf(TestAddress) == &TestAddress);
}
void TestAlignment() void TestAlignment()
{ {
int32 Unaligned = 0xAAAA; int32 Unaligned = 0xAAAA;
@ -47,7 +83,7 @@ void TestAlignment()
int32 AlignedArbitrary16 = Memory::AlignArbitrary(Unaligned, 16); int32 AlignedArbitrary16 = Memory::AlignArbitrary(Unaligned, 16);
int32 AlignedArbitrary32 = Memory::AlignArbitrary(Unaligned, 32); int32 AlignedArbitrary32 = Memory::AlignArbitrary(Unaligned, 32);
int32 AlignedArbitrary64 = Memory::AlignArbitrary(Unaligned, 64); int32 AlignedArbitrary64 = Memory::AlignArbitrary(Unaligned, 64);
always_check((Memory::IsAligned(Aligned8, 8) && Aligned8 > Unaligned)); always_check((Memory::IsAligned(Aligned8, 8) && Aligned8 > Unaligned));
always_check((Memory::IsAligned(Aligned16, 16) && Aligned16 > Unaligned)); always_check((Memory::IsAligned(Aligned16, 16) && Aligned16 > Unaligned));
always_check((Memory::IsAligned(Aligned32, 32) && Aligned32 > Unaligned)); always_check((Memory::IsAligned(Aligned32, 32) && Aligned32 > Unaligned));
@ -75,7 +111,7 @@ void TestMemoryBuffer()
uint8* PtrB = reinterpret_cast<uint8*>(&TempB); uint8* PtrB = reinterpret_cast<uint8*>(&TempB);
uint8* PtrC = reinterpret_cast<uint8*>(&TempC); uint8* PtrC = reinterpret_cast<uint8*>(&TempC);
uint8* PtrD = reinterpret_cast<uint8*>(&TempD); uint8* PtrD = reinterpret_cast<uint8*>(&TempD);
TempA = 0x0123456789ABCDEF; TempA = 0x0123456789ABCDEF;
TempB = 0x0123456789AB0000; TempB = 0x0123456789AB0000;
Memory::Memmove(PtrA, PtrA + 2, 6); Memory::Memmove(PtrA, PtrA + 2, 6);
@ -295,7 +331,7 @@ void TestUniquePointer()
always_check(TempC != TempB); always_check(TempC != TempB);
always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempA <=> nullptr) == strong_ordering::greater);
always_check((TempC <=> TempB) != strong_ordering::equal); always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum; int32 TempNum;
TempNum = FCounter::Num; TempNum = FCounter::Num;
@ -310,7 +346,7 @@ void TestUniquePointer()
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter); FCounter* PtrX = TempB.ReleaseAndReset(new FCounter);
always_check(FCounter::Num == TempNum + 1); always_check(FCounter::Num == TempNum + 1);
delete PtrX; delete PtrX;
TempNum = FCounter::Num; TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter()); FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum + 1); always_check(FCounter::Num == TempNum + 1);
@ -331,7 +367,7 @@ void TestUniquePointer()
Temp[0] = 15; Temp[0] = 15;
always_check(Temp.Get()[0] = 15); always_check(Temp.Get()[0] = 15);
} }
FCounter::Num = 0; FCounter::Num = 0;
FArrayDeleter::Num = 0; FArrayDeleter::Num = 0;
@ -348,7 +384,7 @@ void TestUniquePointer()
always_check(TempC != TempB); always_check(TempC != TempB);
always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempA <=> nullptr) == strong_ordering::greater);
always_check((TempC <=> TempB) != strong_ordering::equal); always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum; int32 TempNum;
TempNum = FCounter::Num; TempNum = FCounter::Num;
@ -363,7 +399,7 @@ void TestUniquePointer()
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]); FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]);
always_check(FCounter::Num == TempNum + 4); always_check(FCounter::Num == TempNum + 4);
delete [] PtrX; delete [] PtrX;
TempNum = FCounter::Num; TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter()); FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum + 4); always_check(FCounter::Num == TempNum + 4);
@ -378,7 +414,7 @@ void TestUniquePointer()
always_check( FCounter::Num == 0); always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 4); always_check(FArrayDeleter::Num == 4);
{ {
TUniquePtr<int32> Temp = MakeUnique<int32>(); TUniquePtr<int32> Temp = MakeUnique<int32>();
*Temp = 15; *Temp = 15;
@ -401,7 +437,7 @@ void TestUniquePointer()
always_check(TempC != TempB); always_check(TempC != TempB);
always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempA <=> nullptr) == strong_ordering::greater);
always_check((TempC <=> TempB) != strong_ordering::equal); always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum; int32 TempNum;
TempNum = FCounter::Num; TempNum = FCounter::Num;
@ -416,7 +452,7 @@ void TestUniquePointer()
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter); FCounter* PtrX = TempB.ReleaseAndReset(new FCounter);
always_check(FCounter::Num == TempNum + 1); always_check(FCounter::Num == TempNum + 1);
delete PtrX; delete PtrX;
TempNum = FCounter::Num; TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter()); FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum + 1); always_check(FCounter::Num == TempNum + 1);
@ -466,7 +502,7 @@ void TestUniquePointer()
always_check(TempC != TempB); always_check(TempC != TempB);
always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempA <=> nullptr) == strong_ordering::greater);
always_check((TempC <=> TempB) != strong_ordering::equal); always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum; int32 TempNum;
TempNum = FCounter::Num; TempNum = FCounter::Num;
@ -481,7 +517,7 @@ void TestUniquePointer()
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]); FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]);
always_check(FCounter::Num == TempNum + 4); always_check(FCounter::Num == TempNum + 4);
delete [] PtrX; delete [] PtrX;
TempNum = FCounter::Num; TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter()); FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum + 4); always_check(FCounter::Num == TempNum + 4);
@ -544,13 +580,13 @@ void TestSharedPointer()
always_check(TempC != TempB); always_check(TempC != TempB);
always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempA <=> nullptr) == strong_ordering::greater);
always_check((TempC <=> TempB) != strong_ordering::equal); always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum; int32 TempNum;
TempNum = FCounter::Num; TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter()); TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum); always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num; TempNum = FCounter::Num;
TempC.Reset(new FCounter, FDeleter()); TempC.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum); always_check(FCounter::Num == TempNum);
@ -562,7 +598,7 @@ void TestSharedPointer()
always_check(TempA.GetDeleter<FDeleter>() == nullptr); always_check(TempA.GetDeleter<FDeleter>() == nullptr);
always_check(TempC.GetDeleter<FDeleter>() != nullptr); always_check(TempC.GetDeleter<FDeleter>() != nullptr);
always_check(TempC.GetDeleter<FDeleter>()->Num == 2); always_check(TempC.GetDeleter<FDeleter>()->Num == 2);
TSharedRef<FCounter> TempD(MoveTemp(TempB)); TSharedRef<FCounter> TempD(MoveTemp(TempB));
} }
@ -591,7 +627,7 @@ void TestSharedPointer()
always_check(TempC != TempB); always_check(TempC != TempB);
always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempA <=> nullptr) == strong_ordering::greater);
always_check((TempC <=> TempB) != strong_ordering::equal); always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum; int32 TempNum;
TempNum = FCounter::Num; TempNum = FCounter::Num;
@ -632,7 +668,7 @@ void TestSharedPointer()
always_check(TempC != TempB); always_check(TempC != TempB);
always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempA <=> nullptr) == strong_ordering::greater);
always_check((TempC <=> TempB) != strong_ordering::equal); always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum; int32 TempNum;
TempNum = FCounter::Num; TempNum = FCounter::Num;
@ -688,7 +724,7 @@ void TestSharedPointer()
always_check(TempC != TempB); always_check(TempC != TempB);
always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempA <=> nullptr) == strong_ordering::greater);
always_check((TempC <=> TempB) != strong_ordering::equal); always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum; int32 TempNum;
TempNum = FCounter::Num; TempNum = FCounter::Num;
@ -1080,12 +1116,12 @@ void TestInOutPointer()
{ {
{ {
TUniquePtr<int64> Temp; TUniquePtr<int64> Temp;
[](int64** InPtr) { *InPtr = new int64; } (OutPtr(Temp)); [](int64** InPtr) { *InPtr = new int64; } (OutPtr(Temp));
always_check(Temp.IsValid()); always_check(Temp.IsValid());
Temp.Reset(); Temp.Reset();
[](int64** InPtr) { *InPtr = new int64; } (OutPtr(Temp, TDefaultDelete<int64>())); [](int64** InPtr) { *InPtr = new int64; } (OutPtr(Temp, TDefaultDelete<int64>()));
always_check(Temp.IsValid()); always_check(Temp.IsValid());
} }

View File

@ -70,7 +70,7 @@ void TestReferenceWrapper()
always_check(TempB(1, 1, 1) == 1); always_check(TempB(1, 1, 1) == 1);
TempB.Get() = &TestFunctionA; TempB.Get() = &TestFunctionA;
always_check(TempA(1, 1, 1) == 3); always_check(TempA(1, 1, 1) == 3);
int32 ArrayA[3] = { 1, 2, 3 }; int32 ArrayA[3] = { 1, 2, 3 };
TReferenceWrapper<int32> ArrayB[3] = { ArrayA[1], ArrayA[0], ArrayA[2] }; TReferenceWrapper<int32> ArrayB[3] = { ArrayA[1], ArrayA[0], ArrayA[2] };
always_check(ArrayB[0] == 2); always_check(ArrayB[0] == 2);
@ -164,7 +164,7 @@ void TestOptional()
always_check(GetTypeHash(MakeOptional<int32>(114)) == GetTypeHash(MakeOptional<int32>(114))); always_check(GetTypeHash(MakeOptional<int32>(114)) == GetTypeHash(MakeOptional<int32>(114)));
always_check(GetTypeHash(MakeOptional<int32>(114)) != GetTypeHash(MakeOptional<int32>(514))); always_check(GetTypeHash(MakeOptional<int32>(114)) != GetTypeHash(MakeOptional<int32>(514)));
} }
{ {
TOptional<uint8> TempA = Invalid; TOptional<uint8> TempA = Invalid;
TOptional<int16> TempB = 16; TOptional<int16> TempB = 16;
@ -257,7 +257,7 @@ void TestVariant()
{ {
using VariantType = TVariant<int32, int64, float64>; using VariantType = TVariant<int32, int64, float64>;
VariantType TempArray[] = { 10, 15ll, 1.5 }; VariantType TempArray[] = { 10, 15ll, 1.5 };
for(auto&& TempA : TempArray) for(auto&& TempA : TempArray)
{ {
Visit( Visit(
@ -273,7 +273,7 @@ void TestVariant()
); );
VariantType TempB = Visit([](auto&& A) -> VariantType { return A + A; }, TempA); VariantType TempB = Visit([](auto&& A) -> VariantType { return A + A; }, TempA);
Visit( Visit(
[](auto&& A, auto&& B) [](auto&& A, auto&& B)
{ {
@ -287,7 +287,7 @@ void TestVariant()
); );
Visit([](auto&& A) { A *= 2; }, TempA); Visit([](auto&& A) { A *= 2; }, TempA);
Visit( Visit(
[](auto&& A) [](auto&& A)
{ {
@ -300,7 +300,7 @@ void TestVariant()
TempA TempA
); );
} }
for (auto&& TempA : TempArray) { for (auto&& TempA : TempArray) {
Visit( Visit(
TOverloaded TOverloaded
@ -414,7 +414,7 @@ void TestVariant()
auto ReturnRD = Visit<int32>(TestQualifiers, MoveTemp(TempRD)); auto ReturnRD = Visit<int32>(TestQualifiers, MoveTemp(TempRD));
always_check((CSameAs<int32, decltype(ReturnRD)>)); always_check((CSameAs<int32, decltype(ReturnRD)>));
} }
{ {
always_check(GetTypeHash(TVariant<int32, float>(114)) == GetTypeHash(TVariant<int32, float>(114))); always_check(GetTypeHash(TVariant<int32, float>(114)) == GetTypeHash(TVariant<int32, float>(114)));
always_check(GetTypeHash(TVariant<int32, float>(114)) != GetTypeHash(TVariant<int32, float>(514))); always_check(GetTypeHash(TVariant<int32, float>(114)) != GetTypeHash(TVariant<int32, float>(514)));
@ -569,16 +569,16 @@ void TestAny()
FAny TempD(InPlaceType<FFloating>, 0.0); FAny TempD(InPlaceType<FFloating>, 0.0);
FAny TempG(TempA); FAny TempG(TempA);
FAny TempH(TempC); FAny TempH(TempC);
FAny TempK, TempL, TempM, TempN; FAny TempK, TempL, TempM, TempN;
TempK = TempA; TempK = TempA;
TempL = TempD; TempL = TempD;
TempM = FAny(FFloating(0.0)); TempM = FAny(FFloating(0.0));
TempN = FAny(Invalid); TempN = FAny(Invalid);
TempL = FFloating(303.0); TempL = FFloating(303.0);
TempM = FFloating(404.0); TempM = FFloating(404.0);
FAny TempO; FAny TempO;
TempO.Emplace<FFloating>(202.0); TempO.Emplace<FFloating>(202.0);
TempO.Emplace<FFloating>(404.0); TempO.Emplace<FFloating>(404.0);
@ -692,7 +692,7 @@ void TestTuple()
always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const int32, char>&&>().GetValue<0>()), const volatile int32&&>));
always_check((CSameAs<decltype(DeclVal<const volatile TTuple< volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>));
always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>));
always_check((CSameAs<decltype(DeclVal< TTuple< int32&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< int32&, char>&>().GetValue<0>()), int32&>));
always_check((CSameAs<decltype(DeclVal< TTuple<const int32&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const int32&, char>&>().GetValue<0>()), const int32&>));
always_check((CSameAs<decltype(DeclVal< TTuple< volatile int32&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< volatile int32&, char>&>().GetValue<0>()), volatile int32&>));
@ -773,7 +773,7 @@ void TestTuple()
always_check((CSameAs<TTupleElement<0, const volatile TTuple<double, float&, char&&>>, const volatile double>)); always_check((CSameAs<TTupleElement<0, const volatile TTuple<double, float&, char&&>>, const volatile double>));
always_check((CSameAs<TTupleElement<1, const volatile TTuple<double, float&, char&&>>, float&>)); always_check((CSameAs<TTupleElement<1, const volatile TTuple<double, float&, char&&>>, float&>));
always_check((CSameAs<TTupleElement<2, const volatile TTuple<double, float&, char&&>>, char&&>)); always_check((CSameAs<TTupleElement<2, const volatile TTuple<double, float&, char&&>>, char&&>));
always_check((TTupleIndex<double, TTuple<double, float&, char&&>> == 0)); always_check((TTupleIndex<double, TTuple<double, float&, char&&>> == 0));
always_check((TTupleIndex<float&, TTuple<double, float&, char&&>> == 1)); always_check((TTupleIndex<float&, TTuple<double, float&, char&&>> == 1));
always_check((TTupleIndex<char&&, TTuple<double, float&, char&&>> == 2)); always_check((TTupleIndex<char&&, TTuple<double, float&, char&&>> == 2));
@ -816,7 +816,7 @@ void TestTuple()
Temp.Fourteenth = 0; Temp.Fourteenth = 0;
Temp.Fifteenth = 0; Temp.Fifteenth = 0;
Temp.Sixteenth = 0; Temp.Sixteenth = 0;
always_check(CDefaultConstructible<Type>); always_check(CDefaultConstructible<Type>);
always_check(CTriviallyDefaultConstructible<Type>); always_check(CTriviallyDefaultConstructible<Type>);
always_check(CConstructibleFrom<Type>); always_check(CConstructibleFrom<Type>);
@ -906,7 +906,7 @@ void TestTuple()
{ {
int32 TempO = 15; int32 TempO = 15;
TTuple<int32&&, const int64> TempA = { MoveTemp(TempO), 514 }; TTuple<int32&&, const int64> TempA = { MoveTemp(TempO), 514 };
TempA.Apply( TempA.Apply(
[](auto&& A, auto&& B) [](auto&& A, auto&& B)
{ {
@ -916,7 +916,7 @@ void TestTuple()
always_check((CSameAs<decltype(B), const int64&>)); always_check((CSameAs<decltype(B), const int64&>));
} }
); );
MoveTemp(TempA).Apply( MoveTemp(TempA).Apply(
[](auto&& A, auto&& B) [](auto&& A, auto&& B)
{ {
@ -943,7 +943,7 @@ void TestTuple()
); );
VisitTuple([](auto&& A) { A++; }, TempB); VisitTuple([](auto&& A) { A++; }, TempB);
VisitTuple( VisitTuple(
[]<typename T> (T&& A) []<typename T> (T&& A)
{ {
@ -1146,7 +1146,7 @@ void TestFunction()
// TFunction<void()> ObjectG = MoveTemp(UniqueA); // TFunction<void()> ObjectG = MoveTemp(UniqueA);
TUniqueFunction<void()> UniqueG = MoveTemp(UniqueA); TUniqueFunction<void()> UniqueG = MoveTemp(UniqueA);
} }
{ {
TFunctionRef<void()> RefA = [] { }; TFunctionRef<void()> RefA = [] { };
TFunction<void()> ObjectA = [] { }; TFunction<void()> ObjectA = [] { };
@ -1163,7 +1163,7 @@ void TestFunction()
// TFunctionRef<void()> RefD; RefD = UniqueA; // TFunctionRef<void()> RefD; RefD = UniqueA;
// TFunction<void()> ObjectD; ObjectD = UniqueA; // TFunction<void()> ObjectD; ObjectD = UniqueA;
// TUniqueFunction<void()> UniqueD; UniqueD = UniqueA; // TUniqueFunction<void()> UniqueD; UniqueD = UniqueA;
// TFunctionRef<void()> RefE; RefE = MoveTemp(RefA); // TFunctionRef<void()> RefE; RefE = MoveTemp(RefA);
// TFunction<void()> ObjectE; ObjectE = MoveTemp(RefA); // TFunction<void()> ObjectE; ObjectE = MoveTemp(RefA);
// TUniqueFunction<void()> UniqueE; UniqueE = MoveTemp(RefA); // TUniqueFunction<void()> UniqueE; UniqueE = MoveTemp(RefA);
@ -1279,7 +1279,7 @@ void TestAtomic()
{ {
{ {
TAtomic<int32> TempA; TAtomic<int32> TempA;
always_check(TempA.bIsAlwaysLockFree); always_check(TempA.bIsAlwaysLockFree);
always_check((TempA = 11) == 11); always_check((TempA = 11) == 11);
TempA.Store(12); TempA.Store(12);
@ -1510,42 +1510,10 @@ void TestPropagateConst()
} }
} }
NAMESPACE_UNNAMED_BEGIN
template <typename T>
struct TTestStructA
{
T* Pad;
T* Data;
TTestStructA(T* InData) : Pad(nullptr), Data(InData) { }
~TTestStructA() { delete Data; }
T** operator&() { return &Data; }
};
template <typename T>
int32 TestFunctionB(TTestStructA<T>* Ptr)
{
return 0;
}
template <typename T>
int32 TestFunctionB(T** Ptr)
{
return 1;
}
NAMESPACE_UNNAMED_END
void TestMiscTemplates() void TestMiscTemplates()
{ {
TTestStructA<int32> ObjectA(new int32(3));
always_check(TestFunctionB(&ObjectA) == 1);
always_check(TestFunctionB(AddressOf(ObjectA)) == 0);
always_check(AddressOf(TestMiscTemplates) == &TestMiscTemplates);
struct FTestRetainedRef { explicit FTestRetainedRef(TRetainedRef<const int64> InRef) { } }; struct FTestRetainedRef { explicit FTestRetainedRef(TRetainedRef<const int64> InRef) { } };
int64 IntA; int64 IntA;
FTestRetainedRef TempA(IntA); FTestRetainedRef TempA(IntA);
// FTestRetainedRef TempB(114514); // FTestRetainedRef TempB(114514);

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Address.h"
#include "Memory/Allocator.h" #include "Memory/Allocator.h"
#include "Containers/Array.h" #include "Containers/Array.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
@ -58,7 +59,7 @@ public:
{ {
checkf(Extent == DynamicExtent || Extent == InCount, TEXT("Illegal range count. Please check InCount.")); checkf(Extent == DynamicExtent || Extent == InCount, TEXT("Illegal range count. Please check InCount."));
Impl.Pointer = AddressOf(*InFirst); Impl.Pointer = ToAddress(InFirst);
if constexpr (Extent == DynamicExtent) if constexpr (Extent == DynamicExtent)
{ {
@ -72,7 +73,7 @@ public:
{ {
checkf(Extent == DynamicExtent || Extent == InLast - InFirst, TEXT("Illegal range iterator. Please check InLast - InFirst.")); checkf(Extent == DynamicExtent || Extent == InLast - InFirst, TEXT("Illegal range iterator. Please check InLast - InFirst."));
Impl.Pointer = AddressOf(*InFirst); Impl.Pointer = ToAddress(InFirst);
if constexpr (Extent == DynamicExtent) if constexpr (Extent == DynamicExtent)
{ {
@ -84,7 +85,8 @@ public:
template <size_t N> requires (Extent == DynamicExtent || N == Extent) template <size_t N> requires (Extent == DynamicExtent || N == Extent)
FORCEINLINE constexpr TArrayView(ElementType(&InArray)[N]) FORCEINLINE constexpr TArrayView(ElementType(&InArray)[N])
{ {
Impl.Pointer = AddressOf(InArray[0]); // @TODO: Refactor this to use the GetData() function.
Impl.Pointer = InArray;
if constexpr (Extent == DynamicExtent) if constexpr (Extent == DynamicExtent)
{ {
@ -114,7 +116,8 @@ public:
{ {
checkf(Extent == DynamicExtent || Extent == InValue.Num(), TEXT("Illegal view extent. Please check InValue.Num().")); checkf(Extent == DynamicExtent || Extent == InValue.Num(), TEXT("Illegal view extent. Please check InValue.Num()."));
Impl.Pointer = AddressOf(InValue[0]); // @TODO: Refactor this to use the GetData() function.
Impl.Pointer = InValue.GetData().Get();
if constexpr (Extent == DynamicExtent) if constexpr (Extent == DynamicExtent)
{ {

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Address.h"
#include "Templates/Invoke.h" #include "Templates/Invoke.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Templates/Noncopyable.h" #include "Templates/Noncopyable.h"
@ -128,7 +129,7 @@ concept CContiguousIterator = CRandomAccessIterator<I> && CLValueReference<TIter
&& CSameAs<TIteratorElementType<I>, TRemoveCVRef<TIteratorReferenceType<I>>> && CSameAs<TIteratorElementType<I>, TRemoveCVRef<TIteratorReferenceType<I>>>
&& requires(I& Iter) && requires(I& Iter)
{ {
{ AddressOf(*Iter) } -> CSameAs<TAddPointer<TIteratorReferenceType<I>>>; { ToAddress(Iter) } -> CSameAs<TAddPointer<TIteratorReferenceType<I>>>;
}; };
static_assert(CContiguousIterator<int32*>); static_assert(CContiguousIterator<int32*>);
@ -173,8 +174,8 @@ public:
template <CBidirectionalIterator J> requires (CSizedSentinelFor<J, IteratorType>) template <CBidirectionalIterator J> requires (CSizedSentinelFor<J, IteratorType>)
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<J, IteratorType> operator<=>(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return RHS.GetBase() <=> LHS.GetBase(); } NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<J, IteratorType> operator<=>(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return RHS.GetBase() <=> LHS.GetBase(); }
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator*() const { IteratorType Temp = GetBase(); return *--Temp; } NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator*() const { IteratorType Temp = GetBase(); return *--Temp; }
NODISCARD FORCEINLINE constexpr TIteratorPointerType<IteratorType> operator->() const { return AddressOf(operator*()); } NODISCARD FORCEINLINE constexpr TIteratorPointerType<IteratorType> operator->() const { IteratorType Temp = GetBase(); return ToAddress(--Temp); }
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator[](ptrdiff Index) const requires (CRandomAccessIterator<IteratorType>) { return GetBase()[-Index - 1]; } NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator[](ptrdiff Index) const requires (CRandomAccessIterator<IteratorType>) { return GetBase()[-Index - 1]; }
@ -402,7 +403,7 @@ public:
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator*() const requires (CDereferenceable<const IteratorType>) { CheckThis(true); return *Current; } NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator*() const requires (CDereferenceable<const IteratorType>) { CheckThis(true); return *Current; }
NODISCARD FORCEINLINE constexpr TIteratorPointerType<IteratorType> operator->() const requires (CContiguousIterator<IteratorType>) { CheckThis(true); return AddressOf(operator*()); } NODISCARD FORCEINLINE constexpr TIteratorPointerType<IteratorType> operator->() const requires (CContiguousIterator<IteratorType>) { CheckThis(true); return ToAddress(Current); }
NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator[](ptrdiff Index) const requires (CRandomAccessIterator<IteratorType>) { TCountedIterator Temp = *this + Index; return *Temp; } NODISCARD FORCEINLINE constexpr TIteratorReferenceType<IteratorType> operator[](ptrdiff Index) const requires (CRandomAccessIterator<IteratorType>) { TCountedIterator Temp = *this + Index; return *Temp; }

View File

@ -0,0 +1,43 @@
#pragma once
#include "CoreTypes.h"
#include "Memory/PointerTraits.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
/** Obtains a raw pointer from a pointer-like type. */
template <typename T> requires (TPointerTraits<T>::bIsPointer || requires(const T& Ptr) { Ptr.operator->(); })
constexpr auto ToAddress(const T& Ptr) noexcept
{
if constexpr (TPointerTraits<T>::bIsPointer) {
return TPointerTraits<T>::ToAddress(Ptr);
}
else {
return ToAddress(Ptr.operator->());
}
}
/** Obtains the actual address of the object or function arg, even in presence of overloaded operator&. */
template <typename T> requires (CObject<T>)
FORCEINLINE constexpr T* AddressOf(T& Object)
{
return reinterpret_cast<T*>(&const_cast<char&>(reinterpret_cast<const volatile char&>(Object)));
}
/** Obtains the actual address of the object or function arg, even in presence of overloaded operator&. */
template <typename T> requires (!CObject<T>)
FORCEINLINE constexpr T* AddressOf(T& Object)
{
return &Object;
}
/** Rvalue overload is deleted to prevent taking the address of const rvalues. */
template <typename T>
const T* AddressOf(const T&&) = delete;
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -7,7 +7,7 @@ NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_MODULE_BEGIN(Utility)
/** The class template provides the standardized way to access certain properties of pointer-like types. */ /** The class template provides the standardized way to access certain properties of pointer-like types. */
template <typename T> template <typename>
struct TPointerTraits struct TPointerTraits
{ {
static constexpr bool bIsPointer = false; static constexpr bool bIsPointer = false;
@ -21,7 +21,7 @@ struct TPointerTraits<T*>
using PointerType = T*; using PointerType = T*;
using ElementType = T; using ElementType = T;
static FORCEINLINE constexpr ElementType* ToAddress(PointerType InPtr) static FORCEINLINE constexpr ElementType* ToAddress(PointerType InPtr)
{ {
return InPtr; return InPtr;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Address.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Containers/Iterator.h" #include "Containers/Iterator.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
@ -45,7 +46,8 @@ public:
FORCEINLINE constexpr TConstantIterator& operator=(TConstantIterator&&) requires (CMoveAssignable<T>) = default; FORCEINLINE constexpr TConstantIterator& operator=(TConstantIterator&&) requires (CMoveAssignable<T>) = default;
NODISCARD FORCEINLINE constexpr const T& operator*() const { return Value; } NODISCARD FORCEINLINE constexpr const T& operator*() const { return Value; }
NODISCARD FORCEINLINE constexpr const T* operator->() const { return AddressOf(Value); }
FORCEINLINE constexpr TConstantIterator& operator++() { return *this; } FORCEINLINE constexpr TConstantIterator& operator++() { return *this; }
@ -89,7 +91,8 @@ public:
template <typename U> requires (CConvertibleTo<U*, T*>) template <typename U> requires (CConvertibleTo<U*, T*>)
FORCEINLINE constexpr TConstantIterator& operator=(const TConstantIterator<U>& InValue) { Ptr = InValue.Ptr; return *this; } FORCEINLINE constexpr TConstantIterator& operator=(const TConstantIterator<U>& InValue) { Ptr = InValue.Ptr; return *this; }
NODISCARD FORCEINLINE constexpr const T& operator*() const { return *Ptr; } NODISCARD FORCEINLINE constexpr const T& operator*() const { return *Ptr; }
NODISCARD FORCEINLINE constexpr const T* operator->() const { return Ptr; }
FORCEINLINE constexpr TConstantIterator& operator++() { return *this; } FORCEINLINE constexpr TConstantIterator& operator++() { return *this; }
@ -154,8 +157,8 @@ public:
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(FDefaultSentinel) const& { return static_cast<ptrdiff>(0) <=> Length; } NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(FDefaultSentinel) const& { return static_cast<ptrdiff>(0) <=> Length; }
NODISCARD FORCEINLINE constexpr const TRemoveReference<T>& operator*() const { CheckThis(true); return *Current; } NODISCARD FORCEINLINE constexpr const TRemoveReference<T>& operator*() const { CheckThis(true); return *Current; }
NODISCARD FORCEINLINE constexpr const TRemoveReference<T>* operator->() const { CheckThis(true); return AddressOf(operator*()); } NODISCARD FORCEINLINE constexpr const TRemoveReference<T>* operator->() const { CheckThis(true); return ToAddress(Current); }
NODISCARD FORCEINLINE constexpr const TRemoveReference<T>& operator[](ptrdiff) const { return *this; } NODISCARD FORCEINLINE constexpr const TRemoveReference<T>& operator[](ptrdiff) const { return *this; }

View File

@ -117,22 +117,22 @@ public:
FORCEINLINE TString& operator=(TString&& InValue) { NativeData = MoveTemp(InValue.NativeData); InValue.NativeData.PushBack(LITERAL(ElementType, '\0')); return *this; } FORCEINLINE TString& operator=(TString&& InValue) { NativeData = MoveTemp(InValue.NativeData); InValue.NativeData.PushBack(LITERAL(ElementType, '\0')); return *this; }
/** Compares the contents of two strings. */ /** Compares the contents of two strings. */
FORCEINLINE NODISCARD friend bool operator==(const TString& LHS, const TString& RHS) { return TStringView<ElementType>(LHS) == TStringView<ElementType>(RHS); } NODISCARD friend FORCEINLINE bool operator==(const TString& LHS, const TString& RHS) { return TStringView<ElementType>(LHS) == TStringView<ElementType>(RHS); }
/** Compares the contents of a string and a character. */ /** Compares the contents of a string and a character. */
FORCEINLINE NODISCARD friend bool operator==(const TString& LHS, ElementType RHS) { return TStringView<ElementType>(LHS) == RHS; } NODISCARD friend FORCEINLINE bool operator==(const TString& LHS, ElementType RHS) { return TStringView<ElementType>(LHS) == RHS; }
FORCEINLINE NODISCARD friend bool operator==(const TString& LHS, const ElementType* RHS) { return TStringView<ElementType>(LHS) == RHS; } NODISCARD friend FORCEINLINE bool operator==(const TString& LHS, const ElementType* RHS) { return TStringView<ElementType>(LHS) == RHS; }
FORCEINLINE NODISCARD friend bool operator==( ElementType LHS, const TString& RHS) { return LHS == TStringView<ElementType>(RHS); } NODISCARD friend FORCEINLINE bool operator==( ElementType LHS, const TString& RHS) { return LHS == TStringView<ElementType>(RHS); }
FORCEINLINE NODISCARD friend bool operator==(const ElementType* LHS, const TString& RHS) { return LHS == TStringView<ElementType>(RHS); } NODISCARD friend FORCEINLINE bool operator==(const ElementType* LHS, const TString& RHS) { return LHS == TStringView<ElementType>(RHS); }
/** Compares the contents of 'LHS' and 'RHS' lexicographically. */ /** Compares the contents of 'LHS' and 'RHS' lexicographically. */
FORCEINLINE NODISCARD friend auto operator<=>(const TString& LHS, const TString& RHS) { return TStringView<ElementType>(LHS) <=> TStringView<ElementType>(RHS); } NODISCARD friend FORCEINLINE auto operator<=>(const TString& LHS, const TString& RHS) { return TStringView<ElementType>(LHS) <=> TStringView<ElementType>(RHS); }
/** Compares the contents of 'LHS' and 'RHS' lexicographically. */ /** Compares the contents of 'LHS' and 'RHS' lexicographically. */
FORCEINLINE NODISCARD friend auto operator<=>(const TString& LHS, ElementType RHS) { return TStringView<ElementType>(LHS) <=> RHS; } NODISCARD friend FORCEINLINE auto operator<=>(const TString& LHS, ElementType RHS) { return TStringView<ElementType>(LHS) <=> RHS; }
FORCEINLINE NODISCARD friend auto operator<=>(const TString& LHS, const ElementType* RHS) { return TStringView<ElementType>(LHS) <=> RHS; } NODISCARD friend FORCEINLINE auto operator<=>(const TString& LHS, const ElementType* RHS) { return TStringView<ElementType>(LHS) <=> RHS; }
FORCEINLINE NODISCARD friend auto operator<=>( ElementType LHS, const TString& RHS) { return LHS <=> TStringView<ElementType>(RHS); } NODISCARD friend FORCEINLINE auto operator<=>(ElementType LHS, const TString& RHS) { return LHS <=> TStringView<ElementType>(RHS); }
FORCEINLINE NODISCARD friend auto operator<=>(const ElementType* LHS, const TString& RHS) { return LHS <=> TStringView<ElementType>(RHS); } NODISCARD friend FORCEINLINE auto operator<=>(const ElementType* LHS, const TString& RHS) { return LHS <=> TStringView<ElementType>(RHS); }
/** Inserts 'InValue' before 'Index' in the string. */ /** Inserts 'InValue' before 'Index' in the string. */
FORCEINLINE Iterator Insert(size_t Index, ElementType InValue) FORCEINLINE Iterator Insert(size_t Index, ElementType InValue)

View File

@ -2,6 +2,7 @@
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Memory.h" #include "Memory/Memory.h"
#include "Memory/Address.h"
#include "Templates/Meta.h" #include "Templates/Meta.h"
#include "Templates/Invoke.h" #include "Templates/Invoke.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
@ -96,7 +97,7 @@ class alignas(16) TFunctionStorage<false, bIsUnique>
public: public:
FORCEINLINE constexpr TFunctionStorage() = default; FORCEINLINE constexpr TFunctionStorage() = default;
TFunctionStorage(const TFunctionStorage& InValue) requires (!bIsUnique) TFunctionStorage(const TFunctionStorage& InValue) requires (!bIsUnique)
: RTTI(InValue.RTTI) : RTTI(InValue.RTTI)
{ {
@ -151,7 +152,7 @@ public:
{ {
Destroy(); Destroy();
} }
TFunctionStorage& operator=(const TFunctionStorage& InValue) requires (!bIsUnique) TFunctionStorage& operator=(const TFunctionStorage& InValue) requires (!bIsUnique)
{ {
if (&InValue == this) UNLIKELY return *this; if (&InValue == this) UNLIKELY return *this;
@ -322,7 +323,7 @@ private:
using FMoveConstruct = void(*)(void*, void*); using FMoveConstruct = void(*)(void*, void*);
using FDestruct = void(*)(void* ); using FDestruct = void(*)(void* );
const FMoveConstruct MoveConstruct; const FMoveConstruct MoveConstruct;
const FDestruct Destruct; const FDestruct Destruct;
@ -343,7 +344,7 @@ private:
) )
{ } { }
}; };
struct FCopyableRTTI : public FMovableRTTI struct FCopyableRTTI : public FMovableRTTI
{ {
using FCopyConstruct = void(*)(void*, const void*); using FCopyConstruct = void(*)(void*, const void*);
@ -363,7 +364,7 @@ private:
}; };
using FRTTI = TConditional<bIsUnique, FMovableRTTI, FCopyableRTTI>; using FRTTI = TConditional<bIsUnique, FMovableRTTI, FCopyableRTTI>;
static_assert(alignof(FRTTI) >= 4); static_assert(alignof(FRTTI) >= 4);
static constexpr uintptr_t RepresentationMask = 3; static constexpr uintptr_t RepresentationMask = 3;
@ -375,7 +376,7 @@ private:
Small = 2, // InternalStorage Small = 2, // InternalStorage
Big = 3, // ExternalStorage Big = 3, // ExternalStorage
}; };
union union
{ {
uint8 InternalStorage[64 - sizeof(uintptr) - sizeof(uintptr)]; uint8 InternalStorage[64 - sizeof(uintptr) - sizeof(uintptr)];
@ -387,7 +388,7 @@ private:
FORCEINLINE constexpr ERepresentation GetRepresentation() const { return static_cast<ERepresentation>(RTTI & RepresentationMask); } FORCEINLINE constexpr ERepresentation GetRepresentation() const { return static_cast<ERepresentation>(RTTI & RepresentationMask); }
FORCEINLINE constexpr const FRTTI& GetRTTI() const { return *reinterpret_cast<const FRTTI*>(RTTI & ~RepresentationMask); } FORCEINLINE constexpr const FRTTI& GetRTTI() const { return *reinterpret_cast<const FRTTI*>(RTTI & ~RepresentationMask); }
FORCEINLINE constexpr void* GetStorage() FORCEINLINE constexpr void* GetStorage()
{ {
switch (GetRepresentation()) switch (GetRepresentation())
@ -399,7 +400,7 @@ private:
default: check_no_entry(); return nullptr; default: check_no_entry(); return nullptr;
} }
} }
FORCEINLINE constexpr const void* GetStorage() const FORCEINLINE constexpr const void* GetStorage() const
{ {
switch (GetRepresentation()) switch (GetRepresentation())
@ -461,7 +462,7 @@ public:
using ResultType = Ret; using ResultType = Ret;
using ArgumentType = TTypeSequence<Ts...>; using ArgumentType = TTypeSequence<Ts...>;
FORCEINLINE constexpr TFunctionImpl() = default; FORCEINLINE constexpr TFunctionImpl() = default;
FORCEINLINE constexpr TFunctionImpl(const TFunctionImpl&) = default; FORCEINLINE constexpr TFunctionImpl(const TFunctionImpl&) = default;
FORCEINLINE constexpr TFunctionImpl(TFunctionImpl&&) = default; FORCEINLINE constexpr TFunctionImpl(TFunctionImpl&&) = default;
@ -648,7 +649,7 @@ public:
{ {
Impl::template Emplace<T>(Forward<Ts>(Args)...); Impl::template Emplace<T>(Forward<Ts>(Args)...);
} }
/** /**
* Constructs an TFunction with initial content an function object of type TDecay<T>, * Constructs an TFunction with initial content an function object of type TDecay<T>,
* direct-non-list-initialized from IL, Forward<Ts>(Args).... * direct-non-list-initialized from IL, Forward<Ts>(Args)....
@ -694,7 +695,7 @@ public:
Impl::Destroy(); Impl::Destroy();
return Impl::template Emplace<T>(Forward<Ts>(Args)...); return Impl::template Emplace<T>(Forward<Ts>(Args)...);
} }
/** /**
* Changes the function object to one of type TDecay<T> constructed from the arguments. * Changes the function object to one of type TDecay<T> constructed from the arguments.
* First destroys the current function object (if any) by Reset(), then constructs an object of type * First destroys the current function object (if any) by Reset(), then constructs an object of type
@ -790,7 +791,7 @@ public:
if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Impl::Invalidate(); if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Impl::Invalidate();
else Impl::template Emplace<T>(Forward<T>(InValue)); else Impl::template Emplace<T>(Forward<T>(InValue));
} }
/** /**
* Constructs an TUniqueFunction with initial content an function object of type TDecay<T>, * Constructs an TUniqueFunction with initial content an function object of type TDecay<T>,
* direct-non-list-initialized from Forward<Ts>(Args).... * direct-non-list-initialized from Forward<Ts>(Args)....
@ -801,7 +802,7 @@ public:
{ {
Impl::template Emplace<T>(Forward<Ts>(Args)...); Impl::template Emplace<T>(Forward<Ts>(Args)...);
} }
/** /**
* Constructs an TUniqueFunction with initial content an function object of type TDecay<T>, * Constructs an TUniqueFunction with initial content an function object of type TDecay<T>,
* direct-non-list-initialized from IL, Forward<Ts>(Args).... * direct-non-list-initialized from IL, Forward<Ts>(Args)....
@ -844,7 +845,7 @@ public:
using DecayedType = TDecay<T>; using DecayedType = TDecay<T>;
return Impl::template Emplace<T>(Forward<Ts>(Args)...); return Impl::template Emplace<T>(Forward<Ts>(Args)...);
} }
/** /**
* Changes the function object to one of type TDecay<T> constructed from the arguments. * Changes the function object to one of type TDecay<T> constructed from the arguments.
* First destroys the current function object (if any) by Reset(), then constructs an object of type * First destroys the current function object (if any) by Reset(), then constructs an object of type

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Address.h"
#include "Templates/Invoke.h" #include "Templates/Invoke.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Templates/Optional.h" #include "Templates/Optional.h"
@ -31,7 +32,7 @@ public:
/** Copies content of other into a new instance. */ /** Copies content of other into a new instance. */
FORCEINLINE constexpr TReferenceWrapper(const TReferenceWrapper&) = default; FORCEINLINE constexpr TReferenceWrapper(const TReferenceWrapper&) = default;
/** Converting copy constructor. */ /** Converting copy constructor. */
template <typename T = ReferencedType> requires (CConvertibleTo<T&, ReferencedType&>) template <typename T = ReferencedType> requires (CConvertibleTo<T&, ReferencedType&>)
FORCEINLINE constexpr TReferenceWrapper(const TReferenceWrapper<T>& InValue) FORCEINLINE constexpr TReferenceWrapper(const TReferenceWrapper<T>& InValue)

View File

@ -89,24 +89,6 @@ FORCEINLINE constexpr T Exchange(T& A, U&& B)
template <typename T> template <typename T>
TAddRValueReference<T> DeclVal(); TAddRValueReference<T> DeclVal();
/** Obtains the actual address of the object or function arg, even in presence of overloaded operator&. */
template <typename T> requires (CObject<T>)
FORCEINLINE constexpr T* AddressOf(T& Object)
{
return reinterpret_cast<T*>(&const_cast<char&>(reinterpret_cast<const volatile char&>(Object)));
}
/** Obtains the actual address of the object or function arg, even in presence of overloaded operator&. */
template <typename T> requires (!CObject<T>)
FORCEINLINE constexpr T* AddressOf(T& Object)
{
return &Object;
}
/** Rvalue overload is deleted to prevent taking the address of const rvalues. */
template <typename T>
const T* AddressOf(const T&&) = delete;
struct FIgnore final struct FIgnore final
{ {
template <typename T> template <typename T>
@ -116,7 +98,7 @@ struct FIgnore final
/** /**
* An object of unspecified type such that any value can be assigned to it with no effect. * An object of unspecified type such that any value can be assigned to it with no effect.
* Intended for use with Tie when unpacking a TTuple, as placeholders for unused arguments * Intended for use with Tie when unpacking a TTuple, as placeholders for unused arguments
* or using Ignore to avoid warnings about unused return values from NODISCARD functions. * or using Ignore to avoid warnings about unused return values from NODISCARD functions.
*/ */
inline constexpr FIgnore Ignore; inline constexpr FIgnore Ignore;
@ -137,7 +119,7 @@ inline constexpr FIgnore Ignore;
/** /**
* This class is used to create a set of overloaded functions. * This class is used to create a set of overloaded functions.
* *
* Visit(TOverloaded { * Visit(TOverloaded {
* [](auto A) { ... }, * [](auto A) { ... },
* [](double A) { ... }, * [](double A) { ... },

View File

@ -9,6 +9,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Testing) NAMESPACE_BEGIN(Testing)
REDCRAFTUTILITY_API void TestMemory(); REDCRAFTUTILITY_API void TestMemory();
REDCRAFTUTILITY_API void TestAddress();
REDCRAFTUTILITY_API void TestAlignment(); REDCRAFTUTILITY_API void TestAlignment();
REDCRAFTUTILITY_API void TestMemoryBuffer(); REDCRAFTUTILITY_API void TestMemoryBuffer();
REDCRAFTUTILITY_API void TestMemoryMalloc(); REDCRAFTUTILITY_API void TestMemoryMalloc();