feat(templates): add type hash support and the corresponding testing

This commit is contained in:
_Redstone_c_ 2022-03-31 16:40:31 +08:00
parent c4c205e35b
commit 54ab72224f
8 changed files with 121 additions and 7 deletions

View File

@ -153,6 +153,9 @@ void TestOptional()
TOptional<FTracker> TempZ(MakeOptional<FTracker>());
TempZ = MakeOptional<FTracker>();
TempZ = FTracker();
always_check(GetTypeHash(MakeOptional<int32>(114)) == GetTypeHash(MakeOptional<int32>(114)));
always_check(GetTypeHash(MakeOptional<int32>(114)) != GetTypeHash(MakeOptional<int32>(514)));
}
void TestVariant()
@ -319,6 +322,8 @@ void TestVariant()
auto ReturnRD = MoveTemp(TempRD).Visit<int32>(TestQualifiers);
always_check((TIsSame<int32, decltype(ReturnRD)>::Value));
always_check(GetTypeHash(TVariant<int32, float>(114)) == GetTypeHash(TVariant<int32, float>(114)));
always_check(GetTypeHash(TVariant<int32, float>(114)) != GetTypeHash(TVariant<int32, float>(514)));
}
void TestAny()
@ -898,6 +903,9 @@ void TestTuple()
always_check(C == 'A');
always_check((TIsSame<decltype(C), char>::Value));
}
always_check(GetTypeHash(MakeTuple(114, 1.0f)) == GetTypeHash(MakeTuple(114, 1.0f)));
always_check(GetTypeHash(MakeTuple(114, 1.0f)) != GetTypeHash(MakeTuple(514, 1.0f)));
}
NAMESPACE_UNNAMED_BEGIN

View File

