diff --git a/Redcraft.Utility/Source/Public/Templates/Function.h b/Redcraft.Utility/Source/Public/Templates/Function.h index 0d4562a..c34a584 100644 --- a/Redcraft.Utility/Source/Public/Templates/Function.h +++ b/Redcraft.Utility/Source/Public/Templates/Function.h @@ -390,7 +390,7 @@ inline constexpr size_t FUNCTION_DEFAULT_INLINE_SIZE = ANY_DEFAULT_INLINE_S inline constexpr size_t FUNCTION_DEFAULT_INLINE_ALIGNMENT = ANY_DEFAULT_INLINE_ALIGNMENT; template -using TFunctionRef = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; +using TFunctionRef = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; template using TFunction = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; diff --git a/Redcraft.Utility/Source/Public/Templates/ReferenceWrapper.h b/Redcraft.Utility/Source/Public/Templates/ReferenceWrapper.h index 26eb6ba..cba33e1 100644 --- a/Redcraft.Utility/Source/Public/Templates/ReferenceWrapper.h +++ b/Redcraft.Utility/Source/Public/Templates/ReferenceWrapper.h @@ -3,37 +3,69 @@ #include "CoreTypes.h" #include "Templates/Invoke.h" #include "Templates/Utility.h" +#include "Templates/Optional.h" #include "TypeTraits/TypeTraits.h" NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) -template -class TReferenceWrapper +template requires (TIsObject::Value || TIsFunction::Value) +struct TReferenceWrapper { public: - using Type = T; + using Type = ReferencedType; - template requires (!TIsSame::Type>::Value) - constexpr TReferenceWrapper(U&& Object) : Ptr(AddressOf(Forward(Object))) { } + template requires TIsConvertible::Value + constexpr TReferenceWrapper(T&& Object) : Pointer(AddressOf(Forward(Object))) { } TReferenceWrapper(const TReferenceWrapper&) = default; - TReferenceWrapper& operator=(const TReferenceWrapper& x) = default; + + template requires TIsConvertible::Value + constexpr TReferenceWrapper(const TReferenceWrapper& InValue) + : Pointer(InValue.Pointer) + { } - constexpr operator T&() const { return *Ptr; } - constexpr T& Get() const { return *Ptr; } + TReferenceWrapper& operator=(const TReferenceWrapper&) = default; + + template requires TIsConvertible::Value + constexpr TReferenceWrapper& operator=(const TReferenceWrapper& InValue) + { + Pointer = InValue.Pointer; + return *this; + } + + constexpr operator ReferencedType&() const { return *Pointer; } + constexpr ReferencedType& Get() const { return *Pointer; } template - constexpr TInvokeResult::Type operator()(Types&&... Args) const + constexpr TInvokeResult::Type operator()(Types&&... Args) const { return Invoke(Get(), Forward(Args)...); } + + constexpr size_t GetTypeHash() const requires CHashable + { + return NAMESPACE_REDCRAFT::GetTypeHash(Get()); + } + constexpr void Swap(TReferenceWrapper& InValue) + { + ReferencedType* Temp = Pointer; + Pointer = InValue.Pointer; + InValue.Pointer = Temp; + } + private: - T* Ptr; + ReferencedType* Pointer; + + template requires (TIsObject::Value || TIsFunction::Value) friend struct TReferenceWrapper; + + // Optimize TOptional with these hacking + constexpr TReferenceWrapper(FInvalid) : Pointer(nullptr) { }; + template requires TIsObject::Value && (!TIsArray::Value) && TIsDestructible::Value friend struct TOptional; }; @@ -75,6 +107,124 @@ template struct TUnwrapReference> { using Type template struct TUnwrapRefDecay { using Type = typename TUnwrapReference::Type>::Type; }; +template +struct TOptional> +{ +private: + + using OptionalType = TReferenceWrapper; + + template + struct TAllowUnwrapping : TBoolConstant& >::Value + || TIsConstructible& >::Value + || TIsConstructible&&>::Value + || TIsConstructible&&>::Value + || TIsConvertible< TOptional&, OptionalType>::Value + || TIsConvertible&, OptionalType>::Value + || TIsConvertible< TOptional&&, OptionalType>::Value + || TIsConvertible&&, OptionalType>::Value + || TIsAssignable& >::Value + || TIsAssignable& >::Value + || TIsAssignable&&>::Value + || TIsAssignable&&>::Value + )> { }; + +public: + + using ValueType = OptionalType; + + constexpr TOptional() : Reference(Invalid) { } + + constexpr TOptional(FInvalid) : TOptional() { } + + template requires TIsConstructible::Value + constexpr explicit TOptional(FInPlace, Types&&... Args) + : Reference(Forward(Args)...) + { } + + template requires TIsConstructible::Value + && (!TIsSame::Type, FInPlace>::Value) && (!TIsSame::Type, TOptional>::Value) + constexpr explicit (!TIsConvertible::Value) TOptional(T&& InValue) + : TOptional(InPlace, Forward(InValue)) + { } + + TOptional(const TOptional& InValue) = default; + TOptional(TOptional&& InValue) = default; + + template requires TIsConstructible::Value && TAllowUnwrapping::Value + constexpr explicit (!TIsConvertible::Value) TOptional(const TOptional& InValue) + : Reference(InValue.Reference) + { } + + ~TOptional() = default; + + TOptional& operator=(const TOptional& InValue) = default; + TOptional& operator=(TOptional&& InValue) = default; + + template requires TIsConstructible::Value && TIsAssignable::Value && TAllowUnwrapping::Value + constexpr TOptional& operator=(const TOptional& InValue) + { + Reference = InValue.Reference; + return *this; + } + + template requires TIsConstructible::Value && TIsAssignable::Value + constexpr TOptional& operator=(T&& InValue) + { + Reference = InValue; + return *this; + } + + template requires TIsConstructible::Value + constexpr OptionalType& Emplace(ArgTypes&&... Args) + { + Reference = TReferenceWrapper(Forward(Args)...); + return Reference; + } + + constexpr bool IsValid() const { return Reference.Pointer != nullptr; } + constexpr explicit operator bool() const { return Reference.Pointer != nullptr; } + + 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 Reference; } + 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 Reference; } + 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 Reference; } + 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 Reference; } + + constexpr const OptionalType* operator->() const { return &GetValue(); } + constexpr OptionalType* operator->() { 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(); } + + constexpr OptionalType& Get( OptionalType& DefaultValue) & { return IsValid() ? GetValue() : DefaultValue; } + constexpr const OptionalType& Get(const OptionalType& DefaultValue) const& { return IsValid() ? GetValue() : DefaultValue; } + + constexpr void Reset() + { + Reference = Invalid; + } + + constexpr size_t GetTypeHash() const requires CHashable + { + if (!IsValid()) return 2824517378; + return Reference.GetTypeHash(); + } + + constexpr void Swap(TOptional& InValue) + { + Reference.Swap(InValue.Reference); + } + +private: + + TReferenceWrapper Reference; + template requires TIsObject::Value && (!TIsArray::Value) && TIsDestructible::Value friend struct TOptional; + +}; + NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END