diff --git a/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp b/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp index f72faa4..403086e 100644 --- a/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp @@ -108,6 +108,14 @@ struct FTestStrongOrdering friend strong_ordering operator<=>(FTestStrongOrdering LHS, FTestStrongOrdering RHS) { return LHS.Num <=> RHS.Num; } }; +struct FTestSynth +{ + int32 A; + FTestSynth(int32 InA) : A(InA) { } + friend bool operator==(FTestSynth LHS, FTestSynth RHS) { return LHS.A == RHS.A; } + friend bool operator< (FTestSynth LHS, FTestSynth RHS) { return LHS.A < RHS.A; } +}; + NAMESPACE_UNNAMED_END void TestCompare() @@ -200,6 +208,17 @@ void TestCompare() always_check((TCompareThreeWay()(0, 0) == strong_ordering::equal)); always_check((TCompareThreeWay() (0, 0.0) == strong_ordering::equal)); + + always_check(TSynthThreeWay{}(FTestPartialOrdering(-1), FTestPartialOrdering( 0)) == partial_ordering::less); + always_check(TSynthThreeWay{}(FTestPartialOrdering( 0), FTestPartialOrdering( 0)) == partial_ordering::equivalent); + always_check(TSynthThreeWay{}(FTestPartialOrdering( 0), FTestPartialOrdering(-1)) == partial_ordering::greater); + + always_check(TSynthThreeWay{}(FTestPartialOrdering( 0, true), FTestPartialOrdering( 0, false)) == partial_ordering::unordered); + + always_check(TSynthThreeWay{}(FTestSynth(-1), FTestSynth( 0)) == weak_ordering::less); + always_check(TSynthThreeWay{}(FTestSynth( 0), FTestSynth( 0)) == weak_ordering::equivalent); + always_check(TSynthThreeWay{}(FTestSynth( 0), FTestSynth(-1)) == weak_ordering::greater); + always_check((StrongOrder(0, 0) == strong_ordering::equal)); always_check((WeakOrder(0, 0) == strong_ordering::equal)); always_check((PartialOrder(0, 0) == strong_ordering::equal)); diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/Compare.h b/Redcraft.Utility/Source/Public/Miscellaneous/Compare.h index f969b68..326036f 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/Compare.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/Compare.h @@ -1,6 +1,7 @@ #pragma once #include "CoreTypes.h" +#include "Templates/Utility.h" #include "Concepts/Concepts.h" #include "TypeTraits/TypeTraits.h" @@ -52,7 +53,7 @@ concept CThreeWayComparableWith = CWeaklyEqualityComparableWith && CPartia CThreeWayComparable && CThreeWayComparable && CCommonReferenceWith::Type&, const typename TRemoveReference::Type&> && CThreeWayComparable::Type&, const typename TRemoveReference::Type&>::Type, OrderingType> && - requires(const TRemoveReference::Type& A, const TRemoveReference::Type& B) + requires(const TRemoveReference::Type& A, const TRemoveReference::Type& B) { { A <=> B } -> CThreeWayComparesAs; { B <=> A } -> CThreeWayComparesAs; @@ -67,7 +68,7 @@ struct TCompareThreeWayResult using Type = decltype(DeclVal::Type&>() <=> DeclVal::Type&>()); }; -template requires CSameAs || CThreeWayComparable +template requires (CSameAs || CThreeWayComparable) struct TCompareThreeWay { constexpr auto operator()(T&& LHS, T&& RHS) const @@ -86,6 +87,61 @@ struct TCompareThreeWay } }; +template +concept CSynthThreeWayComparable = CThreeWayComparable || + requires(const TRemoveReference::Type& A, const TRemoveReference::Type& B) + { + { A < B } -> CBooleanTestable; + { B < A } -> CBooleanTestable; + }; + +template +concept CSynthThreeWayComparableWith = CThreeWayComparableWith || + requires(const TRemoveReference::Type& A, const TRemoveReference::Type& B) + { + { A < B } -> CBooleanTestable; + { B < A } -> CBooleanTestable; + }; + +template requires (CSameAs || CSynthThreeWayComparable) +struct TSynthThreeWay +{ + constexpr auto operator()(T&& LHS, T&& RHS) const + { + if constexpr (CThreeWayComparable) + { + return Forward(LHS) <=> Forward(RHS); + } + else + { + return Forward(LHS) < Forward(RHS) ? weak_ordering::less : Forward(RHS) < Forward(LHS) ? weak_ordering::greater : weak_ordering::equivalent; + } + } +}; + +template <> +struct TSynthThreeWay +{ + template requires CSynthThreeWayComparableWith + constexpr auto operator()(T&& LHS, U&& RHS) const + { + if constexpr (CThreeWayComparableWith) + { + return Forward(LHS) <=> Forward(RHS); + } + else + { + return Forward(LHS) < Forward(RHS) ? weak_ordering::less : Forward(RHS) < Forward(LHS) ? weak_ordering::greater : weak_ordering::equivalent; + } + } +}; + +template +struct TSynthThreeWayResult +{ + using Type = decltype(TSynthThreeWay{}(DeclVal::Type&>(), DeclVal::Type&>())); +}; + NAMESPACE_UNNAMED_BEGIN inline constexpr decltype(NAMESPACE_STD::strong_order) StrongOrder;