refactor(templates): make FTypeInfo behave more like std::type_info and optimize TAny

This commit is contained in:
_Redstone_c_ 2022-04-05 17:00:33 +08:00
parent 2a3a5aec35
commit a539f70535
4 changed files with 60 additions and 65 deletions

View File

@ -237,22 +237,23 @@ NAMESPACE_UNNAMED_END
void TestTypeInfo() void TestTypeInfo()
{ {
FTypeInfo TempA; const FTypeInfo& TempA = Typeid(void);
FTypeInfo TempB(Invalid); const FTypeInfo& TempB = Typeid(void);
always_check(TempA == TempB); always_check(TempA == TempB);
always_check(TempA == Typeid(void)); always_check(TempA == Typeid(void));
FTypeInfo TempC(Typeid(TTestTemplateType<int8, int16>)); const FTypeInfo& TempC(Typeid(TTestTemplateType<int8, int16>));
FTypeInfo TempD = Typeid(TTestTemplateType<int8, int32>); const FTypeInfo& TempD = Typeid(TTestTemplateType<int8, int32>);
FTypeInfo TempE, TempF; const FTypeInfo& TempE = TempC;
TempE = TempC; const FTypeInfo& TempF = TempD;
TempF = MoveTemp(TempD);
always_check(TempE != TempF); always_check(TempE != TempF);
always_check((TempE < TempF) == (TempF > TempE)); always_check((TempE < TempF) == (TempF > TempE));
always_check((TempE > TempF) == (TempF < TempE)); always_check((TempE > TempF) == (TempF < TempE));
always_check((TempE <= TempF) == (TempF >= TempE));
always_check((TempE >= TempF) == (TempF <= TempE));
always_check((TempE <=> TempF) != 0); always_check((TempE <=> TempF) != 0);
} }

View File

