Compare commits

..

7 Commits

17 changed files with 1443 additions and 819 deletions

View File

@ -2,7 +2,11 @@
#include "Memory/Memory.h"
#include "Memory/Alignment.h"
#include "Memory/PointerTraits.h"
#include "Memory/UniquePointer.h"
#include "Memory/SharedPointer.h"
#include "Memory/MemoryOperator.h"
#include "Memory/ObserverPointer.h"
#include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN
@ -17,6 +21,10 @@ void TestMemory()
TestMemoryBuffer();
TestMemoryMalloc();
TestMemoryOperator();
TestPointerTraits();
TestUniquePointer();
TestSharedPointer();
TestObserverPointer();
}
void TestAlignment()
@ -206,6 +214,890 @@ void TestMemoryOperator()
Memory::Free(PtrB);
}
void TestPointerTraits()
{
always_check(!TPointerTraits<int64>::bIsPointer);
always_check(TPointerTraits<int64*>::bIsPointer);
always_check((CSameAs<TPointerTraits<int64*>::PointerType, int64*>));
always_check((CSameAs<TPointerTraits<int64*>::ElementType, int64>));
always_check(TPointerTraits<int64*>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<int64(*)[]>::bIsPointer);
always_check((CSameAs<TPointerTraits<int64(*)[]>::PointerType, int64(*)[]>));
always_check((CSameAs<TPointerTraits<int64(*)[]>::ElementType, int64>));
always_check(TPointerTraits<int64*>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<TSharedPtr<int64>>::bIsPointer);
always_check((CSameAs<TPointerTraits<TSharedPtr<int64>>::PointerType, TSharedPtr<int64>>));
always_check((CSameAs<TPointerTraits<TSharedPtr<int64>>::ElementType, int64>));
always_check(TPointerTraits<TSharedPtr<int64>>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<TSharedPtr<int64[]>>::bIsPointer);
always_check((CSameAs<TPointerTraits<TSharedPtr<int64[]>>::PointerType, TSharedPtr<int64[]>>));
always_check((CSameAs<TPointerTraits<TSharedPtr<int64[]>>::ElementType, int64>));
always_check(TPointerTraits<TSharedPtr<int64[]>>::ToAddress(nullptr) == nullptr);
}
NAMESPACE_UNNAMED_BEGIN
struct FCounter
{
static int32 Num;
FCounter() { ++Num; }
~FCounter() { --Num; }
};
int32 FCounter::Num = 0;
struct FDeleter
{
static int32 Num;
void operator()(FCounter* Ptr) { delete Ptr; ++Num; }
};
int32 FDeleter::Num = 0;
struct FArrayDeleter
{
static int32 Num;
void operator()(FCounter* Ptr) { delete [] Ptr; ++Num; }
};
int32 FArrayDeleter::Num = 0;
NAMESPACE_UNNAMED_END
void TestUniquePointer()
{
{
TUniqueRef<int32> Temp(new int32);
*Temp = 15;
always_check(*Temp.Get() = 15);
}
FCounter::Num = 0;
FDeleter::Num = 0;
{
FCounter* PtrA = new FCounter;
FCounter* PtrB = new FCounter;
FCounter* PtrC = new FCounter;
TUniqueRef<FCounter> TempA(PtrA);
TUniqueRef<FCounter, FDeleter> TempB(PtrB);
TUniqueRef<FCounter, FDeleter> TempC(PtrC, FDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter);
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter);
always_check(FCounter::Num == TempNum + 1);
delete PtrX;
TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum + 1);
delete PtrY;
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempC.GetDeleter().Num == 2);
}
always_check(FCounter::Num == 0);
always_check(FDeleter::Num == 4);
{
TUniqueRef<int32[]> Temp(new int32[4]);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
FCounter::Num = 0;
FArrayDeleter::Num = 0;
{
FCounter* PtrA = new FCounter[4];
FCounter* PtrB = new FCounter[4];
FCounter* PtrC = new FCounter[4];
TUniqueRef<FCounter[]> TempA(PtrA);
TUniqueRef<FCounter[], FArrayDeleter> TempB(PtrB);
TUniqueRef<FCounter[], FArrayDeleter> TempC(PtrC, FArrayDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4]);
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]);
always_check(FCounter::Num == TempNum + 4);
delete [] PtrX;
TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum + 4);
delete [] PtrY;
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempC.GetDeleter().Num == 2);
}
always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 4);
{
TUniquePtr<int32> Temp = MakeUnique<int32>(NoInit);
*Temp = 15;
always_check(*Temp.Get() = 15);
}
{
TUniquePtr<int32> Temp = MakeUnique<int32>();
*Temp = 15;
always_check(*Temp.Get() = 15);
}
FCounter::Num = 0;
FDeleter::Num = 0;
{
FCounter* PtrA = new FCounter;
FCounter* PtrB = new FCounter;
FCounter* PtrC = new FCounter;
TUniquePtr<FCounter> TempA(PtrA);
TUniquePtr<FCounter, FDeleter> TempB(PtrB);
TUniquePtr<FCounter, FDeleter> TempC(PtrC, FDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter);
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter);
always_check(FCounter::Num == TempNum + 1);
delete PtrX;
TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum + 1);
delete PtrY;
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempC.GetDeleter().Num == 2);
TUniquePtr<FCounter, FDeleter> TempD(MoveTemp(TempB));
TUniquePtr<FCounter, FDeleter> TempE;
TempE = MoveTemp(TempC);
TempE = nullptr;
TempB.Reset(new FCounter);
always_check(!!TempB);
always_check(TempB.IsValid());
delete TempB.Release();
}
always_check(FCounter::Num == 0);
always_check(FDeleter::Num == 4);
{
TUniquePtr<int32[]> Temp = MakeUnique<int32[]>(4, NoInit);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
{
TUniquePtr<int32[]> Temp = MakeUnique<int32[]>(4);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
FCounter::Num = 0;
FArrayDeleter::Num = 0;
{
FCounter* PtrA = new FCounter[4];
FCounter* PtrB = new FCounter[4];
FCounter* PtrC = new FCounter[4];
TUniquePtr<FCounter[]> TempA(PtrA);
TUniquePtr<FCounter[], FArrayDeleter> TempB(PtrB);
TUniquePtr<FCounter[], FArrayDeleter> TempC(PtrC, FArrayDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4]);
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]);
always_check(FCounter::Num == TempNum + 4);
delete [] PtrX;
TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum + 4);
delete [] PtrY;
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempC.GetDeleter().Num == 2);
TUniquePtr<FCounter[], FArrayDeleter> TempD(MoveTemp(TempB));
TUniquePtr<FCounter[], FArrayDeleter> TempE;
TempE = MoveTemp(TempC);
TempE = nullptr;
TempB.Reset(new FCounter[4]);
always_check(!!TempB);
always_check(TempB.IsValid());
delete [] TempB.Release();
}
always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 4);
{
TUniquePtr<int32> TempA;
TUniquePtr<const int32> TempB = MoveTemp(TempA);
TUniquePtr<const int32> TempC;
TempC = MoveTemp(TempA);
}
{
TUniquePtr<int32[]> TempA;
TUniquePtr<const int32[]> TempB = MoveTemp(TempA);
TUniquePtr<const int32[]> TempC;
TempC = MoveTemp(TempA);
}
}
void TestSharedPointer()
{
FCounter::Num = 0;
FDeleter::Num = 0;
{
FCounter* PtrA = new FCounter;
FCounter* PtrB = new FCounter;
FCounter* PtrC = new FCounter;
TSharedRef<FCounter> TempA(PtrA);
TSharedRef<FCounter> TempB(PtrB, FDeleter());
TSharedRef<FCounter> TempC(PtrC, FDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempC.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempA.GetDeleter<FDeleter>() == nullptr);
always_check(TempC.GetDeleter<FDeleter>() != nullptr);
always_check(TempC.GetDeleter<FDeleter>()->Num == 2);
TSharedRef<FCounter> TempD(MoveTemp(TempB));
}
always_check(FCounter::Num == 0);
always_check(FDeleter::Num == 4);
{
TSharedRef<int32[]> Temp = MakeShared<int32[]>(4, NoInit);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
{
TSharedRef<int32[]> Temp = MakeShared<int32[]>(4);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
FCounter::Num = 0;
FArrayDeleter::Num = 0;
{
FCounter* PtrA = new FCounter[4];
FCounter* PtrB = new FCounter[4];
FCounter* PtrC = new FCounter[4];
TSharedRef<FCounter[]> TempA(PtrA);
TSharedRef<FCounter[]> TempB(PtrB, FArrayDeleter());
TSharedRef<FCounter[]> TempC(PtrC, FArrayDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempA.GetDeleter<FArrayDeleter>() == nullptr);
always_check(TempC.GetDeleter<FArrayDeleter>() != nullptr);
always_check(TempC.GetDeleter<FArrayDeleter>()->Num == 2);
TSharedRef<FCounter[]> TempD(MoveTemp(TempB));
}
always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 4);
FCounter::Num = 0;
FDeleter::Num = 0;
{
FCounter* PtrA = new FCounter;
FCounter* PtrB = new FCounter;
FCounter* PtrC = new FCounter;
TSharedPtr<FCounter> TempA(PtrA);
TSharedPtr<FCounter> TempB(PtrB, FDeleter());
TSharedPtr<FCounter> TempC(PtrC, FDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempA.GetDeleter<FDeleter>() == nullptr);
always_check(TempC.GetDeleter<FDeleter>() != nullptr);
always_check(TempC.GetDeleter<FDeleter>()->Num == 2);
TSharedPtr<FCounter> TempD(MoveTemp(TempB));
TSharedPtr<FCounter> TempE;
TempE = MoveTemp(TempC);
TempE = nullptr;
TempB.Reset(new FCounter, FDeleter());
always_check(!!TempB);
always_check(TempB.IsValid());
}
always_check(FCounter::Num == 0);
always_check(FDeleter::Num == 5);
{
TSharedPtr<int32[]> Temp = MakeShared<int32[]>(4, NoInit);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
{
TSharedPtr<int32[]> Temp = MakeShared<int32[]>(4);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
FCounter::Num = 0;
FArrayDeleter::Num = 0;
{
FCounter* PtrA = new FCounter[4];
FCounter* PtrB = new FCounter[4];
FCounter* PtrC = new FCounter[4];
TSharedPtr<FCounter[]> TempA(PtrA);
TSharedPtr<FCounter[]> TempB(PtrB, FArrayDeleter());
TSharedPtr<FCounter[]> TempC(PtrC, FArrayDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempA.GetDeleter<FArrayDeleter>() == nullptr);
always_check(TempC.GetDeleter<FArrayDeleter>() != nullptr);
always_check(TempC.GetDeleter<FArrayDeleter>()->Num == 2);
TSharedPtr<FCounter[]> TempD(MoveTemp(TempB));
TSharedPtr<FCounter[]> TempE;
TempE = MoveTemp(TempC);
TempE = nullptr;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(!!TempB);
always_check(TempB.IsValid());
}
always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 5);
{
TSharedPtr<bool> Temp;
always_check(!Temp.IsValid());
if (Temp.Get() == nullptr) { }
}
{
TSharedPtr<int32> Temp(new int32(123));
always_check(Temp.IsValid());
always_check(Temp.IsUnique());
const int32 DeferenceTest = *Temp;
Temp.Reset();
always_check(Temp.GetSharedReferenceCount() == 0);
}
{
TSharedPtr<bool> TempA(new bool(false));
TSharedPtr<bool> TempB(TempA);
}
{
TSharedPtr<bool> TempA(new bool(false));
TSharedPtr<bool> TempB;
TempB = TempA;
}
{
struct FSharedTest { bool bTest; };
TSharedPtr<FSharedTest> TempA(new FSharedTest());
TempA->bTest = true;
(*TempA).bTest = false;
TSharedPtr<FSharedTest> TempB(TempA);
TempA.Reset();
}
{
class FBase { bool bTest; };
class FDerived : public FBase { };
{
TSharedPtr<FBase> TempA(new FDerived());
TSharedPtr<FDerived> TempB(StaticCast<FDerived>(TempA));
}
{
TSharedPtr<FDerived> TempA(new FDerived());
TSharedPtr<FBase> TempB(TempA);
}
{
TSharedPtr<FDerived> TempA(new FDerived());
TSharedPtr<FBase> TempB;
TempB = TempA;
}
}
{
bool* Ptr = nullptr;
TSharedPtr<bool> Temp(Ptr);
always_check(!Temp.IsValid());
}
{
TSharedPtr<bool> Temp(new bool(true));
always_check(Temp.IsValid());
}
{
TWeakPtr<bool> Temp;
always_check(!Temp.Lock().IsValid());
}
{
TSharedPtr<int32> TempShared(new int32(64));
TWeakPtr<int32> TempWeak(TempShared);
always_check(TempWeak.Lock().IsValid());
}
{
TSharedPtr<int32> TempShared(new int32(64));
TWeakPtr<int32> TempWeak;
TempWeak = TempShared;
always_check(TempWeak.Lock().IsValid());
TempWeak.Reset();
always_check(!TempWeak.Lock().IsValid());
}
{
TSharedPtr<int32> TempShared(new int32(64));
TWeakPtr<int32> TempWeak = TempShared;
TempShared.Reset();
always_check(!TempWeak.Lock().IsValid());
}
{
TSharedPtr<int32> TempA(new int32(64));
TSharedPtr<int32> TempB(new int32(21));
TSharedPtr<int32> TempC(TempB);
always_check(!(TempA == TempB));
always_check(TempA != TempB);
always_check(TempB == TempC);
}
{
TSharedPtr<int32> TempA(new int32(64));
TSharedPtr<int32> TempB(new int32(21));
TWeakPtr<int32> WeakA(TempA);
TWeakPtr<int32> WeakB(TempB);
TWeakPtr<int32> WeakC(TempB);
always_check(!(WeakA.Lock() == WeakB.Lock()));
always_check(WeakA.Lock() != WeakB.Lock());
always_check(WeakB.Lock() == WeakC.Lock());
}
{
TSharedPtr<const int32> TempA(new int32(10));
TSharedPtr<const float32> TempB(new float32(1.0f));
TSharedPtr<const float32> TempC(new float32(2.0f));
if (TempB == TempC) { }
TempB = TempC;
TSharedPtr<float32> TempD(new float32(123.0f));
TempB = TempD;
TWeakPtr<const float32> TempE = TempB;
TWeakPtr<float32> TempF;
TempF = ConstCast<float32>(TempC);
*TempF.Lock() = 20.0f;
}
{
TSharedPtr<struct FTest> Temp;
struct FTest { int32 Value; };
Temp = TSharedPtr<FTest>(new FTest());
Temp->Value = 20;
}
{
TSharedPtr<bool> TempA(nullptr);
TSharedPtr<float32> TempB = nullptr;
TWeakPtr<bool> TempD(nullptr);
TWeakPtr<float32> TempE = nullptr;
TempB = TSharedPtr<float32>(new float32(0.1f));
TempB = nullptr;
TempB = MakeShared<float32>(30.0f);
TSharedPtr<float64> TempC(MakeShared<float64>(2.0));
struct FTest
{
TSharedPtr<float32> Value;
TSharedPtr<float32> FuncA() { return Value; }
TSharedPtr<float32> FuncB() { return MakeShared<float32>(123.0f); }
};
}
{
TSharedRef<float32> Temp(new float32(123.0f));
}
{
TSharedRef<float32> Temp(new float32(123.0f));
const float& RefA = *Temp;
const float& RefB = *Temp.Get();
}
{
TSharedRef<float32> Temp = MakeShared<float32>(123.0f);
}
{
TSharedRef<int32> TempA(new int32(1));
TSharedPtr<int32> TempB(TempA);
}
{
TSharedPtr<int32> TempA(new int32(1));
TSharedRef<int32> TempB(TempA.ToSharedRef());
}
{
TSharedRef<int32> Temp(new int32(10));
Temp = TSharedRef<int32>(new int32(20));
}
{
TSharedRef<int32> TempA(new int32(99));
TWeakPtr<int32> TempB = TempA;
always_check(TempB.Lock());
}
{
TSharedRef<int32> IntRef1(new int32(99));
TSharedRef<int32> IntRef2(new int32(21));
always_check(!(IntRef1 == IntRef2));
always_check(IntRef1 != IntRef2);
}
{
TSharedRef<int32> TempA(new int32(21));
TSharedPtr<int32> TempB(TempA);
TSharedPtr<int32> TempC;
always_check(TempA == TempB && TempB == TempA);
always_check(!(TempA != TempB || TempB != TempA));
always_check(!(TempA == TempC) && (TempA != TempC));
}
{
struct FTest : public TSharedFromThis<FTest>
{
TSharedRef<FTest> FuncTest() { return AsShared(); }
};
TSharedPtr<FTest> TempA(new FTest());
{
FTest* Ptr = TempA.Get();
TSharedRef<FTest> TempB(Ptr->FuncTest());
}
}
{
TSharedRef<int32> TempA = MakeShared<int32>();
TSharedRef<const int32> TempB = TempA;
TSharedRef<const int32> TempC = MakeShared<int32>();
TempC = TempA;
}
{
TSharedRef<int32[]> TempA = MakeShared<int32[]>(4);
TSharedRef<const int32[]> TempB = TempA;
TSharedRef<const int32[]> TempC = MakeShared<int32[]>(4);
TempC = TempA;
}
{
TSharedPtr<int32> TempA;
TSharedPtr<const int32> TempB = TempA;
TSharedPtr<const int32> TempC;
TempC = TempA;
}
{
TSharedPtr<int32[]> TempA;
TSharedPtr<const int32[]> TempB = TempA;
TSharedPtr<const int32[]> TempC;
TempC = TempA;
}
{
TWeakPtr<int32> TempA;
TWeakPtr<const int32> TempB = TempA;
TWeakPtr<const int32> TempC;
TempC = TempA;
}
{
TWeakPtr<int32[]> TempA;
TWeakPtr<const int32[]> TempB = TempA;
TWeakPtr<const int32[]> TempC;
TempC = TempA;
}
}
void TestObserverPointer()
{
{
int32 IntA;
int32 IntB;
TObserverPtr<int32> TempA;
TObserverPtr<int32> TempB = nullptr;
TObserverPtr<int32> TempC(&IntA);
TObserverPtr<int32> TempD(TempC);
TempA = TempC;
TempB = MakeObserver<int32>(&IntB);
always_check(TempA == TempC);
always_check(TempB == &IntB);
always_check(TempB.IsValid());
always_check(TempA.Release() == &IntA);
always_check(!TempA.IsValid());
TempA.Reset(&IntA);
always_check(TempA == &IntA);
always_check(GetTypeHash(TempA) == GetTypeHash(&IntA));
Swap(TempA, TempB);
always_check(TempA == &IntB);
always_check(TempB == &IntA);
}
{
int32 IntA[4];
int32 IntB[4];
TObserverPtr<int32[]> TempA;
TObserverPtr<int32[]> TempB = nullptr;
TObserverPtr<int32[]> TempC(IntA);
TObserverPtr<int32[]> TempD(TempC);
TempA = TempC;
TempB = MakeObserver<int32[]>(IntB);
always_check(TempA == TempC);
always_check(TempB == IntB);
always_check(TempB.IsValid());
always_check(TempA.Release() == IntA);
always_check(!TempA.IsValid());
TempA.Reset(IntA);
always_check(TempA == IntA);
always_check(GetTypeHash(TempA) == GetTypeHash(&IntA));
Swap(TempA, TempB);
always_check(TempA == IntB);
always_check(TempB == IntA);
}
}
NAMESPACE_END(Testing)
NAMESPACE_MODULE_END(Utility)

View File

@ -25,8 +25,7 @@ void TestTemplates()
TestFunction();
TestAtomic();
TestScopeHelper();
TestUniquePointer();
TestSharedPointer();
TestPropagateConst();
TestMiscTemplates();
}
@ -1471,797 +1470,44 @@ void TestScopeHelper()
}
NAMESPACE_UNNAMED_BEGIN
struct FCounter
{
static int32 Num;
FCounter() { ++Num; }
~FCounter() { --Num; }
};
int32 FCounter::Num = 0;
struct FDeleter
{
static int32 Num;
void operator()(FCounter* Ptr) { delete Ptr; ++Num; }
};
int32 FDeleter::Num = 0;
struct FArrayDeleter
{
static int32 Num;
void operator()(FCounter* Ptr) { delete [] Ptr; ++Num; }
};
int32 FArrayDeleter::Num = 0;
NAMESPACE_UNNAMED_END
void TestUniquePointer()
void TestPropagateConst()
{
{
TUniqueRef<int32> Temp(new int32);
*Temp = 15;
always_check(*Temp.Get() = 15);
}
FCounter::Num = 0;
FDeleter::Num = 0;
struct FTestA
{
FCounter* PtrA = new FCounter;
FCounter* PtrB = new FCounter;
FCounter* PtrC = new FCounter;
TUniqueRef<FCounter> TempA(PtrA);
TUniqueRef<FCounter, FDeleter> TempB(PtrB);
TUniqueRef<FCounter, FDeleter> TempC(PtrC, FDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter);
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter);
always_check(FCounter::Num == TempNum + 1);
delete PtrX;
TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum + 1);
delete PtrY;
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempC.GetDeleter().Num == 2);
}
always_check(FCounter::Num == 0);
always_check(FDeleter::Num == 4);
void Check(bool bFlag) { always_check(!bFlag); }
void Check(bool bFlag) const { always_check( bFlag); }
};
struct FTestB
{
TUniqueRef<int32[]> Temp(new int32[4]);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
FTestB() { Ptr = &Object; }
FTestA Object;
TPropagateConst<FTestA*> Ptr;
};
FCounter::Num = 0;
FArrayDeleter::Num = 0;
FTestB TempA;
const FTestB TempB;
{
FCounter* PtrA = new FCounter[4];
FCounter* PtrB = new FCounter[4];
FCounter* PtrC = new FCounter[4];
TUniqueRef<FCounter[]> TempA(PtrA);
TUniqueRef<FCounter[], FArrayDeleter> TempB(PtrB);
TUniqueRef<FCounter[], FArrayDeleter> TempC(PtrC, FArrayDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4]);
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]);
always_check(FCounter::Num == TempNum + 4);
delete [] PtrX;
TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum + 4);
delete [] PtrY;
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempC.GetDeleter().Num == 2);
}
always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 4);
{
TUniquePtr<int32> Temp = MakeUnique<int32>(NoInit);
*Temp = 15;
always_check(*Temp.Get() = 15);
TempA.Ptr->Check(false);
TempB.Ptr->Check(true);
}
{
TUniquePtr<int32> Temp = MakeUnique<int32>();
*Temp = 15;
always_check(*Temp.Get() = 15);
}
int64 IntA;
int64 IntB;
FCounter::Num = 0;
FDeleter::Num = 0;
{
FCounter* PtrA = new FCounter;
FCounter* PtrB = new FCounter;
FCounter* PtrC = new FCounter;
TUniquePtr<FCounter> TempA(PtrA);
TUniquePtr<FCounter, FDeleter> TempB(PtrB);
TUniquePtr<FCounter, FDeleter> TempC(PtrC, FDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter);
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter);
always_check(FCounter::Num == TempNum + 1);
delete PtrX;
TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum + 1);
delete PtrY;
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempC.GetDeleter().Num == 2);
TUniquePtr<FCounter, FDeleter> TempD(MoveTemp(TempB));
TUniquePtr<FCounter, FDeleter> TempE;
TempE = MoveTemp(TempC);
TempE = nullptr;
TempB.Reset(new FCounter);
always_check(!!TempB);
always_check(TempB.IsValid());
delete TempB.Release();
}
always_check(FCounter::Num == 0);
always_check(FDeleter::Num == 4);
{
TUniquePtr<int32[]> Temp = MakeUnique<int32[]>(4, NoInit);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
{
TUniquePtr<int32[]> Temp = MakeUnique<int32[]>(4);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
FCounter::Num = 0;
FArrayDeleter::Num = 0;
{
FCounter* PtrA = new FCounter[4];
FCounter* PtrB = new FCounter[4];
FCounter* PtrC = new FCounter[4];
TUniquePtr<FCounter[]> TempA(PtrA);
TUniquePtr<FCounter[], FArrayDeleter> TempB(PtrB);
TUniquePtr<FCounter[], FArrayDeleter> TempC(PtrC, FArrayDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4]);
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]);
always_check(FCounter::Num == TempNum + 4);
delete [] PtrX;
TempNum = FCounter::Num;
FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum + 4);
delete [] PtrY;
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempC.GetDeleter().Num == 2);
TUniquePtr<FCounter[], FArrayDeleter> TempD(MoveTemp(TempB));
TUniquePtr<FCounter[], FArrayDeleter> TempE;
TempE = MoveTemp(TempC);
TempE = nullptr;
TempB.Reset(new FCounter[4]);
always_check(!!TempB);
always_check(TempB.IsValid());
delete [] TempB.Release();
}
always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 4);
{
TUniquePtr<int32> TempA;
TUniquePtr<const int32> TempB = MoveTemp(TempA);
TUniquePtr<const int32> TempC;
TempC = MoveTemp(TempA);
}
{
TUniquePtr<int32[]> TempA;
TUniquePtr<const int32[]> TempB = MoveTemp(TempA);
TUniquePtr<const int32[]> TempC;
TempC = MoveTemp(TempA);
}
}
void TestSharedPointer()
{
FCounter::Num = 0;
FDeleter::Num = 0;
{
FCounter* PtrA = new FCounter;
FCounter* PtrB = new FCounter;
FCounter* PtrC = new FCounter;
TSharedRef<FCounter> TempA(PtrA);
TSharedRef<FCounter> TempB(PtrB, FDeleter());
TSharedRef<FCounter> TempC(PtrC, FDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempC.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempA.GetDeleter<FDeleter>() == nullptr);
always_check(TempC.GetDeleter<FDeleter>() != nullptr);
always_check(TempC.GetDeleter<FDeleter>()->Num == 2);
TSharedRef<FCounter> TempD(MoveTemp(TempB));
}
always_check(FCounter::Num == 0);
always_check(FDeleter::Num == 4);
{
TSharedRef<int32[]> Temp = MakeShared<int32[]>(4, NoInit);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
{
TSharedRef<int32[]> Temp = MakeShared<int32[]>(4);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
FCounter::Num = 0;
FArrayDeleter::Num = 0;
{
FCounter* PtrA = new FCounter[4];
FCounter* PtrB = new FCounter[4];
FCounter* PtrC = new FCounter[4];
TSharedRef<FCounter[]> TempA(PtrA);
TSharedRef<FCounter[]> TempB(PtrB, FArrayDeleter());
TSharedRef<FCounter[]> TempC(PtrC, FArrayDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempA.GetDeleter<FArrayDeleter>() == nullptr);
always_check(TempC.GetDeleter<FArrayDeleter>() != nullptr);
always_check(TempC.GetDeleter<FArrayDeleter>()->Num == 2);
TSharedRef<FCounter[]> TempD(MoveTemp(TempB));
}
always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 4);
FCounter::Num = 0;
FDeleter::Num = 0;
{
FCounter* PtrA = new FCounter;
FCounter* PtrB = new FCounter;
FCounter* PtrC = new FCounter;
TSharedPtr<FCounter> TempA(PtrA);
TSharedPtr<FCounter> TempB(PtrB, FDeleter());
TSharedPtr<FCounter> TempC(PtrC, FDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter, FDeleter());
always_check(FCounter::Num == TempNum);
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempA.GetDeleter<FDeleter>() == nullptr);
always_check(TempC.GetDeleter<FDeleter>() != nullptr);
always_check(TempC.GetDeleter<FDeleter>()->Num == 2);
TSharedPtr<FCounter> TempD(MoveTemp(TempB));
TSharedPtr<FCounter> TempE;
TempE = MoveTemp(TempC);
TempE = nullptr;
TempB.Reset(new FCounter, FDeleter());
always_check(!!TempB);
always_check(TempB.IsValid());
}
always_check(FCounter::Num == 0);
always_check(FDeleter::Num == 5);
{
TSharedPtr<int32[]> Temp = MakeShared<int32[]>(4, NoInit);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
{
TSharedPtr<int32[]> Temp = MakeShared<int32[]>(4);
Temp[0] = 15;
always_check(Temp.Get()[0] = 15);
}
FCounter::Num = 0;
FArrayDeleter::Num = 0;
{
FCounter* PtrA = new FCounter[4];
FCounter* PtrB = new FCounter[4];
FCounter* PtrC = new FCounter[4];
TSharedPtr<FCounter[]> TempA(PtrA);
TSharedPtr<FCounter[]> TempB(PtrB, FArrayDeleter());
TSharedPtr<FCounter[]> TempC(PtrC, FArrayDeleter());
always_check(TempA == PtrA);
always_check(TempC != TempB);
always_check((TempA <=> PtrA) == strong_ordering::equal);
always_check((TempC <=> TempB) != strong_ordering::equal);
int32 TempNum;
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
TempNum = FCounter::Num;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(FCounter::Num == TempNum);
always_check(GetTypeHash(TempB) == GetTypeHash(TempB.Get()));
Swap(TempB, TempC);
always_check(TempA.GetDeleter<FArrayDeleter>() == nullptr);
always_check(TempC.GetDeleter<FArrayDeleter>() != nullptr);
always_check(TempC.GetDeleter<FArrayDeleter>()->Num == 2);
TSharedPtr<FCounter[]> TempD(MoveTemp(TempB));
TSharedPtr<FCounter[]> TempE;
TempE = MoveTemp(TempC);
TempE = nullptr;
TempB.Reset(new FCounter[4], FArrayDeleter());
always_check(!!TempB);
always_check(TempB.IsValid());
}
always_check( FCounter::Num == 0);
always_check(FArrayDeleter::Num == 5);
{
TSharedPtr<bool> Temp;
always_check(!Temp.IsValid());
if (Temp.Get() == nullptr) { }
}
{
TSharedPtr<int32> Temp(new int32(123));
always_check(Temp.IsValid());
always_check(Temp.IsUnique());
const int32 DeferenceTest = *Temp;
Temp.Reset();
always_check(Temp.GetSharedReferenceCount() == 0);
}
{
TSharedPtr<bool> TempA(new bool(false));
TSharedPtr<bool> TempB(TempA);
}
{
TSharedPtr<bool> TempA(new bool(false));
TSharedPtr<bool> TempB;
TempB = TempA;
}
{
struct FSharedTest { bool bTest; };
TSharedPtr<FSharedTest> TempA(new FSharedTest());
TempA->bTest = true;
(*TempA).bTest = false;
TSharedPtr<FSharedTest> TempB(TempA);
TempA.Reset();
}
{
class FBase { bool bTest; };
class FDerived : public FBase { };
{
TSharedPtr<FBase> TempA(new FDerived());
TSharedPtr<FDerived> TempB(StaticCast<FDerived>(TempA));
}
{
TSharedPtr<FDerived> TempA(new FDerived());
TSharedPtr<FBase> TempB(TempA);
}
{
TSharedPtr<FDerived> TempA(new FDerived());
TSharedPtr<FBase> TempB;
TempB = TempA;
}
}
{
bool* Ptr = nullptr;
TSharedPtr<bool> Temp(Ptr);
always_check(!Temp.IsValid());
}
{
TSharedPtr<bool> Temp(new bool(true));
always_check(Temp.IsValid());
}
{
TWeakPtr<bool> Temp;
always_check(!Temp.Lock().IsValid());
}
{
TSharedPtr<int32> TempShared(new int32(64));
TWeakPtr<int32> TempWeak(TempShared);
always_check(TempWeak.Lock().IsValid());
}
{
TSharedPtr<int32> TempShared(new int32(64));
TWeakPtr<int32> TempWeak;
TempWeak = TempShared;
always_check(TempWeak.Lock().IsValid());
TempWeak.Reset();
always_check(!TempWeak.Lock().IsValid());
}
{
TSharedPtr<int32> TempShared(new int32(64));
TWeakPtr<int32> TempWeak = TempShared;
TempShared.Reset();
always_check(!TempWeak.Lock().IsValid());
}
{
TSharedPtr<int32> TempA(new int32(64));
TSharedPtr<int32> TempB(new int32(21));
TSharedPtr<int32> TempC(TempB);
always_check(!(TempA == TempB));
always_check(TempA != TempB);
always_check(TempB == TempC);
}
{
TSharedPtr<int32> TempA(new int32(64));
TSharedPtr<int32> TempB(new int32(21));
TWeakPtr<int32> WeakA(TempA);
TWeakPtr<int32> WeakB(TempB);
TWeakPtr<int32> WeakC(TempB);
always_check(!(WeakA.Lock() == WeakB.Lock()));
always_check(WeakA.Lock() != WeakB.Lock());
always_check(WeakB.Lock() == WeakC.Lock());
}
{
TSharedPtr<const int32> TempA(new int32(10));
TSharedPtr<const float32> TempB(new float32(1.0f));
TSharedPtr<const float32> TempC(new float32(2.0f));
if (TempB == TempC) { }
TPropagateConst<int64*> TempA;
TPropagateConst<int64*> TempB = &IntA;
TPropagateConst<int64*> TempC = &IntB;
TempA = TempB;
TempB = TempC;
TSharedPtr<float32> TempD(new float32(123.0f));
TempB = TempD;
TWeakPtr<const float32> TempE = TempB;
TWeakPtr<float32> TempF;
TempF = ConstCast<float32>(TempC);
*TempF.Lock() = 20.0f;
always_check(TempA.IsValid());
always_check(TempA == &IntA);
always_check(TempB == TempC);
}
{
TSharedPtr<struct FTest> Temp;
struct FTest { int32 Value; };
Temp = TSharedPtr<FTest>(new FTest());
Temp->Value = 20;
}
{
TSharedPtr<bool> TempA(nullptr);
TSharedPtr<float32> TempB = nullptr;
TWeakPtr<bool> TempD(nullptr);
TWeakPtr<float32> TempE = nullptr;
TempB = TSharedPtr<float32>(new float32(0.1f));
TempB = nullptr;
TempB = MakeShared<float32>(30.0f);
TSharedPtr<float64> TempC(MakeShared<float64>(2.0));
struct FTest
{
TSharedPtr<float32> Value;
TSharedPtr<float32> FuncA() { return Value; }
TSharedPtr<float32> FuncB() { return MakeShared<float32>(123.0f); }
};
}
{
TSharedRef<float32> Temp(new float32(123.0f));
}
{
TSharedRef<float32> Temp(new float32(123.0f));
const float& RefA = *Temp;
const float& RefB = *Temp.Get();
}
{
TSharedRef<float32> Temp = MakeShared<float32>(123.0f);
}
{
TSharedRef<int32> TempA(new int32(1));
TSharedPtr<int32> TempB(TempA);
}
{
TSharedPtr<int32> TempA(new int32(1));
TSharedRef<int32> TempB(TempA.ToSharedRef());
}
{
TSharedRef<int32> Temp(new int32(10));
Temp = TSharedRef<int32>(new int32(20));
}
{
TSharedRef<int32> TempA(new int32(99));
TWeakPtr<int32> TempB = TempA;
always_check(TempB.Lock());
}
{
TSharedRef<int32> IntRef1(new int32(99));
TSharedRef<int32> IntRef2(new int32(21));
always_check(!(IntRef1 == IntRef2));
always_check(IntRef1 != IntRef2);
}
{
TSharedRef<int32> TempA(new int32(21));
TSharedPtr<int32> TempB(TempA);
TSharedPtr<int32> TempC;
always_check(TempA == TempB && TempB == TempA);
always_check(!(TempA != TempB || TempB != TempA));
always_check(!(TempA == TempC) && (TempA != TempC));
}
{
struct FTest : public TSharedFromThis<FTest>
{
TSharedRef<FTest> FuncTest() { return AsShared(); }
};
TSharedPtr<FTest> TempA(new FTest());
{
FTest* Ptr = TempA.Get();
TSharedRef<FTest> TempB(Ptr->FuncTest());
}
}
{
TSharedRef<int32> TempA = MakeShared<int32>();
TSharedRef<const int32> TempB = TempA;
TSharedRef<const int32> TempC = MakeShared<int32>();
TempC = TempA;
}
{
TSharedRef<int32[]> TempA = MakeShared<int32[]>(4);
TSharedRef<const int32[]> TempB = TempA;
TSharedRef<const int32[]> TempC = MakeShared<int32[]>(4);
TempC = TempA;
}
{
TSharedPtr<int32> TempA;
TSharedPtr<const int32> TempB = TempA;
TSharedPtr<const int32> TempC;
TempC = TempA;
}
{
TSharedPtr<int32[]> TempA;
TSharedPtr<const int32[]> TempB = TempA;
TSharedPtr<const int32[]> TempC;
TempC = TempA;
}
{
TWeakPtr<int32> TempA;
TWeakPtr<const int32> TempB = TempA;
TWeakPtr<const int32> TempC;
TempC = TempA;
}
{
TWeakPtr<int32[]> TempA;
TWeakPtr<const int32[]> TempB = TempA;
TWeakPtr<const int32[]> TempC;
TempC = TempA;
}
}
NAMESPACE_UNNAMED_BEGIN
@ -2298,27 +1544,11 @@ void TestMiscTemplates()
always_check(TestFunctionB(AddressOf(ObjectA)) == 0);
always_check(AddressOf(TestMiscTemplates) == &TestMiscTemplates);
always_check(!TPointerTraits<int64>::bIsPointer);
struct FTestRetainedRef { explicit FTestRetainedRef(TRetainedRef<const int64> InRef) { } };
always_check(TPointerTraits<int64*>::bIsPointer);
always_check((CSameAs<TPointerTraits<int64*>::PointerType, int64*>));
always_check((CSameAs<TPointerTraits<int64*>::ElementType, int64>));
always_check(TPointerTraits<int64*>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<int64(*)[]>::bIsPointer);
always_check((CSameAs<TPointerTraits<int64(*)[]>::PointerType, int64(*)[]>));
always_check((CSameAs<TPointerTraits<int64(*)[]>::ElementType, int64>));
always_check(TPointerTraits<int64*>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<TSharedPtr<int64>>::bIsPointer);
always_check((CSameAs<TPointerTraits<TSharedPtr<int64>>::PointerType, TSharedPtr<int64>>));
always_check((CSameAs<TPointerTraits<TSharedPtr<int64>>::ElementType, int64>));
always_check(TPointerTraits<TSharedPtr<int64>>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<TSharedPtr<int64[]>>::bIsPointer);
always_check((CSameAs<TPointerTraits<TSharedPtr<int64[]>>::PointerType, TSharedPtr<int64[]>>));
always_check((CSameAs<TPointerTraits<TSharedPtr<int64[]>>::ElementType, int64>));
always_check(TPointerTraits<TSharedPtr<int64[]>>::ToAddress(nullptr) == nullptr);
int64 IntA;
FTestRetainedRef TempA(IntA);
// FTestRetainedRef TempB(114514);
}

