// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "UObject/GCObject.h" #include "Templates/EnableIf.h" #include "Templates/PointerIsConvertibleFromTo.h" #include "Templates/UniquePtr.h" namespace UE4StrongObjectPtr_Private { class FInternalReferenceCollector: public FGCObject { public: explicit FInternalReferenceCollector(const volatile UObject* InObject) : Object(InObject) { check(IsInGameThread()); } virtual ~FInternalReferenceCollector() { check(IsInGameThread() || IsInGarbageCollectorThread()); } bool IsValid() const { return Object != nullptr; } template FORCEINLINE UObjectType* GetAs() const { return (UObjectType*)Object; } FORCEINLINE void Set(const volatile UObject* InObject) { Object = InObject; } //~ FGCObject interface virtual void AddReferencedObjects(FReferenceCollector& Collector) override { Collector.AddReferencedObject(Object); } virtual FString GetReferencerName() const override { return "UE4StrongObjectPtr_Private::FInternalReferenceCollector"; } private: const volatile UObject* Object; }; } // namespace UE4StrongObjectPtr_Private /** * Specific implementation of FGCObject that prevents a single UObject-based pointer from being GC'd while this guard is in scope. * @note This is the "full-fat" version of FGCObjectScopeGuard which uses a heap-allocated FGCObject so *can* safely be used with containers that treat types as trivially relocatable. */ template class TStrongObjectPtr { public: TStrongObjectPtr(TStrongObjectPtr&& InOther) = default; TStrongObjectPtr& operator=(TStrongObjectPtr&& InOther) = default; ~TStrongObjectPtr() = default; FORCEINLINE_DEBUGGABLE TStrongObjectPtr(TYPE_OF_NULLPTR = nullptr) { static_assert(TPointerIsConvertibleFromTo::Value, "TStrongObjectPtr can only be constructed with UObject types"); } FORCEINLINE_DEBUGGABLE explicit TStrongObjectPtr(ObjectType* InObject) { static_assert(TPointerIsConvertibleFromTo::Value, "TStrongObjectPtr can only be constructed with UObject types"); Reset(InObject); } FORCEINLINE_DEBUGGABLE TStrongObjectPtr(const TStrongObjectPtr& InOther) { Reset(InOther.Get()); } template < typename OtherObjectType, typename = decltype(ImplicitConv((OtherObjectType*)nullptr))> FORCEINLINE_DEBUGGABLE TStrongObjectPtr(const TStrongObjectPtr& InOther) { Reset(InOther.Get()); } FORCEINLINE_DEBUGGABLE TStrongObjectPtr& operator=(const TStrongObjectPtr& InOther) { Reset(InOther.Get()); return *this; } template < typename OtherObjectType, typename = decltype(ImplicitConv((OtherObjectType*)nullptr))> FORCEINLINE_DEBUGGABLE TStrongObjectPtr& operator=(const TStrongObjectPtr& InOther) { Reset(InOther.Get()); return *this; } FORCEINLINE_DEBUGGABLE ObjectType& operator*() const { check(IsValid()); return *Get(); } FORCEINLINE_DEBUGGABLE ObjectType* operator->() const { check(IsValid()); return Get(); } FORCEINLINE_DEBUGGABLE bool IsValid() const { return ReferenceCollector && ReferenceCollector->IsValid(); } FORCEINLINE_DEBUGGABLE explicit operator bool() const { return IsValid(); } FORCEINLINE_DEBUGGABLE ObjectType* Get() const { return ReferenceCollector ? ReferenceCollector->GetAs() : nullptr; } FORCEINLINE_DEBUGGABLE void Reset(ObjectType* InNewObject = nullptr) { if (ReferenceCollector) { ReferenceCollector->Set(InNewObject); } else if (InNewObject) { ReferenceCollector = MakeUnique(InNewObject); } } FORCEINLINE_DEBUGGABLE friend uint32 GetTypeHash(const TStrongObjectPtr& InStrongObjectPtr) { return GetTypeHash(InStrongObjectPtr.Get()); } private: TUniquePtr ReferenceCollector; }; template FORCEINLINE bool operator==(const TStrongObjectPtr& InLHS, const TStrongObjectPtr& InRHS) { return InLHS.Get() == InRHS.Get(); } template FORCEINLINE bool operator!=(const TStrongObjectPtr& InLHS, const TStrongObjectPtr& InRHS) { return InLHS.Get() != InRHS.Get(); }