feat(templates): add type hash support and the corresponding testing
This commit is contained in:
parent
c4c205e35b
commit
54ab72224f
@ -153,6 +153,9 @@ void TestOptional()
|
|||||||
TOptional<FTracker> TempZ(MakeOptional<FTracker>());
|
TOptional<FTracker> TempZ(MakeOptional<FTracker>());
|
||||||
TempZ = MakeOptional<FTracker>();
|
TempZ = MakeOptional<FTracker>();
|
||||||
TempZ = 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()
|
void TestVariant()
|
||||||
@ -319,6 +322,8 @@ void TestVariant()
|
|||||||
auto ReturnRD = MoveTemp(TempRD).Visit<int32>(TestQualifiers);
|
auto ReturnRD = MoveTemp(TempRD).Visit<int32>(TestQualifiers);
|
||||||
always_check((TIsSame<int32, decltype(ReturnRD)>::Value));
|
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()
|
void TestAny()
|
||||||
@ -898,6 +903,9 @@ void TestTuple()
|
|||||||
always_check(C == 'A');
|
always_check(C == 'A');
|
||||||
always_check((TIsSame<decltype(C), char>::Value));
|
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
|
NAMESPACE_UNNAMED_BEGIN
|
||||||
|
@ -6,7 +6,7 @@ NAMESPACE_REDCRAFT_BEGIN
|
|||||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||||
NAMESPACE_MODULE_BEGIN(Utility)
|
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)
|
constexpr auto GetData(T&& Container)
|
||||||
{
|
{
|
||||||
return Container.GetData();
|
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, 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)
|
constexpr auto GetData(T&& Container)
|
||||||
{
|
{
|
||||||
return Container.data();
|
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)
|
constexpr auto GetNum(T&& Container)
|
||||||
{
|
{
|
||||||
return Container.Num();
|
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, 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)
|
constexpr auto GetNum(T&& Container)
|
||||||
{
|
{
|
||||||
return Container.size();
|
return Container.size();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "CoreTypes.h"
|
#include "CoreTypes.h"
|
||||||
#include "Templates/Utility.h"
|
#include "Templates/Utility.h"
|
||||||
|
#include "Templates/TypeHash.h"
|
||||||
#include "Concepts/Comparable.h"
|
#include "Concepts/Comparable.h"
|
||||||
#include "TypeTraits/TypeTraits.h"
|
#include "TypeTraits/TypeTraits.h"
|
||||||
#include "Miscellaneous/AssertionMacros.h"
|
#include "Miscellaneous/AssertionMacros.h"
|
||||||
@ -189,6 +190,12 @@ public:
|
|||||||
constexpr OptionalType& Get( OptionalType& DefaultValue) & { return IsValid() ? GetValue() : DefaultValue; }
|
constexpr OptionalType& Get( OptionalType& DefaultValue) & { return IsValid() ? GetValue() : DefaultValue; }
|
||||||
constexpr const OptionalType& Get(const OptionalType& DefaultValue) const& { 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()
|
constexpr void Reset()
|
||||||
{
|
{
|
||||||
if (bIsValid)
|
if (bIsValid)
|
||||||
|
@ -11,3 +11,4 @@
|
|||||||
#include "Templates/Any.h"
|
#include "Templates/Any.h"
|
||||||
#include "Templates/IntegerSequence.h"
|
#include "Templates/IntegerSequence.h"
|
||||||
#include "Templates/Tuple.h"
|
#include "Templates/Tuple.h"
|
||||||
|
#include "Templates/TypeHash.h"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "CoreTypes.h"
|
#include "CoreTypes.h"
|
||||||
#include "Templates/Utility.h"
|
#include "Templates/Utility.h"
|
||||||
|
#include "Templates/TypeHash.h"
|
||||||
#include "TypeTraits/TypeTraits.h"
|
#include "TypeTraits/TypeTraits.h"
|
||||||
#include "Templates/IntegerSequence.h"
|
#include "Templates/IntegerSequence.h"
|
||||||
#include "Templates/ReferenceWrapper.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() 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)); }
|
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>
|
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)...);
|
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(Utility)
|
||||||
NAMESPACE_MODULE_END(Redcraft)
|
NAMESPACE_MODULE_END(Redcraft)
|
||||||
NAMESPACE_REDCRAFT_END
|
NAMESPACE_REDCRAFT_END
|
||||||
|
80
Redcraft.Utility/Source/Public/Templates/TypeHash.h
Normal file
80
Redcraft.Utility/Source/Public/Templates/TypeHash.h
Normal 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
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "CoreTypes.h"
|
#include "CoreTypes.h"
|
||||||
#include "Templates/Invoke.h"
|
#include "Templates/Invoke.h"
|
||||||
|
#include "Templates/TypeHash.h"
|
||||||
#include "Templates/Utility.h"
|
#include "Templates/Utility.h"
|
||||||
#include "TypeTraits/TypeTraits.h"
|
#include "TypeTraits/TypeTraits.h"
|
||||||
#include "Miscellaneous/AssertionMacros.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));
|
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()
|
constexpr void Reset()
|
||||||
{
|
{
|
||||||
if (GetIndex() == INDEX_NONE) return;
|
if (GetIndex() == INDEX_NONE) return;
|
||||||
|
Loading…
Reference in New Issue
Block a user