From 522c71f2b615b36dde1527528ad5136ea7b9a6ac Mon Sep 17 00:00:00 2001 From: _Redstone_c_ Date: Tue, 3 May 2022 18:22:41 +0800 Subject: [PATCH] refactor(templates): optimize the implementation of TOptional and TVariant --- .../Private/Testing/TemplatesTesting.cpp | 485 ++++++++++-------- .../Source/Public/Templates/Optional.h | 9 + .../Source/Public/Templates/Variant.h | 114 +--- 3 files changed, 296 insertions(+), 312 deletions(-) diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index ebb6a67..995727a 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -85,247 +85,277 @@ void TestReferenceWrapper() 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 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 TempZ(MakeOptional()); - TempZ = MakeOptional(); - TempZ = FTracker(); + TOptional TempK, TempL, TempM, TempN; + TempK = TempA; + TempL = TempD; + TempM = MakeOptional(0); + TempN = MakeOptional(Invalid); - always_check(GetTypeHash(MakeOptional(114)) == GetTypeHash(MakeOptional(114))); - always_check(GetTypeHash(MakeOptional(114)) != GetTypeHash(MakeOptional(514))); + *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))); + } + + { + TOptional TempA = Invalid; + TOptional TempB = 16; + TOptional TempC = 32; + + always_check(TempA != TempB); + always_check(TempB != TempC); + always_check(TempB <= TempC); + always_check(TempA <=> TempB == partial_ordering::unordered); + } } 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 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 TempZ(Invalid); - TempZ = TVariant(); - TempZ = FTracker(); + TVariant TempK, TempL, TempM, TempN; + TempK = TempA; + TempL = TempD; + TempM = TVariant(0); + TempN = TVariant(Invalid); - always_check((TIsSame>::Type>::Value)); - always_check((TIsSame>::Type>::Value)); - always_check((TIsSame>::Type>::Value)); + TempL = 303; + TempM = 404; - always_check((TVariantAlternativeIndex>::Value == 0)); - always_check((TVariantAlternativeIndex>::Value == 1)); + TVariant TempO; + TempO.Emplace(202); + TempO.Emplace<0>(404); - bool bIsConst; - bool bIsLValue; - bool bIsRValue; + always_check(TempO); + always_check(TempO.IsValid()); - auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& Arg) -> int32 + 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); + } + { - 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; - }; + 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; } + }; - bIsConst = false; - bIsLValue = true; - bIsRValue = false; + TVariant TempZ(Invalid); + TempZ = TVariant(); + TempZ = FTracker(); - TVariant TempLA = 10; - auto ReturnLA = TempLA.Visit(TestQualifiers); - always_check((TIsSame::Value)); + always_check((TIsSame>::Type>::Value)); + always_check((TIsSame>::Type>::Value)); + always_check((TIsSame>::Type>::Value)); - bIsConst = true; - bIsLValue = true; - bIsRValue = false; + always_check((TVariantAlternativeIndex>::Value == 0)); + always_check((TVariantAlternativeIndex>::Value == 1)); - const TVariant TempLB = TempLA; - auto ReturnLB = TempLB.Visit(TestQualifiers); - always_check((TIsSame::Value)); + 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))); + } - bIsConst = false; - bIsLValue = false; - bIsRValue = true; + { + TVariant TempA = Invalid; + TVariant TempB = static_cast(16); + TVariant TempC = static_cast(16); + TVariant TempD = static_cast(32); - 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))); + always_check(TempA != TempB); + always_check(TempB != TempC); + always_check(TempB != TempC); + always_check(TempD >= TempC); + always_check(TempA <=> TempB == partial_ordering::unordered); + } } void TestAny() @@ -530,6 +560,19 @@ void TestAny() TempZ = FAny(); TempZ = FTracker(); } + + { + FAny TempA = Invalid; + FAny TempB = static_cast(16); + FAny TempC = static_cast(16); + FAny TempD = static_cast(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() diff --git a/Redcraft.Utility/Source/Public/Templates/Optional.h b/Redcraft.Utility/Source/Public/Templates/Optional.h index 4428d32..4b60b9b 100644 --- a/Redcraft.Utility/Source/Public/Templates/Optional.h +++ b/Redcraft.Utility/Source/Public/Templates/Optional.h @@ -5,6 +5,7 @@ #include "Templates/TypeHash.h" #include "Concepts/Comparable.h" #include "TypeTraits/TypeTraits.h" +#include "Miscellaneous/Compare.h" #include "Miscellaneous/AssertionMacros.h" NAMESPACE_REDCRAFT_BEGIN @@ -262,6 +263,14 @@ constexpr bool operator==(const TOptional& LHS, const TOptional& RHS) return *LHS == *RHS; } +template requires CSynthThreeWayComparableWith +constexpr partial_ordering operator<=>(const TOptional& LHS, const TOptional& RHS) +{ + if (LHS.IsValid() != RHS.IsValid()) return partial_ordering::unordered; + if (LHS.IsValid() == false) return partial_ordering::equivalent; + return SynthThreeWayCompare(*LHS, *RHS); +} + template requires CWeaklyEqualityComparableWith constexpr bool operator==(const TOptional& LHS, const U& RHS) { diff --git a/Redcraft.Utility/Source/Public/Templates/Variant.h b/Redcraft.Utility/Source/Public/Templates/Variant.h index 42ae085..efd71ad 100644 --- a/Redcraft.Utility/Source/Public/Templates/Variant.h +++ b/Redcraft.Utility/Source/Public/Templates/Variant.h @@ -5,6 +5,8 @@ #include "Templates/Utility.h" #include "Templates/TypeHash.h" #include "TypeTraits/TypeTraits.h" +#include "Miscellaneous/Compare.h" +#include "Miscellaneous/TypeInfo.h" #include "Miscellaneous/AssertionMacros.h" NAMESPACE_REDCRAFT_BEGIN @@ -74,85 +76,6 @@ struct TVariantSelectedType using Type = void; }; -template -constexpr void VariantDestroy(void* InValue) -{ - if constexpr (!TIsTriviallyDestructible::Value) - { - typedef T DestructOptionalType; - reinterpret_cast(InValue)->DestructOptionalType::~DestructOptionalType(); - } -} - -using FVariantDestroyFunc = void(*)(void*); - -template -constexpr void VariantCopyConstruct(void* Target, const void* Source) -{ - if constexpr (!TIsCopyConstructible::Value || TIsConst::Value) check_no_entry(); - else new(reinterpret_cast(Target)) T(*reinterpret_cast(Source)); -} - -using FVariantCopyConstructFunc = void(*)(void*, const void*); - -template -constexpr void VariantMoveConstruct(void* Target, void* Source) -{ - if constexpr (!TIsMoveConstructible::Value || TIsConst::Value) check_no_entry(); - else new(reinterpret_cast(Target)) T(MoveTemp(*reinterpret_cast(Source))); -} - -using FVariantMoveConstructFunc = void(*)(void*, void*); - -template -constexpr void VariantCopyAssign(void* Target, const void* Source) -{ - if constexpr (!TIsCopyAssignable::Value || TIsConst::Value) check_no_entry(); - else *reinterpret_cast(Target) = *reinterpret_cast(Source); -} - -using FVariantCopyAssignFunc = void(*)(void*, const void*); - -template -constexpr void VariantMoveAssign(void* Target, void* Source) -{ - if constexpr (!TIsMoveAssignable::Value || TIsConst::Value) check_no_entry(); - else *reinterpret_cast(Target) = MoveTemp(*reinterpret_cast(Source)); -} - -using FVariantMoveAssignFunc = void(*)(void*, void*); - -template -constexpr bool VariantEqualityOperator(const void* LHS, const void* RHS) -{ - if constexpr (!CEqualityComparable) check_no_entry(); - else return *reinterpret_cast(LHS) == *reinterpret_cast(RHS); - return false; -} - -using FVariantEqualityOperatorFunc = bool(*)(const void*, const void*); - -template -constexpr void VariantSwap(void* A, void* B) -{ - if constexpr (TIsSwappable::Value) Swap(*reinterpret_cast(A), *reinterpret_cast(B)); - else check_no_entry(); -} - -using FVariantSwapFunc = void(*)(void*, void*); - -template -struct TVariantHelper -{ - static constexpr FVariantDestroyFunc DestroyFuncs[] = { VariantDestroy... }; - static constexpr FVariantCopyConstructFunc CopyConstructFuncs[] = { VariantCopyConstruct... }; - static constexpr FVariantMoveConstructFunc MoveConstructFuncs[] = { VariantMoveConstruct... }; - static constexpr FVariantCopyAssignFunc CopyAssignFuncs[] = { VariantCopyAssign... }; - static constexpr FVariantMoveAssignFunc MoveAssignFuncs[] = { VariantMoveAssign... }; - static constexpr FVariantEqualityOperatorFunc EqualityOperatorFuncs[] = { VariantEqualityOperator... }; - static constexpr FVariantSwapFunc SwapFuncs[] = { VariantSwap... }; -}; - template constexpr R VariantVisitLValue(F&& Func, void* Arg) { @@ -219,13 +142,13 @@ struct TVariant constexpr TVariant(const TVariant& InValue) requires (true && ... && TIsCopyConstructible::Value) : TypeIndex(static_cast(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::Value) : TypeIndex(static_cast(InValue.GetIndex())) { - if (IsValid()) Helper::MoveConstructFuncs[InValue.GetIndex()](&Value, &InValue.Value); + if (IsValid()) TypeInfos[InValue.GetIndex()]->MoveConstruct(&Value, &InValue.Value); } template requires (I < AlternativeSize) @@ -264,11 +187,11 @@ struct TVariant 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 { Reset(); - Helper::CopyConstructFuncs[InValue.GetIndex()](&Value, &InValue.Value); + TypeInfos[InValue.GetIndex()]->CopyConstruct(&Value, &InValue.Value); TypeIndex = static_cast(InValue.GetIndex()); } @@ -285,11 +208,11 @@ struct TVariant 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 { Reset(); - Helper::MoveConstructFuncs[InValue.GetIndex()](&Value, &InValue.Value); + TypeInfos[InValue.GetIndex()]->MoveConstruct(&Value, &InValue.Value); TypeIndex = static_cast(InValue.GetIndex()); } @@ -332,6 +255,8 @@ struct TVariant return Emplace::Value>(Forward(Args)...); } + constexpr const FTypeInfo& GetTypeInfo() const { return IsValid() ? *TypeInfos[GetIndex()] : Typeid(void); } + constexpr size_t GetIndex() const { return TypeIndex != 0xFF ? TypeIndex : INDEX_NONE; } constexpr bool IsValid() const { return TypeIndex != 0xFF; } constexpr explicit operator bool() const { return TypeIndex != 0xFF; } @@ -421,7 +346,7 @@ struct TVariant if constexpr (!(true && ... && TIsTriviallyDestructible::Value)) { - Helper::DestroyFuncs[GetIndex()](&Value); + TypeInfos[GetIndex()]->Destroy(&Value); } TypeIndex = static_cast(INDEX_NONE); @@ -430,7 +355,7 @@ struct TVariant constexpr size_t GetTypeHash() const requires (true && ... && CHashable) { 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::Value && TIsSwappable::Value)) @@ -453,7 +378,7 @@ struct TVariant if (GetIndex() == InValue.GetIndex()) { - Helper::SwapFuncs[GetIndex()](&Value, &InValue.Value); + TypeInfos[GetIndex()]->SwapItem(&Value, &InValue.Value); return; } @@ -463,8 +388,8 @@ struct TVariant } private: - - using Helper = NAMESPACE_PRIVATE::TVariantHelper; + + static constexpr const FTypeInfo* TypeInfos[] = { &Typeid(Types)... }; TAlignedUnion<1, Types...>::Type Value; uint8 TypeIndex; @@ -473,7 +398,14 @@ private: { if (LHS.GetIndex() != RHS.GetIndex()) return false; 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) + { + 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); } };