#include "Testing/Testing.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) NAMESPACE_PRIVATE_BEGIN 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<int64>(&FTestStructA::Num, &TempA); int64 TempE = InvokeResult<int64>(&FTestStructA::Num, TempA); always_check(TempD == 123); always_check(TempE == 123); } void TestReferenceWrapper() { typedef int32(*FFuncType)(int32, int32, int32); FFuncType TempA = [](int32 A, int32 B, int32 C) -> int32 { return A * B * C; }; TReferenceWrapper<FFuncType> 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<int32> 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((CSameAs<int32, TUnwrapRefDecay<int32>>)); always_check((CSameAs<int32&, TUnwrapRefDecay<TReferenceWrapper<int32>>>)); } 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(0)); TOptional<int32> TempJ(Invalid); TOptional<int32> TempK, TempL, TempM, TempN; TempK = TempA; TempL = TempD; TempM = MakeOptional(0); TempN = 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); always_check(TempO >= 200); always_check(400 >= 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(114)) == GetTypeHash(MakeOptional(114))); always_check(GetTypeHash(MakeOptional(114)) != GetTypeHash(MakeOptional(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); } { struct FTest { FTest(initializer_list<int32>, int32) { } }; TOptional<FTest> Temp(InPlace, { 0, 1, 2 }, 3); Temp.Emplace({ 0, 1, 2 }, 3); } { int32 IntegerA = 0; int32 IntegerB = 0; TOptional<int32&> TempA; TOptional<int32&> TempB(Invalid); TOptional<int32&> TempC(IntegerA); TOptional<int32&> TempD(TempA); TOptional<int32&> TempE(TempC); TOptional<const int32&> TempF; TOptional<const int32&> TempG(Invalid); TOptional<const int32&> TempH(IntegerA); TOptional<const int32&> TempI(TempA); TOptional<const int32&> TempJ(TempC); TOptional<int32&> TempK, TempL, TempM, TempN; TempK = TempA; TempL = TempE; TempM = IntegerB; TempN = Invalid; *TempL = 303; *TempM = 404; always_check(!TempA); always_check(!TempF.IsValid()); always_check(IntegerA == 303); always_check(IntegerB == 404); always_check(TempH == 303); always_check(TempM == 404); always_check(IntegerA < IntegerB); always_check(TempH < TempM); *TempC = 404; always_check(IntegerA == IntegerB); always_check(TempH == TempM); always_check(TempA.Get(IntegerA) == TempM); always_check(TempC.IsValid()); TempC.Reset(); always_check(!TempC.IsValid()); } { TOptional<int32> TempA = 303; TOptional<int32> TempB = 404; TOptional<int32&> TempC = TempA; TOptional<int32&> TempD = TempB; TOptional<const int32&> TempE = TempA; TOptional<const int32&> TempF = TempB; TOptional<int32> TempG = TempC; TOptional<int32> TempH = TempF; always_check(TempG == 303); always_check(TempH == 404); always_check(TempG == TempC); always_check(TempH == TempF); always_check(TempE == TempG); always_check(TempD == TempH); } } void TestVariant() { { TVariant<int32> TempA; TVariant<int32> TempB(Invalid); TVariant<int32> TempC(InPlaceType<int32>, 0); TVariant<int32> TempD(0); // TVariant<int32> TempE(0ll); // 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); always_check(TempO >= 200); always_check(400 >= 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 FVariantType = TVariant<int32, int64, float64>; FVariantType TempArray[] = { 10, 15ll, 1.5 }; for(auto&& TempA : TempArray) { Visit( [](auto&& A) { // ReSharper disable once CppInconsistentNaming using T = TRemoveCVRef<decltype(A)>; if constexpr (CSameAs<T, int32>) always_check(A == 10); else if constexpr (CSameAs<T, int64>) always_check(A == 15ll); else if constexpr (CSameAs<T, float64>) always_check(A == 1.5); else always_check_no_entry(); }, TempA ); FVariantType TempB = Visit([](auto&& A) -> FVariantType { return A + A; }, TempA); Visit( [](auto&& A, auto&& B) { // ReSharper disable once CppInconsistentNaming using T = TRemoveCVRef<decltype(A)>; if constexpr (CSameAs<T, int32>) always_check(A == 10 && B == 20); else if constexpr (CSameAs<T, int64>) always_check(A == 15ll && B == 30ll); else if constexpr (CSameAs<T, float64>) always_check(A == 1.5 && B == 3.0); else always_check_no_entry(); }, TempA, TempB ); Visit([](auto&& A) { A *= 2; }, TempA); Visit( [](auto&& A) { // ReSharper disable once CppInconsistentNaming using T = TRemoveCVRef<decltype(A)>; if constexpr (CSameAs<T, int32>) always_check(A == 20); else if constexpr (CSameAs<T, int64>) always_check(A == 30ll); else if constexpr (CSameAs<T, float64>) always_check(A == 3.0); else always_check_no_entry(); }, TempA ); } for (auto&& TempA : TempArray) { Visit( TOverloaded { [](int32 A) { always_check(A == 20); }, [](int64 A) { always_check(A == 30ll); }, [](float64 A) { always_check(A == 3.0); }, [](auto A) { always_check_no_entry(); }, }, TempA ); } } { 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<FTracker> TempZ(Invalid); TempZ = TVariant<FTracker>(); TempZ = FTracker(); always_check((CSameAs<int32, TVariantAlternative<0, TVariant<int32, float>>>)); always_check((CSameAs<float, TVariantAlternative<1, TVariant<int32, float>>>)); always_check((CSameAs<const int32, TVariantAlternative<0, const TVariant<int32, float>>>)); always_check((TVariantIndex<int32, TVariant<int32, float>> == 0)); always_check((TVariantIndex<float, TVariant<int32, float>> == 1)); bool bIsConst; bool bIsLValue; bool bIsRValue; auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& A) -> int32 { // ReSharper disable once CppInconsistentNaming using T = decltype(A); always_check(A == 10); always_check(CConst<TRemoveReference<T>> == bIsConst); always_check(CLValueReference<T> == bIsLValue); always_check(CRValueReference<T> == bIsRValue); return 0; }; bIsConst = false; bIsLValue = true; bIsRValue = false; // ReSharper disable CppInconsistentNaming TVariant<int32> TempLA = 10; auto ReturnLA = Visit(TestQualifiers, TempLA); always_check((CSameAs<int32, decltype(ReturnLA)>)); bIsConst = true; bIsLValue = true; bIsRValue = false; const TVariant<int32> TempLB = TempLA; auto ReturnLB = Visit(TestQualifiers, TempLB); always_check((CSameAs<int32, decltype(ReturnLB)>)); bIsConst = false; bIsLValue = false; bIsRValue = true; TVariant<int32> TempRA = 10; auto ReturnRA = Visit(TestQualifiers, MoveTemp(TempRA)); always_check((CSameAs<int32, decltype(ReturnRA)>)); bIsConst = true; bIsLValue = false; bIsRValue = true; const TVariant<int32> TempRB = TempLA; auto ReturnRB = Visit(TestQualifiers, MoveTemp(TempRB)); always_check((CSameAs<int32, decltype(ReturnRB)>)); bIsConst = false; bIsLValue = true; bIsRValue = false; TVariant<int32> TempLC = 10; auto ReturnLC = Visit<int32>(TestQualifiers, TempLC); always_check((CSameAs<int32, decltype(ReturnLC)>)); bIsConst = true; bIsLValue = true; bIsRValue = false; const TVariant<int32> TempLD = TempLC; auto ReturnLD = Visit<int32>(TestQualifiers, TempLD); always_check((CSameAs<int32, decltype(ReturnLD)>)); bIsConst = false; bIsLValue = false; bIsRValue = true; TVariant<int32> TempRC = 10; auto ReturnRC = Visit<int32>(TestQualifiers, MoveTemp(TempRC)); always_check((CSameAs<int32, decltype(ReturnRC)>)); bIsConst = true; bIsLValue = false; bIsRValue = true; const TVariant<int32> TempRD = TempLC; auto ReturnRD = Visit<int32>(TestQualifiers, MoveTemp(TempRD)); always_check((CSameAs<int32, decltype(ReturnRD)>)); // ReSharper restore CppInconsistentNaming } { always_check(GetTypeHash(TVariant<int32, float>(114)) == GetTypeHash(TVariant<int32, float>(114))); always_check(GetTypeHash(TVariant<int32, float>(114)) != GetTypeHash(TVariant<int32, float>(514))); } { TVariant<uint8, int16, int32> TempA = Invalid; 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); always_check(TempA != TempB); always_check(TempB != TempC); always_check(TempB != TempC); always_check(TempD >= TempC); always_check(TempA <=> TempB == partial_ordering::unordered); } { struct FTest { FTest(initializer_list<int32>, int32) { } }; TVariant<FTest> TempA(InPlaceIndex<0>, { 0, 1, 2 }, 3); TempA.Emplace<0>({ 0, 1, 2 }, 3); TVariant<FTest> TempB(InPlaceType<FTest>, { 0, 1, 2 }, 3); TempB.Emplace<FTest>({ 0, 1, 2 }, 3); } } 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<int32>, 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<int32>(202); TempO.Emplace<int32>(404); always_check(TempO); always_check(TempO.IsValid()); always_check(TempO == 404); always_check(TempO >= 400); always_check(500 >= TempO); always_check(TempO.GetValue<int32>() == 404); always_check(TempO.Get<int32>(500) == 404); TempO.Reset(); always_check(TempO.Get<int32>(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<FIntegral>, 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<FIntegral>(202); TempO.Emplace<FIntegral>(404); always_check(TempO); always_check(TempO.IsValid()); always_check(TempO == FIntegral(404)); always_check(TempO.GetValue<FIntegral>() == FIntegral(404)); always_check(TempO.Get<FIntegral>(500) == FIntegral(404)); TempO.Reset(); always_check(TempO.Get<FIntegral>(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<FFloating>, 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<FFloating>(202.0); TempO.Emplace<FFloating>(404.0); always_check(TempO); always_check(TempO.IsValid()); always_check(TempO == FFloating(404.0)); always_check(TempO.GetValue<FFloating>() == FFloating(404.0)); always_check(TempO.Get<FFloating>(500.0) == FFloating(404.0)); TempO.Reset(); always_check(TempO.Get<FFloating>(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<int32>, 0); FAny TempC(InPlaceType<FIntegral>, 0); FAny TempD(InPlaceType<FFloating>, 0.0); FAny TempE(InPlaceType<FTracker>); 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<FTracker>()); always_check(TempD == Invalid); always_check(TempE == int32(0)); FAny TempZ(Invalid); TempZ = FAny(); TempZ = FTracker(); } { struct FTest { FTest(initializer_list<int32>, int32) { } }; FAny Temp(InPlaceType<FTest>, { 0, 1, 2 }, 3); Temp.Emplace<FTest>({ 0, 1, 2 }, 3); } } void TestTuple() { always_check((CSameAs<decltype(DeclVal< TTuple< int32, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const int32, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< volatile int32, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const volatile int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< int32, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const int32, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< volatile int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const volatile int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< int32, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< volatile int32, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const volatile int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< volatile int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const volatile int32, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< int32, char>&&>().GetValue<0>()), int32&&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const int32, char>&&>().GetValue<0>()), const int32&&>)); always_check((CSameAs<decltype(DeclVal< TTuple< volatile int32, char>&&>().GetValue<0>()), volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< int32, char>&&>().GetValue<0>()), const int32&&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const int32, char>&&>().GetValue<0>()), const int32&&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< int32, char>&&>().GetValue<0>()), volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< volatile int32, char>&&>().GetValue<0>()), volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< TTuple< int32&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const int32&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< volatile int32&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const volatile int32&, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< int32&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const int32&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< volatile int32&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const volatile int32&, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< int32&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const int32&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< volatile int32&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const volatile int32&, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< int32&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const int32&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< volatile int32&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const volatile int32&, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< int32&, char>&&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const int32&, char>&&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< volatile int32&, char>&&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const volatile int32&, char>&&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< int32&, char>&&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const int32&, char>&&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< volatile int32&, char>&&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const volatile int32&, char>&&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< int32&, char>&&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const int32&, char>&&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< volatile int32&, char>&&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const volatile int32&, char>&&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< int32&, char>&&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const int32&, char>&&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< volatile int32&, char>&&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const volatile int32&, char>&&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< int32&&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const int32&&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< volatile int32&&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const volatile int32&&, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< int32&&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const int32&&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< volatile int32&&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const volatile int32&&, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< int32&&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const int32&&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< volatile int32&&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const volatile int32&&, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< int32&&, char>&>().GetValue<0>()), int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const int32&&, char>&>().GetValue<0>()), const int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< volatile int32&&, char>&>().GetValue<0>()), volatile int32&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const volatile int32&&, char>&>().GetValue<0>()), const volatile int32&>)); always_check((CSameAs<decltype(DeclVal< TTuple< int32&&, char>&&>().GetValue<0>()), int32&&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const int32&&, char>&&>().GetValue<0>()), const int32&&>)); always_check((CSameAs<decltype(DeclVal< TTuple< volatile int32&&, char>&&>().GetValue<0>()), volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< TTuple<const volatile int32&&, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< int32&&, char>&&>().GetValue<0>()), int32&&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const int32&&, char>&&>().GetValue<0>()), const int32&&>)); always_check((CSameAs<decltype(DeclVal<const TTuple< volatile int32&&, char>&&>().GetValue<0>()), volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const TTuple<const volatile int32&&, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< int32&&, char>&&>().GetValue<0>()), int32&&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const int32&&, char>&&>().GetValue<0>()), const int32&&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple< volatile int32&&, char>&&>().GetValue<0>()), volatile int32&&>)); always_check((CSameAs<decltype(DeclVal< volatile TTuple<const volatile int32&&, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< int32&&, char>&&>().GetValue<0>()), int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const int32&&, char>&&>().GetValue<0>()), const int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple< volatile int32&&, char>&&>().GetValue<0>()), volatile int32&&>)); always_check((CSameAs<decltype(DeclVal<const volatile TTuple<const volatile int32&&, char>&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs<TTupleElement<0, TTuple<double, float&, char&&>>, double>)); always_check((CSameAs<TTupleElement<1, TTuple<double, float&, char&&>>, float&>)); always_check((CSameAs<TTupleElement<2, TTuple<double, float&, char&&>>, char&&>)); always_check((CSameAs<TTupleElement<0, const TTuple<double, float&, char&&>>, const double>)); always_check((CSameAs<TTupleElement<1, const TTuple<double, float&, char&&>>, float&>)); always_check((CSameAs<TTupleElement<2, const TTuple<double, float&, char&&>>, char&&>)); always_check((CSameAs<TTupleElement<0, volatile TTuple<double, float&, char&&>>, volatile double>)); always_check((CSameAs<TTupleElement<1, volatile TTuple<double, float&, char&&>>, float&>)); always_check((CSameAs<TTupleElement<2, volatile TTuple<double, float&, char&&>>, char&&>)); always_check((CSameAs<TTupleElement<0, const volatile TTuple<double, float&, char&&>>, const volatile double>)); always_check((CSameAs<TTupleElement<1, const volatile TTuple<double, float&, char&&>>, float&>)); always_check((CSameAs<TTupleElement<2, const volatile TTuple<double, float&, char&&>>, char&&>)); always_check((TTupleIndex<double, TTuple<double, float&, char&&>> == 0)); always_check((TTupleIndex<float&, TTuple<double, float&, char&&>> == 1)); always_check((TTupleIndex<char&&, TTuple<double, float&, char&&>> == 2)); always_check((TTupleIndex<double, const TTuple<double, float&, char&&>> == 0)); always_check((TTupleIndex<float&, const TTuple<double, float&, char&&>> == 1)); always_check((TTupleIndex<char&&, const TTuple<double, float&, char&&>> == 2)); always_check((TTupleIndex<double, volatile TTuple<double, float&, char&&>> == 0)); always_check((TTupleIndex<float&, volatile TTuple<double, float&, char&&>> == 1)); always_check((TTupleIndex<char&&, volatile TTuple<double, float&, char&&>> == 2)); always_check((TTupleIndex<double, const volatile TTuple<double, float&, char&&>> == 0)); always_check((TTupleIndex<float&, const volatile TTuple<double, float&, char&&>> == 1)); always_check((TTupleIndex<char&&, const volatile TTuple<double, float&, char&&>> == 2)); // always_check((CSameAs<TTupleElement<0, int32>, double>)); // always_check((TTupleIndex<int32, int32> == 0)); // always_check((CSameAs<TTupleElement<4, TTuple<double, float&, char&&>>, double>)); { using FType = TTuple<int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64>; FType 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(CDefaultConstructible<FType>); always_check(CTriviallyDefaultConstructible<FType>); always_check(CConstructibleFrom<FType>); always_check(CTriviallyConstructibleFrom<FType>); always_check(CCopyConstructible<FType>); always_check(CTriviallyCopyConstructible<FType>); always_check(CMoveConstructible<FType>); always_check(CTriviallyMoveConstructible<FType>); always_check(CCopyAssignable<FType>); always_check(CTriviallyCopyAssignable<FType>); always_check(CMoveAssignable<FType>); always_check(CTriviallyMoveAssignable<FType>); always_check(CDestructible<FType>); always_check(CTriviallyDestructible<FType>); } { TTuple<int32, int32> TempA(0, 1); TTuple<int32, int32> TempB = { 0, 1 }; TTuple<int64, double> TempC = TempB; TTuple<int64, double> TempD = MoveTemp(TempB); TTuple<double, int64> TempE, TempF; TempE = TempC; TempF = MoveTemp(TempD); always_check(TempC.GetValue<0>() == 0); always_check(TempC.GetValue<int64>() == 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<int32, FTracker> TempA(404, -1); TTuple<double, FTracker> TempB(3.14, 1); TTuple<float, FTracker> TempC(1.42f, -1); TTuple<> TempD = { }; auto TempE = TupleCat(MoveTemp(TempA), TempB, MoveTemp(TempC), MoveTemp(TempD)); always_check(TempE.GetValue<int32>() == 404); always_check(TempE.GetValue<double>() == 3.14); always_check(TempE.GetValue<float>() == 1.42f); always_check((CSameAs<decltype(TempE), TTuple<int32, FTracker, double, FTracker, float, FTracker>>)); always_check((CSameAs<decltype(TempE), TTupleCatResult<TTuple<int32, FTracker>, TTuple<double, FTracker>, TTuple<float, FTracker>>>)); } { 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<int32, double&> TempC(10, TempB); int16 TempD = 10; FTracker TempE(0); TTuple<int16&, FTracker&&> 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((CSameAs<decltype(TempG), TTuple<int32, double&, int16&, FTracker&&>>)); always_check((CSameAs<decltype(TempG), TTupleCatResult<TTuple<int32, double&>, TTuple<int16&, FTracker&&>>>)); } { int32 TempO = 15; TTuple<int32&&, const int64> TempA = { MoveTemp(TempO), 514 }; TempA.Apply( [](auto&& A, auto&& B) { always_check(A == 15); always_check(B == 514); always_check((CSameAs<decltype(A), int32&>)); always_check((CSameAs<decltype(B), const int64&>)); } ); MoveTemp(TempA).Apply( [](auto&& A, auto&& B) { always_check(A == 15); always_check(B == 514); always_check((CSameAs<decltype(A), int32&&>)); always_check((CSameAs<decltype(B), const int64&&>)); } ); } { TTuple<int32, char> TempA = { 1, 'A' }; TempA.Visit([](auto&& A) { A++; }); TempA.Visit( []<typename T> (T&& A) { if constexpr (CSameAs<T&&, int32&>) always_check(A == 2); else if constexpr (CSameAs<T&&, char&>) always_check(A == 'B'); else always_check_no_entry(); } ); always_check(TempA.Visit([](auto A) { return A; }, 0) == 2 ); always_check(TempA.Visit([](auto A) { return A; }, 1) == 'B'); } { TTuple<int32, char> TempA = { 1, 'A' }; TTuple<int32, char> TempB = TempA.Transform([](auto&& InValue) { return InValue + 1; }); VisitTuple( []<typename T> (T&& A) { if constexpr (CSameAs<T&&, int32&>) always_check(A == 2); else if constexpr (CSameAs<T&&, char&>) always_check(A == 'B'); else always_check_no_entry(); }, TempB ); VisitTuple([](auto&& A) { A++; }, TempB); VisitTuple( []<typename T> (T&& A) { if constexpr (CSameAs<T&&, int32&>) always_check(A == 3); else if constexpr (CSameAs<T&&, char&>) 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'); } }; Ignore = MakeTuple(1, 1.2f, 'A').Construct<FTest>(); } { 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((CSameAs<decltype(C), char>)); } 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 GFunctionDebug; struct FPrintAdd { FPrintAdd(int32 InNum) : Num(InNum) { } void F(int32 I) const { GFunctionDebug.Print(Num + I); } int32 Num; }; void PrintNum(int32 I) { GFunctionDebug.Print(I); } struct FPrintNum { void operator()(int32 I) const { GFunctionDebug.Print(I); } }; NAMESPACE_UNNAMED_END void TestFunction() { { // TFunctionRef<void()> TempA; TFunction<void()> TempB; TUniqueFunction<void()> TempC; } { struct FFunctor { int32 operator()() & { return 0; } int32 operator()() && { return 1; } int32 operator()() const& { return 2; } int32 operator()() const&& { return 3; } }; FFunctor Functor; TFunctionRef<int32() > TempA = Functor; TFunctionRef<int32() & > TempB = Functor; TFunctionRef<int32() && > TempC = Functor; TFunctionRef<int32() const > TempD = Functor; TFunctionRef<int32() const& > TempE = Functor; TFunctionRef<int32() const&&> 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<int32(int32)> TempA = FuncA; Offset = 0xFB00; always_check(TempA(0xAA) == 0xFBAA); TFunction<int32(int32)> TempB = FuncA; Offset = 0xFC00; always_check(TempB(0xAB) == 0xFCAB); TUniqueFunction<int32(int32)> TempC = FuncA; Offset = 0xFD00; always_check(TempC(0xAC) == 0xFDAC); } { struct FFunctor { int32 A; FFunctor(int32 InA) : A(InA) { } int32 operator()() const { return A; } }; TFunction<void()> TempA = FFunctor(0xAA); TFunction<void()> TempB(InPlaceType<FFunctor>, 0xBB); TempA(); TempB(); TFunction<int32()> TempC = FFunctor(0xAA); TFunction<int32()> TempD(InPlaceType<FFunctor>, 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<FFunctor>(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<FFunctor>(0xFF); always_check(TempC.IsValid()); always_check(TempD.IsValid()); always_check(TempC() == 0xEE); always_check(TempD() == 0xFF); } { TFunctionRef<void()> RefA = [] { }; TFunction<void()> ObjectA = [] { }; TUniqueFunction<void()> UniqueA = [] { }; TFunctionRef<void()> RefB = RefA; // TFunction<void()> ObjectB = RefA; // TUniqueFunction<void()> UniqueB = RefA; TFunctionRef<void()> RefC = ObjectA; TFunction<void()> ObjectC = ObjectA; TUniqueFunction<void()> UniqueC = ObjectA; TFunctionRef<void()> RefD = UniqueA; // TFunction<void()> ObjectD = UniqueA; // TUniqueFunction<void()> UniqueD = UniqueA; TFunctionRef<void()> RefE = MoveTemp(RefA); // TFunction<void()> ObjectE = MoveTemp(RefA); // TUniqueFunction<void()> UniqueE = MoveTemp(RefA); TFunctionRef<void()> RefF = MoveTemp(ObjectA); TFunction<void()> ObjectF = MoveTemp(ObjectA); TUniqueFunction<void()> UniqueF = MoveTemp(ObjectA); TFunctionRef<void()> RefG = MoveTemp(UniqueA); // TFunction<void()> ObjectG = MoveTemp(UniqueA); TUniqueFunction<void()> UniqueG = MoveTemp(UniqueA); } { TFunctionRef<void()> RefA = [] { }; TFunction<void()> ObjectA = [] { }; TUniqueFunction<void()> UniqueA = [] { }; // TFunctionRef<void()> RefB; RefB = RefA; // TFunction<void()> ObjectB; ObjectB = RefA; // TUniqueFunction<void()> UniqueB; UniqueB = RefA; // TFunctionRef<void()> RefC; RefC = ObjectA; TFunction<void()> ObjectC; ObjectC = ObjectA; TUniqueFunction<void()> UniqueC; UniqueC = ObjectA; // TFunctionRef<void()> RefD; RefD = UniqueA; // TFunction<void()> ObjectD; ObjectD = UniqueA; // TUniqueFunction<void()> UniqueD; UniqueD = UniqueA; // TFunctionRef<void()> RefE; RefE = MoveTemp(RefA); // TFunction<void()> ObjectE; ObjectE = MoveTemp(RefA); // TUniqueFunction<void()> UniqueE; UniqueE = MoveTemp(RefA); // TFunctionRef<void()> RefF; RefF = MoveTemp(ObjectA); TFunction<void()> ObjectF; ObjectF = MoveTemp(ObjectA); TUniqueFunction<void()> UniqueF; UniqueF = MoveTemp(ObjectA); // TFunctionRef<void()> RefG; RefG = MoveTemp(UniqueA); // TFunction<void()> ObjectG; ObjectG = MoveTemp(UniqueA); TUniqueFunction<void()> UniqueG; UniqueG = MoveTemp(UniqueA); } { struct FFunctor { int32 A; FFunctor(int32 InA) : A(InA) { } int32 operator()() const { return A; } }; FFunctor Functor(0xCC); // TFunctionRef<void()> RefA; TFunction<void()> ObjectA; TUniqueFunction<void()> UniqueA; // RefA = Functor; ObjectA = Functor; UniqueA = Functor; // RefA.Emplace<FFunctor>(0xCC); ObjectA.Emplace<FFunctor>(0xCC); UniqueA.Emplace<FFunctor>(0xCC); } { TFunction<void(int32)> Display = PrintNum; Display(-9); TFunction<void()> Display42 = [] { PrintNum(42); }; Display42(); TFunction<void()> Display31337 = [] { PrintNum(31337); }; Display31337(); TFunction<void(const FPrintAdd&, int32)> AddDisplay = &FPrintAdd::F; const FPrintAdd Foo(314159); AddDisplay(Foo, 1); AddDisplay(314159, 1); TFunction<int32(FPrintAdd const&)> Num = &FPrintAdd::Num; GFunctionDebug.Print(Num(Foo)); TFunction<void(int32)> AddDisplay2 = [Foo](int32 A) { Foo.F(A); }; AddDisplay2(2); TFunction<void(int32)> AddDisplay3 = [Ptr = &Foo](int32 A) { Ptr->F(A); }; AddDisplay3(3); TFunction<void(int32)> DisplayObject = FPrintNum(); DisplayObject(18); auto Factorial = [](int32 N) { TFunction<int32(int32)> Fac = [&](int32 N) { return (N < 2) ? 1 : N * Fac(N - 1); }; return Fac(N); }; for (int32 I = 5; I < 8; ++I) GFunctionDebug.Print(Factorial(I)); always_check(GFunctionDebug.Index == 12); always_check(GFunctionDebug.Output[0] == -9); always_check(GFunctionDebug.Output[1] == 42); always_check(GFunctionDebug.Output[2] == 31337); always_check(GFunctionDebug.Output[3] == 314160); always_check(GFunctionDebug.Output[4] == 314160); always_check(GFunctionDebug.Output[5] == 314159); always_check(GFunctionDebug.Output[6] == 314161); always_check(GFunctionDebug.Output[7] == 314162); always_check(GFunctionDebug.Output[8] == 18); always_check(GFunctionDebug.Output[9] == 120); always_check(GFunctionDebug.Output[10] == 720); always_check(GFunctionDebug.Output[11] == 5040); } { TFunction<bool(bool)> Identity = [](bool In) { return In; }; TFunction<bool(bool)> NotIdentity = NotFn(Identity); always_check(NotFn(Identity)(false)); always_check(Identity(true)); always_check(NotIdentity(false)); } { struct FTest { FTest(initializer_list<int32>, int32) { } void operator()() { } }; TFunction<void()> TempA(InPlaceType<FTest>, { 0, 1, 2 }, 3); TempA.Emplace<FTest>({ 0, 1, 2 }, 3); TUniqueFunction<void()> TempB(InPlaceType<FTest>, { 0, 1, 2 }, 3); TempB.Emplace<FTest>({ 0, 1, 2 }, 3); } } void TestAtomic() { { TAtomic<int32> TempA; always_check(TempA.bIsAlwaysLockFree); always_check((TempA = 11) == 11); TempA.Store(12); always_check(TempA.Load() == 12); always_check((int32)TempA == 12); always_check(TempA.Exchange(13) == 12); int32 TempB = 13; always_check(TempA.CompareExchange(TempB, 15) == true); always_check(TempA.CompareExchange(TempB, 15) == false); always_check(TempA.CompareExchange(TempB, 15) == true); TempA.Wait(13); TempA.Notify(); always_check(TempA.FetchAdd(1) == 15); always_check(TempA.FetchSub(1) == 16); always_check(TempA.FetchMul(3) == 15); always_check(TempA.FetchDiv(3) == 45); always_check(TempA.FetchMod(16) == 15); always_check(TempA.FetchAnd(0xFF) == 15); always_check(TempA.FetchOr(0xFFFF) == 0xF); always_check(TempA.FetchXor(0xFF) == 0xFFFF); always_check(TempA.FetchLsh(4) == 0xFF00); always_check(TempA.FetchRsh(4) == 0xFF000); always_check(++TempA == 0xFF01); always_check(TempA++ == 0xFF01); always_check(--TempA == 0xFF01); always_check(TempA-- == 0xFF01); always_check((TempA += 1) == 0xFF01); always_check((TempA -= 1) == 0xFF00); always_check((TempA *= 16) == 0xFF000); always_check((TempA /= 16) == 0xFF00); always_check((TempA %= 0x1000) == 0xF00); always_check((TempA &= 1) == 0x0); always_check((TempA |= 1) == 0x1); always_check((TempA ^= 0xF) == 0xE); always_check((TempA <<= 4) == 0xE0); always_check((TempA >>= 4) == 0xE); } { int32 A; TAtomicRef<int32> TempA(A); always_check(TempA.bIsAlwaysLockFree); always_check((TempA = 11) == 11); TempA.Store(12); always_check(TempA.Load() == 12); always_check((int32)TempA == 12); always_check(TempA.Exchange(13) == 12); int32 TempB = 13; always_check(TempA.CompareExchange(TempB, 15) == true); always_check(TempA.CompareExchange(TempB, 15) == false); always_check(TempA.CompareExchange(TempB, 15) == true); TempA.Wait(13); TempA.Notify(); always_check(TempA.FetchAdd(1) == 15); always_check(TempA.FetchSub(1) == 16); always_check(TempA.FetchMul(3) == 15); always_check(TempA.FetchDiv(3) == 45); always_check(TempA.FetchMod(16) == 15); always_check(TempA.FetchAnd(0xFF) == 15); always_check(TempA.FetchOr(0xFFFF) == 0xF); always_check(TempA.FetchXor(0xFF) == 0xFFFF); always_check(TempA.FetchLsh(4) == 0xFF00); always_check(TempA.FetchRsh(4) == 0xFF000); always_check(++TempA == 0xFF01); always_check(TempA++ == 0xFF01); always_check(--TempA == 0xFF01); always_check(TempA-- == 0xFF01); always_check((TempA += 1) == 0xFF01); always_check((TempA -= 1) == 0xFF00); always_check((TempA *= 16) == 0xFF000); always_check((TempA /= 16) == 0xFF00); always_check((TempA %= 0x1000) == 0xF00); always_check((TempA &= 1) == 0x0); always_check((TempA |= 1) == 0x1); always_check((TempA ^= 0xF) == 0xE); always_check((TempA <<= 4) == 0xE0); always_check((TempA >>= 4) == 0xE); } { FAtomicFlag Flag; always_check(Flag.TestAndSet() == false); always_check(Flag.Test() == true); Flag.Clear(); always_check(Flag.Test() == false); Flag.Wait(true); Flag.Notify(); } { int32 TempA = 10; int32 TempB = KillDependency(TempA); always_check(TempB == 10); } { AtomicThreadFence(); AtomicSignalFence(); } } void TestScopeHelper() { { int32 CheckNum = 0; { TScopeCallback ScopeCallback([&]() { CheckNum = 2; }); always_check(CheckNum == 0); CheckNum = 1; always_check(CheckNum == 1); } always_check(CheckNum == 2); } { int32 CheckNum = 0; { TScopeCallback ScopeCallback([&]() { CheckNum = 2; }); always_check(CheckNum == 0); CheckNum = 1; always_check(CheckNum == 1); ScopeCallback.Release(); } always_check(CheckNum == 1); } { int32 CheckNum = 0; { TScopeCallback ScopeCallbackA([&]() { CheckNum = 2; }); TScopeCallback ScopeCallbackB(MoveTemp(ScopeCallbackA)); always_check(CheckNum == 0); CheckNum = 1; always_check(CheckNum == 1); } always_check(CheckNum == 2); } { int32 CheckNum = 1; { TGuardValue GuardValue(CheckNum); CheckNum = 2; always_check(CheckNum == 2); } always_check(CheckNum == 1); } { int32 CheckNum = 1; { TGuardValue GuardValue(CheckNum, 2); always_check(CheckNum == 2); } always_check(CheckNum == 1); } { int32 CheckNum = 1; { TGuardValue GuardValue(CheckNum, 2); always_check(CheckNum == 2); GuardValue.Release(); } always_check(CheckNum == 2); } { int32 CheckNum = 1; { TGuardValue GuardValueA(CheckNum, 2); TGuardValue GuardValueB(MoveTemp(GuardValueA)); always_check(CheckNum == 2); } always_check(CheckNum == 1); } { int32 CheckNum = 1; { TScopeCounter GuardValue(CheckNum); always_check(CheckNum == 2); } always_check(CheckNum == 1); } } void TestPropagateConst() { { struct FTestA { void Check(bool bFlag) { always_check(!bFlag); } void Check(bool bFlag) const { always_check( bFlag); } }; struct FTestB { FTestB() { Ptr = &Object; } FTestA Object; TPropagateConst<FTestA*> Ptr; }; FTestB TempA; const FTestB TempB; TempA.Ptr->Check(false); TempB.Ptr->Check(true); } { int64 IntA; int64 IntB; TPropagateConst<int64*> TempA; TPropagateConst<int64*> TempB = &IntA; TPropagateConst<int64*> TempC = &IntB; TempA = TempB; TempB = TempC; always_check(TempA.IsValid()); always_check(TempA == &IntA); always_check(TempB == TempC); } } void TestMiscTemplates() { struct FTestRetainedRef { explicit FTestRetainedRef(TRetainedRef<const int64> InRef) { } }; int64 IntA; FTestRetainedRef TempA(IntA); // FTestRetainedRef TempB(114514); } NAMESPACE_PRIVATE_END void TestTemplates() { NAMESPACE_PRIVATE::TestInvoke(); NAMESPACE_PRIVATE::TestReferenceWrapper(); NAMESPACE_PRIVATE::TestOptional(); NAMESPACE_PRIVATE::TestVariant(); NAMESPACE_PRIVATE::TestAny(); NAMESPACE_PRIVATE::TestTuple(); NAMESPACE_PRIVATE::TestFunction(); NAMESPACE_PRIVATE::TestAtomic(); NAMESPACE_PRIVATE::TestScopeHelper(); NAMESPACE_PRIVATE::TestPropagateConst(); NAMESPACE_PRIVATE::TestMiscTemplates(); } NAMESPACE_END(Testing) NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END