View File

@ -0,0 +1,151 @@
#pragma once
#include "CoreTypes.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "Memory/PointerTraits.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TObserverPtr;
NAMESPACE_PRIVATE_BEGIN
template <typename T> struct TIsTObserverPtr : FFalse { };
template <typename T> struct TIsTObserverPtr<TObserverPtr<T>> : FTrue { };
NAMESPACE_PRIVATE_END
template <typename T>
concept CTObserverPtr = NAMESPACE_PRIVATE::TIsTObserverPtr<TRemoveCV<T>>::Value;
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TObserverPtr
{
public:
using ElementType = T;
FORCEINLINE constexpr TObserverPtr() : Pointer(nullptr) { }
FORCEINLINE constexpr TObserverPtr(nullptr_t) : TObserverPtr() { }
FORCEINLINE constexpr explicit TObserverPtr(T* InPtr) : Pointer(InPtr) { }
FORCEINLINE constexpr TObserverPtr(const TObserverPtr&) = default;
FORCEINLINE constexpr TObserverPtr(TObserverPtr&&) = default;
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE constexpr TObserverPtr(TObserverPtr<U> InValue) : Pointer(InValue.Pointer) { }
FORCEINLINE constexpr ~TObserverPtr() = default;
FORCEINLINE constexpr TObserverPtr& operator=(const TObserverPtr&) = default;
FORCEINLINE constexpr TObserverPtr& operator=(TObserverPtr&&) = default;
NODISCARD friend FORCEINLINE constexpr bool operator==(const TObserverPtr& LHS, const TObserverPtr& RHS) { return LHS.Get() == RHS.Get(); }
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TObserverPtr& LHS, const TObserverPtr& RHS) { return LHS.Get() <=> RHS.Get(); }
NODISCARD FORCEINLINE constexpr bool operator==(T* InPtr) const& { return Get() == InPtr; }
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(T* InPtr) const& { return Get() <=> InPtr; }
NODISCARD FORCEINLINE constexpr T* Release() { return Exchange(Pointer, nullptr); }
FORCEINLINE constexpr void Reset(T* InPtr = nullptr) { Pointer = InPtr; }
NODISCARD FORCEINLINE constexpr T* Get() const { return Pointer; }
NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr T& operator*() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return *Get(); }
NODISCARD FORCEINLINE constexpr T* operator->() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get(); }
NODISCARD FORCEINLINE constexpr operator ElementType*() { return Get(); }
NODISCARD FORCEINLINE constexpr operator const ElementType*() const { return Get(); }
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TObserverPtr& A) { return GetTypeHash(A.Get()); }
friend FORCEINLINE constexpr void Swap(TObserverPtr& A, TObserverPtr& B) { Swap(A.Pointer, B.Pointer); }
private:
T* Pointer;
};
template <typename T>
class TObserverPtr<T[]>
{
public:
using ElementType = T;
FORCEINLINE constexpr TObserverPtr() : Pointer(nullptr) { }
FORCEINLINE constexpr TObserverPtr(nullptr_t) : TObserverPtr() { }
template <typename U = T*> requires (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>)
FORCEINLINE constexpr explicit TObserverPtr(U InPtr) : Pointer(InPtr) { }
FORCEINLINE constexpr TObserverPtr(const TObserverPtr&) = default;
FORCEINLINE constexpr TObserverPtr(TObserverPtr&&) = default;
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE constexpr TObserverPtr(TObserverPtr<U> InValue) : Pointer(InValue.Pointer) { }
FORCEINLINE constexpr ~TObserverPtr() = default;
FORCEINLINE constexpr TObserverPtr& operator=(const TObserverPtr&) = default;
FORCEINLINE constexpr TObserverPtr& operator=(TObserverPtr&&) = default;
NODISCARD friend FORCEINLINE constexpr bool operator==(const TObserverPtr& LHS, const TObserverPtr& RHS) { return LHS.Get() == RHS.Get(); }
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TObserverPtr& LHS, const TObserverPtr& RHS) { return LHS.Get() <=> RHS.Get(); }
template <typename U = T*> requires (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>))
NODISCARD FORCEINLINE constexpr bool operator==(U InPtr) const& { return Get() == InPtr; }
template <typename U = T*> requires (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>))
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(U InPtr) const& { return Get() <=> InPtr; }
NODISCARD FORCEINLINE constexpr T* Release() { return Exchange(Pointer, nullptr); }
template <typename U = T*> requires (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>))
FORCEINLINE constexpr void Reset(U InPtr = nullptr) { Pointer = InPtr; }
NODISCARD FORCEINLINE constexpr T* Get() const { return Pointer; }
NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr T& operator[](size_t Index) const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; }
NODISCARD FORCEINLINE constexpr operator ElementType*() { return Get(); }
NODISCARD FORCEINLINE constexpr operator const ElementType*() const { return Get(); }
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TObserverPtr& A) { return GetTypeHash(A.Get()); }
friend FORCEINLINE constexpr void Swap(TObserverPtr& A, TObserverPtr& B) { Swap(A.Pointer, B.Pointer); }
private:
T* Pointer;
};
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
NODISCARD FORCEINLINE constexpr TObserverPtr<T> MakeObserver(TRemoveExtent<T>* InPtr) { return TObserverPtr<T>(InPtr); }
DEFINE_TPointerTraits(TObserverPtr);
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -5,14 +5,13 @@
#include "Templates/Atomic.h"
#include "Templates/Invoke.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "Memory/PointerTraits.h"
#include "Memory/UniquePointer.h"
#include "Memory/MemoryOperator.h"
#include "Templates/Noncopyable.h"
#include "TypeTraits/PrimaryType.h"
#include "Templates/PointerTraits.h"
#include "Templates/UniquePointer.h"
#include "TypeTraits/Miscellaneous.h"
#include "TypeTraits/TypeProperties.h"
#include "TypeTraits/SupportedOperations.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)