@ -11,31 +11,24 @@ NAMESPACE_MODULE_BEGIN(Utility)
struct FTypeInfo struct FTypeInfo
{ {
constexpr FTypeInfo() : FTypeInfo(typeid(void)) { } FTypeInfo() = delete;
FTypeInfo(FTypeInfo&&) = delete;
FTypeInfo(const FTypeInfo&) = delete;
FTypeInfo& operator=(FTypeInfo&&) = delete;
FTypeInfo& operator=(const FTypeInfo&) = delete;
constexpr FTypeInfo(FInvalid) : FTypeInfo() { } FORCEINLINE size_t GetTypeHash() const { return reinterpret_cast<const std::type_info*>(this)->hash_code(); }
FORCEINLINE const char* GetName() const { return reinterpret_cast<const std::type_info*>(this)->name(); }
constexpr FTypeInfo(const std::type_info& InTypeInfo) : Ptr(&InTypeInfo) { }
size_t GetTypeHash() const { return Ptr->hash_code(); }
const char* GetName() const { return Ptr->name(); }
private: private:
const std::type_info* Ptr; friend FORCEINLINE bool operator==(const FTypeInfo& LHS, const FTypeInfo& RHS) { return &LHS != &RHS ? *reinterpret_cast<const std::type_info*>(&LHS) == *reinterpret_cast<const std::type_info*>(&RHS) : true; }
friend FORCEINLINE bool operator< (const FTypeInfo& LHS, const FTypeInfo& RHS) { return reinterpret_cast<const std::type_info*>(&LHS)->before(*reinterpret_cast<const std::type_info*>(&RHS)); }
friend FORCEINLINE bool operator<=(const FTypeInfo& LHS, const FTypeInfo& RHS) { return LHS == RHS || LHS < RHS; }
friend FORCEINLINE bool operator>=(const FTypeInfo& LHS, const FTypeInfo& RHS) { return LHS == RHS || LHS > RHS; }
friend FORCEINLINE bool operator> (const FTypeInfo& LHS, const FTypeInfo& RHS) { return !(LHS < RHS); }
friend bool operator==(FTypeInfo LHS, FTypeInfo RHS) { return *LHS.Ptr == *RHS.Ptr; } friend FORCEINLINE strong_ordering operator<=>(const FTypeInfo& LHS, const FTypeInfo& RHS)
friend bool operator<(FTypeInfo LHS, FTypeInfo RHS) { return LHS.Ptr->before(*RHS.Ptr); }
friend bool operator<=(FTypeInfo LHS, FTypeInfo RHS) { return LHS == RHS || LHS.Ptr->before(*RHS.Ptr); }
friend bool operator>=(FTypeInfo LHS, FTypeInfo RHS) { return LHS == RHS || !LHS.Ptr->before(*RHS.Ptr); }
friend bool operator>(FTypeInfo LHS, FTypeInfo RHS) { return !LHS.Ptr->before(*RHS.Ptr); }
friend strong_ordering operator<=>(FTypeInfo LHS, FTypeInfo RHS)
{ {
if (LHS == RHS) return strong_ordering::equal; if (LHS == RHS) return strong_ordering::equal;
return LHS < RHS ? strong_ordering::less : strong_ordering::greater; return LHS < RHS ? strong_ordering::less : strong_ordering::greater;
@ -43,7 +36,7 @@ private:
}; };
#define Typeid(...) (FTypeInfo(typeid(__VA_ARGS__))) #define Typeid(...) (*reinterpret_cast<const FTypeInfo*>(&typeid(__VA_ARGS__)))
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)

View File

@ -135,11 +135,11 @@ struct TAny
template <typename T> template <typename T>
struct TIsTriviallyStorable : TBoolConstant<TIsInlineStorable<T>::Value && TIsTrivial<T>::Value && TIsTriviallyCopyable<T>::Value> { }; struct TIsTriviallyStorable : TBoolConstant<TIsInlineStorable<T>::Value && TIsTrivial<T>::Value && TIsTriviallyCopyable<T>::Value> { };
constexpr TAny() : TypeInfo(Typeid(void)), RTTI(nullptr) { } constexpr TAny() : TypeInfo(nullptr), RTTI(nullptr) { }
constexpr TAny(FInvalid) : TAny() { } constexpr TAny(FInvalid) : TAny() { }
TAny(const TAny& InValue) FORCEINLINE TAny(const TAny& InValue)
: TypeInfo(InValue.TypeInfo), RTTI(InValue.RTTI) : TypeInfo(InValue.TypeInfo), RTTI(InValue.RTTI)
{ {
if (!IsValid()) return; if (!IsValid()) return;
@ -149,7 +149,7 @@ struct TAny
else DynamicValue = RTTI->CopyNew(InValue.GetData()); else DynamicValue = RTTI->CopyNew(InValue.GetData());
} }
TAny(TAny&& InValue) FORCEINLINE TAny(TAny&& InValue)
: TypeInfo(InValue.TypeInfo), RTTI(InValue.RTTI) : TypeInfo(InValue.TypeInfo), RTTI(InValue.RTTI)
{ {
if (!IsValid()) return; if (!IsValid()) return;
@ -159,14 +159,14 @@ struct TAny
else else
{ {
DynamicValue = InValue.DynamicValue; DynamicValue = InValue.DynamicValue;
InValue.TypeInfo = Typeid(void); InValue.TypeInfo = nullptr;
} }
} }
template <typename T, typename... Types> requires TIsObject<typename TDecay<T>::Type>::Value template <typename T, typename... Types> requires TIsObject<typename TDecay<T>::Type>::Value
&& (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value && (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value
&& TIsConstructible<typename TDecay<T>::Type, Types...>::Value && TIsConstructible<typename TDecay<T>::Type, Types...>::Value
explicit TAny(TInPlaceType<T>, Types&&... Args) FORCEINLINE explicit TAny(TInPlaceType<T>, Types&&... Args)
{ {
using SelectedType = typename TDecay<T>::Type; using SelectedType = typename TDecay<T>::Type;
EmplaceImpl<SelectedType>(Forward<Types>(Args)...); EmplaceImpl<SelectedType>(Forward<Types>(Args)...);
@ -175,15 +175,15 @@ struct TAny
template <typename T> requires (!TIsSame<typename TDecay<T>::Type, TAny>::Value) && (!TIsTInPlaceType<typename TDecay<T>::Type>::Value) template <typename T> requires (!TIsSame<typename TDecay<T>::Type, TAny>::Value) && (!TIsTInPlaceType<typename TDecay<T>::Type>::Value)
&& TIsObject<typename TDecay<T>::Type>::Value && (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value && TIsObject<typename TDecay<T>::Type>::Value && (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value
&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value && TIsConstructible<typename TDecay<T>::Type, T&&>::Value
TAny(T&& InValue) : TAny(InPlaceType<typename TDecay<T>::Type>, Forward<T>(InValue)) FORCEINLINE TAny(T&& InValue) : TAny(InPlaceType<typename TDecay<T>::Type>, Forward<T>(InValue))
{ } { }
~TAny() FORCEINLINE ~TAny()
{ {
Reset(); ResetImpl();
} }
TAny& operator=(const TAny& InValue) FORCEINLINE TAny& operator=(const TAny& InValue)
{ {
if (&InValue == this) return *this; if (&InValue == this) return *this;
@ -191,14 +191,14 @@ struct TAny
{ {
Reset(); Reset();
} }
else if (TypeInfo == InValue.TypeInfo) else if (GetTypeInfo() == InValue.GetTypeInfo())
{ {
if (IsTrivial()) Memory::Memcpy(InlineValue, InValue.InlineValue); if (IsTrivial()) Memory::Memcpy(InlineValue, InValue.InlineValue);
else RTTI->CopyAssign(GetData(), InValue.GetData()); else RTTI->CopyAssign(GetData(), InValue.GetData());
} }
else else
{ {
Reset(); ResetImpl();
TypeInfo = InValue.TypeInfo; TypeInfo = InValue.TypeInfo;
RTTI = InValue.RTTI; RTTI = InValue.RTTI;
@ -211,7 +211,7 @@ struct TAny
return *this; return *this;
} }
TAny& operator=(TAny&& InValue) FORCEINLINE TAny& operator=(TAny&& InValue)
{ {
if (&InValue == this) return *this; if (&InValue == this) return *this;
@ -219,7 +219,7 @@ struct TAny
{ {
Reset(); Reset();
} }
else if (TypeInfo == InValue.TypeInfo) else if (GetTypeInfo() == InValue.GetTypeInfo())
{ {
if (IsTrivial()) Memory::Memcpy(InlineValue, InValue.InlineValue); if (IsTrivial()) Memory::Memcpy(InlineValue, InValue.InlineValue);
else if (IsInline()) RTTI->MoveAssign(GetData(), InValue.GetData()); else if (IsInline()) RTTI->MoveAssign(GetData(), InValue.GetData());
@ -227,12 +227,12 @@ struct TAny
{ {
RTTI->Delete(DynamicValue); RTTI->Delete(DynamicValue);
DynamicValue = InValue.DynamicValue; DynamicValue = InValue.DynamicValue;
InValue.TypeInfo = Typeid(void); InValue.TypeInfo = nullptr;
} }
} }
else else
{ {
Reset(); ResetImpl();
TypeInfo = InValue.TypeInfo; TypeInfo = InValue.TypeInfo;
RTTI = InValue.RTTI; RTTI = InValue.RTTI;
@ -248,11 +248,11 @@ struct TAny
template <typename T> requires (!TIsSame<typename TDecay<T>::Type, TAny>::Value) && (!TIsTInPlaceType<typename TDecay<T>::Type>::Value) template <typename T> requires (!TIsSame<typename TDecay<T>::Type, TAny>::Value) && (!TIsTInPlaceType<typename TDecay<T>::Type>::Value)
&& TIsObject<typename TDecay<T>::Type>::Value && (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value && TIsObject<typename TDecay<T>::Type>::Value && (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value
&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value && TIsConstructible<typename TDecay<T>::Type, T&&>::Value
TAny& operator=(T&& InValue) FORCEINLINE TAny& operator=(T&& InValue)
{ {
using SelectedType = typename TDecay<T>::Type; using SelectedType = typename TDecay<T>::Type;
if (TypeInfo == Typeid(SelectedType)) if (HoldsAlternative<SelectedType>())
{ {
if constexpr (TIsTriviallyStorable<SelectedType>::Value) if constexpr (TIsTriviallyStorable<SelectedType>::Value)
Memory::Memcpy(&InlineValue, &InValue, sizeof(SelectedType)); Memory::Memcpy(&InlineValue, &InValue, sizeof(SelectedType));
@ -270,22 +270,23 @@ struct TAny
template <typename T, typename... Types> requires TIsObject<typename TDecay<T>::Type>::Value template <typename T, typename... Types> requires TIsObject<typename TDecay<T>::Type>::Value
&& (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value && (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value
&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value && TIsConstructible<typename TDecay<T>::Type, T&&>::Value
typename TDecay<T>::Type& Emplace(Types&&... Args) FORCEINLINE typename TDecay<T>::Type& Emplace(Types&&... Args)
{ {
Reset(); ResetImpl();
using SelectedType = typename TDecay<T>::Type; using SelectedType = typename TDecay<T>::Type;
EmplaceImpl<SelectedType>(Forward<Types>(Args)...); EmplaceImpl<SelectedType>(Forward<Types>(Args)...);
return GetValue<SelectedType>(); return GetValue<SelectedType>();
} }
constexpr FTypeInfo GetTypeInfo() const { return TypeInfo; } constexpr const FTypeInfo& GetTypeInfo() const { return TypeInfo != nullptr ? *TypeInfo : Typeid(void); }
constexpr bool IsValid() const { return TypeInfo != Typeid(void); }
constexpr explicit operator bool() const { return TypeInfo != 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 IsInline() const { return RTTI != nullptr ? RTTI->bIsInline : true; }
constexpr bool IsTrivial() const { return RTTI == nullptr; } constexpr bool IsTrivial() const { return RTTI == nullptr; }
template <typename T> constexpr bool HoldsAlternative() const { return IsValid() ? TypeInfo == Typeid(T) : false; } template <typename T> constexpr bool HoldsAlternative() const { return IsValid() ? GetTypeInfo() == Typeid(T) : false; }
constexpr void* GetData() { return IsInline() ? &InlineValue : DynamicValue; } constexpr void* GetData() { return IsInline() ? &InlineValue : DynamicValue; }
constexpr const void* GetData() const { return IsInline() ? &InlineValue : DynamicValue; } constexpr const void* GetData() const { return IsInline() ? &InlineValue : DynamicValue; }
@ -308,17 +309,10 @@ struct TAny
template <typename T> requires TIsSame<T, typename TDecay<T>::Type>::Value&& TIsObject<typename TDecay<T>::Type>::Value && (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value template <typename T> requires TIsSame<T, typename TDecay<T>::Type>::Value&& TIsObject<typename TDecay<T>::Type>::Value && (!TIsArray<typename TDecay<T>::Type>::Value) && TIsDestructible<typename TDecay<T>::Type>::Value
constexpr const T& Get(const T& DefaultValue) const& { return HoldsAlternative<T>() ? GetValue<T>() : DefaultValue; } constexpr const T& Get(const T& DefaultValue) const& { return HoldsAlternative<T>() ? GetValue<T>() : DefaultValue; }
void Reset() FORCEINLINE void Reset()
{ {
if (!IsValid()) return; TypeInfo = nullptr;
ResetImpl();
TypeInfo = Typeid(void);
if (IsTrivial());
else if (IsInline()) RTTI->Destroy(&InlineValue);
else RTTI->Delete(DynamicValue);
RTTI = nullptr;
} }
private: private:
@ -329,13 +323,13 @@ private:
void* DynamicValue; void* DynamicValue;
}; };
FTypeInfo TypeInfo; const FTypeInfo* TypeInfo;
const NAMESPACE_PRIVATE::FAnyRTTI* RTTI; const NAMESPACE_PRIVATE::FAnyRTTI* RTTI;
template <typename SelectedType, typename... Types> template <typename SelectedType, typename... Types>
FORCEINLINE void EmplaceImpl(Types&&... Args) FORCEINLINE void EmplaceImpl(Types&&... Args)
{ {
TypeInfo = Typeid(SelectedType); TypeInfo = &Typeid(SelectedType);
if constexpr (TIsTriviallyStorable<SelectedType>::Value) if constexpr (TIsTriviallyStorable<SelectedType>::Value)
{ {
@ -354,6 +348,13 @@ private:
} }
} }
FORCEINLINE void ResetImpl()
{
if (!IsValid() || IsTrivial()) return;
else if (IsInline()) RTTI->Destroy(&InlineValue);
else RTTI->Delete(DynamicValue);
}
}; };
template <typename T, size_t InlineSize, size_t InlineAlignment> template <typename T, size_t InlineSize, size_t InlineAlignment>

View File

@ -16,8 +16,8 @@ struct FNoncopyable
struct FNonmovable struct FNonmovable
{ {
FNonmovable() = default; FNonmovable() = default;
FNonmovable(const FNonmovable&&) = delete; FNonmovable(FNonmovable&&) = delete;
FNonmovable& operator=(const FNonmovable&&) = delete; FNonmovable& operator=(FNonmovable&&) = delete;
}; };
struct FSingleton : public FNoncopyable, public FNonmovable { }; struct FSingleton : public FNoncopyable, public FNonmovable { };