// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Templates/UnrealTemplate.h" #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) #define METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO 1 #else #define METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO 0 #endif namespace Metasound { namespace Frontend { class FAccessPoint; struct FAccessToken {}; /** TAccessPtr * * TAccessPtr is used to determine whether an object has been destructed or not. * It is useful when an object cannot be wrapped in a TSharedPtr. A TAccessPtr * works similar to a TWeakPtr, but it cannot pin the object. Object pointers * held within a TAccessPtr must only be accessed on the thread where the objects * gets destructed to avoid having the object destructed while in use. * * If the TAccessPtr's underlying object is accessed when the pointer is invalid, * a fallback object will be returned. * * @tparam Type - The type of object to track. */ template class TAccessPtr { enum EConstCast { Tag }; public: using FTokenType = FAccessToken; static Type FallbackObject; /** Returns true if object is valid. Should only be called in same * thread which created the token. */ bool IsValid() const { return (Get() != nullptr); } FORCEINLINE explicit operator bool() const { return IsValid(); } Type* Get() const { #if METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO CachedObjectPtr = GetObject(); #endif return GetObject(); } Type& operator*() const { if (Type* Object = Get()) { return *Object; } checkNoEntry(); return FallbackObject; } Type* operator->() const { if (Type* Object = Get()) { return Object; } return &FallbackObject; } template TAccessPtr GetMemberAccessPtr(TFunction InGetMember) const { TFunction GetMemberFromObject = [=]() -> MemberType* { if (Type* Object = Get()) { return InGetMember(*Object); } return static_cast(nullptr); }; return TAccessPtr(GetMemberFromObject); } TAccessPtr() //: Object(nullptr) : GetObject([]() { return static_cast(nullptr); }) { #if METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO Get(); #endif } template TAccessPtr(const TAccessPtr& InOther, EConstCast InTag) //: Token(InOther.Token) //, Object(const_cast(InOther.Object)) { TFunction OtherGetObject = InOther.GetObject; GetObject = [=]() -> Type* { return const_cast(OtherGetObject()); }; #if METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO Get(); #endif } template < typename OtherType, typename = decltype(ImplicitConv((OtherType*)nullptr)) > TAccessPtr(const TAccessPtr& InOther) //: Token(InOther.Token) //, Object(InOther.Object) { TFunction OtherGetObject = InOther.GetObject; GetObject = [=]() -> Type* { return static_cast(OtherGetObject()); }; #if METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO Get(); #endif } TAccessPtr(const TAccessPtr& InOther) = default; TAccessPtr& operator=(const TAccessPtr& InOther) = default; TAccessPtr(TAccessPtr&& InOther) = default; TAccessPtr& operator=(TAccessPtr&& InOther) = default; private: template friend TAccessPtr MakeAccessPtr(const FAccessPoint& InAccessPoint, RelatedType& InRef); template friend TAccessPtr ConstCastAccessPtr(const TAccessPtr& InAccessPtr); template friend class TAccessPtr; #if METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO mutable Type* CachedObjectPtr = nullptr; #endif TFunction GetObject; TAccessPtr(TFunction InGetObject) : GetObject(InGetObject) { #if METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO Get(); #endif } TAccessPtr(TWeakPtr AccessToken, Type& InRef) { Type* RefPtr = &InRef; GetObject = [=]() -> Type* { Type* Object = nullptr; if (AccessToken.IsValid()) { Object = RefPtr; } return Object; }; #if METASOUND_FRONTEND_ACCESSPTR_DEBUG_INFO Get(); #endif } }; template Type TAccessPtr::FallbackObject = Type(); /** FAccessPoint acts as a lifecycle tracker for the TAccessPtrs it creates. * When this object is destructed, all associated TAccessPtrs will become invalid. */ class FAccessPoint { public: using FTokenType = FAccessToken; FAccessPoint() { Token = MakeShared(); } FAccessPoint(const FAccessPoint&) { // Do not copy token from other access point on copy. Token = MakeShared(); } // Do not copy token from other access point on assignment FAccessPoint& operator=(const FAccessPoint&) { return *this; } private: template friend TAccessPtr MakeAccessPtr(const FAccessPoint& InAccessPoint, Type& InRef); FAccessPoint(FAccessPoint&&) = delete; FAccessPoint& operator=(FAccessPoint&&) = delete; TSharedPtr Token; }; template TAccessPtr MakeAccessPtr(const FAccessPoint& InAccessPoint, Type& InRef) { return TAccessPtr(InAccessPoint.Token, InRef); } template TAccessPtr ConstCastAccessPtr(const TAccessPtr& InAccessPtr) { return TAccessPtr(InAccessPtr, TAccessPtr::EConstCast::Tag); } } }