#pragma once #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 requires (CObject || CFunction) class TReferenceWrapper { public: using Type = ReferencedType; template requires (CConvertibleTo) constexpr TReferenceWrapper(T&& Object) { ReferencedType& Reference = Forward(Object); Pointer = AddressOf(Reference); } TReferenceWrapper(const TReferenceWrapper&) = default; template requires (CConvertibleTo) constexpr TReferenceWrapper(const TReferenceWrapper& InValue) : Pointer(InValue.Pointer) { } TReferenceWrapper& operator=(const TReferenceWrapper&) = default; template requires (CConvertibleTo) 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 operator()(Ts&&... 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: ReferencedType* Pointer; template requires (CObject || CFunction) friend class TReferenceWrapper; // Optimize TOptional with these hacking constexpr TReferenceWrapper(FInvalid) : Pointer(nullptr) { }; template requires (CDestructible) friend class TOptional; }; template TReferenceWrapper(T&) -> TReferenceWrapper; template void Ref(const T&&) = delete; template constexpr TReferenceWrapper Ref(T& InValue) { return TReferenceWrapper(InValue); } template constexpr TReferenceWrapper Ref(TReferenceWrapper InValue) { return Ref(InValue.Get()); } template constexpr TReferenceWrapper Ref(const T& InValue) { return TReferenceWrapper(InValue); } template constexpr TReferenceWrapper Ref(TReferenceWrapper InValue) { return Ref(InValue.Get()); } NAMESPACE_PRIVATE_BEGIN template struct TIsTReferenceWrapperImpl : FFalse { }; template struct TIsTReferenceWrapperImpl> : FTrue { }; template struct TUnwrapReferenceImpl { using Type = T; }; template struct TUnwrapReferenceImpl> { using Type = T&; }; template struct TUnwrapRefDecayImpl { using Type = typename TUnwrapReferenceImpl>::Type; }; NAMESPACE_PRIVATE_END template concept CTReferenceWrapper = NAMESPACE_PRIVATE::TIsTReferenceWrapperImpl::Value; template using TUnwrapReference = typename NAMESPACE_PRIVATE::TUnwrapReferenceImpl::Type; template using TUnwrapRefDecay = typename NAMESPACE_PRIVATE::TUnwrapRefDecayImpl::Type; template class TOptional> { private: using OptionalType = TReferenceWrapper; template struct TAllowUnwrapping : TBoolConstant < !( CConstructibleFrom& > || CConstructibleFrom& > || CConstructibleFrom&&> || CConstructibleFrom&&> || CConvertibleTo< TOptional&, OptionalType> || CConvertibleTo&, OptionalType> || CConvertibleTo< TOptional&&, OptionalType> || CConvertibleTo&&, OptionalType> || CAssignableFrom& > || CAssignableFrom& > || CAssignableFrom&&> || CAssignableFrom&&> )> { }; public: using ValueType = OptionalType; constexpr TOptional() : Reference(Invalid) { } constexpr TOptional(FInvalid) : TOptional() { } template requires (CConstructibleFrom) constexpr explicit TOptional(FInPlace, Ts&&... Args) : Reference(Forward(Args)...) { } template requires (CConstructibleFrom && !CSameAs, FInPlace> && !CSameAs, TOptional>) constexpr explicit (!CConvertibleTo) TOptional(T&& InValue) : TOptional(InPlace, Forward(InValue)) { } TOptional(const TOptional& InValue) = default; TOptional(TOptional&& InValue) = default; template requires (CConstructibleFrom && TAllowUnwrapping::Value) constexpr explicit (!CConvertibleTo) TOptional(const TOptional& InValue) : Reference(InValue.Reference) { } ~TOptional() = default; TOptional& operator=(const TOptional& InValue) = default; TOptional& operator=(TOptional&& InValue) = default; template requires (CConstructibleFrom && CAssignableFrom && TAllowUnwrapping::Value) constexpr TOptional& operator=(const TOptional& InValue) { Reference = InValue.Reference; return *this; } template requires (CConstructibleFrom && CAssignableFrom) constexpr TOptional& operator=(T&& InValue) { Reference = InValue; return *this; } template requires (CConstructibleFrom) 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 (CDestructible) friend class TOptional; }; NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END