View File

@ -3,12 +3,11 @@
#include "CoreTypes.h"
#include "Templates/Invoke.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "Memory/PointerTraits.h"
#include "Templates/Noncopyable.h"
#include "TypeTraits/PrimaryType.h"
#include "Templates/PointerTraits.h"
#include "TypeTraits/Miscellaneous.h"
#include "TypeTraits/TypeProperties.h"
#include "TypeTraits/SupportedOperations.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)

View File

@ -1,6 +1,7 @@
#pragma once
#include "CoreTypes.h"
#include "Miscellaneous/ProgramSupport.h"
#include "Miscellaneous/PreprocessorHelpers.h"
#ifdef NDEBUG
@ -67,12 +68,12 @@ NAMESPACE_PRIVATE_END
# define check(InExpr)
# define checkf(InExpr, InFormat, ...)
# define check_no_entry()
# define check_no_entry() { Unreachable(); }
# define check_no_reentry()
# define check_no_recursion()
# define verify(InExpr) { if(InExpr) { } }
# define verifyf(InExpr, InFormat, ...) { if(InExpr) { } }
# define unimplemented()
# define unimplemented() { Unreachable(); }
#endif

View File

@ -0,0 +1,118 @@
#pragma once
#include "CoreTypes.h"
#include <cstdlib>
#include <utility>
#include <csignal>
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
#pragma warning(push)
#pragma warning(disable : 4996)
using FAtexitHandler = void();
using FSignalHandler = void(int);;
/** Indicates program execution status. */
enum class EExitCode : int
{
Success = EXIT_SUCCESS,
Failure = EXIT_FAILURE,
};
/** Defines signal types. */
enum class ESignalType : int
{
SoftwareTermination = SIGTERM, // Termination request, sent to the program.
SegmentationFault = SIGSEGV, // Invalid memory access as segmentation fault.
ExternalInterrupt = SIGINT, // External interrupt, usually initiated by the user.
IllegalInstruction = SIGILL, // Invalid program image, such as invalid instruction.
AbnormalTermination = SIGABRT, // Abnormal termination condition, as is e.g. initiated by Abort().
ArithmeticException = SIGFPE, // Erroneous arithmetic operation such as divide by zero.
};
inline static FSignalHandler* GSignalDefault = SIG_DFL; // Defines default signal handling strategies.
inline static FSignalHandler* GSignalIgnored = SIG_IGN; // Defines Signal is ignored strategies.
inline static FSignalHandler* GSignalError = SIG_ERR; // Return value of signal specifying that an error was encountered.
/** The integer type that can be accessed as an atomic entity from an asynchronous signal handler. */
using FSignalAtomic = NAMESPACE_STD::sig_atomic_t;
/** Causes abnormal program termination without cleaning up. */
NORETURN FORCEINLINE void Abort()
{
NAMESPACE_STD::abort();
}
/** Causes normal program termination with cleaning up. */
NORETURN FORCEINLINE void Exit(EExitCode ExitCode)
{
NAMESPACE_STD::exit(static_cast<int>(ExitCode));
};
/** Causes quick program termination without completely cleaning up. */
NORETURN FORCEINLINE void QuickExit(EExitCode ExitCode)
{
NAMESPACE_STD::quick_exit(static_cast<int>(ExitCode));
};
/** Causes normal program termination without cleaning up. */
NORETURN FORCEINLINE void QuickExitWithoutCleaning(EExitCode ExitCode)
{
NAMESPACE_STD::_Exit(static_cast<int>(ExitCode));
};
/** Registers a function to be called on Exit() invocation. */
FORCEINLINE bool AtExit(FAtexitHandler* InFunc)
{
return NAMESPACE_STD::atexit(InFunc) == 0;
}
/** Registers a function to be called on QuickExit invocation. */
FORCEINLINE bool AtQuickExit(FAtexitHandler* InFunc)
{
return NAMESPACE_STD::at_quick_exit(InFunc) == 0;
}
/** Marks unreachable point of execution. */
NORETURN FORCEINLINE void Unreachable()
{
# ifdef __cpp_lib_unreachable
{
NAMESPACE_STD::unreachable();
}
# endif
}
/** Calls the host environment's command processor. */
FORCEINLINE EExitCode System(const char* InCommand)
{
return static_cast<EExitCode>(NAMESPACE_STD::system(InCommand));
}
/** Access to the list of environment variables. */
NODISCARD FORCEINLINE const char* GetEnv(const char* InEnv)
{
return NAMESPACE_STD::getenv(InEnv);
}
/** Sets a signal handler for particular signal. */
FORCEINLINE FSignalHandler* Signal(ESignalType InType, FSignalHandler* InFunc)
{
return NAMESPACE_STD::signal(static_cast<int>(InType), InFunc);
}
/** Runs the signal handler for particular signal. */
FORCEINLINE bool Raise(ESignalType InType)
{
return NAMESPACE_STD::raise(static_cast<int>(InType)) == 0;
}
#pragma warning(pop)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -6,6 +6,7 @@
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h"
#include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN

