From 54ab72224f0d8a32622711a231c835ad5c4a75b7 Mon Sep 17 00:00:00 2001 From: _Redstone_c_ Date: Thu, 31 Mar 2022 16:40:31 +0800 Subject: [PATCH] feat(templates): add type hash support and the corresponding testing --- .../Private/Testing/TemplatesTesting.cpp | 8 ++ .../Source/Public/Memory/Memory.h | 6 +- .../Source/Public/Templates/Container.h | 8 +- .../Source/Public/Templates/Optional.h | 7 ++ .../Source/Public/Templates/Templates.h | 1 + .../Source/Public/Templates/Tuple.h | 11 +++ .../Source/Public/Templates/TypeHash.h | 80 +++++++++++++++++++ .../Source/Public/Templates/Variant.h | 7 ++ 8 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 Redcraft.Utility/Source/Public/Templates/TypeHash.h diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index 6c30e6c..ef3cd0b 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -153,6 +153,9 @@ void TestOptional() TOptional TempZ(MakeOptional()); TempZ = MakeOptional(); TempZ = FTracker(); + + always_check(GetTypeHash(MakeOptional(114)) == GetTypeHash(MakeOptional(114))); + always_check(GetTypeHash(MakeOptional(114)) != GetTypeHash(MakeOptional(514))); } void TestVariant() @@ -319,6 +322,8 @@ void TestVariant() auto ReturnRD = MoveTemp(TempRD).Visit(TestQualifiers); always_check((TIsSame::Value)); + always_check(GetTypeHash(TVariant(114)) == GetTypeHash(TVariant(114))); + always_check(GetTypeHash(TVariant(114)) != GetTypeHash(TVariant(514))); } void TestAny() @@ -898,6 +903,9 @@ void TestTuple() always_check(C == 'A'); always_check((TIsSame::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 diff --git a/Redcraft.Utility/Source/Public/Memory/Memory.h b/Redcraft.Utility/Source/Public/Memory/Memory.h index b3bda74..d1a3c38 100644 --- a/Redcraft.Utility/Source/Public/Memory/Memory.h +++ b/Redcraft.Utility/Source/Public/Memory/Memory.h @@ -53,21 +53,21 @@ FORCEINLINE void* Memcpy(void* Destination, const void* Source, size_t Count) return std::memcpy(Destination, Source, Count); } -template +template FORCEINLINE void Memset(T& Source, uint8 ValueToSet) { static_assert(!TIsPointer::Value, "For pointers use the three parameters function"); Memset(&Source, ValueToSet, sizeof(T)); } -template +template FORCEINLINE void Memzero(T& Source) { static_assert(!TIsPointer::Value, "For pointers use the two parameters function"); Memzero(&Source, sizeof(T)); } -template +template FORCEINLINE void Memcpy(T& Destination, const T& Source) { static_assert(!TIsPointer::Value, "For pointers use the three parameters function"); diff --git a/Redcraft.Utility/Source/Public/Templates/Container.h b/Redcraft.Utility/Source/Public/Templates/Container.h index f253bc6..d711579 100644 --- a/Redcraft.Utility/Source/Public/Templates/Container.h +++ b/Redcraft.Utility/Source/Public/Templates/Container.h @@ -6,7 +6,7 @@ NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) -template requires requires(T Container) { Container.GetData(); } +template requires requires(T&& Container) { Container.GetData(); } constexpr auto GetData(T&& Container) { return Container.GetData(); @@ -17,13 +17,13 @@ template constexpr T* GetData( T(&& Container) template constexpr const T* GetData(const T(& Container)[N]) { return Container; } template constexpr const T* GetData(const T(&& Container)[N]) { return Container; } -template requires requires(T Container) { Container.data(); } +template requires requires(T&& Container) { Container.data(); } constexpr auto GetData(T&& Container) { return Container.data(); } -template requires requires(T Container) { Container.Num(); } +template requires requires(T&& Container) { Container.Num(); } constexpr auto GetNum(T&& Container) { return Container.Num(); @@ -34,7 +34,7 @@ template constexpr size_t GetNum( T(&& Container)[N] template constexpr size_t GetNum(const T(& Container)[N]) { return N; } template constexpr size_t GetNum(const T(&& Container)[N]) { return N; } -template requires requires(T Container) { Container.size(); } +template requires requires(T&& Container) { Container.size(); } constexpr auto GetNum(T&& Container) { return Container.size(); diff --git a/Redcraft.Utility/Source/Public/Templates/Optional.h b/Redcraft.Utility/Source/Public/Templates/Optional.h index cb712ea..01cee6f 100644 --- a/Redcraft.Utility/Source/Public/Templates/Optional.h +++ b/Redcraft.Utility/Source/Public/Templates/Optional.h @@ -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 + { + if (!IsValid()) return NAMESPACE_REDCRAFT::GetTypeHash(nullptr); + return NAMESPACE_REDCRAFT::GetTypeHash(GetValue()); + } + constexpr void Reset() { if (bIsValid) diff --git a/Redcraft.Utility/Source/Public/Templates/Templates.h b/Redcraft.Utility/Source/Public/Templates/Templates.h index 3dc5b6f..ba950e7 100644 --- a/Redcraft.Utility/Source/Public/Templates/Templates.h +++ b/Redcraft.Utility/Source/Public/Templates/Templates.h @@ -11,3 +11,4 @@ #include "Templates/Any.h" #include "Templates/IntegerSequence.h" #include "Templates/Tuple.h" +#include "Templates/TypeHash.h" diff --git a/Redcraft.Utility/Source/Public/Templates/Tuple.h b/Redcraft.Utility/Source/Public/Templates/Tuple.h index 7e32c3a..bea569c 100644 --- a/Redcraft.Utility/Source/Public/Templates/Tuple.h +++ b/Redcraft.Utility/Source/Public/Templates/Tuple.h @@ -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 requires TIsConstructible::Value constexpr T Construct() volatile&& { return Super::template Construct(static_cast< volatile TTuple&&>(*this)); } template requires TIsConstructible::Value constexpr T Construct() const volatile&& { return Super::template Construct(static_cast(*this)); } + constexpr size_t GetTypeHash() const requires (true && ... && CHashable); + }; template @@ -590,6 +593,14 @@ constexpr void VisitTuple(F&& Func, FirstTupleType&& FirstTuple, TupleTypes&&... NAMESPACE_PRIVATE::TTupleVisitImpl::Value>>::F(Forward(Func), Forward(FirstTuple), Forward(Tuples)...); } +template +constexpr size_t TTuple::GetTypeHash() const requires (true && ... && CHashable) +{ + 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 diff --git a/Redcraft.Utility/Source/Public/Templates/TypeHash.h b/Redcraft.Utility/Source/Public/Templates/TypeHash.h new file mode 100644 index 0000000..f017369 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Templates/TypeHash.h @@ -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 requires TIsIntegral::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(A); + if constexpr (sizeof(T) == 16) return static_cast(A ^ (A >> 64)); + else return INDEX_NONE; +} + +template requires TIsFloatingPoint::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(&A)); + if constexpr (sizeof(T) == 2) return GetTypeHash(*reinterpret_cast(&A)); + if constexpr (sizeof(T) == 4) return GetTypeHash(*reinterpret_cast(&A)); + if constexpr (sizeof(T) == 8) return GetTypeHash(*reinterpret_cast(&A)); + if constexpr (sizeof(T) == 16) return GetTypeHash(*reinterpret_cast(&A) + *(reinterpret_cast(&A) + 1)); + else return INDEX_NONE; +} + +template requires TIsEnum::Value +constexpr size_t GetTypeHash(T A) +{ + return GetTypeHash(static_cast::Type>(A)); +} + +constexpr size_t GetTypeHash(nullptr_t) +{ + return GetTypeHash(2.7182818284590452353602874713527); +} + +constexpr size_t GetTypeHash(const void* A) +{ + return GetTypeHash(reinterpret_cast(A)); +} + +template requires requires(T&& A) { { GetTypeHash(A.GetTypeHash()) } -> CSameAs; } +constexpr size_t GetTypeHash(T&& A) +{ + return GetTypeHash(A.GetTypeHash()); +} + +template +concept CHashable = requires(T&& A) { { GetTypeHash(A) } -> CSameAs; }; + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Templates/Variant.h b/Redcraft.Utility/Source/Public/Templates/Variant.h index a6f0bd2..ccd585f 100644 --- a/Redcraft.Utility/Source/Public/Templates/Variant.h +++ b/Redcraft.Utility/Source/Public/Templates/Variant.h @@ -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::VisitConstRValueFuncs[GetIndex()](Forward(Func), &Value)); } + constexpr size_t GetTypeHash() const requires (true && ... && CHashable) + { + if (!IsValid()) return NAMESPACE_REDCRAFT::GetTypeHash(nullptr); + return Visit([](auto&& A) { return NAMESPACE_REDCRAFT::GetTypeHash(A); }); + } + constexpr void Reset() { if (GetIndex() == INDEX_NONE) return;