refactor(templates): optimize the implementation of TOptional and TVariant
This commit is contained in:
parent
a737eea487
commit
522c71f2b6
@ -85,247 +85,277 @@ void TestReferenceWrapper()
|
|||||||
|
|
||||||
void TestOptional()
|
void TestOptional()
|
||||||
{
|
{
|
||||||
TOptional<int32> TempA;
|
|
||||||
TOptional<int32> TempB(Invalid);
|
|
||||||
TOptional<int32> TempC(InPlace, 0);
|
|
||||||
TOptional<int32> TempD(0);
|
|
||||||
TOptional<int32> TempE(0l);
|
|
||||||
TOptional<int32> TempF(0.0);
|
|
||||||
TOptional<int32> TempG(TempA);
|
|
||||||
TOptional<int32> TempH(TempD);
|
|
||||||
TOptional<int32> TempI(MakeOptional<int32>(0));
|
|
||||||
TOptional<int32> TempJ(MakeOptional<int32>(Invalid));
|
|
||||||
|
|
||||||
TOptional<int32> TempK, TempL, TempM, TempN;
|
|
||||||
TempK = TempA;
|
|
||||||
TempL = TempD;
|
|
||||||
TempM = MakeOptional<int32>(0);
|
|
||||||
TempN = MakeOptional<int32>(Invalid);
|
|
||||||
|
|
||||||
*TempL = 303;
|
|
||||||
*TempM = 404;
|
|
||||||
|
|
||||||
TOptional<int32> TempO;
|
|
||||||
TempO.Emplace(404);
|
|
||||||
|
|
||||||
always_check(TempO);
|
|
||||||
always_check(TempO.IsValid());
|
|
||||||
|
|
||||||
always_check(*TempO == 404);
|
|
||||||
always_check(TempO.GetValue() == 404);
|
|
||||||
always_check(TempO.Get(500) == 404);
|
|
||||||
|
|
||||||
TempO.Reset();
|
|
||||||
always_check(TempO == TempO);
|
|
||||||
always_check(!(TempO != TempO));
|
|
||||||
always_check(TempO.Get(500) == 500);
|
|
||||||
|
|
||||||
int32 TempP = 200;
|
|
||||||
TempO = TempP;
|
|
||||||
TempO = 300;
|
|
||||||
|
|
||||||
always_check(TempO != TempA);
|
|
||||||
always_check(TempO != TempD);
|
|
||||||
always_check(TempO == TempO);
|
|
||||||
always_check(TempO == 300);
|
|
||||||
always_check(300 == TempO);
|
|
||||||
|
|
||||||
int16 TempQ = 1024;
|
|
||||||
TOptional<int16> TempR = TempQ;
|
|
||||||
|
|
||||||
TOptional<int32> TempS(InPlace, TempQ);
|
|
||||||
TOptional<int32> TempT(TempQ);
|
|
||||||
TOptional<int32> TempU(TempR);
|
|
||||||
TOptional<int32> TempV(MakeOptional<int16>(2048));
|
|
||||||
|
|
||||||
TOptional<int32> TempW, TempX, TempY;
|
|
||||||
TempW = TempQ;
|
|
||||||
TempX = TempR;
|
|
||||||
TempY = MakeOptional<int16>(2048);
|
|
||||||
|
|
||||||
struct FTracker
|
|
||||||
{
|
{
|
||||||
FTracker() { }
|
TOptional<int32> TempA;
|
||||||
FTracker(const FTracker& InValue) { always_check_no_entry(); }
|
TOptional<int32> TempB(Invalid);
|
||||||
FTracker(FTracker&& InValue) { }
|
TOptional<int32> TempC(InPlace, 0);
|
||||||
FTracker& operator=(const FTracker& InValue) { always_check_no_entry(); return *this; }
|
TOptional<int32> TempD(0);
|
||||||
FTracker& operator=(FTracker&& InValue) { return *this; }
|
TOptional<int32> TempE(0l);
|
||||||
};
|
TOptional<int32> TempF(0.0);
|
||||||
|
TOptional<int32> TempG(TempA);
|
||||||
|
TOptional<int32> TempH(TempD);
|
||||||
|
TOptional<int32> TempI(MakeOptional<int32>(0));
|
||||||
|
TOptional<int32> TempJ(MakeOptional<int32>(Invalid));
|
||||||
|
|
||||||
TOptional<FTracker> TempZ(MakeOptional<FTracker>());
|
TOptional<int32> TempK, TempL, TempM, TempN;
|
||||||
TempZ = MakeOptional<FTracker>();
|
TempK = TempA;
|
||||||
TempZ = FTracker();
|
TempL = TempD;
|
||||||
|
TempM = MakeOptional<int32>(0);
|
||||||
|
TempN = MakeOptional<int32>(Invalid);
|
||||||
|
|
||||||
always_check(GetTypeHash(MakeOptional<int32>(114)) == GetTypeHash(MakeOptional<int32>(114)));
|
*TempL = 303;
|
||||||
always_check(GetTypeHash(MakeOptional<int32>(114)) != GetTypeHash(MakeOptional<int32>(514)));
|
*TempM = 404;
|
||||||
|
|
||||||
|
TOptional<int32> TempO;
|
||||||
|
TempO.Emplace(404);
|
||||||
|
|
||||||
|
always_check(TempO);
|
||||||
|
always_check(TempO.IsValid());
|
||||||
|
|
||||||
|
always_check(*TempO == 404);
|
||||||
|
always_check(TempO.GetValue() == 404);
|
||||||
|
always_check(TempO.Get(500) == 404);
|
||||||
|
|
||||||
|
TempO.Reset();
|
||||||
|
always_check(TempO == TempO);
|
||||||
|
always_check(!(TempO != TempO));
|
||||||
|
always_check(TempO.Get(500) == 500);
|
||||||
|
|
||||||
|
int32 TempP = 200;
|
||||||
|
TempO = TempP;
|
||||||
|
TempO = 300;
|
||||||
|
|
||||||
|
always_check(TempO != TempA);
|
||||||
|
always_check(TempO != TempD);
|
||||||
|
always_check(TempO == TempO);
|
||||||
|
always_check(TempO == 300);
|
||||||
|
always_check(300 == TempO);
|
||||||
|
|
||||||
|
int16 TempQ = 1024;
|
||||||
|
TOptional<int16> TempR = TempQ;
|
||||||
|
|
||||||
|
TOptional<int32> TempS(InPlace, TempQ);
|
||||||
|
TOptional<int32> TempT(TempQ);
|
||||||
|
TOptional<int32> TempU(TempR);
|
||||||
|
TOptional<int32> TempV(MakeOptional<int16>(2048));
|
||||||
|
|
||||||
|
TOptional<int32> TempW, TempX, TempY;
|
||||||
|
TempW = TempQ;
|
||||||
|
TempX = TempR;
|
||||||
|
TempY = MakeOptional<int16>(2048);
|
||||||
|
|
||||||
|
struct FTracker
|
||||||
|
{
|
||||||
|
FTracker() { }
|
||||||
|
FTracker(const FTracker& InValue) { always_check_no_entry(); }
|
||||||
|
FTracker(FTracker&& InValue) { }
|
||||||
|
FTracker& operator=(const FTracker& InValue) { always_check_no_entry(); return *this; }
|
||||||
|
FTracker& operator=(FTracker&& InValue) { return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TOptional<FTracker> TempZ(MakeOptional<FTracker>());
|
||||||
|
TempZ = MakeOptional<FTracker>();
|
||||||
|
TempZ = FTracker();
|
||||||
|
|
||||||
|
always_check(GetTypeHash(MakeOptional<int32>(114)) == GetTypeHash(MakeOptional<int32>(114)));
|
||||||
|
always_check(GetTypeHash(MakeOptional<int32>(114)) != GetTypeHash(MakeOptional<int32>(514)));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TOptional<uint8> TempA = Invalid;
|
||||||
|
TOptional<int16> TempB = 16;
|
||||||
|
TOptional<int64> TempC = 32;
|
||||||
|
|
||||||
|
always_check(TempA != TempB);
|
||||||
|
always_check(TempB != TempC);
|
||||||
|
always_check(TempB <= TempC);
|
||||||
|
always_check(TempA <=> TempB == partial_ordering::unordered);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestVariant()
|
void TestVariant()
|
||||||
{
|
{
|
||||||
TVariant<int32> TempA;
|
|
||||||
TVariant<int32> TempB(Invalid);
|
|
||||||
TVariant<int32> TempC(InPlaceType<int32>, 0);
|
|
||||||
TVariant<int32> TempD(0);
|
|
||||||
TVariant<int32> TempE(0l);
|
|
||||||
TVariant<int32> TempF(0.0);
|
|
||||||
TVariant<int32> TempG(TempA);
|
|
||||||
TVariant<int32> TempH(TempD);
|
|
||||||
TVariant<int32> TempI(TVariant<int32>(0));
|
|
||||||
TVariant<int32> TempJ(TVariant<int32>(Invalid));
|
|
||||||
|
|
||||||
TVariant<int32> TempK, TempL, TempM, TempN;
|
|
||||||
TempK = TempA;
|
|
||||||
TempL = TempD;
|
|
||||||
TempM = TVariant<int32>(0);
|
|
||||||
TempN = TVariant<int32>(Invalid);
|
|
||||||
|
|
||||||
TempL = 303;
|
|
||||||
TempM = 404;
|
|
||||||
|
|
||||||
TVariant<int32> TempO;
|
|
||||||
TempO.Emplace<int32>(202);
|
|
||||||
TempO.Emplace<0>(404);
|
|
||||||
|
|
||||||
always_check(TempO);
|
|
||||||
always_check(TempO.IsValid());
|
|
||||||
|
|
||||||
always_check(TempO == 404);
|
|
||||||
always_check(TempO.GetValue<int32>() == 404);
|
|
||||||
always_check(TempO.Get<0>(500) == 404);
|
|
||||||
|
|
||||||
TempO.Reset();
|
|
||||||
always_check(TempO == TempO);
|
|
||||||
always_check(!(TempO != TempO));
|
|
||||||
always_check(TempO.Get<int32>(500) == 500);
|
|
||||||
|
|
||||||
int32 TempP = 200;
|
|
||||||
TempO = TempP;
|
|
||||||
TempO = 300;
|
|
||||||
|
|
||||||
always_check(TempO != TempA);
|
|
||||||
always_check(TempO != TempD);
|
|
||||||
always_check(TempO == TempO);
|
|
||||||
always_check(TempO == 300);
|
|
||||||
always_check(300 == TempO);
|
|
||||||
|
|
||||||
Swap(TempD, TempA);
|
|
||||||
|
|
||||||
int16 TempQ = 1024;
|
|
||||||
TVariant<int16, int32> TempR = TempQ;
|
|
||||||
|
|
||||||
TVariant<int16, int32> TempS(InPlaceType<int32>, TempQ);
|
|
||||||
TVariant<int16, int32> TempT(TempQ);
|
|
||||||
TVariant<int16, int32> TempU(TempR);
|
|
||||||
TVariant<int16, int32> TempV(TVariant<int16, int32>(2048));
|
|
||||||
|
|
||||||
TVariant<int16, int32> TempW, TempX, TempY;
|
|
||||||
TempW = TempQ;
|
|
||||||
TempX = TempR;
|
|
||||||
TempY = TVariant<int16, int32>(2048);
|
|
||||||
|
|
||||||
Swap(TempW, TempX);
|
|
||||||
Swap(TempW, TempX);
|
|
||||||
|
|
||||||
struct FTracker
|
|
||||||
{
|
{
|
||||||
FTracker() { }
|
TVariant<int32> TempA;
|
||||||
FTracker(const FTracker& InValue) { always_check_no_entry(); }
|
TVariant<int32> TempB(Invalid);
|
||||||
FTracker(FTracker&& InValue) { }
|
TVariant<int32> TempC(InPlaceType<int32>, 0);
|
||||||
FTracker& operator=(const FTracker& InValue) { always_check_no_entry(); return *this; }
|
TVariant<int32> TempD(0);
|
||||||
FTracker& operator=(FTracker&& InValue) { return *this; }
|
TVariant<int32> TempE(0l);
|
||||||
};
|
TVariant<int32> TempF(0.0);
|
||||||
|
TVariant<int32> TempG(TempA);
|
||||||
|
TVariant<int32> TempH(TempD);
|
||||||
|
TVariant<int32> TempI(TVariant<int32>(0));
|
||||||
|
TVariant<int32> TempJ(TVariant<int32>(Invalid));
|
||||||
|
|
||||||
TVariant<FTracker> TempZ(Invalid);
|
TVariant<int32> TempK, TempL, TempM, TempN;
|
||||||
TempZ = TVariant<FTracker>();
|
TempK = TempA;
|
||||||
TempZ = FTracker();
|
TempL = TempD;
|
||||||
|
TempM = TVariant<int32>(0);
|
||||||
|
TempN = TVariant<int32>(Invalid);
|
||||||
|
|
||||||
always_check((TIsSame<int32, TVariantAlternativeType<0, TVariant<int32, float>>::Type>::Value));
|
TempL = 303;
|
||||||
always_check((TIsSame<float, TVariantAlternativeType<1, TVariant<int32, float>>::Type>::Value));
|
TempM = 404;
|
||||||
always_check((TIsSame<const int32, TVariantAlternativeType<0, const TVariant<int32, float>>::Type>::Value));
|
|
||||||
|
|
||||||
always_check((TVariantAlternativeIndex<int32, TVariant<int32, float>>::Value == 0));
|
TVariant<int32> TempO;
|
||||||
always_check((TVariantAlternativeIndex<float, TVariant<int32, float>>::Value == 1));
|
TempO.Emplace<int32>(202);
|
||||||
|
TempO.Emplace<0>(404);
|
||||||
|
|
||||||
bool bIsConst;
|
always_check(TempO);
|
||||||
bool bIsLValue;
|
always_check(TempO.IsValid());
|
||||||
bool bIsRValue;
|
|
||||||
|
|
||||||
auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& Arg) -> int32
|
always_check(TempO == 404);
|
||||||
|
always_check(TempO.GetValue<int32>() == 404);
|
||||||
|
always_check(TempO.Get<0>(500) == 404);
|
||||||
|
|
||||||
|
TempO.Reset();
|
||||||
|
always_check(TempO == TempO);
|
||||||
|
always_check(!(TempO != TempO));
|
||||||
|
always_check(TempO.Get<int32>(500) == 500);
|
||||||
|
|
||||||
|
int32 TempP = 200;
|
||||||
|
TempO = TempP;
|
||||||
|
TempO = 300;
|
||||||
|
|
||||||
|
always_check(TempO != TempA);
|
||||||
|
always_check(TempO != TempD);
|
||||||
|
always_check(TempO == TempO);
|
||||||
|
always_check(TempO == 300);
|
||||||
|
always_check(300 == TempO);
|
||||||
|
|
||||||
|
Swap(TempD, TempA);
|
||||||
|
|
||||||
|
int16 TempQ = 1024;
|
||||||
|
TVariant<int16, int32> TempR = TempQ;
|
||||||
|
|
||||||
|
TVariant<int16, int32> TempS(InPlaceType<int32>, TempQ);
|
||||||
|
TVariant<int16, int32> TempT(TempQ);
|
||||||
|
TVariant<int16, int32> TempU(TempR);
|
||||||
|
TVariant<int16, int32> TempV(TVariant<int16, int32>(2048));
|
||||||
|
|
||||||
|
TVariant<int16, int32> TempW, TempX, TempY;
|
||||||
|
TempW = TempQ;
|
||||||
|
TempX = TempR;
|
||||||
|
TempY = TVariant<int16, int32>(2048);
|
||||||
|
|
||||||
|
Swap(TempW, TempX);
|
||||||
|
Swap(TempW, TempX);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
using T = decltype(Arg);
|
struct FTracker
|
||||||
always_check(Arg == 10);
|
{
|
||||||
always_check(TIsConst<typename TRemoveReference<T>::Type>::Value == bIsConst);
|
FTracker() { }
|
||||||
always_check(TIsLValueReference<T>::Value == bIsLValue);
|
FTracker(const FTracker& InValue) { always_check_no_entry(); }
|
||||||
always_check(TIsRValueReference<T>::Value == bIsRValue);
|
FTracker(FTracker&& InValue) { }
|
||||||
return 0;
|
FTracker& operator=(const FTracker& InValue) { always_check_no_entry(); return *this; }
|
||||||
};
|
FTracker& operator=(FTracker&& InValue) { return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
bIsConst = false;
|
TVariant<FTracker> TempZ(Invalid);
|
||||||
bIsLValue = true;
|
TempZ = TVariant<FTracker>();
|
||||||
bIsRValue = false;
|
TempZ = FTracker();
|
||||||
|
|
||||||
TVariant<int32> TempLA = 10;
|
always_check((TIsSame<int32, TVariantAlternativeType<0, TVariant<int32, float>>::Type>::Value));
|
||||||
auto ReturnLA = TempLA.Visit(TestQualifiers);
|
always_check((TIsSame<float, TVariantAlternativeType<1, TVariant<int32, float>>::Type>::Value));
|
||||||
always_check((TIsSame<int32, decltype(ReturnLA)>::Value));
|
always_check((TIsSame<const int32, TVariantAlternativeType<0, const TVariant<int32, float>>::Type>::Value));
|
||||||
|
|
||||||
bIsConst = true;
|
always_check((TVariantAlternativeIndex<int32, TVariant<int32, float>>::Value == 0));
|
||||||
bIsLValue = true;
|
always_check((TVariantAlternativeIndex<float, TVariant<int32, float>>::Value == 1));
|
||||||
bIsRValue = false;
|
|
||||||
|
|
||||||
const TVariant<int32> TempLB = TempLA;
|
bool bIsConst;
|
||||||
auto ReturnLB = TempLB.Visit(TestQualifiers);
|
bool bIsLValue;
|
||||||
always_check((TIsSame<int32, decltype(ReturnLB)>::Value));
|
bool bIsRValue;
|
||||||
|
|
||||||
|
auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& Arg) -> int32
|
||||||
|
{
|
||||||
|
using T = decltype(Arg);
|
||||||
|
always_check(Arg == 10);
|
||||||
|
always_check(TIsConst<typename TRemoveReference<T>::Type>::Value == bIsConst);
|
||||||
|
always_check(TIsLValueReference<T>::Value == bIsLValue);
|
||||||
|
always_check(TIsRValueReference<T>::Value == bIsRValue);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
bIsConst = false;
|
||||||
|
bIsLValue = true;
|
||||||
|
bIsRValue = false;
|
||||||
|
|
||||||
|
TVariant<int32> TempLA = 10;
|
||||||
|
auto ReturnLA = TempLA.Visit(TestQualifiers);
|
||||||
|
always_check((TIsSame<int32, decltype(ReturnLA)>::Value));
|
||||||
|
|
||||||
|
bIsConst = true;
|
||||||
|
bIsLValue = true;
|
||||||
|
bIsRValue = false;
|
||||||
|
|
||||||
|
const TVariant<int32> TempLB = TempLA;
|
||||||
|
auto ReturnLB = TempLB.Visit(TestQualifiers);
|
||||||
|
always_check((TIsSame<int32, decltype(ReturnLB)>::Value));
|
||||||
|
|
||||||
|
bIsConst = false;
|
||||||
|
bIsLValue = false;
|
||||||
|
bIsRValue = true;
|
||||||
|
|
||||||
|
TVariant<int32> TempRA = 10;
|
||||||
|
auto ReturnRA = MoveTemp(TempRA).Visit(TestQualifiers);
|
||||||
|
always_check((TIsSame<int32, decltype(ReturnRA)>::Value));
|
||||||
|
|
||||||
|
bIsConst = true;
|
||||||
|
bIsLValue = false;
|
||||||
|
bIsRValue = true;
|
||||||
|
|
||||||
|
const TVariant<int32> TempRB = TempLA;
|
||||||
|
auto ReturnRB = MoveTemp(TempRB).Visit(TestQualifiers);
|
||||||
|
always_check((TIsSame<int32, decltype(ReturnRB)>::Value));
|
||||||
|
|
||||||
|
bIsConst = false;
|
||||||
|
bIsLValue = true;
|
||||||
|
bIsRValue = false;
|
||||||
|
|
||||||
|
TVariant<int32> TempLC = 10;
|
||||||
|
auto ReturnLC = TempLC.Visit<int32>(TestQualifiers);
|
||||||
|
always_check((TIsSame<int32, decltype(ReturnLC)>::Value));
|
||||||
|
|
||||||
|
bIsConst = true;
|
||||||
|
bIsLValue = true;
|
||||||
|
bIsRValue = false;
|
||||||
|
|
||||||
|
const TVariant<int32> TempLD = TempLC;
|
||||||
|
auto ReturnLD = TempLD.Visit<int32>(TestQualifiers);
|
||||||
|
always_check((TIsSame<int32, decltype(ReturnLD)>::Value));
|
||||||
|
|
||||||
|
bIsConst = false;
|
||||||
|
bIsLValue = false;
|
||||||
|
bIsRValue = true;
|
||||||
|
|
||||||
|
TVariant<int32> TempRC = 10;
|
||||||
|
auto ReturnRC = MoveTemp(TempRC).Visit<int32>(TestQualifiers);
|
||||||
|
always_check((TIsSame<int32, decltype(ReturnRC)>::Value));
|
||||||
|
|
||||||
|
bIsConst = true;
|
||||||
|
bIsLValue = false;
|
||||||
|
bIsRValue = true;
|
||||||
|
|
||||||
|
const TVariant<int32> TempRD = TempLC;
|
||||||
|
auto ReturnRD = MoveTemp(TempRD).Visit<int32>(TestQualifiers);
|
||||||
|
always_check((TIsSame<int32, decltype(ReturnRD)>::Value));
|
||||||
|
|
||||||
|
always_check(GetTypeHash(TVariant<int32, float>(114)) == GetTypeHash(TVariant<int32, float>(114)));
|
||||||
|
always_check(GetTypeHash(TVariant<int32, float>(114)) != GetTypeHash(TVariant<int32, float>(514)));
|
||||||
|
}
|
||||||
|
|
||||||
bIsConst = false;
|
{
|
||||||
bIsLValue = false;
|
TVariant<uint8, int16, int32> TempA = Invalid;
|
||||||
bIsRValue = true;
|
TVariant<uint8, int16, int32> TempB = static_cast<int16>(16);
|
||||||
|
TVariant<uint8, int16, int32> TempC = static_cast<int32>(16);
|
||||||
|
TVariant<uint8, int16, int32> TempD = static_cast<int32>(32);
|
||||||
|
|
||||||
TVariant<int32> TempRA = 10;
|
always_check(TempA != TempB);
|
||||||
auto ReturnRA = MoveTemp(TempRA).Visit(TestQualifiers);
|
always_check(TempB != TempC);
|
||||||
always_check((TIsSame<int32, decltype(ReturnRA)>::Value));
|
always_check(TempB != TempC);
|
||||||
|
always_check(TempD >= TempC);
|
||||||
bIsConst = true;
|
always_check(TempA <=> TempB == partial_ordering::unordered);
|
||||||
bIsLValue = false;
|
}
|
||||||
bIsRValue = true;
|
|
||||||
|
|
||||||
const TVariant<int32> TempRB = TempLA;
|
|
||||||
auto ReturnRB = MoveTemp(TempRB).Visit(TestQualifiers);
|
|
||||||
always_check((TIsSame<int32, decltype(ReturnRB)>::Value));
|
|
||||||
|
|
||||||
bIsConst = false;
|
|
||||||
bIsLValue = true;
|
|
||||||
bIsRValue = false;
|
|
||||||
|
|
||||||
TVariant<int32> TempLC = 10;
|
|
||||||
auto ReturnLC = TempLC.Visit<int32>(TestQualifiers);
|
|
||||||
always_check((TIsSame<int32, decltype(ReturnLC)>::Value));
|
|
||||||
|
|
||||||
bIsConst = true;
|
|
||||||
bIsLValue = true;
|
|
||||||
bIsRValue = false;
|
|
||||||
|
|
||||||
const TVariant<int32> TempLD = TempLC;
|
|
||||||
auto ReturnLD = TempLD.Visit<int32>(TestQualifiers);
|
|
||||||
always_check((TIsSame<int32, decltype(ReturnLD)>::Value));
|
|
||||||
|
|
||||||
bIsConst = false;
|
|
||||||
bIsLValue = false;
|
|
||||||
bIsRValue = true;
|
|
||||||
|
|
||||||
TVariant<int32> TempRC = 10;
|
|
||||||
auto ReturnRC = MoveTemp(TempRC).Visit<int32>(TestQualifiers);
|
|
||||||
always_check((TIsSame<int32, decltype(ReturnRC)>::Value));
|
|
||||||
|
|
||||||
bIsConst = true;
|
|
||||||
bIsLValue = false;
|
|
||||||
bIsRValue = true;
|
|
||||||
|
|
||||||
const TVariant<int32> TempRD = TempLC;
|
|
||||||
auto ReturnRD = MoveTemp(TempRD).Visit<int32>(TestQualifiers);
|
|
||||||
always_check((TIsSame<int32, decltype(ReturnRD)>::Value));
|
|
||||||
|
|
||||||
always_check(GetTypeHash(TVariant<int32, float>(114)) == GetTypeHash(TVariant<int32, float>(114)));
|
|
||||||
always_check(GetTypeHash(TVariant<int32, float>(114)) != GetTypeHash(TVariant<int32, float>(514)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestAny()
|
void TestAny()
|
||||||
@ -530,6 +560,19 @@ void TestAny()
|
|||||||
TempZ = FAny();
|
TempZ = FAny();
|
||||||
TempZ = FTracker();
|
TempZ = FTracker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
FAny TempA = Invalid;
|
||||||
|
FAny TempB = static_cast<int16>(16);
|
||||||
|
FAny TempC = static_cast<int32>(16);
|
||||||
|
FAny TempD = static_cast<int32>(32);
|
||||||
|
|
||||||
|
always_check(TempA != TempB);
|
||||||
|
always_check(TempB != TempC);
|
||||||
|
always_check(TempB != TempC);
|
||||||
|
always_check(TempD >= TempC);
|
||||||
|
always_check(TempA <=> TempB == partial_ordering::unordered);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestTuple()
|
void TestTuple()
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "Templates/TypeHash.h"
|
#include "Templates/TypeHash.h"
|
||||||
#include "Concepts/Comparable.h"
|
#include "Concepts/Comparable.h"
|
||||||
#include "TypeTraits/TypeTraits.h"
|
#include "TypeTraits/TypeTraits.h"
|
||||||
|
#include "Miscellaneous/Compare.h"
|
||||||
#include "Miscellaneous/AssertionMacros.h"
|
#include "Miscellaneous/AssertionMacros.h"
|
||||||
|
|
||||||
NAMESPACE_REDCRAFT_BEGIN
|
NAMESPACE_REDCRAFT_BEGIN
|
||||||
@ -262,6 +263,14 @@ constexpr bool operator==(const TOptional<T>& LHS, const TOptional<U>& RHS)
|
|||||||
return *LHS == *RHS;
|
return *LHS == *RHS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U> requires CSynthThreeWayComparableWith<T, U>
|
||||||
|
constexpr partial_ordering operator<=>(const TOptional<T>& LHS, const TOptional<U>& RHS)
|
||||||
|
{
|
||||||
|
if (LHS.IsValid() != RHS.IsValid()) return partial_ordering::unordered;
|
||||||
|
if (LHS.IsValid() == false) return partial_ordering::equivalent;
|
||||||
|
return SynthThreeWayCompare(*LHS, *RHS);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename U> requires CWeaklyEqualityComparableWith<T, U>
|
template <typename T, typename U> requires CWeaklyEqualityComparableWith<T, U>
|
||||||
constexpr bool operator==(const TOptional<T>& LHS, const U& RHS)
|
constexpr bool operator==(const TOptional<T>& LHS, const U& RHS)
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include "Templates/Utility.h"
|
#include "Templates/Utility.h"
|
||||||
#include "Templates/TypeHash.h"
|
#include "Templates/TypeHash.h"
|
||||||
#include "TypeTraits/TypeTraits.h"
|
#include "TypeTraits/TypeTraits.h"
|
||||||
|
#include "Miscellaneous/Compare.h"
|
||||||
|
#include "Miscellaneous/TypeInfo.h"
|
||||||
#include "Miscellaneous/AssertionMacros.h"
|
#include "Miscellaneous/AssertionMacros.h"
|
||||||
|
|
||||||
NAMESPACE_REDCRAFT_BEGIN
|
NAMESPACE_REDCRAFT_BEGIN
|
||||||
@ -74,85 +76,6 @@ struct TVariantSelectedType<T>
|
|||||||
using Type = void;
|
using Type = void;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr void VariantDestroy(void* InValue)
|
|
||||||
{
|
|
||||||
if constexpr (!TIsTriviallyDestructible<T>::Value)
|
|
||||||
{
|
|
||||||
typedef T DestructOptionalType;
|
|
||||||
reinterpret_cast<T*>(InValue)->DestructOptionalType::~DestructOptionalType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using FVariantDestroyFunc = void(*)(void*);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr void VariantCopyConstruct(void* Target, const void* Source)
|
|
||||||
{
|
|
||||||
if constexpr (!TIsCopyConstructible<T>::Value || TIsConst<T>::Value) check_no_entry();
|
|
||||||
else new(reinterpret_cast<T*>(Target)) T(*reinterpret_cast<const T*>(Source));
|
|
||||||
}
|
|
||||||
|
|
||||||
using FVariantCopyConstructFunc = void(*)(void*, const void*);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr void VariantMoveConstruct(void* Target, void* Source)
|
|
||||||
{
|
|
||||||
if constexpr (!TIsMoveConstructible<T>::Value || TIsConst<T>::Value) check_no_entry();
|
|
||||||
else new(reinterpret_cast<T*>(Target)) T(MoveTemp(*reinterpret_cast<T*>(Source)));
|
|
||||||
}
|
|
||||||
|
|
||||||
using FVariantMoveConstructFunc = void(*)(void*, void*);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr void VariantCopyAssign(void* Target, const void* Source)
|
|
||||||
{
|
|
||||||
if constexpr (!TIsCopyAssignable<T>::Value || TIsConst<T>::Value) check_no_entry();
|
|
||||||
else *reinterpret_cast<T*>(Target) = *reinterpret_cast<const T*>(Source);
|
|
||||||
}
|
|
||||||
|
|
||||||
using FVariantCopyAssignFunc = void(*)(void*, const void*);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr void VariantMoveAssign(void* Target, void* Source)
|
|
||||||
{
|
|
||||||
if constexpr (!TIsMoveAssignable<T>::Value || TIsConst<T>::Value) check_no_entry();
|
|
||||||
else *reinterpret_cast<T*>(Target) = MoveTemp(*reinterpret_cast<T*>(Source));
|
|
||||||
}
|
|
||||||
|
|
||||||
using FVariantMoveAssignFunc = void(*)(void*, void*);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr bool VariantEqualityOperator(const void* LHS, const void* RHS)
|
|
||||||
{
|
|
||||||
if constexpr (!CEqualityComparable<T>) check_no_entry();
|
|
||||||
else return *reinterpret_cast<const T*>(LHS) == *reinterpret_cast<const T*>(RHS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
using FVariantEqualityOperatorFunc = bool(*)(const void*, const void*);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr void VariantSwap(void* A, void* B)
|
|
||||||
{
|
|
||||||
if constexpr (TIsSwappable<T>::Value) Swap(*reinterpret_cast<T*>(A), *reinterpret_cast<T*>(B));
|
|
||||||
else check_no_entry();
|
|
||||||
}
|
|
||||||
|
|
||||||
using FVariantSwapFunc = void(*)(void*, void*);
|
|
||||||
|
|
||||||
template <typename... Types>
|
|
||||||
struct TVariantHelper
|
|
||||||
{
|
|
||||||
static constexpr FVariantDestroyFunc DestroyFuncs[] = { VariantDestroy<Types>... };
|
|
||||||
static constexpr FVariantCopyConstructFunc CopyConstructFuncs[] = { VariantCopyConstruct<Types>... };
|
|
||||||
static constexpr FVariantMoveConstructFunc MoveConstructFuncs[] = { VariantMoveConstruct<Types>... };
|
|
||||||
static constexpr FVariantCopyAssignFunc CopyAssignFuncs[] = { VariantCopyAssign<Types>... };
|
|
||||||
static constexpr FVariantMoveAssignFunc MoveAssignFuncs[] = { VariantMoveAssign<Types>... };
|
|
||||||
static constexpr FVariantEqualityOperatorFunc EqualityOperatorFuncs[] = { VariantEqualityOperator<Types>... };
|
|
||||||
static constexpr FVariantSwapFunc SwapFuncs[] = { VariantSwap<Types>... };
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename R, typename F, typename T>
|
template <typename R, typename F, typename T>
|
||||||
constexpr R VariantVisitLValue(F&& Func, void* Arg)
|
constexpr R VariantVisitLValue(F&& Func, void* Arg)
|
||||||
{
|
{
|
||||||
@ -219,13 +142,13 @@ struct TVariant
|
|||||||
constexpr TVariant(const TVariant& InValue) requires (true && ... && TIsCopyConstructible<Types>::Value)
|
constexpr TVariant(const TVariant& InValue) requires (true && ... && TIsCopyConstructible<Types>::Value)
|
||||||
: TypeIndex(static_cast<uint8>(InValue.GetIndex()))
|
: TypeIndex(static_cast<uint8>(InValue.GetIndex()))
|
||||||
{
|
{
|
||||||
if (IsValid()) Helper::CopyConstructFuncs[InValue.GetIndex()](&Value, &InValue.Value);
|
if (IsValid()) TypeInfos[InValue.GetIndex()]->CopyConstruct(&Value, &InValue.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr TVariant(TVariant&& InValue) requires (true && ... && TIsMoveConstructible<Types>::Value)
|
constexpr TVariant(TVariant&& InValue) requires (true && ... && TIsMoveConstructible<Types>::Value)
|
||||||
: TypeIndex(static_cast<uint8>(InValue.GetIndex()))
|
: TypeIndex(static_cast<uint8>(InValue.GetIndex()))
|
||||||
{
|
{
|
||||||
if (IsValid()) Helper::MoveConstructFuncs[InValue.GetIndex()](&Value, &InValue.Value);
|
if (IsValid()) TypeInfos[InValue.GetIndex()]->MoveConstruct(&Value, &InValue.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t I, typename... ArgTypes> requires (I < AlternativeSize)
|
template <size_t I, typename... ArgTypes> requires (I < AlternativeSize)
|
||||||
@ -264,11 +187,11 @@ struct TVariant
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetIndex() == InValue.GetIndex()) Helper::CopyAssignFuncs[InValue.GetIndex()](&Value, &InValue.Value);
|
if (GetIndex() == InValue.GetIndex()) TypeInfos[InValue.GetIndex()]->CopyAssign(&Value, &InValue.Value);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
Helper::CopyConstructFuncs[InValue.GetIndex()](&Value, &InValue.Value);
|
TypeInfos[InValue.GetIndex()]->CopyConstruct(&Value, &InValue.Value);
|
||||||
TypeIndex = static_cast<uint8>(InValue.GetIndex());
|
TypeIndex = static_cast<uint8>(InValue.GetIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,11 +208,11 @@ struct TVariant
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetIndex() == InValue.GetIndex()) Helper::MoveAssignFuncs[InValue.GetIndex()](&Value, &InValue.Value);
|
if (GetIndex() == InValue.GetIndex()) TypeInfos[InValue.GetIndex()]->MoveAssign(&Value, &InValue.Value);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
Helper::MoveConstructFuncs[InValue.GetIndex()](&Value, &InValue.Value);
|
TypeInfos[InValue.GetIndex()]->MoveConstruct(&Value, &InValue.Value);
|
||||||
TypeIndex = static_cast<uint8>(InValue.GetIndex());
|
TypeIndex = static_cast<uint8>(InValue.GetIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,6 +255,8 @@ struct TVariant
|
|||||||
return Emplace<TAlternativeIndex<T>::Value>(Forward<ArgTypes>(Args)...);
|
return Emplace<TAlternativeIndex<T>::Value>(Forward<ArgTypes>(Args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr const FTypeInfo& GetTypeInfo() const { return IsValid() ? *TypeInfos[GetIndex()] : Typeid(void); }
|
||||||
|
|
||||||
constexpr size_t GetIndex() const { return TypeIndex != 0xFF ? TypeIndex : INDEX_NONE; }
|
constexpr size_t GetIndex() const { return TypeIndex != 0xFF ? TypeIndex : INDEX_NONE; }
|
||||||
constexpr bool IsValid() const { return TypeIndex != 0xFF; }
|
constexpr bool IsValid() const { return TypeIndex != 0xFF; }
|
||||||
constexpr explicit operator bool() const { return TypeIndex != 0xFF; }
|
constexpr explicit operator bool() const { return TypeIndex != 0xFF; }
|
||||||
@ -421,7 +346,7 @@ struct TVariant
|
|||||||
|
|
||||||
if constexpr (!(true && ... && TIsTriviallyDestructible<Types>::Value))
|
if constexpr (!(true && ... && TIsTriviallyDestructible<Types>::Value))
|
||||||
{
|
{
|
||||||
Helper::DestroyFuncs[GetIndex()](&Value);
|
TypeInfos[GetIndex()]->Destroy(&Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeIndex = static_cast<uint8>(INDEX_NONE);
|
TypeIndex = static_cast<uint8>(INDEX_NONE);
|
||||||
@ -430,7 +355,7 @@ struct TVariant
|
|||||||
constexpr size_t GetTypeHash() const requires (true && ... && CHashable<Types>)
|
constexpr size_t GetTypeHash() const requires (true && ... && CHashable<Types>)
|
||||||
{
|
{
|
||||||
if (!IsValid()) return 114514;
|
if (!IsValid()) return 114514;
|
||||||
return HashCombine(NAMESPACE_REDCRAFT::GetTypeHash(GetIndex()), Visit([](const auto& A) { return NAMESPACE_REDCRAFT::GetTypeHash(A); }));
|
return HashCombine(NAMESPACE_REDCRAFT::GetTypeHash(GetIndex()), TypeInfos[GetIndex()]->HashItem(&Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void Swap(TVariant& InValue) requires (true && ... && (TIsMoveConstructible<Types>::Value && TIsSwappable<Types>::Value))
|
constexpr void Swap(TVariant& InValue) requires (true && ... && (TIsMoveConstructible<Types>::Value && TIsSwappable<Types>::Value))
|
||||||
@ -453,7 +378,7 @@ struct TVariant
|
|||||||
|
|
||||||
if (GetIndex() == InValue.GetIndex())
|
if (GetIndex() == InValue.GetIndex())
|
||||||
{
|
{
|
||||||
Helper::SwapFuncs[GetIndex()](&Value, &InValue.Value);
|
TypeInfos[GetIndex()]->SwapItem(&Value, &InValue.Value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,8 +388,8 @@ struct TVariant
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
using Helper = NAMESPACE_PRIVATE::TVariantHelper<Types...>;
|
static constexpr const FTypeInfo* TypeInfos[] = { &Typeid(Types)... };
|
||||||
|
|
||||||
TAlignedUnion<1, Types...>::Type Value;
|
TAlignedUnion<1, Types...>::Type Value;
|
||||||
uint8 TypeIndex;
|
uint8 TypeIndex;
|
||||||
@ -473,7 +398,14 @@ private:
|
|||||||
{
|
{
|
||||||
if (LHS.GetIndex() != RHS.GetIndex()) return false;
|
if (LHS.GetIndex() != RHS.GetIndex()) return false;
|
||||||
if (LHS.IsValid() == false) return true;
|
if (LHS.IsValid() == false) return true;
|
||||||
return Helper::EqualityOperatorFuncs[LHS.GetIndex()](&LHS.Value, &RHS.Value);
|
return TypeInfos[LHS.GetIndex()]->EqualityCompare(&LHS.Value, &RHS.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr partial_ordering operator<=>(const TVariant& LHS, const TVariant& RHS) requires (true && ... && CSynthThreeWayComparable<Types>)
|
||||||
|
{
|
||||||
|
if (LHS.GetIndex() != RHS.GetIndex()) return partial_ordering::unordered;
|
||||||
|
if (LHS.IsValid() == false) return partial_ordering::equivalent;
|
||||||
|
return TypeInfos[LHS.GetIndex()]->SynthThreeWayCompare(&LHS.Value, &RHS.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user