View File

@ -0,0 +1,156 @@
#pragma once
#include "CoreTypes.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "Memory/PointerTraits.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
template <typename T> requires (TPointerTraits<T>::bIsPointer)
class TPropagateConst;
NAMESPACE_PRIVATE_BEGIN
template <typename T> struct TIsTPropagateConst : FFalse { };
template <typename T> struct TIsTPropagateConst<TPropagateConst<T>> : FTrue { };
NAMESPACE_PRIVATE_END
template <typename T>
concept CTPropagateConst = NAMESPACE_PRIVATE::TIsTPropagateConst<TRemoveCV<T>>::Value;
/**
* TPropagateConst is a const-propagating wrapper for pointers and pointer-like objects.
* It treats the wrapped pointer as a pointer to const when accessed through a const access path, hence the name.
*/
template <typename T> requires (TPointerTraits<T>::bIsPointer)
class TPropagateConst final
{
public:
using ElementType = TPointerTraits<T>::ElementType;
/** Constructs an TPropagateConst, default-initializing underlying pointer. */
FORCEINLINE constexpr TPropagateConst() = default;
/** Initializes underlying pointer if by direct-non-list-initialization with the expression Forward<U>(InValue). */
template <typename U> requires (CConstructibleFrom<T, U> && !CTPropagateConst<TRemoveCVRef<U>>)
FORCEINLINE constexpr explicit (!CConvertibleTo<U, T>) TPropagateConst(U&& InValue)
: Ptr(Forward<U>(InValue))
{ }
/** Explicitly defaulted copy/move constructor that copy/move constructs underlying pointer. */
FORCEINLINE constexpr TPropagateConst(const TPropagateConst&) = default;
FORCEINLINE constexpr TPropagateConst(TPropagateConst&&) = default;
/** Initializes underlying pointer as if by direct-non-list-initialization. */
template <typename U> requires (CConstructibleFrom<T, const U&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<const U&, T>) TPropagateConst(const TPropagateConst<U>& InValue)
: Ptr(InValue.Ptr)
{ }
/** Initializes underlying pointer as if by direct-non-list-initialization. */
template <typename U> requires (CConstructibleFrom<T, U&&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<U&&, T>) TPropagateConst(TPropagateConst<U>&& InValue)
: Ptr(MoveTemp(InValue.Ptr))
{ }
/** Destructs an TPropagateConst, destroying the contained underlying pointer */
FORCEINLINE constexpr ~TPropagateConst() = default;
/** Explicitly defaulted copy/move assignment operator that copy/move assigns underlying pointer. */
FORCEINLINE constexpr TPropagateConst& operator=(const TPropagateConst& InValue) = default;
FORCEINLINE constexpr TPropagateConst& operator=(TPropagateConst&& InValue) = default;
/** Assigns underlying pointer from 'InValue'. */
template <typename U> requires (CAssignableFrom<T, const U&>)
FORCEINLINE constexpr TPropagateConst& operator=(const TPropagateConst<T>& InValue)
{
Ptr = InValue.Ptr;
return *this;
}
/** Assigns underlying pointer from 'InValue'. */
template <typename U> requires (CAssignableFrom<T, U&&>)
FORCEINLINE constexpr TPropagateConst& operator=(TPropagateConst<T>&& InValue)
{
Ptr = MoveTemp(InValue.Ptr);
return *this;
}
/** Assigns underlying pointer from 'InValue'. */
template <typename U> requires (CConvertibleTo<U, T>)
FORCEINLINE constexpr TPropagateConst& operator=(U&& InValue)
{
Ptr = Forward<U>(InValue);
return *this;
}
/** Compares the pointer values of two TPropagateConst. */
NODISCARD friend FORCEINLINE constexpr bool operator==(const TPropagateConst& LHS, const TPropagateConst& RHS) requires (CWeaklyEqualityComparable<T>) { return LHS.Ptr == RHS.Ptr; }
/** Compares the pointer values of two TPropagateConst. */
NODISCARD friend FORCEINLINE constexpr decltype(auto) operator<=>(const TPropagateConst& LHS, const TPropagateConst& RHS) requires (CSynthThreeWayComparable<T>) { return SynthThreeWayCompare(LHS.Ptr, RHS.Ptr); }
/** Compares the pointer values with a underlying pointer. */
template <typename U> requires (CWeaklyEqualityComparable<T, U>)
NODISCARD FORCEINLINE constexpr bool operator==(U InPtr) const& { return Ptr == InPtr; }
/** Compares the pointer values with a underlying pointer. */
template <typename U> requires (CSynthThreeWayComparable<T, U>)
NODISCARD FORCEINLINE constexpr decltype(auto) operator<=>(U InPtr) const& { return SynthThreeWayCompare(Ptr, InPtr); }
/** @return The pointer to the object pointed to by the wrapped pointer. */
NODISCARD FORCEINLINE constexpr ElementType* Get() { return TPointerTraits<T>::ToAddress(Ptr); }
NODISCARD FORCEINLINE constexpr const ElementType* Get() const { return TPointerTraits<T>::ToAddress(Ptr); }
/** @return true if *this owns an object, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; }
/** @return The a reference or pointer to the object owned by *this, i.e. Get(). */
NODISCARD FORCEINLINE constexpr ElementType& operator*() { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return *Get(); }
NODISCARD FORCEINLINE constexpr const ElementType& operator*() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return *Get(); }
NODISCARD FORCEINLINE constexpr ElementType* operator->() { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get(); }
NODISCARD FORCEINLINE constexpr const ElementType* operator->() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get(); }
/** @return The element at index, i.e. Get()[Index]. */
NODISCARD FORCEINLINE constexpr T& operator[](size_t Index) { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; }
NODISCARD FORCEINLINE constexpr const T& operator[](size_t Index) const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; }
/** @return The pointer to the object pointed to by the wrapped pointer-like object. */
NODISCARD FORCEINLINE constexpr operator ElementType*() requires (CConvertibleTo<T, ElementType*>) { return Ptr; }
NODISCARD FORCEINLINE constexpr operator const ElementType*() const requires (CConvertibleTo<T, ElementType*>) { return Ptr; }
/** @return The reference to the pointer-like object stored. */
NODISCARD FORCEINLINE constexpr T& GetUnderlying() { return Ptr; }
NODISCARD FORCEINLINE constexpr const T& GetUnderlying() const { return Ptr; }
/** Overloads the GetTypeHash algorithm for TPropagateConst. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TPropagateConst& A) requires (CHashable<T>)
{
return GetTypeHash(A.Ptr);
}
/** Overloads the Swap algorithm for TPropagateConst. */
friend FORCEINLINE constexpr void Swap(TPropagateConst& A, TPropagateConst& B) requires (CSwappable<T>)
{
Swap(A.Ptr, B.Ptr);
}
private:
T Ptr;
};
template <typename T>
TPropagateConst(T) -> TPropagateConst<T>;
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -4,6 +4,7 @@
#include "Templates/Invoke.h"
#include "Templates/Utility.h"
#include "Templates/Optional.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN

