Compare commits
7 Commits
52cd65dbad
...
73b5305d34
Author | SHA1 | Date | |
---|---|---|---|
73b5305d34 | |||
c7f50957db | |||
0d99fad3f0 | |||
1b2ea5c2a6 | |||
2ef2c4a729 | |||
e498d9b0b8 | |||
d029ab0dfc |
@ -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)
|
||||
|
@ -25,8 +25,7 @@ void TestTemplates()
|
||||
TestFunction();
|
||||
TestAtomic();
|
||||
TestScopeHelper();
|
||||
TestUniquePointer();
|
||||
TestSharedPointer();
|
||||
TestPropagateConst();
|
||||
TestMiscTemplates();
|
||||
}
|
||||
|
||||
@ -1471,797 +1470,44 @@ void TestScopeHelper()
|
||||
|
||||
}
|
||||
|
||||
NAMESPACE_UNNAMED_BEGIN
|
||||
|
||||
struct FCounter
|
||||
void TestPropagateConst()
|
||||
{
|
||||
static int32 Num;
|
||||
FCounter() { ++Num; }
|
||||
~FCounter() { --Num; }
|
||||
{
|
||||
struct FTestA
|
||||
{
|
||||
void Check(bool bFlag) { always_check(!bFlag); }
|
||||
void Check(bool bFlag) const { always_check( bFlag); }
|
||||
};
|
||||
|
||||
int32 FCounter::Num = 0;
|
||||
|
||||
struct FDeleter
|
||||
struct FTestB
|
||||
{
|
||||
static int32 Num;
|
||||
void operator()(FCounter* Ptr) { delete Ptr; ++Num; }
|
||||
FTestB() { Ptr = &Object; }
|
||||
FTestA Object;
|
||||
TPropagateConst<FTestA*> Ptr;
|
||||
};
|
||||
|
||||
int32 FDeleter::Num = 0;
|
||||
FTestB TempA;
|
||||
const FTestB TempB;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
151
Redcraft.Utility/Source/Public/Memory/ObserverPointer.h
Normal file
151
Redcraft.Utility/Source/Public/Memory/ObserverPointer.h
Normal 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
|
@ -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)
|
@ -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)
|
@ -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
|
||||
|
||||
|
118
Redcraft.Utility/Source/Public/Miscellaneous/ProgramSupport.h
Normal file
118
Redcraft.Utility/Source/Public/Miscellaneous/ProgramSupport.h
Normal 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
|
@ -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
|
||||
|
156
Redcraft.Utility/Source/Public/Templates/PropagateConst.h
Normal file
156
Redcraft.Utility/Source/Public/Templates/PropagateConst.h
Normal 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
|
@ -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
|
||||
|
73
Redcraft.Utility/Source/Public/Templates/RetainedReference.h
Normal file
73
Redcraft.Utility/Source/Public/Templates/RetainedReference.h
Normal 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
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user