From 8a3b089648e293f16db0382d776f20228130a1d2 Mon Sep 17 00:00:00 2001 From: _Redstone_c_ Date: Sun, 13 Mar 2022 23:18:07 +0800 Subject: [PATCH] feat(templates): add TOptional and the corresponding testing --- .../Private/Testing/TemplatesTesting.cpp | 74 ++++++ .../Source/Public/Miscellaneous/CoreDefines.h | 12 +- .../Source/Public/Templates/Container.h | 12 +- .../Source/Public/Templates/Optional.h | 226 +++++++++++------- .../Source/Public/Templates/Templates.h | 1 + .../Source/Public/Templates/Utility.h | 16 +- .../Source/Public/Testing/TemplatesTesting.h | 1 + 7 files changed, 240 insertions(+), 102 deletions(-) diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index 4823826..82dcd40 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -11,6 +11,7 @@ void TestTemplates() TestInvoke(); TestReferenceWrapper(); TestCompare(); + TestOptional(); TestMiscellaneous(); } @@ -195,6 +196,79 @@ void TestCompare() } +void TestOptional() +{ + TOptional TempA; + TOptional TempB(Invalid); + TOptional TempC(InPlace, 0); + TOptional TempD(0); + TOptional TempE(0l); + TOptional TempF(0.0); + TOptional TempG(TempA); + TOptional TempH(TempD); + TOptional TempI(MakeOptional(0)); + TOptional TempJ(MakeOptional(Invalid)); + + TOptional TempK, TempL, TempM, TempN; + TempK = TempA; + TempL = TempD; + TempM = MakeOptional(0); + TempN = MakeOptional(Invalid); + + *TempL = 303; + *TempM = 404; + + TOptional TempO; + TempO.Emplace(404); + + always_check(TempO); + always_check(TempO.IsValid()); + + always_check(*TempO == 404); + always_check(TempO.GetValue() == 404); + always_check(TempO.Get(500) == 404); + + TempO.Reset(); + always_check(TempO == TempO); + always_check(TempO.Get(500) == 500); + + int32 TempP = 200; + TempO = TempP; + TempO = 300; + + always_check(TempO != TempA); + always_check(TempO != TempD); + always_check(TempO == TempO); + always_check(TempO == 300); + always_check(300 == TempO); + + int16 TempQ = 1024; + TOptional TempR = TempQ; + + TOptional TempS(InPlace, TempQ); + TOptional TempT(TempQ); + TOptional TempU(TempR); + TOptional TempV(MakeOptional(2048)); + + TOptional TempW, TempX, TempY; + TempW = TempQ; + TempX = TempR; + TempY = MakeOptional(2048); + + struct FTracker + { + FTracker() { } + FTracker(const FTracker& InValue) { always_check_no_entry(); } + FTracker(FTracker&& InValue) { } + FTracker& operator=(const FTracker& InValue) { always_check_no_entry(); return *this; } + FTracker& operator=(FTracker&& InValue) { return *this; } + }; + + TOptional TempZ(MakeOptional()); + TempZ = MakeOptional(); + TempZ = FTracker(); +} + NAMESPACE_UNNAMED_BEGIN template diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/CoreDefines.h b/Redcraft.Utility/Source/Public/Miscellaneous/CoreDefines.h index a90443b..fdd1f40 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/CoreDefines.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/CoreDefines.h @@ -41,14 +41,10 @@ NAMESPACE_MODULE_BEGIN(Utility) enum { INDEX_NONE = -1 }; enum { UNICODE_BOM = 0xfeff }; -enum EForceInit -{ - ForceInit, - ForceInitToZero -}; - -enum ENoInit { NoInit }; -enum EInPlace { InPlace }; +enum EForceInit { ForceInit }; +enum ENoInit { NoInit }; +enum EInvalid { Invalid }; +enum EInPlace { InPlace }; NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) diff --git a/Redcraft.Utility/Source/Public/Templates/Container.h b/Redcraft.Utility/Source/Public/Templates/Container.h index 99dd079..f253bc6 100644 --- a/Redcraft.Utility/Source/Public/Templates/Container.h +++ b/Redcraft.Utility/Source/Public/Templates/Container.h @@ -12,9 +12,9 @@ constexpr auto GetData(T&& Container) return Container.GetData(); } -template constexpr T* GetData(T(&Container)[N]) { return Container; } -template constexpr T* GetData(T(&& Container)[N]) { return Container; } -template constexpr const T* GetData(const T(&Container)[N]) { return Container; } +template constexpr T* GetData( T(& Container)[N]) { return Container; } +template constexpr T* GetData( T(&& Container)[N]) { return 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(); } @@ -29,9 +29,9 @@ constexpr auto GetNum(T&& Container) return Container.Num(); } -template constexpr size_t GetNum(T(&Container)[N]) { return N; } -template constexpr size_t GetNum(T(&& Container)[N]) { return N; } -template constexpr size_t GetNum(const T(&Container)[N]) { return N; } +template constexpr size_t GetNum( T(& Container)[N]) { return N; } +template constexpr size_t GetNum( T(&& Container)[N]) { return 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(); } diff --git a/Redcraft.Utility/Source/Public/Templates/Optional.h b/Redcraft.Utility/Source/Public/Templates/Optional.h index 2f30864..ee33843 100644 --- a/Redcraft.Utility/Source/Public/Templates/Optional.h +++ b/Redcraft.Utility/Source/Public/Templates/Optional.h @@ -1,6 +1,8 @@ #pragma once #include "CoreTypes.h" +#include "Templates/Compare.h" +#include "Concepts/Comparable.h" #include "TypeTraits/TypeTraits.h" #include "Miscellaneous/AssertionMacros.h" @@ -8,39 +10,54 @@ NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) -template +template struct TOptional { public: - using Type = T; + using Type = OptionalType; constexpr TOptional() : bIsValid(false) { } - template requires TIsConstructible::Value + constexpr TOptional(EInvalid) : TOptional() { } + + template requires TIsConstructible::Value constexpr explicit TOptional(EInPlace, Types&&... Args) : bIsValid(true) { - new(&Value) T(Forward(Args)...); + new(&Value) OptionalType(Forward(Args)...); } - template requires TIsConstructible::Value && !TIsSame::Type, EInPlace>::Value && !TIsSame::Type, TOptional>::Value - constexpr explicit(!TIsConvertible::Value) TOptional(U&& InValue) - : TOptional(InPlace, Forward(InValue)) + template requires TIsConstructible::Value + && (!TIsSame::Type, EInPlace>::Value) && (!TIsSame::Type, TOptional>::Value) + constexpr explicit(!TIsConvertible::Value) TOptional(T&& InValue) + : TOptional(InPlace, Forward(InValue)) { } - - template requires TIsConstructible::Value - constexpr explicit(!TIsConvertible::Value) TOptional(const TOptional& InValue) - : bIsValid(InValue.bIsValid) + + constexpr TOptional(const TOptional& InValue) + : bIsValid(InValue.IsValid()) { - if (InValue.bIsValid) new(&Value) T(InValue.GetValue()); + if (InValue.IsValid()) new(&Value) OptionalType(InValue.GetValue()); } - template requires TIsConstructible::Value - constexpr explicit(!TIsConvertible::Value) TOptional(TOptional&& InValue) - : bIsValid(InValue.bIsValid) + constexpr TOptional(TOptional&& InValue) + : bIsValid(InValue.IsValid()) { - if (InValue.bIsValid) new(&Value) T(MoveTempIfPossible(InValue).GetValue()); + if (InValue.IsValid()) new(&Value) OptionalType(MoveTemp(InValue.GetValue())); + } + + template requires TIsConstructible::Value + constexpr explicit(!TIsConvertible::Value) TOptional(const TOptional& InValue) + : bIsValid(InValue.IsValid()) + { + if (InValue.IsValid()) new(&Value) OptionalType(InValue.GetValue()); + } + + template requires TIsConstructible::Value + constexpr explicit(!TIsConvertible::Value) TOptional(TOptional&& InValue) + : bIsValid(InValue.IsValid()) + { + if (InValue.IsValid()) new(&Value) OptionalType(MoveTemp(InValue.GetValue())); } constexpr ~TOptional() @@ -48,56 +65,103 @@ public: Reset(); } - template requires TIsConstructible::Value - constexpr TOptional& operator=(const TOptional& InValue) + constexpr TOptional& operator=(const TOptional& InValue) { - if (InValue == this) return *this; + if (&InValue == this) return *this; - Reset(); - - if (InValue.bIsValid) + if (!InValue.IsValid()) { - new(&Value) T(InValue.GetValue()); + Reset(); + return *this; + } + + if (IsValid()) GetValue() = InValue.GetValue(); + else + { + new(&Value) OptionalType(InValue.GetValue()); bIsValid = true; } return *this; } - template requires TIsConstructible::Value - constexpr TOptional& operator=(TOptional&& InValue) + constexpr TOptional& operator=(TOptional&& InValue) { - if (InValue == this) return *this; + if (&InValue == this) return *this; - Reset(); - - if (InValue.bIsValid) + if (!InValue.IsValid()) { - new(&Value) T(MoveTempIfPossible(InValue).GetValue()); + Reset(); + return *this; + } + + if (IsValid()) GetValue() = MoveTemp(InValue.GetValue()); + else + { + new(&Value) OptionalType(MoveTemp(InValue.GetValue())); bIsValid = true; } return *this; } - template requires TIsConstructible::Value - constexpr TOptional& operator=(U&& InValue) + template requires TIsConstructible::Value + constexpr TOptional& operator=(const TOptional& InValue) { - Reset(); + if (!InValue.IsValid()) + { + Reset(); + return *this; + } - new(&Value) T(MoveTempIfPossible(InValue)); - bIsValid = true; + if (IsValid()) GetValue() = InValue.GetValue(); + else + { + new(&Value) OptionalType(InValue.GetValue()); + bIsValid = true; + } return *this; } + template requires TIsConstructible::Value + constexpr TOptional& operator=(TOptional&& InValue) + { + if (!InValue.IsValid()) + { + Reset(); + return *this; + } + + if (IsValid()) GetValue() = MoveTemp(InValue.GetValue()); + else + { + new(&Value) OptionalType(MoveTemp(InValue.GetValue())); + bIsValid = true; + } + + return *this; + } + + template requires TIsConstructible::Value + constexpr TOptional& operator=(T&& InValue) + { + if (IsValid()) GetValue() = Forward(InValue); + else + { + new(&Value) OptionalType(Forward(InValue)); + bIsValid = true; + } + + return *this; + } template - constexpr T& Emplace(ArgsType&&... Args) + constexpr OptionalType& Emplace(ArgsType&&... Args) { Reset(); - T* Result = new(&Value) T(Forward(Args)...); + OptionalType* Result = new(&Value) OptionalType(Forward(Args)...); bIsValid = true; return *Result; @@ -106,24 +170,24 @@ public: constexpr bool IsValid() const { return bIsValid; } constexpr explicit operator bool() const { return bIsValid; } - constexpr T& GetValue() & { checkf(IsValid(), TEXT("It is an error to call GetValue() on an unset TOptional. Please either check IsSet() or use Get(DefaultValue) instead.")); return *(T*)&Value; } - constexpr T&& GetValue() && { checkf(IsValid(), TEXT("It is an error to call GetValue() on an unset TOptional. Please either check IsSet() or use Get(DefaultValue) instead.")); return *(T*)&Value; } - constexpr const T& GetValue() const& { checkf(IsValid(), TEXT("It is an error to call GetValue() on an unset TOptional. Please either check IsSet() or use Get(DefaultValue) instead.")); return *(T*)&Value; } - constexpr const T&& GetValue() const&& { checkf(IsValid(), TEXT("It is an error to call GetValue() on an unset TOptional. Please either check IsSet() or use Get(DefaultValue) instead.")); return *(T*)&Value; } + constexpr OptionalType& GetValue() & { checkf(IsValid(), TEXT("It is an error to call GetValue() on an unset TOptional. Please either check IsValid() or use Get(DefaultValue) instead.")); return *(OptionalType*)&Value; } + constexpr OptionalType&& GetValue() && { checkf(IsValid(), TEXT("It is an error to call GetValue() on an unset TOptional. Please either check IsValid() or use Get(DefaultValue) instead.")); return MoveTemp(*(OptionalType*)&Value); } + constexpr const OptionalType& GetValue() const& { checkf(IsValid(), TEXT("It is an error to call GetValue() on an unset TOptional. Please either check IsValid() or use Get(DefaultValue) instead.")); return *(OptionalType*)&Value; } + constexpr const OptionalType&& GetValue() const&& { checkf(IsValid(), TEXT("It is an error to call GetValue() on an unset TOptional. Please either check IsValid() or use Get(DefaultValue) instead.")); return MoveTemp(*(OptionalType*)&Value); } - constexpr const T* operator->() const { return &GetValue(); } - constexpr T* operator->() { return &GetValue(); } + constexpr const OptionalType* operator->() const { return &GetValue(); } + constexpr OptionalType* operator->() { return &GetValue(); } - constexpr T& operator*() & { return GetValue(); } - constexpr T&& operator*() && { return GetValue(); } - constexpr const T& operator*() const& { return GetValue(); } - constexpr const T&& operator*() const&& { return GetValue(); } + constexpr OptionalType& operator*() & { return GetValue(); } + constexpr OptionalType&& operator*() && { return GetValue(); } + constexpr const OptionalType& operator*() const& { return GetValue(); } + constexpr const OptionalType&& operator*() const&& { return GetValue(); } - template - constexpr T Get(U&& DefaultValue) && { return IsValid() ? GetValue() : DefaultValue; } + template + constexpr OptionalType Get(T&& DefaultValue) && { return IsValid() ? GetValue() : DefaultValue; } - template - constexpr T Get(U&& DefaultValue) const& { return IsValid() ? GetValue() : DefaultValue; } + template + constexpr OptionalType Get(T&& DefaultValue) const& { return IsValid() ? GetValue() : DefaultValue; } constexpr void Reset() { @@ -131,14 +195,14 @@ public: { bIsValid = false; - typedef T DestructOptionalType; - ((T*)&Value)->DestructOptionalType::~DestructOptionalType(); + typedef OptionalType DestructOptionalType; + ((OptionalType*)&Value)->DestructOptionalType::~DestructOptionalType(); } } private: - TAlignedStorage::Type Value; + TAlignedStorage::Type Value; bool bIsValid; }; @@ -149,7 +213,7 @@ TOptional(T) ->TOptional; template constexpr bool operator==(const TOptional& LHS, const TOptional& RHS) { - if (LHS.IsValid() != LHS.IsValid()) return false; + if (LHS.IsValid() != RHS.IsValid()) return false; if (LHS.IsValid() == false) return true; return *LHS == *RHS; } @@ -157,32 +221,34 @@ constexpr bool operator==(const TOptional& LHS, const TOptional& RHS) template constexpr bool operator!=(const TOptional& LHS, const TOptional& RHS) { - if (LHS.IsValid() != LHS.IsValid()) return true; - if (LHS.IsValid() == false) return false; + if (LHS.IsValid() != RHS.IsValid()) return true; + if (LHS.IsValid() == false) return true; return *LHS != *RHS; } -//template -//constexpr bool operator<(const TOptional&, const TOptional&); -//template -//constexpr bool operator>(const TOptional&, const TOptional&); -//template -//constexpr bool operator<=(const TOptional&, const TOptional&); -//template -//constexpr bool operator>=(const TOptional&, const TOptional&); +template +constexpr bool operator==(const TOptional& LHS, const U& RHS) +{ + return LHS.IsValid() ? *LHS == RHS : false; +} -//template constexpr bool operator==(const TOptional&, const U&); -//template constexpr bool operator==(const T&, const TOptional&); -//template constexpr bool operator!=(const TOptional&, const U&); -//template constexpr bool operator!=(const T&, const TOptional&); -//template constexpr bool operator<(const TOptional&, const U&); -//template constexpr bool operator<(const T&, const TOptional&); -//template constexpr bool operator>(const TOptional&, const U&); -//template constexpr bool operator>(const T&, const TOptional&); -//template constexpr bool operator<=(const TOptional&, const U&); -//template constexpr bool operator<=(const T&, const TOptional&); -//template constexpr bool operator>=(const TOptional&, const U&); -//template constexpr bool operator>=(const T&, const TOptional&); +template +constexpr bool operator!=(const TOptional& LHS, const U& RHS) +{ + return LHS.IsValid() ? *LHS != RHS : true; +} + +template +constexpr bool operator==(const T& LHS, const TOptional& RHS) +{ + return RHS.IsValid() ? LHS == *RHS : false; +} + +template +constexpr bool operator!=(const T& LHS, const TOptional& RHS) +{ + return RHS.IsValid() ? LHS != *RHS : true; +} template constexpr TOptional::Type> MakeOptional(T&& InValue) @@ -196,21 +262,21 @@ constexpr TOptional MakeOptional(Types&&... Args) return TOptional(InPlace, Forward(Args)...); } -template +template requires TIsMoveConstructible::Value&& TIsSwappable::Value constexpr void Swap(TOptional& A, TOptional& B) { if (!A && !B) return; if (A && !B) { - B = A; + B = MoveTemp(A); A.Reset(); return; } if (B && !A) { - A = B; + A = MoveTemp(B); B.Reset(); return; } diff --git a/Redcraft.Utility/Source/Public/Templates/Templates.h b/Redcraft.Utility/Source/Public/Templates/Templates.h index a8938c4..7624233 100644 --- a/Redcraft.Utility/Source/Public/Templates/Templates.h +++ b/Redcraft.Utility/Source/Public/Templates/Templates.h @@ -7,3 +7,4 @@ #include "Templates/Invoke.h" #include "Templates/ReferenceWrapper.h" #include "Templates/Compare.h" +#include "Templates/Optional.h" diff --git a/Redcraft.Utility/Source/Public/Templates/Utility.h b/Redcraft.Utility/Source/Public/Templates/Utility.h index b596782..3019691 100644 --- a/Redcraft.Utility/Source/Public/Templates/Utility.h +++ b/Redcraft.Utility/Source/Public/Templates/Utility.h @@ -23,7 +23,7 @@ constexpr const T(&AsConst(T(&Array)[N]))[N] } template -FORCEINLINE typename TRemoveReference::Type&& MoveTemp(T&& Obj) +constexpr typename TRemoveReference::Type&& MoveTemp(T&& Obj) { typedef typename TRemoveReference::Type CastType; @@ -34,31 +34,31 @@ FORCEINLINE typename TRemoveReference::Type&& MoveTemp(T&& Obj) } template -FORCEINLINE T CopyTemp(T& Val) +constexpr T CopyTemp(T& Val) { return const_cast(Val); } template -FORCEINLINE T CopyTemp(const T& Val) +constexpr T CopyTemp(const T& Val) { return Val; } template -FORCEINLINE T&& CopyTemp(T&& Val) +constexpr T&& CopyTemp(T&& Val) { return MoveTemp(Val); } template -FORCEINLINE T&& Forward(typename TRemoveReference::Type& Obj) +constexpr T&& Forward(typename TRemoveReference::Type& Obj) { return (T&&)Obj; } template -FORCEINLINE T&& Forward(typename TRemoveReference::Type&& Obj) +constexpr T&& Forward(typename TRemoveReference::Type&& Obj) { return (T&&)Obj; } @@ -80,7 +80,7 @@ constexpr T Exchange(T& A, U&& B) } template -T&& DeclVal(); +constexpr T&& DeclVal(); template requires TIsObject::Value constexpr T* AddressOf(T& Object) @@ -88,7 +88,7 @@ constexpr T* AddressOf(T& Object) return reinterpret_cast(&const_cast(reinterpret_cast(Object))); } -template requires !TIsObject::Value +template requires (!TIsObject::Value) constexpr T* AddressOf(T& Object) { return &Object; diff --git a/Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h b/Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h index 77c6dca..fb1041a 100644 --- a/Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h +++ b/Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h @@ -10,6 +10,7 @@ void REDCRAFTUTILITY_API TestTemplates(); void REDCRAFTUTILITY_API TestInvoke(); void REDCRAFTUTILITY_API TestReferenceWrapper(); void REDCRAFTUTILITY_API TestCompare(); +void REDCRAFTUTILITY_API TestOptional(); void REDCRAFTUTILITY_API TestMiscellaneous(); NAMESPACE_MODULE_END(Utility)