#include "Testing/TemplatesTesting.h" #include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/Compare.h" #include "Templates/Templates.h" #pragma warning(disable : 4930) #pragma warning(disable : 4101) #pragma warning(disable : 4244) NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_BEGIN(Testing) void TestTemplates() { TestInvoke(); TestReferenceWrapper(); TestOptional(); TestVariant(); TestAny(); TestTuple(); TestFunction(); TestMiscTemplates(); } NAMESPACE_UNNAMED_BEGIN int32 TestFunctionA(int32 A, int32 B, int32 C) { return A + B + C; } struct FTestStructA { int32 Num; FTestStructA(int32 InNum) : Num(InNum) { } int32 Add(int32 A) const { return Num + A; } }; NAMESPACE_UNNAMED_END void TestInvoke() { Invoke([=]() { }); FTestStructA TempA(123); always_check(Invoke(TestFunctionA, 1, 2, 3) == 6); always_check(Invoke(&FTestStructA::Add, TempA, 1) == 124); always_check(Invoke(&FTestStructA::Add, &TempA, 1) == 124); int32 TempB = Invoke(&FTestStructA::Num, &TempA); int32 TempC = Invoke(&FTestStructA::Num, TempA); always_check(TempB == 123); always_check(TempC == 123); int64 TempD = InvokeResult(&FTestStructA::Num, &TempA); int64 TempE = InvokeResult(&FTestStructA::Num, TempA); always_check(TempD == 123); always_check(TempE == 123); } void TestReferenceWrapper() { typedef int32(*FuncType)(int32, int32, int32); FuncType TempA = [](int32 A, int32 B, int32 C) -> int32 { return A * B * C; }; TReferenceWrapper TempB(TempA); always_check(TempB(1, 1, 1) == 1); TempB.Get() = &TestFunctionA; always_check(TempA(1, 1, 1) == 3); int32 ArrayA[3] = { 1, 2, 3 }; TReferenceWrapper ArrayB[3] = { ArrayA[1], ArrayA[0], ArrayA[2] }; always_check(ArrayB[0] == 2); always_check(ArrayB[1] == 1); always_check(ArrayB[2] == 3); for (int32& Element : ArrayB) Element *= 2; always_check(ArrayA[0] == 2); always_check(ArrayA[1] == 4); always_check(ArrayA[2] == 6); always_check((TIsSame::Type>::Value)); always_check((TIsSame>::Type>::Value)); } void TestOptional() { TOptional TempA; TOptional TempB(Invalid); TOptional TempC(InPlace, 0); TOptional TempD(0); TOptional TempE(0l); TOptional TempF(0.0); TOptional TempG(TempA); TOptional TempH(TempD); TOptional TempI(MakeOptional(0)); TOptional TempJ(MakeOptional(Invalid)); TOptional TempK, TempL, TempM, TempN; TempK = TempA; TempL = TempD; TempM = MakeOptional(0); TempN = MakeOptional(Invalid); *TempL = 303; *TempM = 404; TOptional 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 TempR = TempQ; TOptional TempS(InPlace, TempQ); TOptional TempT(TempQ); TOptional TempU(TempR); TOptional TempV(MakeOptional(2048)); TOptional TempW, TempX, TempY; TempW = TempQ; TempX = TempR; TempY = MakeOptional(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 TempZ(MakeOptional()); TempZ = MakeOptional(); TempZ = FTracker(); always_check(GetTypeHash(MakeOptional(114)) == GetTypeHash(MakeOptional(114))); always_check(GetTypeHash(MakeOptional(114)) != GetTypeHash(MakeOptional(514))); } void TestVariant() { TVariant TempA; TVariant TempB(Invalid); TVariant TempC(InPlaceType, 0); TVariant TempD(0); TVariant TempE(0l); TVariant TempF(0.0); TVariant TempG(TempA); TVariant TempH(TempD); TVariant TempI(TVariant(0)); TVariant TempJ(TVariant(Invalid)); TVariant TempK, TempL, TempM, TempN; TempK = TempA; TempL = TempD; TempM = TVariant(0); TempN = TVariant(Invalid); TempL = 303; TempM = 404; TVariant TempO; TempO.Emplace(202); TempO.Emplace<0>(404); always_check(TempO); always_check(TempO.IsValid()); always_check(TempO == 404); always_check(TempO.GetValue() == 404); always_check(TempO.Get<0>(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); Swap(TempD, TempA); int16 TempQ = 1024; TVariant TempR = TempQ; TVariant TempS(InPlaceType, TempQ); TVariant TempT(TempQ); TVariant TempU(TempR); TVariant TempV(TVariant(2048)); TVariant TempW, TempX, TempY; TempW = TempQ; TempX = TempR; TempY = TVariant(2048); Swap(TempW, TempX); Swap(TempW, TempX); 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; } }; TVariant TempZ(Invalid); TempZ = TVariant(); TempZ = FTracker(); always_check((TIsSame>::Type>::Value)); always_check((TIsSame>::Type>::Value)); always_check((TIsSame>::Type>::Value)); always_check((TVariantAlternativeIndex>::Value == 0)); always_check((TVariantAlternativeIndex>::Value == 1)); bool bIsConst; bool bIsLValue; bool bIsRValue; auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& Arg) -> int32 { using T = decltype(Arg); always_check(Arg == 10); always_check(TIsConst::Type>::Value == bIsConst); always_check(TIsLValueReference::Value == bIsLValue); always_check(TIsRValueReference::Value == bIsRValue); return 0; }; bIsConst = false; bIsLValue = true; bIsRValue = false; TVariant TempLA = 10; auto ReturnLA = TempLA.Visit(TestQualifiers); always_check((TIsSame::Value)); bIsConst = true; bIsLValue = true; bIsRValue = false; const TVariant TempLB = TempLA; auto ReturnLB = TempLB.Visit(TestQualifiers); always_check((TIsSame::Value)); bIsConst = false; bIsLValue = false; bIsRValue = true; TVariant TempRA = 10; auto ReturnRA = MoveTemp(TempRA).Visit(TestQualifiers); always_check((TIsSame::Value)); bIsConst = true; bIsLValue = false; bIsRValue = true; const TVariant TempRB = TempLA; auto ReturnRB = MoveTemp(TempRB).Visit(TestQualifiers); always_check((TIsSame::Value)); bIsConst = false; bIsLValue = true; bIsRValue = false; TVariant TempLC = 10; auto ReturnLC = TempLC.Visit(TestQualifiers); always_check((TIsSame::Value)); bIsConst = true; bIsLValue = true; bIsRValue = false; const TVariant TempLD = TempLC; auto ReturnLD = TempLD.Visit(TestQualifiers); always_check((TIsSame::Value)); bIsConst = false; bIsLValue = false; bIsRValue = true; TVariant TempRC = 10; auto ReturnRC = MoveTemp(TempRC).Visit(TestQualifiers); always_check((TIsSame::Value)); bIsConst = true; bIsLValue = false; bIsRValue = true; const TVariant TempRD = TempLC; auto ReturnRD = MoveTemp(TempRD).Visit(TestQualifiers); always_check((TIsSame::Value)); always_check(GetTypeHash(TVariant(114)) == GetTypeHash(TVariant(114))); always_check(GetTypeHash(TVariant(114)) != GetTypeHash(TVariant(514))); } void TestAny() { struct FIntegral { int32 A; FIntegral() { } FIntegral(int32 InA) : A(InA) { } bool operator==(FIntegral RHS) const { return A == RHS.A; } }; struct FFloating { double A; uint8 Pad[64]; FFloating() { } FFloating(double InA) : A(InA) { } bool operator==(FFloating RHS) const { return A == RHS.A; } }; 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; } }; { FAny TempA; FAny TempB(Invalid); FAny TempC(0); FAny TempD(InPlaceType, 0); FAny TempG(TempA); FAny TempH(TempC); FAny TempK, TempL, TempM, TempN; TempK = TempA; TempL = TempD; TempM = FAny(0); TempN = FAny(Invalid); TempL = 303; TempM = 404; FAny TempO; TempO.Emplace(202); 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.Get(500) == 500); int32 TempP = 200; TempO = TempP; TempO = 300; always_check(TempO == 300); always_check(300 == TempO); Swap(TempD, TempA); always_check(!TempD.IsValid()); always_check(0 == TempA); } { FAny TempA; FAny TempB(Invalid); FAny TempC(FIntegral(0)); FAny TempD(InPlaceType, 0); FAny TempG(TempA); FAny TempH(TempC); FAny TempK, TempL, TempM, TempN; TempK = TempA; TempL = TempD; TempM = FAny(FIntegral(0)); TempN = FAny(Invalid); TempL = FIntegral(303); TempM = FIntegral(404); FAny TempO; TempO.Emplace(202); TempO.Emplace(404); always_check(TempO); always_check(TempO.IsValid()); always_check(TempO == FIntegral(404)); always_check(TempO.GetValue() == FIntegral(404)); always_check(TempO.Get(500) == FIntegral(404)); TempO.Reset(); always_check(TempO.Get(500) == FIntegral(500)); FIntegral TempP = FIntegral(200); TempO = TempP; TempO = FIntegral(300); always_check(TempO == FIntegral(300)); always_check(FIntegral(300) == TempO); Swap(TempD, TempA); always_check(!TempD.IsValid()); always_check(FIntegral(0) == TempA); } { FAny TempA; FAny TempB(Invalid); FAny TempC(FFloating(0.0)); FAny TempD(InPlaceType, 0.0); FAny TempG(TempA); FAny TempH(TempC); FAny TempK, TempL, TempM, TempN; TempK = TempA; TempL = TempD; TempM = FAny(FFloating(0.0)); TempN = FAny(Invalid); TempL = FFloating(303.0); TempM = FFloating(404.0); FAny TempO; TempO.Emplace(202.0); TempO.Emplace(404.0); always_check(TempO); always_check(TempO.IsValid()); always_check(TempO == FFloating(404.0)); always_check(TempO.GetValue() == FFloating(404.0)); always_check(TempO.Get(500.0) == FFloating(404.0)); TempO.Reset(); always_check(TempO.Get(500.0) == FFloating(500.0)); FFloating TempP = FFloating(200.0); TempO = TempP; TempO = FFloating(300.0); always_check(TempO == FFloating(300.0)); always_check(FFloating(300.0) == TempO); Swap(TempD, TempA); always_check(!TempD.IsValid()); always_check(FFloating(0.0) == TempA); } { FAny TempA; FAny TempB(InPlaceType, 0); FAny TempC(InPlaceType, 0); FAny TempD(InPlaceType, 0.0); FAny TempE(InPlaceType); Swap(TempA, TempB); Swap(TempA, TempC); Swap(TempA, TempD); Swap(TempA, TempE); Swap(TempB, TempA); Swap(TempB, TempC); Swap(TempB, TempD); Swap(TempB, TempE); Swap(TempC, TempA); Swap(TempC, TempB); Swap(TempC, TempD); Swap(TempC, TempE); Swap(TempD, TempA); Swap(TempD, TempB); Swap(TempD, TempC); Swap(TempD, TempE); Swap(TempE, TempA); Swap(TempE, TempB); Swap(TempE, TempC); Swap(TempE, TempD); always_check(TempA == FIntegral(0)); always_check(TempB == FFloating(0.0)); always_check(TempC.HoldsAlternative()); always_check(TempD == Invalid); always_check(TempE == int32(0)); FAny TempZ(Invalid); TempZ = FAny(); TempZ = FTracker(); } } void TestTuple() { always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), volatile int32&>::Value)); always_check((TIsSame&>().GetValue<0>()), const volatile int32&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), volatile int32&&>::Value)); always_check((TIsSame&&>().GetValue<0>()), const volatile int32&&>::Value)); always_check((TIsSame>::Type, double>::Value)); always_check((TIsSame>::Type, float&>::Value)); always_check((TIsSame>::Type, char&&>::Value)); always_check((TIsSame>::Type, const double>::Value)); always_check((TIsSame>::Type, const float&>::Value)); always_check((TIsSame>::Type, const char&&>::Value)); always_check((TIsSame>::Type, volatile double>::Value)); always_check((TIsSame>::Type, volatile float&>::Value)); always_check((TIsSame>::Type, volatile char&&>::Value)); always_check((TIsSame>::Type, const volatile double>::Value)); always_check((TIsSame>::Type, const volatile float&>::Value)); always_check((TIsSame>::Type, const volatile char&&>::Value)); always_check((TTupleElementIndex>::Value == 0)); always_check((TTupleElementIndex>::Value == 1)); always_check((TTupleElementIndex>::Value == 2)); always_check((TTupleElementIndex>::Value == 0)); always_check((TTupleElementIndex>::Value == 1)); always_check((TTupleElementIndex>::Value == 2)); always_check((TTupleElementIndex>::Value == 0)); always_check((TTupleElementIndex>::Value == 1)); always_check((TTupleElementIndex>::Value == 2)); always_check((TTupleElementIndex>::Value == 0)); always_check((TTupleElementIndex>::Value == 1)); always_check((TTupleElementIndex>::Value == 2)); always_check((TTupleElementIndex>::Value == INDEX_NONE)); // always_check((TIsSame::Type, double>::Value)); // always_check((TTupleElementIndex::Value == 0)); // always_check((TIsSame>::Type, double>::Value)); { using Type = TTuple; Type Temp; Temp.First = 0; Temp.Second = 0; Temp.Third = 0; Temp.Fourth = 0; Temp.Fifth = 0; Temp.Sixth = 0; Temp.Seventh = 0; Temp.Eighth = 0; Temp.Ninth = 0; Temp.Tenth = 0; Temp.Eleventh = 0; Temp.Twelfth = 0; Temp.Thirteenth = 0; Temp.Fourteenth = 0; Temp.Fifteenth = 0; Temp.Sixteenth = 0; always_check(TIsDefaultConstructible::Value); always_check(TIsTriviallyDefaultConstructible::Value); always_check(TIsConstructible::Value); always_check(TIsTriviallyConstructible::Value); always_check(TIsCopyConstructible::Value); always_check(TIsTriviallyCopyConstructible::Value); always_check(TIsMoveConstructible::Value); always_check(TIsTriviallyMoveConstructible::Value); always_check(TIsCopyAssignable::Value); always_check(TIsTriviallyCopyAssignable::Value); always_check(TIsMoveAssignable::Value); always_check(TIsTriviallyMoveAssignable::Value); always_check(TIsDestructible::Value); always_check(TIsTriviallyDestructible::Value); } { TTuple TempA(0, 1); TTuple TempB = { 0, 1 }; TTuple TempC = TempB; TTuple TempD = MoveTemp(TempB); TTuple TempE, TempF; TempE = TempC; TempF = MoveTemp(TempD); always_check(TempC.GetValue<0>() == 0); always_check(TempC.GetValue() == 0); } { TTuple TempA = MakeTuple(1, 2, 3); int32 TempB; Tie(Ignore, TempB, Ignore) = TempA; always_check(TempB == 2); TTuple TempC = ForwardAsTuple(TempB); TempC.GetValue<0>() = 4; always_check(TempB == 4); } struct FTracker { int8 Flag; FTracker(int8 InFlag) : Flag(InFlag) { } FTracker(const FTracker& InValue) { Flag = InValue.Flag - 1; always_check(!Flag); } FTracker(FTracker&& InValue) { Flag = InValue.Flag + 1; always_check(!Flag); } FTracker& operator=(const FTracker& InValue) { Flag = InValue.Flag - 1; always_check(!Flag); return *this; } FTracker& operator=(FTracker&& InValue) { Flag = InValue.Flag + 1; always_check(!Flag); return *this; } }; { TTuple TempA(404, -1); TTuple TempB(3.14, 1); TTuple TempC(1.42f, -1); TTuple<> TempD = { }; auto TempE = TupleCat(MoveTemp(TempA), TempB, MoveTemp(TempC), MoveTemp(TempD)); always_check(TempE.GetValue() == 404); always_check(TempE.GetValue() == 3.14); always_check(TempE.GetValue() == 1.42f); always_check((TIsSame>::Value)); always_check((TIsSame, TTuple, TTuple>::Type>::Value)); } { always_check(MakeTuple(10, 0.0) == MakeTuple(10.0, 0)); always_check(MakeTuple(10, 0.0) != MakeTuple(10.1, 0)); always_check((MakeTuple(10, 0.0) <=> MakeTuple(10.0, 0)) == 0); always_check((MakeTuple(10, 1.0) <=> MakeTuple(10.0, 0)) > 0); always_check((MakeTuple(10, 0.0) <=> MakeTuple(10.1, 0)) < 0); always_check((MakeTuple(10, 0.0) <=> MakeTuple(10.1, 0)) != 0); } { double TempB = 0.0; TTuple TempC(10, TempB); int16 TempD = 10; FTracker TempE(0); TTuple TempF(TempD, MoveTemp(TempE)); auto TempG = TupleCat(TempC, TempF); TempG.GetValue<1>() = 3.14; always_check(TempB == 3.14); always_check(TempG.GetValue<0>() == 10); always_check(TempG.GetValue<2>() == 10); always_check((TIsSame>::Value)); always_check((TIsSame, TTuple>::Type>::Value)); } { int32 TempO = 15; TTuple TempA = { MoveTemp(TempO), 514 }; TempA.Apply( [] (T&& A, U&& B) { always_check(A == 15); always_check(B == 514); always_check((TIsSame::Value)); always_check((TIsSame::Value)); } ); MoveTemp(TempA).Apply( [] (T&& A, U&& B) { always_check(A == 15); always_check(B == 514); always_check((TIsSame::Value)); always_check((TIsSame::Value)); } ); TempA.ApplyAfter( [] (T&& A, U&& B, V&&C) { always_check(A == '-'); always_check(B == 15); always_check(C == 514); always_check((TIsSame::Value)); always_check((TIsSame::Value)); always_check((TIsSame::Value)); }, '-' ); MoveTemp(TempA).ApplyAfter( [] (T&& A, U&& B, V&&C) { always_check(A == '-'); always_check(B == 15); always_check(C == 514); always_check((TIsSame::Value)); always_check((TIsSame::Value)); always_check((TIsSame::Value)); }, '-' ); TempA.ApplyBefore( [] (T&& A, U&& B, V&&C) { always_check(A == 15); always_check(B == 514); always_check(C == '-'); always_check((TIsSame::Value)); always_check((TIsSame::Value)); always_check((TIsSame::Value)); }, '-' ); MoveTemp(TempA).ApplyBefore( [] (T&& A, U&& B, V&&C) { always_check(A == 15); always_check(B == 514); always_check(C == '-'); always_check((TIsSame::Value)); always_check((TIsSame::Value)); always_check((TIsSame::Value)); }, '-' ); } { TTuple TempA = { 1, 'A' }; TTuple TempB = TempA.Transform([](auto&& InValue) { return InValue + 1; }); VisitTuple( [] (T&& A) { if constexpr (TIsSame::Value) always_check(A == 2); else if constexpr (TIsSame::Value) always_check(A == 'B'); else always_check_no_entry(); }, TempB ); VisitTuple([](auto&& A) { A++; }, TempB); VisitTuple( [] (T&& A) { if constexpr (TIsSame::Value) always_check(A == 3); else if constexpr (TIsSame::Value) always_check(A == 'C'); else always_check_no_entry(); }, TempB ); } { struct FTest { FTest(int32 A, float B, char C) { always_check(A == 1); always_check(B == 1.2f); always_check(C == 'A'); } }; MakeTuple(1, 1.2f, 'A').Construct(); } { auto Func = [] { return MakeTuple(1, 2.3, 'A'); }; auto [A, B, C] = Func(); always_check(A == 1); always_check(B == 2.3); always_check(C == 'A'); always_check((TIsSame::Value)); } always_check(GetTypeHash(MakeTuple(114, 1.0f)) == GetTypeHash(MakeTuple(114, 1.0f))); always_check(GetTypeHash(MakeTuple(114, 1.0f)) != GetTypeHash(MakeTuple(514, 1.0f))); } NAMESPACE_UNNAMED_BEGIN struct FFunctionDebug { int32 Index = 0; int32 Output[12]; void Print(int32 In) { Output[Index++] = In; } }; FFunctionDebug FunctionDebug; struct FPrintAdd { FPrintAdd(int32 InNum) : Num(InNum) { } void F(int32 I) const { FunctionDebug.Print(Num + I); } int32 Num; }; void PrintNum(int32 I) { FunctionDebug.Print(I); } struct FPrintNum { void operator()(int32 I) const { FunctionDebug.Print(I); } }; NAMESPACE_UNNAMED_END void TestFunction() { { // TFunctionRef TempA; TFunction TempB; TUniqueFunction TempC; } { struct FFunctor { int32 operator()() & { return 0; } int32 operator()() && { return 1; } int32 operator()() const& { return 2; } int32 operator()() const&& { return 3; } }; FFunctor Functor; TFunctionRef TempA = Functor; TFunctionRef TempB = Functor; TFunctionRef TempC = Functor; TFunctionRef TempD = Functor; TFunctionRef TempE = Functor; TFunctionRef TempF = Functor; always_check( TempA() == 0); always_check( TempB() == 0); always_check(MoveTemp(TempC)() == 1); always_check( TempD() == 2); always_check( TempE() == 2); always_check(MoveTemp(TempF)() == 3); } { int32 Offset = 0xFA00; auto FuncA = [&Offset](int32 In) { return In + Offset; }; TFunctionRef TempA = FuncA; Offset = 0xFB00; always_check(TempA(0xAA) == 0xFBAA); TFunction TempB = FuncA; Offset = 0xFC00; always_check(TempB(0xAB) == 0xFCAB); TUniqueFunction TempC = FuncA; Offset = 0xFD00; always_check(TempC(0xAC) == 0xFDAC); } { struct FFunctor { int32 A; FFunctor(int32 InA) : A(InA) { } int32 operator()() const { return A; } }; TFunction TempA = FFunctor(0xAA); TFunction TempB(InPlaceType, 0xBB); TempA(); TempB(); TFunction TempC = FFunctor(0xAA); TFunction TempD(InPlaceType, 0xBB); always_check(TempC() == 0xAA); always_check(TempD() == 0xBB); TempA = nullptr; TempB = nullptr; always_check(!TempA.IsValid()); always_check(!TempB.IsValid()); TempA = FFunctor(0xCC); TempB.Emplace(0xDD); always_check(TempA.IsValid()); always_check(TempB.IsValid()); TempA(); TempB(); TempC.Reset(); TempD.Reset(); always_check(!TempC.IsValid()); always_check(!TempD.IsValid()); TempC = FFunctor(0xEE); TempD.Emplace(0xFF); always_check(TempC.IsValid()); always_check(TempD.IsValid()); always_check(TempC() == 0xEE); always_check(TempD() == 0xFF); always_check(TempC.TargetType() == Typeid(FFunctor)); always_check(TempD.TargetType() == Typeid(FFunctor)); } { TFunctionRef RefA = [] { }; TFunction ObjectA = [] { }; TUniqueFunction UniqueA = [] { }; TFunctionRef RefB = RefA; // TFunction ObjectB = RefA; // TUniqueFunction UniqueB = RefA; TFunctionRef RefC = ObjectA; TFunction ObjectC = ObjectA; TUniqueFunction UniqueC = ObjectA; TFunctionRef RefD = UniqueA; // TFunction ObjectD = UniqueA; // TUniqueFunction UniqueD = UniqueA; TFunctionRef RefE = MoveTemp(RefA); // TFunction ObjectE = MoveTemp(RefA); // TUniqueFunction UniqueE = MoveTemp(RefA); TFunctionRef RefF = MoveTemp(ObjectA); TFunction ObjectF = MoveTemp(ObjectA); TUniqueFunction UniqueF = MoveTemp(ObjectA); TFunctionRef RefG = MoveTemp(UniqueA); // TFunction ObjectG = MoveTemp(UniqueA); TUniqueFunction UniqueG = MoveTemp(UniqueA); } { TFunctionRef RefA = [] { }; TFunction ObjectA = [] { }; TUniqueFunction UniqueA = [] { }; // TFunctionRef RefB; RefB = RefA; // TFunction ObjectB; ObjectB = RefA; // TUniqueFunction UniqueB; UniqueB = RefA; // TFunctionRef RefC; RefC = ObjectA; TFunction ObjectC; ObjectC = ObjectA; TUniqueFunction UniqueC; UniqueC = ObjectA; // TFunctionRef RefD; RefD = UniqueA; // TFunction ObjectD; ObjectD = UniqueA; // TUniqueFunction UniqueD; UniqueD = UniqueA; // TFunctionRef RefE; RefE = MoveTemp(RefA); // TFunction ObjectE; ObjectE = MoveTemp(RefA); // TUniqueFunction UniqueE; UniqueE = MoveTemp(RefA); // TFunctionRef RefF; RefF = MoveTemp(ObjectA); TFunction ObjectF; ObjectF = MoveTemp(ObjectA); TUniqueFunction UniqueF; UniqueF = MoveTemp(ObjectA); // TFunctionRef RefG; RefG = MoveTemp(UniqueA); // TFunction ObjectG; ObjectG = MoveTemp(UniqueA); TUniqueFunction UniqueG; UniqueG = MoveTemp(UniqueA); } { TFunction Display = PrintNum; Display(-9); TFunction Display42 = [] { PrintNum(42); }; Display42(); TFunction Display31337 = [] { PrintNum(31337); }; Display31337(); TFunction AddDisplay = &FPrintAdd::F; const FPrintAdd Foo(314159); AddDisplay(Foo, 1); AddDisplay(314159, 1); TFunction Num = &FPrintAdd::Num; FunctionDebug.Print(Num(Foo)); TFunction AddDisplay2 = [Foo](int32 A) { Foo.F(A); }; AddDisplay2(2); TFunction AddDisplay3 = [Ptr = &Foo](int32 A) { Ptr->F(A); }; AddDisplay3(3); TFunction DisplayObject = FPrintNum(); DisplayObject(18); auto Factorial = [](int32 N) { TFunction Fac = [&](int32 N) { return (N < 2) ? 1 : N * Fac(N - 1); }; return Fac(N); }; for (int32 I = 5; I < 8; ++I) FunctionDebug.Print(Factorial(I)); always_check(FunctionDebug.Index == 12); always_check(FunctionDebug.Output[0] == -9); always_check(FunctionDebug.Output[1] == 42); always_check(FunctionDebug.Output[2] == 31337); always_check(FunctionDebug.Output[3] == 314160); always_check(FunctionDebug.Output[4] == 314160); always_check(FunctionDebug.Output[5] == 314159); always_check(FunctionDebug.Output[6] == 314161); always_check(FunctionDebug.Output[7] == 314162); always_check(FunctionDebug.Output[8] == 18); always_check(FunctionDebug.Output[9] == 120); always_check(FunctionDebug.Output[10] == 720); always_check(FunctionDebug.Output[11] == 5040); } { TFunction Identity = TIdentity<>(); TFunction NotIdentity = NotFn(Identity); always_check(Identity(true)); always_check(NotIdentity(false)); } { always_check(TPromote ()(4 ) == 4); always_check(TNegate ()(4 ) == -4); always_check(TPlus ()(4, 2) == 6); always_check(TMinus ()(4, 2) == 2); always_check(TMultiplies()(4, 2) == 8); always_check(TDivides ()(4, 2) == 2); always_check(TModulus ()(4, 2) == 0); always_check(TBitNot()(4 ) == -5); always_check(TBitAnd()(4, 2) == 0); always_check(TBitOr ()(4, 2) == 6); always_check(TBitXor()(4, 2) == 6); always_check(TBitLsh()(4, 2) == 16); always_check(TBitRsh()(4, 2) == 1); always_check(TLogicalAnd()(4, 2) == true); always_check(TLogicalOr ()(4, 2) == true); always_check(TLogicalNot()(4 ) == false); always_check(TEqualTo ()(4, 2) == false); always_check(TNotEqualTo ()(4, 2) == true); always_check(TGreater ()(4, 2) == true); always_check(TLess ()(4, 2) == false); always_check(TGreaterEqual()(4, 2) == true); always_check(TLessEqual ()(4, 2) == false); } { TFunction TempA = TPlus <>(); TFunction TempB = TMinus <>(); TFunction TempC = TMultiplies<>(); TFunction TempD = TDivides <>(); TFunction TempE = TModulus <>(); TFunction TempF = TNegate <>(); always_check(TempA(4, 2) == 6); always_check(TempB(4, 2) == 2); always_check(TempC(4, 2) == 8); always_check(TempD(4, 2) == 2); always_check(TempE(4, 2) == 0); always_check(TempF(4 ) == -4); TFunction TempG = TEqualTo <>(); TFunction TempH = TNotEqualTo <>(); TFunction TempI = TGreater <>(); TFunction TempJ = TLess <>(); TFunction TempK = TGreaterEqual<>(); TFunction TempL = TLessEqual <>(); always_check(TempG(4, 2) == false); always_check(TempH(4, 2) == true); always_check(TempI(4, 2) == true); always_check(TempJ(4, 2) == false); always_check(TempK(4, 2) == true); always_check(TempL(4, 2) == false); TFunction TempM = TLogicalAnd<>(); TFunction TempN = TLogicalOr <>(); TFunction TempO = TLogicalNot<>(); always_check(TempM(4, 2) == true); always_check(TempN(4, 2) == true); always_check(TempO(4 ) == false); TFunction TempP = TBitAnd<>(); TFunction TempQ = TBitOr <>(); TFunction TempR = TBitXor<>(); TFunction TempS = TBitNot<>(); always_check(TempP(4, 2) == 0); always_check(TempQ(4, 2) == 6); always_check(TempR(4, 2) == 6); always_check(TempS(4 ) == -5); } } NAMESPACE_UNNAMED_BEGIN template struct TTestStructA { T* Pad; T* Data; TTestStructA(T* InData) : Pad(nullptr), Data(InData) { } ~TTestStructA() { delete Data; } T** operator&() { return &Data; } }; template int32 TestFunctionB(TTestStructA* Ptr) { return 0; } template int32 TestFunctionB(T** Ptr) { return 1; } NAMESPACE_UNNAMED_END void TestMiscTemplates() { TTestStructA ObjectA(new int32(3)); always_check(TestFunctionB(&ObjectA) == 1); always_check(TestFunctionB(AddressOf(ObjectA)) == 0); always_check(AddressOf(TestMiscTemplates) == &TestMiscTemplates); } NAMESPACE_END(Testing) NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END