From eb814e37d37bd3dca0e5915a6b4cac2b9e096515 Mon Sep 17 00:00:00 2001 From: _Redstone_c_ Date: Sat, 30 Apr 2022 23:38:09 +0800 Subject: [PATCH] refactor(templates): optimize TAny implementation, increase inline storage size --- .../Private/Testing/TemplatesTesting.cpp | 14 +- .../Source/Public/Templates/Any.h | 434 ++++++++---------- .../Source/Public/Templates/Function.h | 16 +- 3 files changed, 200 insertions(+), 264 deletions(-) diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index c855850..8c4b190 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -355,7 +355,7 @@ void TestAny() FTracker& operator=(const FTracker& InValue) { always_check_no_entry(); return *this; } FTracker& operator=(FTracker&& InValue) { return *this; } }; - + { FAny TempA; FAny TempB(Invalid); @@ -399,7 +399,7 @@ void TestAny() always_check(!TempD.IsValid()); always_check(0 == TempA); } - + { FAny TempA; FAny TempB(Invalid); @@ -443,7 +443,7 @@ void TestAny() always_check(!TempD.IsValid()); always_check(FIntegral(0) == TempA); } - + { FAny TempA; FAny TempB(Invalid); @@ -451,16 +451,16 @@ void TestAny() 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); @@ -487,7 +487,7 @@ void TestAny() always_check(!TempD.IsValid()); always_check(FFloating(0.0) == TempA); } - + { FAny TempA; FAny TempB(InPlaceType, 0); diff --git a/Redcraft.Utility/Source/Public/Templates/Any.h b/Redcraft.Utility/Source/Public/Templates/Any.h index c1c5c55..fb7e625 100644 --- a/Redcraft.Utility/Source/Public/Templates/Any.h +++ b/Redcraft.Utility/Source/Public/Templates/Any.h @@ -9,193 +9,74 @@ #include "Miscellaneous/TypeInfo.h" #include "Miscellaneous/AssertionMacros.h" +// NOTE: Disable alignment limit warning +#pragma warning(disable : 4359) + NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_PRIVATE_BEGIN -template -void* AnyCopyNew(const void* Source) +enum class EAnyRepresentation : uint8 { - if constexpr (!TIsCopyConstructible::Value) check_no_entry(); - else return new T(*reinterpret_cast(Source)); - return nullptr; -} - -using FAnyCopyNewFunc = void* (*)(const void*); - -template -void* AnyMoveNew(void* Source) -{ - if constexpr (!TIsMoveConstructible::Value) check_no_entry(); - else return new T(MoveTemp(*reinterpret_cast(Source))); - return nullptr; -} - -using FAnyMoveNewFunc = void* (*)(void*); - -template -void AnyDelete(void* InValue) -{ - delete reinterpret_cast(InValue); -} - -using FAnyDeleteFunc = void(*)(void*); - -template -void AnyDestroy(void* InValue) -{ - if constexpr (!TIsTriviallyDestructible::Value) - { - typedef T DestructOptionalType; - reinterpret_cast(InValue)->DestructOptionalType::~DestructOptionalType(); - } -} - -using FAnyDestroyFunc = void(*)(void*); - -template -void AnyCopyConstruct(void* Target, const void* Source) -{ - if constexpr (!TIsCopyConstructible::Value) check_no_entry(); - else new(reinterpret_cast(Target)) T(*reinterpret_cast(Source)); -} - -using FAnyCopyConstructFunc = void(*)(void*, const void*); - -template -void AnyMoveConstruct(void* Target, void* Source) -{ - if constexpr (!TIsMoveConstructible::Value) check_no_entry(); - else new(reinterpret_cast(Target)) T(MoveTemp(*reinterpret_cast(Source))); -} - -using FAnyMoveConstructFunc = void(*)(void*, void*); - -template -void AnyCopyAssign(void* Target, const void* Source) -{ - if constexpr (TIsCopyAssignable::Value) *reinterpret_cast(Target) = *reinterpret_cast(Source); - else if constexpr (TIsCopyConstructible::Value) { AnyDestroy(Target); AnyCopyConstruct(Target, Source); } - else check_no_entry(); -} - -using FAnyCopyAssignFunc = void(*)(void*, const void*); - -template -void AnyMoveAssign(void* Target, void* Source) -{ - if constexpr (TIsMoveAssignable::Value) *reinterpret_cast(Target) = MoveTemp(*reinterpret_cast(Source)); - else if constexpr (TIsMoveConstructible::Value) { AnyDestroy(Target); AnyMoveConstruct(Target, Source); } - else check_no_entry(); -} - -using FAnyMoveAssignFunc = void(*)(void*, void*); - -//template -//constexpr bool AnyEqualityOperator(const void* LHS, const void* RHS) -//{ -// if constexpr (!CEqualityComparable) check_no_entry(); -// else return *reinterpret_cast(LHS) == *reinterpret_cast(RHS); -// return false; -//} -// -//using FAnyEqualityOperatorFunc = bool(*)(const void*, const void*); -// -//template -//void AnySwap(void* A, void* B) -//{ -// if constexpr (TIsSwappable::Value) Swap(*reinterpret_cast(A), *reinterpret_cast(B)); -// else check_no_entry(); -//} -// -//using FAnySwapFunc = void(*)(void*, void*); -// -//template -//size_t AnyTypeHash(const void* InValue) -//{ -// if constexpr (CHashable) return GetTypeHash(*reinterpret_cast(InValue)); -// else return 3516520171; -//} -// -//using FAnyTypeHashFunc = size_t(*)(const void*); - -struct FAnyRTTI -{ - bool bIsInline; - FAnyCopyNewFunc CopyNew; - FAnyMoveNewFunc MoveNew; - FAnyDeleteFunc Delete; - FAnyDestroyFunc Destroy; - FAnyCopyConstructFunc CopyConstruct; - FAnyMoveConstructFunc MoveConstruct; - FAnyCopyAssignFunc CopyAssign; - FAnyMoveAssignFunc MoveAssign; -// FAnyEqualityOperatorFunc EqualityOperator; -// FAnySwapFunc SwapObject; -// FAnyTypeHashFunc TypeHash; -}; - -template -struct TAnyRTTIHelper -{ - static constexpr FAnyRTTI RTTI = - { - bInIsInline, - AnyCopyNew, - AnyMoveNew, - AnyDelete, - AnyDestroy, - AnyCopyConstruct, - AnyMoveConstruct, - AnyCopyAssign, - AnyMoveAssign, -// AnyEqualityOperator, -// AnySwap, -// AnyTypeHash, - }; + Trivial, // Trivial +// Inline, // InlineAllocation + Small, // Trivial & Inline + Big, // HeapAllocation }; NAMESPACE_PRIVATE_END -inline constexpr size_t ANY_DEFAULT_INLINE_SIZE = 48; +inline constexpr size_t ANY_DEFAULT_INLINE_SIZE = 64 - sizeof(uintptr); inline constexpr size_t ANY_DEFAULT_INLINE_ALIGNMENT = 16; template requires (Memory::IsValidAlignment(InlineAlignment)) -struct TAny +struct alignas(InlineAlignment) TAny { - template - struct TIsInlineStorable : TBoolConstant { }; - - template - struct TIsTriviallyStorable : TBoolConstant::Value && TIsTrivial::Value && TIsTriviallyCopyable::Value> { }; - - constexpr TAny() : TypeInfo(nullptr), RTTI(nullptr) { } + constexpr TAny() : TypeInfo(0) { } constexpr TAny(FInvalid) : TAny() { } FORCEINLINE TAny(const TAny& InValue) - : TypeInfo(InValue.TypeInfo), RTTI(InValue.RTTI) + : TypeInfo(InValue.TypeInfo) { if (!IsValid()) return; - if (IsTrivial()) Memory::Memcpy(InlineStorage, InValue.InlineStorage); - else if (IsInline()) RTTI->CopyConstruct(GetStorage(), InValue.GetStorage()); - else DynamicStorage = RTTI->CopyNew(InValue.GetStorage()); + switch (GetRepresentation()) + { + case NAMESPACE_PRIVATE::EAnyRepresentation::Trivial: + Memory::Memcpy(InlineAllocation, InValue.InlineAllocation); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Small: + GetTypeInfo().CopyConstruct(GetAllocation(), InValue.GetAllocation()); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Big: + HeapAllocation = Memory::Malloc(GetTypeInfo().GetTypeSize(), GetTypeInfo().GetTypeAlignment()); + GetTypeInfo().CopyConstruct(GetAllocation(), InValue.GetAllocation()); + break; + default: check_no_entry(); + } } FORCEINLINE TAny(TAny&& InValue) - : TypeInfo(InValue.TypeInfo), RTTI(InValue.RTTI) + : TypeInfo(InValue.TypeInfo) { if (!IsValid()) return; - if (IsTrivial()) Memory::Memcpy(InlineStorage, InValue.InlineStorage); - else if (IsInline()) RTTI->MoveConstruct(GetStorage(), InValue.GetStorage()); - else + switch (GetRepresentation()) { - DynamicStorage = InValue.DynamicStorage; - InValue.TypeInfo = nullptr; + case NAMESPACE_PRIVATE::EAnyRepresentation::Trivial: + Memory::Memcpy(InlineAllocation, InValue.InlineAllocation); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Small: + GetTypeInfo().MoveConstruct(GetAllocation(), InValue.GetAllocation()); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Big: + HeapAllocation = InValue.HeapAllocation; + InValue.TypeInfo = 0; + break; + default: check_no_entry(); } } @@ -229,19 +110,38 @@ struct TAny } else if (GetTypeInfo() == InValue.GetTypeInfo()) { - if (IsTrivial()) Memory::Memcpy(InlineStorage, InValue.InlineStorage); - else RTTI->CopyAssign(GetStorage(), InValue.GetStorage()); + switch (GetRepresentation()) + { + case NAMESPACE_PRIVATE::EAnyRepresentation::Trivial: + Memory::Memcpy(InlineAllocation, InValue.InlineAllocation); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Small: + case NAMESPACE_PRIVATE::EAnyRepresentation::Big: + GetTypeInfo().CopyAssign(GetAllocation(), InValue.GetAllocation()); + break; + default: check_no_entry(); + } } else { ResetImpl(); TypeInfo = InValue.TypeInfo; - RTTI = InValue.RTTI; - if (IsTrivial()) Memory::Memcpy(InlineStorage, InValue.InlineStorage); - else if (IsInline()) RTTI->CopyConstruct(GetStorage(), InValue.GetStorage()); - else DynamicStorage = RTTI->CopyNew(InValue.GetStorage()); + switch (GetRepresentation()) + { + case NAMESPACE_PRIVATE::EAnyRepresentation::Trivial: + Memory::Memcpy(InlineAllocation, InValue.InlineAllocation); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Small: + GetTypeInfo().CopyConstruct(GetAllocation(), InValue.GetAllocation()); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Big: + HeapAllocation = Memory::Malloc(GetTypeInfo().GetTypeSize(), GetTypeInfo().GetTypeAlignment()); + GetTypeInfo().CopyConstruct(GetAllocation(), InValue.GetAllocation()); + break; + default: check_no_entry(); + } } return *this; @@ -257,13 +157,20 @@ struct TAny } else if (GetTypeInfo() == InValue.GetTypeInfo()) { - if (IsTrivial()) Memory::Memcpy(InlineStorage, InValue.InlineStorage); - else if (IsInline()) RTTI->MoveAssign(GetStorage(), InValue.GetStorage()); - else + switch (GetRepresentation()) { - RTTI->Delete(DynamicStorage); - DynamicStorage = InValue.DynamicStorage; - InValue.TypeInfo = nullptr; + case NAMESPACE_PRIVATE::EAnyRepresentation::Trivial: + Memory::Memcpy(InlineAllocation, InValue.InlineAllocation); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Small: + GetTypeInfo().MoveAssign(GetAllocation(), InValue.GetAllocation()); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Big: + ResetImpl(); + HeapAllocation = InValue.HeapAllocation; + InValue.TypeInfo = 0; + break; + default: check_no_entry(); } } else @@ -271,11 +178,21 @@ struct TAny ResetImpl(); TypeInfo = InValue.TypeInfo; - RTTI = InValue.RTTI; - if (IsTrivial()) Memory::Memcpy(InlineStorage, InValue.InlineStorage); - else if (IsInline()) RTTI->MoveConstruct(GetStorage(), InValue.GetStorage()); - else DynamicStorage = RTTI->MoveNew(InValue.GetStorage()); + switch (GetRepresentation()) + { + case NAMESPACE_PRIVATE::EAnyRepresentation::Trivial: + Memory::Memcpy(InlineAllocation, InValue.InlineAllocation); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Small: + GetTypeInfo().MoveConstruct(GetAllocation(), InValue.GetAllocation()); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Big: + HeapAllocation = InValue.HeapAllocation; + InValue.TypeInfo = 0; + break; + default: check_no_entry(); + } } return *this; @@ -290,13 +207,11 @@ struct TAny if (HoldsAlternative()) { - if constexpr (TIsTriviallyStorable::Value) - Memory::Memcpy(&InlineStorage, &InValue, sizeof(SelectedType)); - else GetValue() = Forward(InValue); + GetValue() = Forward(InValue); } else { - Reset(); + ResetImpl(); EmplaceImpl(Forward(InValue)); } @@ -315,26 +230,24 @@ struct TAny return GetValue(); } - constexpr const FTypeInfo& GetTypeInfo() const { return TypeInfo != nullptr ? *TypeInfo : Typeid(void); } + constexpr const FTypeInfo& GetTypeInfo() const { return IsValid() ? *reinterpret_cast(TypeInfo & ~RepresentationMask) : Typeid(void); } - constexpr bool IsValid() const { return TypeInfo != nullptr; } - constexpr explicit operator bool() const { return TypeInfo != nullptr; } - constexpr bool IsInline() const { return RTTI != nullptr ? RTTI->bIsInline : true; } - constexpr bool IsTrivial() const { return RTTI == nullptr; } + constexpr bool IsValid() const { return TypeInfo != 0; } + constexpr explicit operator bool() const { return TypeInfo != 0; } template constexpr bool HoldsAlternative() const { return IsValid() ? GetTypeInfo() == Typeid(T) : false; } template requires TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value - constexpr T& GetValue() & { checkf(HoldsAlternative(), TEXT("It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return *reinterpret_cast< T*>(GetStorage()); } + constexpr T& GetValue() & { checkf(HoldsAlternative(), TEXT("It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return *reinterpret_cast< T*>(GetAllocation()); } template requires TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value - constexpr T&& GetValue() && { checkf(HoldsAlternative(), TEXT("It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return MoveTemp(*reinterpret_cast< T*>(GetStorage())); } + constexpr T&& GetValue() && { checkf(HoldsAlternative(), TEXT("It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return MoveTemp(*reinterpret_cast< T*>(GetAllocation())); } template requires TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value - constexpr const T& GetValue() const& { checkf(HoldsAlternative(), TEXT("It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return *reinterpret_cast(GetStorage()); } + constexpr const T& GetValue() const& { checkf(HoldsAlternative(), TEXT("It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return *reinterpret_cast(GetAllocation()); } template requires TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value - constexpr const T&& GetValue() const&& { checkf(HoldsAlternative(), TEXT("It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return MoveTemp(*reinterpret_cast(GetStorage())); } + constexpr const T&& GetValue() const&& { checkf(HoldsAlternative(), TEXT("It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead.")); return MoveTemp(*reinterpret_cast(GetAllocation())); } template requires TIsSame::Type>::Value&& TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value constexpr T& Get( T& DefaultValue) & { return HoldsAlternative() ? GetValue() : DefaultValue; } @@ -344,94 +257,119 @@ struct TAny FORCEINLINE void Reset() { - TypeInfo = nullptr; ResetImpl(); + TypeInfo = 0; } -// FORCEINLINE size_t GetTypeHash() const -// { -// if (!IsValid()) return 20090007; -// return HashCombine(NAMESPACE_REDCRAFT::GetTypeHash(GetTypeInfo()), RTTI->TypeHash(GetStorage())); -// } -// -// FORCEINLINE void Swap(TAny& InValue) -// { -// if (!IsValid() && !InValue.IsValid()) return; -// -// if (IsValid() && !InValue.IsValid()) -// { -// InValue = MoveTemp(*this); -// Reset(); -// return; -// } -// -// if (InValue.IsValid() && !IsValid()) -// { -// *this = MoveTemp(InValue); -// InValue.Reset(); -// return; -// } -// -// if (GetTypeInfo() == InValue.GetTypeInfo()) -// { -// RTTI->SwapObject(GetStorage(), InValue.GetStorage()); -// return; -// } -// -// TAny Temp = MoveTemp(*this); -// *this = MoveTemp(InValue); -// InValue = MoveTemp(Temp); -// } + FORCEINLINE size_t GetTypeHash() const + { + if (!IsValid()) return 20090007; + return HashCombine(GetTypeInfo().GetTypeHash(), GetTypeInfo().HashItem(GetAllocation())); + } + + FORCEINLINE void Swap(TAny& InValue) + { + if (!IsValid() && !InValue.IsValid()) return; + + if (IsValid() && !InValue.IsValid()) + { + InValue = MoveTemp(*this); + Reset(); + return; + } + + if (InValue.IsValid() && !IsValid()) + { + *this = MoveTemp(InValue); + InValue.Reset(); + return; + } + + if (GetTypeInfo() == InValue.GetTypeInfo()) + { + GetTypeInfo().SwapItem(GetAllocation(), InValue.GetAllocation()); + return; + } + + TAny Temp = MoveTemp(*this); + *this = MoveTemp(InValue); + InValue = MoveTemp(Temp); + } private: + static constexpr uintptr_t RepresentationMask = 3; + union { - TAlignedStorage::Type InlineStorage; - void* DynamicStorage; + TAlignedStorage::Type InlineAllocation; + void* HeapAllocation; }; - const FTypeInfo* TypeInfo; - const NAMESPACE_PRIVATE::FAnyRTTI* RTTI; - - constexpr void* GetStorage() { return IsInline() ? &InlineStorage : DynamicStorage; } - constexpr const void* GetStorage() const { return IsInline() ? &InlineStorage : DynamicStorage; } - + uintptr TypeInfo; + + constexpr NAMESPACE_PRIVATE::EAnyRepresentation GetRepresentation() const { return static_cast(TypeInfo & RepresentationMask); } + + constexpr void* GetAllocation() { return GetRepresentation() == NAMESPACE_PRIVATE::EAnyRepresentation::Trivial || GetRepresentation() == NAMESPACE_PRIVATE::EAnyRepresentation::Small ? &InlineAllocation : HeapAllocation; } + constexpr const void* GetAllocation() const { return GetRepresentation() == NAMESPACE_PRIVATE::EAnyRepresentation::Trivial || GetRepresentation() == NAMESPACE_PRIVATE::EAnyRepresentation::Small ? &InlineAllocation : HeapAllocation; } + template FORCEINLINE void EmplaceImpl(Types&&... Args) { - TypeInfo = &Typeid(SelectedType); + TypeInfo = reinterpret_cast(&Typeid(SelectedType)); - if constexpr (TIsTriviallyStorable::Value) + constexpr bool bIsInlineStorable = sizeof(SelectedType) <= InlineSize && alignof(SelectedType) <= InlineAlignment; + constexpr bool bIsTriviallyStorable = bIsInlineStorable && TIsTrivial::Value && TIsTriviallyCopyable::Value; + + if constexpr (bIsTriviallyStorable) { - new(&InlineStorage) SelectedType(Forward(Args)...); - RTTI = nullptr; + new(&InlineAllocation) SelectedType(Forward(Args)...); + TypeInfo |= static_cast(NAMESPACE_PRIVATE::EAnyRepresentation::Trivial); } - else if constexpr (TIsInlineStorable::Value) + else if constexpr (bIsInlineStorable) { - new(&InlineStorage) SelectedType(Forward(Args)...); - RTTI = &NAMESPACE_PRIVATE::TAnyRTTIHelper::RTTI; + new(&InlineAllocation) SelectedType(Forward(Args)...); + TypeInfo |= static_cast(NAMESPACE_PRIVATE::EAnyRepresentation::Small); } else { - DynamicStorage = new SelectedType(Forward(Args)...); - RTTI = &NAMESPACE_PRIVATE::TAnyRTTIHelper::RTTI; + HeapAllocation = new SelectedType(Forward(Args)...); + TypeInfo |= static_cast(NAMESPACE_PRIVATE::EAnyRepresentation::Big); } } FORCEINLINE void ResetImpl() { - if (!IsValid() || IsTrivial()) return; - else if (IsInline()) RTTI->Destroy(&InlineStorage); - else RTTI->Delete(DynamicStorage); + if (!IsValid()) return; + + switch (GetRepresentation()) + { + case NAMESPACE_PRIVATE::EAnyRepresentation::Trivial: + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Small: + GetTypeInfo().Destroy(GetAllocation()); + break; + case NAMESPACE_PRIVATE::EAnyRepresentation::Big: + GetTypeInfo().Destroy(GetAllocation()); + Memory::Free(HeapAllocation); + break; + default: check_no_entry(); + } } -// friend FORCEINLINE bool operator==(const TAny& LHS, const TAny& RHS) -// { -// if (LHS.GetTypeInfo() != RHS.GetTypeInfo()) return false; -// if (LHS.IsValid() == false) return true; -// return LHS.RTTI->EqualityOperator(LHS.GetStorage(), RHS.GetStorage()); -// } + friend FORCEINLINE bool operator==(const TAny& LHS, const TAny& RHS) + { + if (LHS.GetTypeInfo() != RHS.GetTypeInfo()) return false; + if (LHS.IsValid() == false) return true; + return LHS.GetTypeInfo().EqualityCompare(LHS.GetAllocation(), RHS.GetAllocation()); + } + + friend FORCEINLINE partial_ordering operator<=>(const TAny& LHS, const TAny& RHS) + { + if (LHS.GetTypeInfo() != RHS.GetTypeInfo()) return partial_ordering::unordered; + if (LHS.IsValid() == false) return partial_ordering::equivalent; + return LHS.GetTypeInfo().SynthThreeWayCompare(LHS.GetAllocation(), RHS.GetAllocation());; + } }; diff --git a/Redcraft.Utility/Source/Public/Templates/Function.h b/Redcraft.Utility/Source/Public/Templates/Function.h index 7d2ae0f..3f9ce9e 100644 --- a/Redcraft.Utility/Source/Public/Templates/Function.h +++ b/Redcraft.Utility/Source/Public/Templates/Function.h @@ -1,22 +1,20 @@ #pragma once #include "CoreTypes.h" -#include "Memory/Memory.h" -#include "Concepts/Same.h" #include "Templates/Any.h" #include "Templates/Tuple.h" #include "Templates/Invoke.h" #include "Memory/Alignment.h" #include "Templates/Utility.h" #include "Templates/TypeHash.h" -#include "Templates/Container.h" -#include "Concepts/Comparable.h" -#include "Concepts/Convertible.h" #include "TypeTraits/TypeTraits.h" #include "Miscellaneous/TypeInfo.h" #include "Concepts/BooleanTestable.h" #include "Miscellaneous/AssertionMacros.h" +// NOTE: Disable alignment limit warning +#pragma warning(disable : 4359) + NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) @@ -105,7 +103,7 @@ template struct TFunctionCallSpecifiers struct TFunctionCallSpecifiers { using Type = const T&&; }; template -struct TFunctionImpl +struct alignas(InlineAlignment) TFunctionImpl { public: @@ -266,7 +264,7 @@ public: private: - using StorageType = typename TConditional>::Type; + using StorageType = typename TConditional>::Type; using StorageRef = typename TConditional::Type&>::Type; using CallFunc = ResultType(*)(StorageRef, Types&&...); @@ -367,8 +365,8 @@ struct TFunctionSelect using TFunctionRef = typename NAMESPACE_PRIVATE::TFunctionSelect::Type;