From b10963d31013504398461afe2fef641fd2599c4f Mon Sep 17 00:00:00 2001
From: _Redstone_c_ <myredstone1024@gmail.com>
Date: Wed, 16 Mar 2022 11:25:48 +0800
Subject: [PATCH] feat(miscellaneous): add FTypeInfo and the corresponding
 testing

---
 .../Private/Testing/MiscellaneousTesting.cpp  | 30 +++++++++++
 .../Source/Public/Miscellaneous/TypeInfo.h    | 51 +++++++++++++++++++
 .../Public/Testing/MiscellaneousTesting.h     |  1 +
 3 files changed, 82 insertions(+)
 create mode 100644 Redcraft.Utility/Source/Public/Miscellaneous/TypeInfo.h

diff --git a/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp b/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp
index 382156d..3d9d85b 100644
--- a/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp
+++ b/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp
@@ -1,5 +1,6 @@
 #include "Testing/MiscellaneousTesting.h"
 #include "Miscellaneous/AssertionMacros.h"
+#include "Miscellaneous/TypeInfo.h"
 #include "Miscellaneous/Compare.h"
 
 NAMESPACE_REDCRAFT_BEGIN
@@ -10,6 +11,7 @@ void TestMiscellaneous()
 {
 	TestAssertionMacros();
 	TestCompare();
+	TestTypeInfo();
 }
 
 NAMESPACE_PRIVATE_BEGIN
@@ -204,6 +206,34 @@ void TestCompare()
 
 }
 
+NAMESPACE_PRIVATE_BEGIN
+
+template <typename...>
+struct TTestTemplateType { };
+
+NAMESPACE_PRIVATE_END
+
+void TestTypeInfo()
+{
+	FTypeInfo TempA;
+	FTypeInfo TempB(Invalid);
+
+	always_check(TempA == TempB);
+	always_check(TempA == Typeid(void));
+
+	FTypeInfo TempC(Typeid(NAMESPACE_PRIVATE::TTestTemplateType<int8, int16>));
+	FTypeInfo TempD = Typeid(NAMESPACE_PRIVATE::TTestTemplateType<int8, int32>);
+
+	FTypeInfo TempE, TempF;
+	TempE = TempC;
+	TempF = MoveTemp(TempD);
+
+	always_check(TempE != TempF);
+	always_check((TempE < TempF) == (TempF > TempE));
+	always_check((TempE > TempF) == (TempF < TempE));
+	always_check((TempE <=> TempF) != 0);
+}
+
 NAMESPACE_MODULE_END(Utility)
 NAMESPACE_MODULE_END(Redcraft)
 NAMESPACE_REDCRAFT_END
diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/TypeInfo.h b/Redcraft.Utility/Source/Public/Miscellaneous/TypeInfo.h
new file mode 100644
index 0000000..4db6627
--- /dev/null
+++ b/Redcraft.Utility/Source/Public/Miscellaneous/TypeInfo.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "CoreTypes.h"
+#include "Miscellaneous/Compare.h"
+#include "Miscellaneous/Placeholders.h"
+
+#include <typeinfo>
+
+NAMESPACE_REDCRAFT_BEGIN
+NAMESPACE_MODULE_BEGIN(Redcraft)
+NAMESPACE_MODULE_BEGIN(Utility)
+
+struct FTypeInfo
+{
+	constexpr FTypeInfo() : FTypeInfo(typeid(void)) { }
+
+	constexpr FTypeInfo(FInvalid) : FTypeInfo() { }
+
+	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:
+
+	const std::type_info* Ptr;
+
+	friend bool operator==(FTypeInfo LHS, FTypeInfo RHS) { return *LHS.Ptr == *RHS.Ptr; }
+
+	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;
+		return LHS < RHS ? strong_ordering::less : strong_ordering::greater;
+	}
+
+};
+
+#define Typeid(...) (FTypeInfo(typeid(__VA_ARGS__)))
+
+NAMESPACE_MODULE_END(Utility)
+NAMESPACE_MODULE_END(Redcraft)
+NAMESPACE_REDCRAFT_END
diff --git a/Redcraft.Utility/Source/Public/Testing/MiscellaneousTesting.h b/Redcraft.Utility/Source/Public/Testing/MiscellaneousTesting.h
index 9c4058c..833d286 100644
--- a/Redcraft.Utility/Source/Public/Testing/MiscellaneousTesting.h
+++ b/Redcraft.Utility/Source/Public/Testing/MiscellaneousTesting.h
@@ -9,6 +9,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
 REDCRAFTUTILITY_API void TestMiscellaneous();
 REDCRAFTUTILITY_API void TestAssertionMacros();
 REDCRAFTUTILITY_API void TestCompare();
+REDCRAFTUTILITY_API void TestTypeInfo();
 
 NAMESPACE_MODULE_END(Utility)
 NAMESPACE_MODULE_END(Redcraft)