View File

@ -0,0 +1,73 @@
#pragma once
#include "CoreTypes.h"
#include "Templates/Utility.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
/**
* A helper class which replaces T& as a function parameter when the reference is
* intended to be retained by the function (e.g. as a class member). The benefit
* of this class is that it is a compile error to pass an rvalue which might otherwise
* bind to a const reference, which is dangerous when the reference is retained.
*
* struct FRAIIType
* {
* explicit FRAIIType(TRetainedRef<const FThing> InThing) : Ref(InThing) { }
*
* void DoSomething() { Ref.Something(); }
*
* FThing& Ref;
* };
*
*/
template <typename T>
struct TRetainedRef
{
/** Retain a non-const lvalue reference. */
FORCEINLINE constexpr TRetainedRef(T& InRef) : Ref(InRef) { }
/** Can't retain a rvalue reference. */
TRetainedRef(const T& ) = delete;
TRetainedRef( T&&) = delete;
TRetainedRef(const T&&) = delete;
/** @return The managed reference. */
FORCEINLINE constexpr operator T&() const { return Ref; }
FORCEINLINE constexpr T& Get() const { return Ref; }
private:
T& Ref;
};
template <typename T>
struct TRetainedRef<const T>
{
/** Retain a non-const lvalue reference. */
FORCEINLINE constexpr TRetainedRef(T& InRef) : Ref(InRef) { }
/** Retain a const lvalue reference. */
FORCEINLINE constexpr TRetainedRef(const T& InRef) : Ref(InRef) { }
/** Can't retain a rvalue reference. */
TRetainedRef( T&&) = delete;
TRetainedRef(const T&&) = delete;
/** @return The managed reference. */
FORCEINLINE constexpr operator const T&() const { return Ref; }
FORCEINLINE constexpr const T& Get() const { return Ref; }
private:
const T& Ref;
};
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -15,6 +15,5 @@
#include "Templates/Function.h"
#include "Templates/Atomic.h"
#include "Templates/ScopeHelper.h"
#include "Templates/PointerTraits.h"
#include "Templates/UniquePointer.h"
#include "Templates/SharedPointer.h"
#include "Templates/PropagateConst.h"
#include "Templates/RetainedReference.h"

