refactor(templates): optimize the implementation of TOptional and TVariant

This commit is contained in:
_Redstone_c_ 2022-05-03 18:22:41 +08:00
parent a737eea487
commit 522c71f2b6
3 changed files with 296 additions and 312 deletions

View File

@ -85,6 +85,7 @@ void TestReferenceWrapper()
void TestOptional()
{
{
TOptional<int32> TempA;
TOptional<int32> TempB(Invalid);
TOptional<int32> TempC(InPlace, 0);
@ -158,10 +159,23 @@ void TestOptional()
always_check(GetTypeHash(MakeOptional<int32>(114)) == GetTypeHash(MakeOptional<int32>(114)));
always_check(GetTypeHash(MakeOptional<int32>(114)) != GetTypeHash(MakeOptional<int32>(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);
}
}
void TestVariant()
{
{
TVariant<int32> TempA;
TVariant<int32> TempB(Invalid);
TVariant<int32> TempC(InPlaceType<int32>, 0);
@ -225,7 +239,9 @@ void TestVariant()
Swap(TempW, TempX);
Swap(TempW, TempX);
}
{
struct FTracker
{
FTracker() { }
@ -326,6 +342,20 @@ void TestVariant()
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);
}
}
void TestAny()
@ -530,6 +560,19 @@ void TestAny()
TempZ = FAny();
TempZ = FTracker();
}
{
FAny TempA = Invalid;
FAny TempB = static_cast<int16>(16);
FAny TempC = static_cast<int32>(16);
FAny 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);
}
}
void TestTuple()

View File

@ -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<T>& LHS, const TOptional<U>& RHS)
return *LHS == *RHS;
}
template <typename T, typename U> requires CSynthThreeWayComparableWith<T, U>
constexpr partial_ordering operator<=>(const TOptional<T>& LHS, const TOptional<U>& RHS)
{
if (LHS.IsValid() != RHS.IsValid()) return partial_ordering::unordered;
if (LHS.IsValid() == false) return partial_ordering::equivalent;
return SynthThreeWayCompare(*LHS, *RHS);
}
template <typename T, typename U> requires CWeaklyEqualityComparableWith<T, U>
constexpr bool operator==(const TOptional<T>& LHS, const U& RHS)
{

View File

@ -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<T>
using Type = void;
};
template <typename T>
constexpr void VariantDestroy(void* InValue)
{
if constexpr (!TIsTriviallyDestructible<T>::Value)
{
typedef T DestructOptionalType;
reinterpret_cast<T*>(InValue)->DestructOptionalType::~DestructOptionalType();
}
}
using FVariantDestroyFunc = void(*)(void*);
template <typename T>
constexpr void VariantCopyConstruct(void* Target, const void* Source)
{
if constexpr (!TIsCopyConstructible<T>::Value || TIsConst<T>::Value) check_no_entry();
else new(reinterpret_cast<T*>(Target)) T(*reinterpret_cast<const T*>(Source));
}
using FVariantCopyConstructFunc = void(*)(void*, const void*);
template <typename T>
constexpr void VariantMoveConstruct(void* Target, void* Source)
{
if constexpr (!TIsMoveConstructible<T>::Value || TIsConst<T>::Value) check_no_entry();
else new(reinterpret_cast<T*>(Target)) T(MoveTemp(*reinterpret_cast<T*>(Source)));
}
using FVariantMoveConstructFunc = void(*)(void*, void*);
template <typename T>
constexpr void VariantCopyAssign(void* Target, const void* Source)
{
if constexpr (!TIsCopyAssignable<T>::Value || TIsConst<T>::Value) check_no_entry();
else *reinterpret_cast<T*>(Target) = *reinterpret_cast<const T*>(Source);
}
using FVariantCopyAssignFunc = void(*)(void*, const void*);
template <typename T>
constexpr void VariantMoveAssign(void* Target, void* Source)
{
if constexpr (!TIsMoveAssignable<T>::Value || TIsConst<T>::Value) check_no_entry();
else *reinterpret_cast<T*>(Target) = MoveTemp(*reinterpret_cast<T*>(Source));
}
using FVariantMoveAssignFunc = void(*)(void*, void*);
template <typename T>
constexpr bool VariantEqualityOperator(const void* LHS, const void* RHS)
{
if constexpr (!CEqualityComparable<T>) check_no_entry();
else return *reinterpret_cast<const T*>(LHS) == *reinterpret_cast<const T*>(RHS);
return false;
}
using FVariantEqualityOperatorFunc = bool(*)(const void*, const void*);
template <typename T>
constexpr void VariantSwap(void* A, void* B)
{
if constexpr (TIsSwappable<T>::Value) Swap(*reinterpret_cast<T*>(A), *reinterpret_cast<T*>(B));
else check_no_entry();
}
using FVariantSwapFunc = void(*)(void*, void*);
template <typename... Types>
struct TVariantHelper
{
static constexpr FVariantDestroyFunc DestroyFuncs[] = { VariantDestroy<Types>... };
static constexpr FVariantCopyConstructFunc CopyConstructFuncs[] = { VariantCopyConstruct<Types>... };
static constexpr FVariantMoveConstructFunc MoveConstructFuncs[] = { VariantMoveConstruct<Types>... };
static constexpr FVariantCopyAssignFunc CopyAssignFuncs[] = { VariantCopyAssign<Types>... };
static constexpr FVariantMoveAssignFunc MoveAssignFuncs[] = { VariantMoveAssign<Types>... };
static constexpr FVariantEqualityOperatorFunc EqualityOperatorFuncs[] = { VariantEqualityOperator<Types>... };
static constexpr FVariantSwapFunc SwapFuncs[] = { VariantSwap<Types>... };
};
template <typename R, typename F, typename T>
constexpr R VariantVisitLValue(F&& Func, void* Arg)
{
@ -219,13 +142,13 @@ struct TVariant
constexpr TVariant(const TVariant& InValue) requires (true && ... && TIsCopyConstructible<Types>::Value)
: TypeIndex(static_cast<uint8>(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<Types>::Value)
: TypeIndex(static_cast<uint8>(InValue.GetIndex()))
{
if (IsValid()) Helper::MoveConstructFuncs[InValue.GetIndex()](&Value, &InValue.Value);
if (IsValid()) TypeInfos[InValue.GetIndex()]->MoveConstruct(&Value, &InValue.Value);
}
template <size_t I, typename... ArgTypes> 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<uint8>(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<uint8>(InValue.GetIndex());
}
@ -332,6 +255,8 @@ struct TVariant
return Emplace<TAlternativeIndex<T>::Value>(Forward<ArgTypes>(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<Types>::Value))
{
Helper::DestroyFuncs[GetIndex()](&Value);
TypeInfos[GetIndex()]->Destroy(&Value);
}
TypeIndex = static_cast<uint8>(INDEX_NONE);
@ -430,7 +355,7 @@ struct TVariant
constexpr size_t GetTypeHash() const requires (true && ... && CHashable<Types>)
{
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<Types>::Value && TIsSwappable<Types>::Value))
@ -453,7 +378,7 @@ struct TVariant
if (GetIndex() == InValue.GetIndex())
{
Helper::SwapFuncs[GetIndex()](&Value, &InValue.Value);
TypeInfos[GetIndex()]->SwapItem(&Value, &InValue.Value);
return;
}
@ -464,7 +389,7 @@ struct TVariant
private:
using Helper = NAMESPACE_PRIVATE::TVariantHelper<Types...>;
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<Types>)
{
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);
}
};