@ -6,7 +6,7 @@ NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
template <typename T> requires requires(T Container) { Container.GetData(); }
template <typename T> requires requires(T&& Container) { Container.GetData(); }
constexpr auto GetData(T&& Container)
{
return Container.GetData();
@ -17,13 +17,13 @@ template <typename T, size_t N> constexpr T* GetData( T(&& Container)
template <typename T, size_t N> constexpr const T* GetData(const T(& Container)[N]) { return Container; }
template <typename T, size_t N> constexpr const T* GetData(const T(&& Container)[N]) { return Container; }
template <typename T> requires requires(T Container) { Container.data(); }
template <typename T> requires requires(T&& Container) { Container.data(); }
constexpr auto GetData(T&& Container)
{
return Container.data();
}
template <typename T> requires requires(T Container) { Container.Num(); }
template <typename T> requires requires(T&& Container) { Container.Num(); }
constexpr auto GetNum(T&& Container)
{
return Container.Num();
@ -34,7 +34,7 @@ template <typename T, size_t N> constexpr size_t GetNum( T(&& Container)[N]
template <typename T, size_t N> constexpr size_t GetNum(const T(& Container)[N]) { return N; }
template <typename T, size_t N> constexpr size_t GetNum(const T(&& Container)[N]) { return N; }
template <typename T> requires requires(T Container) { Container.size(); }
template <typename T> requires requires(T&& Container) { Container.size(); }
constexpr auto GetNum(T&& Container)
{
return Container.size();

View File

@ -2,6 +2,7 @@
#include "CoreTypes.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "Concepts/Comparable.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/AssertionMacros.h"
@ -189,6 +190,12 @@ public:
constexpr OptionalType& Get( OptionalType& DefaultValue) & { return IsValid() ? GetValue() : DefaultValue; }
constexpr const OptionalType& Get(const OptionalType& DefaultValue) const& { return IsValid() ? GetValue() : DefaultValue; }
constexpr size_t GetTypeHash() const requires CHashable<OptionalType>
{
if (!IsValid()) return NAMESPACE_REDCRAFT::GetTypeHash(nullptr);
return NAMESPACE_REDCRAFT::GetTypeHash(GetValue());
}
constexpr void Reset()
{
if (bIsValid)

View File

@ -11,3 +11,4 @@
#include "Templates/Any.h"
#include "Templates/IntegerSequence.h"
#include "Templates/Tuple.h"
#include "Templates/TypeHash.h"

View File

@ -2,6 +2,7 @@
#include "CoreTypes.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h"
#include "Templates/IntegerSequence.h"
#include "Templates/ReferenceWrapper.h"
@ -368,6 +369,8 @@ public:
template <typename T> requires TIsConstructible<T, Types...>::Value constexpr T Construct() volatile&& { return Super::template Construct<T>(static_cast< volatile TTuple&&>(*this)); }
template <typename T> requires TIsConstructible<T, Types...>::Value constexpr T Construct() const volatile&& { return Super::template Construct<T>(static_cast<const volatile TTuple&&>(*this)); }
constexpr size_t GetTypeHash() const requires (true && ... && CHashable<Types>);
};
template <typename... Types>
@ -590,6 +593,14 @@ constexpr void VisitTuple(F&& Func, FirstTupleType&& FirstTuple, TupleTypes&&...
NAMESPACE_PRIVATE::TTupleVisitImpl<TMakeIndexSequence<TTupleElementSize<FirstTupleType>::Value>>::F(Forward<F>(Func), Forward<FirstTupleType>(FirstTuple), Forward<TupleTypes>(Tuples)...);
}
template <typename... Types>
constexpr size_t TTuple<Types...>::GetTypeHash() const requires (true && ... && CHashable<Types>)
{
size_t Result = 0;
VisitTuple([&Result](auto&& A) { Result = HashCombine(Result, NAMESPACE_REDCRAFT::GetTypeHash(A)); }, *this);
return Result;
}
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -0,0 +1,80 @@
#pragma once
#include "CoreTypes.h"
#include "Concepts/Same.h"
#include "TypeTraits/PrimaryType.h"
#include "TypeTraits/Miscellaneous.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
constexpr size_t HashCombine(size_t A, size_t C)
{
size_t B = 0x9E3779B97F4A7C16;
A += B;
A -= B; A -= C; A ^= (C >> 13);
B -= C; B -= A; B ^= (A << 8);
C -= A; C -= B; C ^= (B >> 13);
A -= B; A -= C; A ^= (C >> 12);
B -= C; B -= A; B ^= (A << 16);
C -= A; C -= B; C ^= (B >> 5);
A -= B; A -= C; A ^= (C >> 3);
B -= C; B -= A; B ^= (A << 10);
C -= A; C -= B; C ^= (B >> 15);
return C;
}
template <typename T> requires TIsIntegral<T>::Value
constexpr size_t GetTypeHash(T A)
{
static_assert(sizeof(T) <= 16, "GetTypeHash only works with T up to 128 bits.");
if constexpr (sizeof(T) <= 8) return static_cast<size_t>(A);
if constexpr (sizeof(T) == 16) return static_cast<size_t>(A ^ (A >> 64));
else return INDEX_NONE;
}
template <typename T> requires TIsFloatingPoint<T>::Value
constexpr size_t GetTypeHash(T A)
{
static_assert(sizeof(T) <= 16, "GetTypeHash only works with T up to 128 bits.");
if constexpr (sizeof(T) == 1) return GetTypeHash(*reinterpret_cast<uint8 *>(&A));
if constexpr (sizeof(T) == 2) return GetTypeHash(*reinterpret_cast<uint16*>(&A));
if constexpr (sizeof(T) == 4) return GetTypeHash(*reinterpret_cast<uint32*>(&A));
if constexpr (sizeof(T) == 8) return GetTypeHash(*reinterpret_cast<uint64*>(&A));
if constexpr (sizeof(T) == 16) return GetTypeHash(*reinterpret_cast<uint64*>(&A) + *(reinterpret_cast<uint64*>(&A) + 1));
else return INDEX_NONE;
}
template <typename T> requires TIsEnum<T>::Value
constexpr size_t GetTypeHash(T A)
{
return GetTypeHash(static_cast<typename TUnderlyingType<T>::Type>(A));
}
constexpr size_t GetTypeHash(nullptr_t)
{
return GetTypeHash(2.7182818284590452353602874713527);
}
constexpr size_t GetTypeHash(const void* A)
{
return GetTypeHash(reinterpret_cast<intptr_t>(A));
}
template <typename T> requires requires(T&& A) { { GetTypeHash(A.GetTypeHash()) } -> CSameAs<size_t>; }
constexpr size_t GetTypeHash(T&& A)
{
return GetTypeHash(A.GetTypeHash());
}
template <typename T>
concept CHashable = requires(T&& A) { { GetTypeHash(A) } -> CSameAs<size_t>; };
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -2,6 +2,7 @@
#include "CoreTypes.h"
#include "Templates/Invoke.h"
#include "Templates/TypeHash.h"
#include "Templates/Utility.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/AssertionMacros.h"
@ -418,6 +419,12 @@ struct TVariant
return R(NAMESPACE_PRIVATE::TVariantVisitHelper<R, F, Types...>::VisitConstRValueFuncs[GetIndex()](Forward<F>(Func), &Value));
}
constexpr size_t GetTypeHash() const requires (true && ... && CHashable<Types>)
{
if (!IsValid()) return NAMESPACE_REDCRAFT::GetTypeHash(nullptr);
return Visit([](auto&& A) { return NAMESPACE_REDCRAFT::GetTypeHash(A); });
}
constexpr void Reset()
{
if (GetIndex() == INDEX_NONE) return;