#pragma once #include "CoreTypes.h" #include "TypeTraits/TypeTraits.h" #include "Miscellaneous/AssertionMacros.h" NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) template struct TOptional { public: using Type = T; constexpr TOptional() : bIsValid(false) { } template requires TIsConstructible::Value constexpr explicit TOptional(EInPlace, Types&&... Args) : bIsValid(true) { new(&Value) T(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 constexpr explicit(!TIsConvertible::Value) TOptional(const TOptional& InValue) : bIsValid(InValue.bIsValid) { if (InValue.bIsValid) new(&Value) T(InValue.GetValue()); } template requires TIsConstructible::Value constexpr explicit(!TIsConvertible::Value) TOptional(TOptional&& InValue) : bIsValid(InValue.bIsValid) { if (InValue.bIsValid) new(&Value) T(MoveTempIfPossible(InValue).GetValue()); } constexpr ~TOptional() { Reset(); } template requires TIsConstructible::Value constexpr TOptional& operator=(const TOptional& InValue) { if (InValue == this) return *this; Reset(); if (InValue.bIsValid) { new(&Value) T(InValue.GetValue()); bIsValid = true; } return *this; } template requires TIsConstructible::Value constexpr TOptional& operator=(TOptional&& InValue) { if (InValue == this) return *this; Reset(); if (InValue.bIsValid) { new(&Value) T(MoveTempIfPossible(InValue).GetValue()); bIsValid = true; } return *this; } template requires TIsConstructible::Value constexpr TOptional& operator=(U&& InValue) { Reset(); new(&Value) T(MoveTempIfPossible(InValue)); bIsValid = true; return *this; } template constexpr T& Emplace(ArgsType&&... Args) { Reset(); T* Result = new(&Value) T(Forward(Args)...); bIsValid = true; return *Result; } 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 const T* operator->() const { return &GetValue(); } constexpr T* 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(); } template constexpr T Get(U&& DefaultValue) && { return IsValid() ? GetValue() : DefaultValue; } template constexpr T Get(U&& DefaultValue) const& { return IsValid() ? GetValue() : DefaultValue; } constexpr void Reset() { if (bIsValid) { bIsValid = false; typedef T DestructOptionalType; ((T*)&Value)->DestructOptionalType::~DestructOptionalType(); } } private: TAlignedStorage::Type Value; bool bIsValid; }; template TOptional(T) ->TOptional; template constexpr bool operator==(const TOptional& LHS, const TOptional& RHS) { if (LHS.IsValid() != LHS.IsValid()) return false; if (LHS.IsValid() == false) return true; return *LHS == *RHS; } template constexpr bool operator!=(const TOptional& LHS, const TOptional& RHS) { if (LHS.IsValid() != LHS.IsValid()) return true; if (LHS.IsValid() == false) return false; 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&, 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 TOptional::Type> MakeOptional(T&& InValue) { return TOptional::Type>(Forward(InValue)); } template constexpr TOptional MakeOptional(Types&&... Args) { return TOptional(InPlace, Forward(Args)...); } template constexpr void Swap(TOptional& A, TOptional& B) { if (!A && !B) return; if (A && !B) { B = A; A.Reset(); return; } if (B && !A) { A = B; B.Reset(); return; } Swap(*A, *B); } NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END