View File

@ -6,6 +6,7 @@
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h"
#include "Templates/ReferenceWrapper.h"
#include <tuple>

View File

@ -1,11 +1,11 @@
#pragma once
#include "CoreTypes.h"
#include "Templates/Meta.h"
#include "Templates/Invoke.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h"
#include "Templates/Meta.h"
#include "Memory/MemoryOperator.h"
#include "Miscellaneous/Compare.h"
#include "Miscellaneous/AssertionMacros.h"

View File

@ -13,6 +13,10 @@ REDCRAFTUTILITY_API void TestAlignment();
REDCRAFTUTILITY_API void TestMemoryBuffer();
REDCRAFTUTILITY_API void TestMemoryMalloc();
REDCRAFTUTILITY_API void TestMemoryOperator();
REDCRAFTUTILITY_API void TestPointerTraits();
REDCRAFTUTILITY_API void TestUniquePointer();
REDCRAFTUTILITY_API void TestSharedPointer();
REDCRAFTUTILITY_API void TestObserverPointer();
NAMESPACE_END(Testing)

View File

@ -18,8 +18,7 @@ REDCRAFTUTILITY_API void TestTuple();
REDCRAFTUTILITY_API void TestFunction();
REDCRAFTUTILITY_API void TestAtomic();
REDCRAFTUTILITY_API void TestScopeHelper();
REDCRAFTUTILITY_API void TestUniquePointer();
REDCRAFTUTILITY_API void TestSharedPointer();
REDCRAFTUTILITY_API void TestPropagateConst();
REDCRAFTUTILITY_API void TestMiscTemplates();
NAMESPACE_END(Testing)