Redcraft/Redcraft.Utility/Source/Public/Memory/SharedPointer.h

1892 lines
80 KiB
C++

#pragma once
#include "CoreTypes.h"
#include "Memory/Memory.h"
#include "Templates/Atomic.h"
#include "Templates/Invoke.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "Memory/PointerTraits.h"
#include "Memory/UniquePointer.h"
#include "Memory/MemoryOperator.h"
#include "Templates/Noncopyable.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
template <typename T> requires (CClass<T>)
class TSharedFromThis;
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TSharedRef;
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TSharedPtr;
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TWeakPtr;
NAMESPACE_PRIVATE_BEGIN
template <typename T> struct TIsTSharedRef : FFalse { };
template <typename T> struct TIsTSharedRef<TSharedRef<T>> : FTrue { };
template <typename T> struct TIsTSharedPtr : FFalse { };
template <typename T> struct TIsTSharedPtr<TSharedPtr<T>> : FTrue { };
template <typename T> struct TIsTWeakPtr : FFalse { };
template <typename T> struct TIsTWeakPtr<TWeakPtr<T>> : FTrue { };
NAMESPACE_PRIVATE_END
template <typename T>
concept CTSharedRef = NAMESPACE_PRIVATE::TIsTSharedRef<TRemoveCV<T>>::Value;
template <typename T>
concept CTSharedPtr = NAMESPACE_PRIVATE::TIsTSharedPtr<TRemoveCV<T>>::Value;
template <typename T>
concept CTWeakPtr = NAMESPACE_PRIVATE::TIsTWeakPtr<TRemoveCV<T>>::Value;
NAMESPACE_PRIVATE_BEGIN
// This is the base object for TSharedPtr and uses constructive interference alignment for performance.
class alignas(Memory::ConstructiveInterference) FSharedController : private FSingleton
{
private:
using RefCounter = TAtomic<size_t>;
// Ensure that counters are lock-free for performance.
static_assert(RefCounter::bIsAlwaysLockFree);
// When this count is zero the object is destroyed.
// This count is the number of TSharedRef and TSharedPtr.
RefCounter SharedReferenceCount;
// When this count is zero the controller is destroyed.
// If SharedCounter is not zero this count is one more than the number of TWeakPtr.
RefCounter WeakReferenceCount;
public:
// The initialization count is one because TSharedPtr already existed when this controller was constructed.
FORCEINLINE FSharedController() : SharedReferenceCount(1) , WeakReferenceCount(1) { }
// The controller is a polymorphic class in order to customize the type of erasure of the deleter.
virtual ~FSharedController() { }
// Destructor object.
virtual void DestroyObject() = 0;
// Destructor this controller.
virtual void DestroyThis() { delete this; }
// Get shared reference count, no definite operation order.
FORCEINLINE RefCounter::ValueType GetSharedReferenceCount()
{
// Get the shared reference count as EMemoryOrder::Relaxed,
// since this count is for reference only and has no guarantees,
// where EMemoryOrder::Relaxed only determines the atomicity of this operation and not the order.
return SharedReferenceCount.Load(EMemoryOrder::Relaxed);
}
// Increases the shared reference count, ensuring that the shared reference count is non-zero before calling.
FORCEINLINE void AddSharedReference()
{
// The check was removed in the release version, so you can use the default EMemoryOrder.
check(SharedReferenceCount.Load() != 0);
// We assume a non-zero reference count, which can be incremented directly with EMemoryOrder::Relaxed,
// where EMemoryOrder::Relaxed only determines the atomicity of this operation and not the order.
SharedReferenceCount.FetchAdd(1, EMemoryOrder::Relaxed);
}
// increment the shared reference count, do not need to ensure that the shared reference count is zero,
// if the shared reference count is zero return false.
bool AddSharedReferenceIfUnexpired()
{
RefCounter::ValueType OldSharedReferenceCount = GetSharedReferenceCount();
// We need to make sure we don't increase the reference count from zero to one.
while (true)
{
// Never add a shared reference if the pointer has already expired.
if (OldSharedReferenceCount == 0) return false;
// Attempt to increment the reference count.
// We do a weak read here because we require a loop where the loop only happens in very unusual cases.
if (SharedReferenceCount.CompareExchange(OldSharedReferenceCount, OldSharedReferenceCount + 1, EMemoryOrder::Relaxed, true)) return true;
}
}
// Release the shared reference count, make sure the shared reference count is not zero before,
// and destroy the object when the shared reference count is released to zero.
void ReleaseSharedReference()
{
// Decrement with EMemoryOrder::Release and get the old value,
// where EMemoryOrder::Release ensures that the side effects of all operations
// on the shared reference count of all threads are visible to this thread,
// preventing the shared reference count from actually going to zero.
RefCounter::ValueType OldSharedReferenceCount = SharedReferenceCount.FetchSub(1, EMemoryOrder::Release);
// Make sure the shared reference count is not zero before.
check(OldSharedReferenceCount != 0);
// Destroy the object when the reference count is released to zero.
if (OldSharedReferenceCount == 1)
{
// Use EMemoryOrder::Acquire to ensure visibility of the side effects of the decrement to any other threads.
AtomicThreadFence(EMemoryOrder::Acquire);
// Destroy objects using the type-erase deleter.
DestroyObject();
// Release a weak reference count to indicate that no TSharedRef and TSharedPtr are referencing this controller.
ReleaseWeakReference();
}
}
// Increases the weak reference count, ensuring that the weak reference count is non-zero before calling.
FORCEINLINE void AddWeakReference()
{
// The use of EMemoryOrder is the same as in AddSharedReference().
check(WeakReferenceCount.Load() != 0);
WeakReferenceCount.FetchAdd(1, EMemoryOrder::Relaxed);
}
// Release the weak reference count, make sure the weak reference count is not zero before,
// and destroy the controller when the weak reference count is released to zero.
void ReleaseWeakReference()
{
// The use of EMemoryOrder is the same as in ReleaseSharedReference().
RefCounter::ValueType OldWeakReferenceCount = WeakReferenceCount.FetchSub(1, EMemoryOrder::Release);
check(OldWeakReferenceCount != 0);
if (OldWeakReferenceCount == 1)
{
AtomicThreadFence(EMemoryOrder::Acquire);
DestroyThis(); // Destroy this controller.
}
}
};
template <typename T, typename E, bool = CEmpty<E> && !CFinal<E>>
class TSharedControllerWithDeleter;
template <typename T, typename E>
class TSharedControllerWithDeleter<T, E, true> final : public FSharedController, private E
{
public:
TSharedControllerWithDeleter() = delete;
FORCEINLINE TSharedControllerWithDeleter(T* InPtr) : E(), Pointer(InPtr) { }
template<typename U>
FORCEINLINE TSharedControllerWithDeleter(T* InPtr, U&& InDeleter) : E(Forward<U>(InDeleter)), Pointer(InPtr) { }
virtual ~TSharedControllerWithDeleter() = default;
virtual void DestroyObject() final { Invoke(GetDeleter(), Pointer); }
FORCEINLINE T* GetPointer() { return Pointer; }
FORCEINLINE E& GetDeleter() { return *this; }
private:
// NOTE: NO_UNIQUE_ADDRESS is not valid in MSVC, use base class instead of member variable
//NO_UNIQUE_ADDRESS E Deleter;
T* Pointer;
};
template <typename T, typename E>
class TSharedControllerWithDeleter<T, E, false> final : public FSharedController
{
public:
TSharedControllerWithDeleter() = delete;
FORCEINLINE TSharedControllerWithDeleter(T* InPtr) : Pointer(InPtr), Deleter() { }
template<typename U>
FORCEINLINE TSharedControllerWithDeleter(T* InPtr, U&& InDeleter) : Pointer(InPtr), Deleter(Forward<U>(InDeleter)) { }
virtual ~TSharedControllerWithDeleter() = default;
virtual void DestroyObject() final { Invoke(GetDeleter(), Pointer); }
FORCEINLINE T* GetPointer() { return Pointer; }
FORCEINLINE E& GetDeleter() { return Deleter; }
private:
T* Pointer;
E Deleter;
};
template <typename T>
class TSharedControllerWithObject final : public FSharedController
{
public:
template <typename... Ts>
FORCEINLINE explicit TSharedControllerWithObject(Ts&&... Args)
{
if constexpr (sizeof...(Ts) == 0)
{
new (&Storage) T;
}
else
{
new (&Storage) T(Forward<Ts>(Args)...);
}
}
virtual ~TSharedControllerWithObject() = default;
virtual void DestroyObject() final { GetPointer()->~T(); }
FORCEINLINE T* GetPointer() const { return reinterpret_cast<T*>(&Storage); }
private:
mutable TAlignedStorage<sizeof(T), alignof(T)> Storage;
};
template <typename T>
class TSharedControllerWithArray final : public FSharedController
{
public:
static TSharedControllerWithArray* New(size_t N)
{
void* Buffer = Memory::Malloc(sizeof(TSharedControllerWithArray) + sizeof(T) * (N - 1), alignof(TSharedControllerWithArray));
const auto Controller = new (Buffer) TSharedControllerWithArray(N);
const T* ElementPtr = new (Controller->GetPointer()) T[N];
check(ElementPtr == Controller->GetPointer());
return Controller;
}
virtual ~TSharedControllerWithArray() = default;
virtual void DestroyObject() final { Memory::Destruct(GetPointer(), Num); }
virtual void DestroyThis() final
{
this->~TSharedControllerWithArray();
Memory::Free(this);
}
FORCEINLINE T* GetPointer() const { return reinterpret_cast<T*>(&Storage); }
private:
size_t Num;
mutable TAlignedStorage<sizeof(T), alignof(T)> Storage;
FORCEINLINE explicit TSharedControllerWithArray(size_t N) : Num(N) { }
};
struct FSharedHelper
{
template <typename T, typename U> requires (CSameAs<T, TDecay<T>> && CSameAs<U, TDecay<U>>
&& (CTSharedRef<T> || CTSharedPtr<T>) && (CTSharedRef<U> || CTSharedPtr<U>))
static T& CopySharedReference(T& This, const U& InValue)
{
if (This.Controller == InValue.Controller)
{
This.Pointer = InValue.Pointer;
return This;
}
if constexpr (CTSharedRef<T>)
{
This.Controller->ReleaseSharedReference();
}
else if (This.Controller != nullptr)
{
This.Controller->ReleaseSharedReference();
}
This.Pointer = InValue.Pointer;
This.Controller = InValue.Controller;
if constexpr (CTSharedRef<T> || CTSharedRef<U>)
{
This.Controller->AddSharedReference();
}
else if (This.Controller != nullptr)
{
This.Controller->AddSharedReference();
}
return This;
}
template <typename T, typename U> requires (CSameAs<T, TDecay<T>> && CSameAs<U, TDecay<U>>
&& (CTSharedRef<T> || CTSharedPtr<T>) && (CTSharedRef<U> || CTSharedPtr<U>))
static T& MoveSharedReference(T& This, U&& InValue)
{
if constexpr (CTSharedRef<T>)
{
Swap(This.Pointer, InValue.Pointer);
Swap(This.Controller, InValue.Controller);
}
else if constexpr (CTSharedPtr<T> && CTSharedPtr<U>)
{
if (&InValue == &This) UNLIKELY return This;
if (This.Controller != nullptr)
{
This.Controller->ReleaseSharedReference();
}
This.Pointer = Exchange(InValue.Pointer, nullptr);
This.Controller = Exchange(InValue.Controller, nullptr);
}
else
{
CopySharedReference(This, InValue);
}
return This;
}
template <typename T, typename U> requires (CSameAs<T, TDecay<T>> && CSameAs<U, TDecay<U>>
&& CTWeakPtr<T> && (CTSharedRef<U> || CTSharedPtr<U> || CTWeakPtr<U>))
static T& CopyWeakReference(T& This, const U& InValue)
{
if constexpr (CTWeakPtr<T> && CTWeakPtr<U>)
{
if (This.Controller == InValue.Controller)
{
This.Pointer = InValue.Pointer;
return This;
}
}
if (This.Controller != nullptr)
{
This.Controller->ReleaseWeakReference();
}
This.Pointer = InValue.Pointer;
This.Controller = InValue.Controller;
if constexpr (CTSharedRef<U>)
{
This.Controller->AddWeakReference();
}
else if (This.Controller != nullptr)
{
This.Controller->AddWeakReference();
}
return This;
}
template <typename T, typename U> requires (CSameAs<T, TDecay<T>> && CSameAs<U, TDecay<U>>
&& CTWeakPtr<T> && (CTSharedRef<U> || CTSharedPtr<U> || CTWeakPtr<U>))
static T& MoveWeakReference(T& This, U&& InValue)
{
if constexpr (CTWeakPtr<T> && CTWeakPtr<U>)
{
if (&InValue == &This) UNLIKELY return This;
if (This.Controller != nullptr)
{
This.Controller->ReleaseWeakReference();
}
This.Pointer = Exchange(InValue.Pointer, nullptr);
This.Controller = Exchange(InValue.Controller, nullptr);
}
else
{
CopyWeakReference(This, InValue);
}
return This;
}
};
template <typename T>
class TSharedProxy : private FSingleton
{
public:
FORCEINLINE TSharedProxy(TRemoveExtent<T>* InPtr, FSharedController* InController)
: Pointer(InPtr), Controller(InController)
{ }
template <typename U> requires (CArray<T> == CArray<U> && ((!CArray<U> && CConvertibleTo<T(*)[], U(*)[]>)
|| (CArray<U> && CConvertibleTo<TRemoveExtent<T>(*)[], TRemoveExtent<U>(*)[]>)))
NODISCARD FORCEINLINE operator TSharedRef<U>() &&
{
check_code({ return TSharedRef<U>(Pointer, Exchange(Controller, nullptr)); });
return TSharedRef<U>(Pointer, Controller);
}
template <typename U> requires (CArray<T> == CArray<U> && ((!CArray<U> && CConvertibleTo<T(*)[], U(*)[]>)
|| (CArray<U> && CConvertibleTo<TRemoveExtent<T>(*)[], TRemoveExtent<U>(*)[]>)))
NODISCARD FORCEINLINE operator TSharedPtr<U>() &&
{
check_code({ return TSharedPtr<U>(Pointer, Exchange(Controller, nullptr)); });
return TSharedPtr<U>(Pointer, Controller);
}
# if DO_CHECK
FORCEINLINE ~TSharedProxy() { checkf(Controller == nullptr, TEXT("The return value from MakeShared() is incorrectly ignored.")); }
# endif
private:
TRemoveExtent<T>* Pointer;
FSharedController* Controller;
};
struct FSharedPtrConstructor { explicit FSharedPtrConstructor() = default; };
inline constexpr FSharedPtrConstructor SharedPtrConstructor{ };
NAMESPACE_PRIVATE_END
/**
* Derive your class from TSharedFromThis to enable access to a TSharedRef directly from an object instance
* that's already been allocated. Note that when your class is managed indirectly rather than directly,
* it is NOT enable access to a TSharedRef, for example managed by the array version of the shared pointer.
*/
template <typename T> requires (CClass<T>)
class TSharedFromThis
{
public:
/**
* Provides access to a shared reference to this object.
* Note that is only valid to call this after a shared pointer to the object has already been created.
* Also note that it is illegal to call this in the object's destructor.
*/
FORCEINLINE TSharedRef<T> AsShared()
{
TSharedPtr<T> SharedThis(AsWeak().Lock());
checkf(SharedThis.Get() == this, TEXT("Your class is now not directly managed. Please check DoesSharedInstanceExist()."));
return MoveTemp(SharedThis).ToSharedRef();
}
/**
* Provides access to a shared reference to this object.
* Note that is only valid to call this after a shared pointer to the object has already been created.
* Also note that it is illegal to call this in the object's destructor.
*/
FORCEINLINE TSharedRef<const T> AsShared() const
{
TSharedPtr<const T> SharedThis(AsWeak().Lock());
checkf(SharedThis.Get() == this, TEXT("Your class is now not directly managed. Please check DoesSharedInstanceExist()."));
return MoveTemp(SharedThis).ToSharedRef();
}
/** Provides access to a weak reference to this object. */
FORCEINLINE TWeakPtr<T> AsWeak()
{
return WeakThis;
}
/** Provides access to a weak reference to this object. */
FORCEINLINE TWeakPtr<const T> AsWeak() const
{
return WeakThis;
}
/** Checks whether our referenced instance is valid, i.e. whether it's safe to call AsShared() or AsWeak(). */
FORCEINLINE bool DoesSharedInstanceExist() const
{
return !WeakThis.Expired();
}
protected:
FORCEINLINE constexpr TSharedFromThis() : WeakThis() { }
FORCEINLINE TSharedFromThis(const TSharedFromThis&) : TSharedFromThis() { }
FORCEINLINE TSharedFromThis& operator=(const TSharedFromThis&) { return *this; }
FORCEINLINE ~TSharedFromThis() = default;
private:
using SharedFromThisType = TSharedFromThis;
// Here it is updated by the private constructor of TSharedRef or TSharedPtr.
mutable TWeakPtr<T> WeakThis;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedRef;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedPtr;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TWeakPtr;
};
/** Shared-ownership non-nullable smart pointer. Use this when you need an object's lifetime to be managed by a shared smart pointer. */
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TSharedRef final
{
private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper;
public:
using ElementType = T;
using WeakType = TWeakPtr<T>;
/** TSharedRef cannot be initialized by nullptr. */
TSharedRef() = delete;
/** TSharedRef cannot be initialized by nullptr. */
TSharedRef(nullptr_t) = delete;
/** Constructs a shared reference that owns the specified object. Must not be nullptr. */
FORCEINLINE explicit TSharedRef(T* InPtr) : TSharedRef(InPtr, TDefaultDelete<T>()) { }
/** Constructs a shared reference that owns the specified object with a deleter. Must not be nullptr. */
template <typename E> requires (CConstructibleFrom<TDecay<E>, E>
&& CInvocable<TDecay<E>, TRemoveExtent<T>*> && CDestructible<TDecay<E>>)
FORCEINLINE TSharedRef(T* InPtr, E&& InDeleter)
: TSharedRef(InPtr, new NAMESPACE_PRIVATE::TSharedControllerWithDeleter<T, TDecay<E>>(InPtr, Forward<E>(InDeleter)))
{
checkf(InPtr != nullptr, TEXT("TSharedRef cannot be initialized by nullptr. Please use TSharedPtr."));
}
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared object, but pointing to a different object, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The object pointer to use (instead of the incoming shared pointer's object).
*/
template <typename U>
FORCEINLINE TSharedRef(const TSharedRef<U>& InValue, T* InPtr)
: Pointer(InPtr), Controller(InValue.Controller)
{
checkf(InPtr != nullptr, TEXT("TSharedRef cannot be initialized by nullptr. Please use TSharedPtr."));
Controller->AddSharedReference();
}
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared object, but pointing to a different object, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The object pointer to use (instead of the incoming shared pointer's object).
*/
template <typename U>
FORCEINLINE TSharedRef(TSharedRef<U>&& InValue, T* InPtr): TSharedRef(InValue, InPtr) { }
/** Constructs a TSharedRef which shares ownership of the object managed by 'InValue'. */
FORCEINLINE TSharedRef(const TSharedRef& InValue) : TSharedRef(InValue, InValue.Get()) { }
/** Constructs a TSharedRef which shares ownership of the object managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedRef(const TSharedRef<U>& InValue) : TSharedRef(InValue, InValue.Get()) { }
/** Constructs a TSharedRef which shares ownership of the object managed by 'InValue'. */
FORCEINLINE TSharedRef(TSharedRef&& InValue) : TSharedRef(InValue) { }
/** Constructs a TSharedRef which shares ownership of the object managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedRef(TSharedRef<U>&& InValue) : TSharedRef(InValue) { }
/** If this owns an object and it is the last TSharedRef owning it, the object is destroyed through the owned deleter. */
FORCEINLINE ~TSharedRef() { Controller->ReleaseSharedReference(); }
/** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TSharedRef& operator=(const TSharedRef& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedRef& operator=(const TSharedRef<U>& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TSharedRef& operator=(TSharedRef&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedRef& operator=(TSharedRef<U>&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Compares the pointer values of two TSharedRef. */
template <typename U> requires (CEqualityComparable<T*, TRemoveExtent<U>*>)
NODISCARD friend FORCEINLINE constexpr bool operator==(const TSharedRef& LHS, const TSharedRef<U>& RHS) { return LHS.Get() == RHS.Get(); }
/** Compares the pointer values of two TSharedRef. */
template <typename U> requires (CThreeWayComparable<T*, TRemoveExtent<U>*>)
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TSharedRef& LHS, const TSharedRef<U>& RHS) { return LHS.Get() <=> RHS.Get(); }
/** Compares the pointer values with nullptr. */
NODISCARD FORCEINLINE constexpr bool operator==(nullptr_t) const& { return Get() == nullptr; }
/** Compares the pointer values with nullptr. */
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(nullptr_t) const& { return Get() <=> static_cast<T*>(nullptr); }
/** TSharedRef cannot be initialized by nullptr. */
void Reset(nullptr_t) = delete;
/** Replaces the managed object. */
FORCEINLINE void Reset(T* InPtr) { *this = MoveTemp(TSharedRef(InPtr)); }
/** TSharedRef cannot be initialized by nullptr. */
template <typename E>
void Reset(nullptr_t, E&&) = delete;
/** Replaces the managed object with a deleter. */
template <typename E> requires (CConstructibleFrom<TDecay<E>, E>
&& CInvocable<TDecay<E>, TRemoveExtent<T>*> && CDestructible<TDecay<E>>)
FORCEINLINE void Reset(T* InPtr, E&& InDeleter) { *this = MoveTemp(TSharedRef(InPtr, Forward<E>(InDeleter))); }
/** @return The pointer to the managed object. */
NODISCARD FORCEINLINE constexpr T* Get() const { return Pointer; }
/** @return The pointer to the owned deleter or nullptr. */
template <typename E> requires (CInvocable<TDecay<E>, TRemoveExtent<T>*> && (CDestructible<E> || CLValueReference<E>))
NODISCARD FORCEINLINE E* GetDeleter() const
{
const auto ControllerWithDeleter = dynamic_cast<NAMESPACE_PRIVATE::TSharedControllerWithDeleter<T, E>*>(Controller);
return ControllerWithDeleter != nullptr ? &ControllerWithDeleter->GetDeleter() : nullptr;
}
/** @return The reference or pointer to the object owned by *this, i.e. Get(). */
NODISCARD FORCEINLINE constexpr T& operator*() const { return *Get(); }
NODISCARD FORCEINLINE constexpr T* operator->() const { return Get(); }
/**
* Returns the number of shared references to this object (including this reference.)
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return The number of instances managing the current object.
*/
NODISCARD FORCEINLINE size_t GetSharedReferenceCount() const { return Controller->GetSharedReferenceCount(); }
/**
* Checks if this is the only instance managing the current object, i.e. whether GetSharedReferenceCount() == 1.
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return true if *this is the only shared_ptr instance managing the current object, false otherwise.
*/
NODISCARD FORCEINLINE bool IsUnique() const { return GetSharedReferenceCount() == 1; }
/**
* Checks whether this TSharedRef precedes other in implementation defined owner-based (as opposed to value-based) order.
* This ensures that the ordering of TSharedRef constructed by the aliasing constructor is not affected by object pointer.
*
* @return The ordering of the addresses of the control blocks.
*/
template <typename U = T> NODISCARD FORCEINLINE strong_ordering OwnerCompare(const TSharedRef<U>& InValue) const { return Controller <=> InValue.Controller; }
template <typename U = T> NODISCARD FORCEINLINE strong_ordering OwnerCompare(const TSharedPtr<U>& InValue) const { return Controller <=> InValue.Controller; }
/** Overloads the GetTypeHash algorithm for TSharedRef. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TSharedRef& A) { return GetTypeHash(A.Get()); }
/** Overloads the Swap algorithm for TSharedRef. */
friend FORCEINLINE constexpr void Swap(TSharedRef& A, TSharedRef& B)
{
Swap(A.Pointer, B.Pointer);
Swap(A.Controller, B.Controller);
}
private:
T* Pointer;
NAMESPACE_PRIVATE::FSharedController* Controller;
FORCEINLINE TSharedRef(NAMESPACE_PRIVATE::FSharedPtrConstructor, const TSharedPtr<T>& InValue)
: Pointer(InValue.Pointer), Controller(InValue.Controller)
{
Controller->AddSharedReference();
}
FORCEINLINE TSharedRef(NAMESPACE_PRIVATE::FSharedPtrConstructor, TSharedPtr<T>&& InValue)
: Pointer(Exchange(InValue.Pointer, nullptr))
, Controller(Exchange(InValue.Controller, nullptr))
{ }
FORCEINLINE TSharedRef(T* InPtr, NAMESPACE_PRIVATE::FSharedController* InController)
: Pointer(InPtr), Controller(InController)
{
check(!((Pointer == nullptr) ^ (Controller == nullptr)));
if constexpr (CClass<T> && !CVolatile<T> && requires { typename T::SharedFromThisType; })
{
using SharedFromThisType = T::SharedFromThisType;
if constexpr (CDerivedFrom<T, SharedFromThisType>)
{
if (Pointer != nullptr)
{
const SharedFromThisType& SharedFromThis = *Pointer;
checkf(!SharedFromThis.DoesSharedInstanceExist(), TEXT("This object is incorrectly managed by multiple TSharedRef or TSharedPtr."));
SharedFromThis.WeakThis = ConstCast<TRemoveCV<T>>(*this);
}
}
}
}
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedRef;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedPtr;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TWeakPtr;
template <typename U> friend class NAMESPACE_PRIVATE::TSharedProxy;
friend struct NAMESPACE_PRIVATE::FSharedHelper;
};
/** Shared-ownership non-nullable smart pointer. Use this when you need an array's lifetime to be managed by a shared smart pointer. */
template <typename T>
class TSharedRef<T[]> final
{
private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper;
public:
using ElementType = T;
using WeakType = TWeakPtr<T>;
/** TSharedRef cannot be initialized by nullptr. */
TSharedRef() = delete;
/** TSharedRef cannot be initialized by nullptr. */
TSharedRef(nullptr_t) = delete;
/** Constructs a shared reference that owns the specified array. Must not be nullptr. */
template <typename U = T*> requires (CPointer<U>&& CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>)
FORCEINLINE explicit TSharedRef(U InPtr) : TSharedRef(InPtr, TDefaultDelete<T[]>()) { }
/** Constructs a shared reference that owns the specified array with a deleter. Must not be nullptr. */
template <typename U = T*, typename E> requires (CConstructibleFrom<TDecay<E>, E>
&& CInvocable<TDecay<E>, TRemoveExtent<T>*> && CDestructible<TDecay<E>>
&& (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>)))
FORCEINLINE TSharedRef(U InPtr, E&& InDeleter)
: TSharedRef(InPtr, new NAMESPACE_PRIVATE::TSharedControllerWithDeleter<T, TDecay<E>>(InPtr, Forward<E>(InDeleter)))
{
checkf(InPtr != nullptr, TEXT("TSharedRef cannot be initialized by nullptr. Please use TSharedPtr."));
}
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared array, but pointing to a different array, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The array pointer to use (instead of the incoming shared pointer's array).
*/
template <typename U, typename V = T*> requires (CNullPointer<V> || (CPointer<V> && CConvertibleTo<TRemovePointer<V>(*)[], T(*)[]>))
FORCEINLINE TSharedRef(const TSharedRef<U>& InValue, V InPtr)
: Pointer(InPtr), Controller(InValue.Controller)
{
checkf(InPtr != nullptr, TEXT("TSharedRef cannot be initialized by nullptr. Please use TSharedPtr."));
Controller->AddSharedReference();
}
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared array, but pointing to a different array, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The array pointer to use (instead of the incoming shared pointer's array).
*/
template <typename U, typename V = T*> requires (CNullPointer<V> || (CPointer<V> && CConvertibleTo<TRemovePointer<V>(*)[], T(*)[]>))
FORCEINLINE TSharedRef(TSharedRef<U>&& InValue, V InPtr) : TSharedRef(InValue, InPtr) { }
/** Constructs a TSharedRef which shares ownership of the array managed by 'InValue'. */
FORCEINLINE TSharedRef(const TSharedRef& InValue) : TSharedRef(InValue, InValue.Get()) { }
/** Constructs a TSharedRef which shares ownership of the array managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedRef(const TSharedRef<U>& InValue) : TSharedRef(InValue, InValue.Get()) { }
/** Constructs a TSharedRef which shares ownership of the array managed by 'InValue'. */
FORCEINLINE TSharedRef(TSharedRef&& InValue) : TSharedRef(InValue) { }
/** Constructs a TSharedRef which shares ownership of the array managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedRef(TSharedRef<U>&& InValue) : TSharedRef(InValue) { }
/** If this owns an array and it is the last TSharedRef owning it, the array is destroyed through the owned deleter. */
FORCEINLINE ~TSharedRef() { Controller->ReleaseSharedReference(); }
/** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TSharedRef& operator=(const TSharedRef& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedRef& operator=(const TSharedRef<U>& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TSharedRef& operator=(TSharedRef&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedRef& operator=(TSharedRef<U>&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Compares the pointer values of two TSharedRef. */
template <typename U> requires (CEqualityComparable<T*, TRemoveExtent<U>*>)
NODISCARD friend FORCEINLINE constexpr bool operator==(const TSharedRef& LHS, const TSharedRef<U>& RHS) { return LHS.Get() == RHS.Get(); }
/** Compares the pointer values of two TSharedRef. */
template <typename U> requires (CThreeWayComparable<T*, TRemoveExtent<U>*>)
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TSharedRef& LHS, const TSharedRef<U>& RHS) { return LHS.Get() <=> RHS.Get(); }
/** Compares the pointer values with nullptr. */
NODISCARD FORCEINLINE constexpr bool operator==(nullptr_t) const& { return Get() == nullptr; }
/** Compares the pointer values with nullptr. */
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(nullptr_t) const& { return Get() <=> static_cast<T*>(nullptr); }
/** TSharedRef cannot be initialized by nullptr. */
void Reset(nullptr_t) = delete;
/** Replaces the managed array. */
template <typename U> requires (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>)
FORCEINLINE void Reset(U InPtr) { *this = MoveTemp(TSharedRef(InPtr)); }
/** TSharedRef cannot be initialized by nullptr. */
template <typename E>
void Reset(nullptr_t, E&&) = delete;
/** Replaces the managed array with a deleter. */
template <typename U, typename E> requires (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>
&& CConstructibleFrom<TDecay<E>, E> && CInvocable<TDecay<E>, TRemoveExtent<T>*> && CDestructible<TDecay<E>>)
FORCEINLINE void Reset(U InPtr, E&& InDeleter) { *this = MoveTemp(TSharedRef(InPtr, Forward<E>(InDeleter))); }
/** @return The pointer to the managed array. */
NODISCARD FORCEINLINE constexpr T* Get() const { return Pointer; }
/** @return The pointer to the owned deleter or nullptr. */
template <typename E> requires (CInvocable<TDecay<E>, TRemoveExtent<T>*> && (CDestructible<E> || CLValueReference<E>))
NODISCARD FORCEINLINE E* GetDeleter() const
{
const auto ControllerWithDeleter = dynamic_cast<NAMESPACE_PRIVATE::TSharedControllerWithDeleter<T, E>*>(Controller);
return ControllerWithDeleter != nullptr ? &ControllerWithDeleter->GetDeleter() : nullptr;
}
/** @return The element at index, i.e. Get()[Index]. */
NODISCARD FORCEINLINE constexpr T& operator[](size_t Index) const { return Get()[Index]; }
/**
* Returns the number of shared references to this array (including this reference.)
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return The number of instances managing the current array.
*/
NODISCARD FORCEINLINE size_t GetSharedReferenceCount() const { return Controller->GetSharedReferenceCount(); }
/**
* Checks if this is the only instance managing the current array, i.e. whether GetSharedReferenceCount() == 1.
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return true if *this is the only shared_ptr instance managing the current array, false otherwise.
*/
NODISCARD FORCEINLINE bool IsUnique() const { return GetSharedReferenceCount() == 1; }
/**
* Checks whether this TSharedRef precedes other in implementation defined owner-based (as opposed to value-based) order.
* This ensures that the ordering of TSharedRef constructed by the aliasing constructor is not affected by array pointer.
*
* @return The ordering of the addresses of the control blocks.
*/
template <typename U = T> NODISCARD FORCEINLINE strong_ordering OwnerCompare(const TSharedRef<U>& InValue) const { return Controller <=> InValue.Controller; }
template <typename U = T> NODISCARD FORCEINLINE strong_ordering OwnerCompare(const TSharedPtr<U>& InValue) const { return Controller <=> InValue.Controller; }
/** Overloads the GetTypeHash algorithm for TSharedRef. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TSharedRef& A) { return GetTypeHash(A.Get()); }
/** Overloads the Swap algorithm for TSharedRef. */
friend FORCEINLINE constexpr void Swap(TSharedRef& A, TSharedRef& B)
{
Swap(A.Pointer, B.Pointer);
Swap(A.Controller, B.Controller);
}
private:
T* Pointer;
NAMESPACE_PRIVATE::FSharedController* Controller;
FORCEINLINE TSharedRef(NAMESPACE_PRIVATE::FSharedPtrConstructor, const TSharedPtr<T[]>& InValue)
: Pointer(InValue.Pointer), Controller(InValue.Controller)
{
Controller->AddSharedReference();
}
FORCEINLINE TSharedRef(NAMESPACE_PRIVATE::FSharedPtrConstructor, TSharedPtr<T[]>&& InValue)
: Pointer(Exchange(InValue.Pointer, nullptr))
, Controller(Exchange(InValue.Controller, nullptr))
{ }
FORCEINLINE TSharedRef(T* InPtr, NAMESPACE_PRIVATE::FSharedController* InController)
: Pointer(InPtr), Controller(InController)
{
check(!((Pointer == nullptr) ^ (Controller == nullptr)));
}
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedRef;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedPtr;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TWeakPtr;
template <typename U> friend class NAMESPACE_PRIVATE::TSharedProxy;
friend struct NAMESPACE_PRIVATE::FSharedHelper;
};
/** Shared-ownership smart pointer. Use this when you need an object's lifetime to be managed by a shared smart pointer. */
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TSharedPtr final
{
private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper;
public:
using ElementType = T;
using WeakType = TWeakPtr<T>;
/** Constructs an empty shared pointer. */
FORCEINLINE constexpr TSharedPtr() : Pointer(nullptr), Controller(nullptr) { }
/** Constructs an empty shared pointer. */
FORCEINLINE constexpr TSharedPtr(nullptr_t) : TSharedPtr() { }
/** Constructs a shared pointer that owns the specified object. Note that nullptr is not managed like std. */
FORCEINLINE explicit TSharedPtr(T* InPtr) : TSharedPtr(InPtr, TDefaultDelete<T>()) { }
/** Constructs a shared pointer that owns the specified object with a deleter. Note that nullptr is not managed like std. */
template <typename E> requires (CConstructibleFrom<TDecay<E>, E>
&& CInvocable<TDecay<E>, TRemoveExtent<T>*> && CDestructible<TDecay<E>>)
FORCEINLINE TSharedPtr(T* InPtr, E&& InDeleter)
: TSharedPtr(InPtr, InPtr != nullptr ? new NAMESPACE_PRIVATE::TSharedControllerWithDeleter<T, TDecay<E>>(InPtr, Forward<E>(InDeleter)) : nullptr)
{ }
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared object, but pointing to a different object, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The object pointer to use (instead of the incoming shared pointer's object).
*/
template <typename U>
FORCEINLINE TSharedPtr(const TSharedPtr<U>& InValue, T* InPtr)
: Pointer(InPtr), Controller(InValue.Controller)
{
checkf(!((Pointer == nullptr) ^ (Controller == nullptr)), TEXT("TSharedPtr's aliasing constructor cannot be initialized by nullptr."));
if (Controller != nullptr)
{
Controller->AddSharedReference();
}
}
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared object, but pointing to a different object, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The object pointer to use (instead of the incoming shared pointer's object).
*/
template <typename U>
FORCEINLINE TSharedPtr(const TSharedRef<U>& InValue, T* InPtr)
{
new (this) TSharedRef<T>(InValue, InPtr);
}
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared object, but pointing to a different object, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The object pointer to use (instead of the incoming shared pointer's object).
*/
template <typename U>
FORCEINLINE TSharedPtr(TSharedPtr<U>&& InValue, T* InPtr)
: Pointer(InPtr), Controller(InValue.Controller)
{
checkf(!((Pointer == nullptr) ^ (Controller == nullptr)), TEXT("TSharedPtr's aliasing constructor cannot be initialized by nullptr."));
InValue.Pointer = nullptr;
InValue.Controller = nullptr;
}
/** Constructs a TSharedPtr which shares ownership of the object managed by 'InValue'. */
FORCEINLINE TSharedPtr(const TSharedPtr& InValue) : TSharedPtr(InValue, InValue.Get()) { }
/** Constructs a TSharedPtr which shares ownership of the object managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr(const TSharedPtr<U>& InValue) : TSharedPtr(InValue, InValue.Get()) { }
/** Constructs a TSharedPtr which shares ownership of the object managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr(const TSharedRef<U>& InValue) : TSharedPtr(InValue, InValue.Get()) { }
/** Constructs a TSharedPtr which shares ownership of the object managed by 'InValue'. */
FORCEINLINE TSharedPtr(TSharedPtr&& InValue) : TSharedPtr(MoveTemp(InValue), InValue.Get()) { }
/** Constructs a TSharedPtr which shares ownership of the object managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr(TSharedPtr<U>&& InValue) : TSharedPtr(MoveTemp(InValue), InValue.Get()) { }
/** Constructs a TSharedPtr which gets ownership of the object managed by 'InValue'. */
template <typename U, typename E> requires (CConvertibleTo<U*, T*> && !CArray<U> && (CDestructible<E> || CLValueReference<E>))
FORCEINLINE TSharedPtr(TUniquePtr<U, E>&& InValue) : TSharedPtr(InValue.Release(), Forward<E>(InValue.GetDeleter())) { }
/** If this owns an object and it is the last TSharedPtr owning it, the object is destroyed through the owned deleter. */
FORCEINLINE ~TSharedPtr() { if (Controller != nullptr) Controller->ReleaseSharedReference(); }
/** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TSharedPtr& operator=(const TSharedPtr& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr& operator=(const TSharedPtr<U>& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr& operator=(const TSharedRef<U>& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TSharedPtr& operator=(TSharedPtr&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr& operator=(TSharedPtr<U>&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed object with the one managed by 'InValue'. */
template <typename U, typename E> requires (CConvertibleTo<U*, T*> && !CArray<U> && (CDestructible<E> || CLValueReference<E>))
FORCEINLINE TSharedPtr& operator=(TUniquePtr<U, E>&& InValue) { return Swap(*this, TSharedPtr(MoveTemp(InValue))); }
/** Effectively the same as calling Reset(). */
FORCEINLINE TSharedPtr& operator=(nullptr_t) { Reset(); return *this; }
/** Compares the pointer values of two TSharedPtr. */
template <typename U> requires (CEqualityComparable<T*, TRemoveExtent<U>*>)
NODISCARD friend FORCEINLINE constexpr bool operator==(const TSharedPtr& LHS, const TSharedPtr<U>& RHS) { return LHS.Get() == RHS.Get(); }
/** Compares the pointer values of two TSharedPtr. */
template <typename U> requires (CThreeWayComparable<T*, TRemoveExtent<U>*>)
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TSharedPtr& LHS, const TSharedPtr<U>& RHS) { return LHS.Get() <=> RHS.Get(); }
/** Compares the pointer values with nullptr. */
NODISCARD FORCEINLINE constexpr bool operator==(nullptr_t) const& { return Get() == nullptr; }
/** Compares the pointer values with nullptr. */
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(nullptr_t) const& { return Get() <=> static_cast<T*>(nullptr); }
/** Converts a shared pointer to a shared reference. The pointer MUST be valid or an assertion will trigger. */
FORCEINLINE TSharedRef<T> ToSharedRef() const&
{
checkf(IsValid(), TEXT("TSharedRef cannot be initialized by nullptr."));
return TSharedRef<T>(NAMESPACE_PRIVATE::SharedPtrConstructor, *this);
}
/** Converts a shared pointer to a shared reference. The pointer MUST be valid or an assertion will trigger. */
FORCEINLINE TSharedRef<T> ToSharedRef() &&
{
checkf(IsValid(), TEXT("TSharedRef cannot be initialized by nullptr."));
return TSharedRef<T>(NAMESPACE_PRIVATE::SharedPtrConstructor, *this);
}
/** Replaces the managed object. */
FORCEINLINE void Reset(T* InPtr = nullptr) { *this = MoveTemp(TSharedPtr(InPtr)); }
/** Replaces the managed object with a deleter. */
template <typename E> requires (CConstructibleFrom<TDecay<E>, E>
&& CInvocable<TDecay<E>, TRemoveExtent<T>*> && CDestructible<TDecay<E>>)
FORCEINLINE void Reset(T* InPtr, E&& InDeleter) { *this = MoveTemp(TSharedPtr(InPtr, Forward<E>(InDeleter))); }
/** @return The pointer to the managed object. */
NODISCARD FORCEINLINE constexpr T* Get() const { return Pointer; }
/** @return The pointer to the owned deleter or nullptr. */
template <typename E> requires (CInvocable<TDecay<E>, TRemoveExtent<T>*> && (CDestructible<E> || CLValueReference<E>))
NODISCARD FORCEINLINE E* GetDeleter() const
{
const auto ControllerWithDeleter = dynamic_cast<NAMESPACE_PRIVATE::TSharedControllerWithDeleter<T, E>*>(Controller);
return ControllerWithDeleter != nullptr ? &ControllerWithDeleter->GetDeleter() : nullptr;
}
/** @return true if *this owns an object, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; }
/** @return The reference or pointer to the object owned by *this, i.e. Get(). */
NODISCARD FORCEINLINE constexpr T& operator*() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return *Get(); }
NODISCARD FORCEINLINE constexpr T* operator->() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get(); }
/**
* Returns the number of shared references to this object (including this reference.)
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return The number of instances managing the current object.
*/
NODISCARD FORCEINLINE size_t GetSharedReferenceCount() const { return Controller != nullptr ? Controller->GetSharedReferenceCount() : 0; }
/**
* Checks if this is the only instance managing the current object, i.e. whether GetSharedReferenceCount() == 1.
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return true if *this is the only shared_ptr instance managing the current object, false otherwise.
*/
NODISCARD FORCEINLINE bool IsUnique() const { return GetSharedReferenceCount() == 1; }
/**
* Checks whether this TSharedPtr precedes other in implementation defined owner-based (as opposed to value-based) order.
* This ensures that the ordering of TSharedPtr constructed by the aliasing constructor is not affected by object pointer.
*
* @return The ordering of the addresses of the control blocks.
*/
template <typename U = T> NODISCARD FORCEINLINE strong_ordering OwnerCompare(const TSharedRef<U>& InValue) const { return Controller <=> InValue.Controller; }
template <typename U = T> NODISCARD FORCEINLINE strong_ordering OwnerCompare(const TSharedPtr<U>& InValue) const { return Controller <=> InValue.Controller; }
/** Overloads the GetTypeHash algorithm for TSharedPtr. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TSharedPtr& A) { return GetTypeHash(A.Get()); }
/** Overloads the Swap algorithm for TSharedPtr. */
friend FORCEINLINE constexpr void Swap(TSharedPtr& A, TSharedPtr& B)
{
Swap(A.Pointer, B.Pointer);
Swap(A.Controller, B.Controller);
}
private:
T* Pointer;
NAMESPACE_PRIVATE::FSharedController* Controller;
FORCEINLINE TSharedPtr(const TWeakPtr<T>& InValue)
{
const bool bIsUnexpired = InValue.Controller != nullptr && InValue.Controller->AddSharedReferenceIfUnexpired();
Pointer = bIsUnexpired ? InValue.Pointer : nullptr;
Controller = bIsUnexpired ? InValue.Controller : nullptr;
}
FORCEINLINE TSharedPtr(T* InPtr, NAMESPACE_PRIVATE::FSharedController* InController)
: Pointer(InPtr), Controller(InController)
{
check(!((Pointer == nullptr) ^ (Controller == nullptr)));
if constexpr (CClass<T> && !CVolatile<T> && requires { typename T::SharedFromThisType; })
{
using SharedFromThisType = T::SharedFromThisType;
if constexpr (CDerivedFrom<T, SharedFromThisType>)
{
if (Pointer != nullptr)
{
const SharedFromThisType& SharedFromThis = *Pointer;
checkf(!SharedFromThis.DoesSharedInstanceExist(), TEXT("This object is incorrectly managed by multiple TSharedRef or TSharedPtr."));
SharedFromThis.WeakThis = ConstCast<TRemoveCV<T>>(*this);
}
}
}
}
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedRef;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedPtr;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TWeakPtr;
template <typename U> friend class NAMESPACE_PRIVATE::TSharedProxy;
friend struct NAMESPACE_PRIVATE::FSharedHelper;
};
/** Shared-ownership smart pointer. Use this when you need an array's lifetime to be managed by a shared smart pointer. */
template <typename T>
class TSharedPtr<T[]> final
{
private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper;
public:
using ElementType = T;
using WeakType = TWeakPtr<T>;
/** Constructs an empty shared pointer. */
FORCEINLINE constexpr TSharedPtr() : Pointer(nullptr), Controller(nullptr) { }
/** Constructs an empty shared pointer. */
FORCEINLINE constexpr TSharedPtr(nullptr_t) : TSharedPtr() { }
/** Constructs a shared pointer that owns the specified array. Note that nullptr is not managed like std. */
template <typename U = T*> requires (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>)
FORCEINLINE explicit TSharedPtr(U InPtr) : TSharedPtr(InPtr, TDefaultDelete<T[]>()) { }
/** Constructs a shared pointer that owns the specified array with a deleter. Note that nullptr is not managed like std. */
template <typename U = T*, typename E> requires (CConstructibleFrom<TDecay<E>, E>
&& CInvocable<TDecay<E>, TRemoveExtent<T>*> && CDestructible<TDecay<E>>
&& (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>)))
FORCEINLINE TSharedPtr(U InPtr, E&& InDeleter)
: TSharedPtr(InPtr, InPtr != nullptr ? new NAMESPACE_PRIVATE::TSharedControllerWithDeleter<T, TDecay<E>>(InPtr, Forward<E>(InDeleter)) : nullptr)
{ }
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared array, but pointing to a different array, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The array pointer to use (instead of the incoming shared pointer's array).
*/
template <typename U, typename V = T*> requires (CNullPointer<V> || (CPointer<V> && CConvertibleTo<TRemovePointer<V>(*)[], T(*)[]>))
FORCEINLINE TSharedPtr(const TSharedPtr<U>& InValue, V InPtr)
: Pointer(InPtr), Controller(InValue.Controller)
{
checkf(!((Pointer == nullptr) ^ (Controller == nullptr)), TEXT("TSharedPtr's aliasing constructor cannot be initialized by nullptr."));
if (Controller != nullptr)
{
Controller->AddSharedReference();
}
}
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared array, but pointing to a different array, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The array pointer to use (instead of the incoming shared pointer's array).
*/
template <typename U, typename V = T*> requires (CNullPointer<V> || (CPointer<V> && CConvertibleTo<TRemovePointer<V>(*)[], T(*)[]>))
FORCEINLINE TSharedPtr(const TSharedRef<U>& InValue, V InPtr)
{
new (this) TSharedRef<T[]>(InValue, InPtr);
}
/**
* Aliasing constructor used to create a shared reference which shares its reference count with
* another shared array, but pointing to a different array, typically a subobject.
* Must not be nullptr.
*
* @param InValue - The shared reference whose reference count should be shared.
* @param InPtr - The array pointer to use (instead of the incoming shared pointer's array).
*/
template <typename U, typename V = T*> requires (CNullPointer<V> || (CPointer<V> && CConvertibleTo<TRemovePointer<V>(*)[], T(*)[]>))
FORCEINLINE TSharedPtr(TSharedPtr<U>&& InValue, V InPtr)
: Pointer(InPtr), Controller(InValue.Controller)
{
checkf(!((Pointer == nullptr) ^ (Controller == nullptr)), TEXT("TSharedPtr's aliasing constructor cannot be initialized by nullptr."));
InValue.Pointer = nullptr;
InValue.Controller = nullptr;
}
/** Constructs a TSharedPtr which shares ownership of the array managed by 'InValue'. */
FORCEINLINE TSharedPtr(const TSharedPtr& InValue) : TSharedPtr(InValue, InValue.Get()) { }
/** Constructs a TSharedPtr which shares ownership of the array managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr(const TSharedPtr<U>& InValue) : TSharedPtr(InValue, InValue.Get()) { }
/** Constructs a TSharedPtr which shares ownership of the array managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr(const TSharedRef<U>& InValue) : TSharedPtr(InValue, InValue.Get()) { }
/** Constructs a TSharedPtr which shares ownership of the array managed by 'InValue'. */
FORCEINLINE TSharedPtr(TSharedPtr&& InValue) : TSharedPtr(MoveTemp(InValue), InValue.Get()) { }
/** Constructs a TSharedPtr which shares ownership of the array managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr(TSharedPtr<U>&& InValue) : TSharedPtr(MoveTemp(InValue), InValue.Get()) { }
/** Constructs a TSharedPtr which gets ownership of the array managed by 'InValue'. */
template <typename U, typename E> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U> && (CDestructible<E> || CLValueReference<E>))
FORCEINLINE TSharedPtr(TUniquePtr<U, E>&& InValue) : TSharedPtr(InValue.Release(), Forward<E>(InValue.GetDeleter())) { }
/** If this owns an array and it is the last TSharedPtr owning it, the array is destroyed through the owned deleter. */
FORCEINLINE ~TSharedPtr() { if (Controller != nullptr) Controller->ReleaseSharedReference(); }
/** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TSharedPtr& operator=(const TSharedPtr& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr& operator=(const TSharedPtr<U>& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr& operator=(const TSharedRef<U>& InValue) { return Helper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TSharedPtr& operator=(TSharedPtr&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr& operator=(TSharedPtr<U>&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed array with the one managed by 'InValue'. */
template <typename U, typename E> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U> && (CDestructible<E> || CLValueReference<E>))
FORCEINLINE TSharedPtr& operator=(TUniquePtr<U, E>&& InValue) { return Swap(*this, TSharedPtr(MoveTemp(InValue))); }
/** Effectively the same as calling Reset(). */
FORCEINLINE TSharedPtr& operator=(nullptr_t) { Reset(); return *this; }
/** Compares the pointer values of two TSharedPtr. */
template <typename U> requires (CEqualityComparable<T*, TRemoveExtent<U>*>)
NODISCARD friend FORCEINLINE constexpr bool operator==(const TSharedPtr& LHS, const TSharedPtr<U>& RHS) { return LHS.Get() == RHS.Get(); }
/** Compares the pointer values of two TSharedPtr. */
template <typename U> requires (CThreeWayComparable<T*, TRemoveExtent<U>*>)
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TSharedPtr& LHS, const TSharedPtr<U>& RHS) { return LHS.Get() <=> RHS.Get(); }
/** Compares the pointer values with nullptr. */
NODISCARD FORCEINLINE constexpr bool operator==(nullptr_t) const& { return Get() == nullptr; }
/** Compares the pointer values with nullptr. */
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(nullptr_t) const& { return Get() <=> static_cast<T*>(nullptr); }
/** Converts a shared pointer to a shared reference. The pointer MUST be valid or an assertion will trigger. */
FORCEINLINE TSharedRef<T[]> ToSharedRef() const&
{
checkf(IsValid(), TEXT("TSharedRef cannot be initialized by nullptr."));
return TSharedRef<T[]>(NAMESPACE_PRIVATE::SharedPtrConstructor, *this);
}
/** Converts a shared pointer to a shared reference. The pointer MUST be valid or an assertion will trigger. */
FORCEINLINE TSharedRef<T[]> ToSharedRef() &&
{
checkf(IsValid(), TEXT("TSharedRef cannot be initialized by nullptr."));
return TSharedRef<T[]>(NAMESPACE_PRIVATE::SharedPtrConstructor, *this);
}
/** Replaces the managed array. */
template <typename U = T*> requires (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>))
FORCEINLINE void Reset(U InPtr = nullptr) { *this = MoveTemp(TSharedPtr(InPtr)); }
/** Replaces the managed array with a deleter. */
template <typename U, typename E> requires (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>)
&& CConstructibleFrom<TDecay<E>, E> && CInvocable<TDecay<E>, TRemoveExtent<T>*> && CDestructible<TDecay<E>>)
FORCEINLINE void Reset(U InPtr, E&& InDeleter) { *this = MoveTemp(TSharedPtr(InPtr, Forward<E>(InDeleter))); }
/** @return The pointer to the managed array. */
NODISCARD FORCEINLINE constexpr T* Get() const { return Pointer; }
/** @return The pointer to the owned deleter or nullptr. */
template <typename E> requires (CInvocable<TDecay<E>, TRemoveExtent<T>*> && (CDestructible<E> || CLValueReference<E>))
NODISCARD FORCEINLINE E* GetDeleter() const
{
const auto ControllerWithDeleter = dynamic_cast<NAMESPACE_PRIVATE::TSharedControllerWithDeleter<T, E>*>(Controller);
return ControllerWithDeleter != nullptr ? &ControllerWithDeleter->GetDeleter() : nullptr;
}
/** @return true if *this owns an array, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; }
/** @return The element at index, i.e. Get()[Index]. */
NODISCARD FORCEINLINE constexpr T& operator[](size_t Index) const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; }
/**
* Returns the number of shared references to this array (including this reference.)
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return The number of instances managing the current array.
*/
NODISCARD FORCEINLINE size_t GetSharedReferenceCount() const { return Controller != nullptr ? Controller->GetSharedReferenceCount() : 0; }
/**
* Checks if this is the only instance managing the current array, i.e. whether GetSharedReferenceCount() == 1.
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return true if *this is the only shared_ptr instance managing the current array, false otherwise.
*/
NODISCARD FORCEINLINE bool IsUnique() const { return GetSharedReferenceCount() == 1; }
/**
* Checks whether this TSharedPtr precedes other in implementation defined owner-based (as opposed to value-based) order.
* This ensures that the ordering of TSharedPtr constructed by the aliasing constructor is not affected by array pointer.
*
* @return The ordering of the addresses of the control blocks.
*/
template <typename U = T> NODISCARD FORCEINLINE strong_ordering OwnerCompare(const TSharedRef<U>& InValue) const { return Controller <=> InValue.Controller; }
template <typename U = T> NODISCARD FORCEINLINE strong_ordering OwnerCompare(const TSharedPtr<U>& InValue) const { return Controller <=> InValue.Controller; }
/** Overloads the GetTypeHash algorithm for TSharedPtr. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TSharedPtr& A) { return GetTypeHash(A.Get()); }
/** Overloads the Swap algorithm for TSharedPtr. */
friend FORCEINLINE constexpr void Swap(TSharedPtr& A, TSharedPtr& B)
{
Swap(A.Pointer, B.Pointer);
Swap(A.Controller, B.Controller);
}
private:
T* Pointer;
NAMESPACE_PRIVATE::FSharedController* Controller;
FORCEINLINE TSharedPtr(const TWeakPtr<T[]>& InValue)
{
const bool bIsUnexpired = InValue.Controller != nullptr && InValue.Controller->AddSharedReferenceIfUnexpired();
Pointer = bIsUnexpired ? InValue.Pointer : nullptr;
Controller = bIsUnexpired ? InValue.Controller : nullptr;
}
FORCEINLINE TSharedPtr(T* InPtr, NAMESPACE_PRIVATE::FSharedController* InController)
: Pointer(InPtr), Controller(InController)
{
check(!((Pointer == nullptr) ^ (Controller == nullptr)));
}
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedRef;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedPtr;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TWeakPtr;
template <typename U> friend class NAMESPACE_PRIVATE::TSharedProxy;
friend struct NAMESPACE_PRIVATE::FSharedHelper;
};
/** TWeakPtr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by shared pointer. */
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TWeakPtr final
{
private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper;
public:
using ElementType = T;
/** Constructs an empty TWeakPtr */
FORCEINLINE constexpr TWeakPtr() : Pointer(nullptr), Controller(nullptr) { }
/** Constructs an empty TWeakPtr */
FORCEINLINE constexpr TWeakPtr(nullptr_t) : TWeakPtr() { }
/** Constructs new TWeakPtr which shares an object managed by 'InValue'. */
FORCEINLINE TWeakPtr(const TWeakPtr& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
{
if (Controller != nullptr)
{
Controller->AddWeakReference();
}
}
/** Constructs new TWeakPtr which shares an object managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE constexpr TWeakPtr(const TWeakPtr<U>& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
{
if (Controller != nullptr)
{
Controller->AddWeakReference();
}
}
/** Move constructors. Moves a TWeakPtr instance from 'InValue' into this. */
FORCEINLINE TWeakPtr(TWeakPtr&& InValue) : Pointer(Exchange(InValue.Pointer, nullptr)), Controller(Exchange(InValue.Controller, nullptr)) { }
/** Move constructors. Moves a TWeakPtr instance from 'InValue' into this. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE constexpr TWeakPtr(TWeakPtr<U>&& InValue) : Pointer(Exchange(InValue.Pointer, nullptr)), Controller(Exchange(InValue.Controller, nullptr)) { }
/** Constructs a weak pointer from a shared reference. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE constexpr TWeakPtr(const TSharedRef<U>& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
{
Controller->AddWeakReference();
}
/** Constructs a weak pointer from a shared pointer. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE constexpr TWeakPtr(const TSharedPtr<U>& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
{
if (Controller != nullptr)
{
Controller->AddWeakReference();
}
}
/** Destroys the TWeakPtr object. Results in no effect to the managed object. */
FORCEINLINE ~TWeakPtr() { if (Controller != nullptr) Controller->ReleaseWeakReference(); }
/** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TWeakPtr& operator=(const TWeakPtr& InValue) { return Helper::CopyWeakReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TWeakPtr<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TWeakPtr& operator=(TWeakPtr&& InValue) { return Helper::MoveWeakReference(*this, MoveTemp(InValue)); }
/** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TWeakPtr& operator=(TWeakPtr<U>&& InValue) { return Helper::MoveWeakReference(*this, MoveTemp(InValue)); }
/** Assignment operator sets this weak pointer from a shared reference. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TSharedRef<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); }
/** Assignment operator sets this weak pointer from a shared pointer. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TSharedPtr<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); }
/** Effectively the same as calling Reset(). */
FORCEINLINE TWeakPtr& operator=(nullptr_t) { Reset(); return *this; }
/** Resets this weak pointer, removing a weak reference to the object. */
FORCEINLINE void Reset()
{
if (Controller != nullptr)
{
Controller->ReleaseWeakReference();
Pointer = nullptr;
Controller = nullptr;
}
}
/**
* Returns the number of shared references to this object (Excluding this reference.)
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return The number of instances managing the current object.
*/
NODISCARD FORCEINLINE size_t GetSharedReferenceCount() const { return Controller != nullptr ? Controller->GetSharedReferenceCount() : 0; }
/** @return true if the weak pointer is expired and a lock operator would have failed. */
NODISCARD FORCEINLINE bool Expired() const { return GetSharedReferenceCount() == 0; }
/** A TSharedPtr which shares ownership of the owned object if Expired() returns false. Else returns nullptr. */
NODISCARD FORCEINLINE TSharedPtr<T> Lock() const { return *this; }
/** Overloads the Swap algorithm for TWeakPtr. */
friend FORCEINLINE constexpr void Swap(TWeakPtr& A, TWeakPtr& B)
{
Swap(A.Pointer, B.Pointer);
Swap(A.Controller, B.Controller);
}
private:
T* Pointer;
NAMESPACE_PRIVATE::FSharedController* Controller;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedRef;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedPtr;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TWeakPtr;
friend struct NAMESPACE_PRIVATE::FSharedHelper;
};
/** TWeakPtr is a smart pointer that holds a non-owning ("weak") reference to an array that is managed by shared pointer. */
template <typename T>
class TWeakPtr<T[]> final
{
private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper;
public:
using ElementType = T;
/** Constructs an empty TWeakPtr */
FORCEINLINE constexpr TWeakPtr() : Pointer(nullptr), Controller(nullptr) { }
/** Constructs an empty TWeakPtr */
FORCEINLINE constexpr TWeakPtr(nullptr_t) : TWeakPtr() { }
/** Constructs new TWeakPtr which shares an array managed by 'InValue'. */
FORCEINLINE TWeakPtr(const TWeakPtr& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
{
if (Controller != nullptr)
{
Controller->AddWeakReference();
}
}
/** Constructs new TWeakPtr which shares an array managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE constexpr TWeakPtr(const TWeakPtr<U>& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
{
if (Controller != nullptr)
{
Controller->AddWeakReference();
}
}
/** Move constructors. Moves a TWeakPtr instance from 'InValue' into this. */
FORCEINLINE TWeakPtr(TWeakPtr&& InValue) : Pointer(Exchange(InValue.Pointer, nullptr)), Controller(Exchange(InValue.Controller, nullptr)) { }
/** Move constructors. Moves a TWeakPtr instance from 'InValue' into this. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE constexpr TWeakPtr(TWeakPtr<U>&& InValue) : Pointer(Exchange(InValue.Pointer, nullptr)), Controller(Exchange(InValue.Controller, nullptr)) { }
/** Constructs a weak pointer from a shared reference. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE constexpr TWeakPtr(const TSharedRef<U>& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
{
Controller->AddWeakReference();
}
/** Constructs a weak pointer from a shared pointer. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE constexpr TWeakPtr(const TSharedPtr<U>& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
{
if (Controller != nullptr)
{
Controller->AddWeakReference();
}
}
/** Destroys the TWeakPtr array. Results in no effect to the managed array. */
FORCEINLINE ~TWeakPtr() { if (Controller != nullptr) Controller->ReleaseWeakReference(); }
/** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TWeakPtr& operator=(const TWeakPtr& InValue) { return Helper::CopyWeakReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TWeakPtr<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TWeakPtr& operator=(TWeakPtr&& InValue) { return Helper::MoveWeakReference(*this, MoveTemp(InValue)); }
/** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TWeakPtr& operator=(TWeakPtr<U>&& InValue) { return Helper::MoveWeakReference(*this, MoveTemp(InValue)); }
/** Assignment operator sets this weak pointer from a shared reference. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TSharedRef<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); }
/** Assignment operator sets this weak pointer from a shared pointer. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TSharedPtr<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); }
/** Effectively the same as calling Reset(). */
FORCEINLINE TWeakPtr& operator=(nullptr_t) { Reset(); return *this; }
/** Resets this weak pointer, removing a weak reference to the array. */
FORCEINLINE void Reset()
{
if (Controller != nullptr)
{
Controller->ReleaseWeakReference();
Pointer = nullptr;
Controller = nullptr;
}
}
/**
* Returns the number of shared references to this array (Excluding this reference.)
* IMPORTANT: With multi-threading this is only an estimate.
*
* @return The number of instances managing the current array.
*/
NODISCARD FORCEINLINE size_t GetSharedReferenceCount() const { return Controller != nullptr ? Controller->GetSharedReferenceCount() : 0; }
/** @return true if the weak pointer is expired and a lock operator would have failed. */
NODISCARD FORCEINLINE bool Expired() const { return GetSharedReferenceCount() == 0; }
/** A TSharedPtr which shares ownership of the owned array if Expired() returns false. Else returns nullptr. */
NODISCARD FORCEINLINE TSharedPtr<T[]> Lock() const { return *this; }
/** Overloads the Swap algorithm for TWeakPtr. */
friend FORCEINLINE constexpr void Swap(TWeakPtr& A, TWeakPtr& B)
{
Swap(A.Pointer, B.Pointer);
Swap(A.Controller, B.Controller);
}
private:
T* Pointer;
NAMESPACE_PRIVATE::FSharedController* Controller;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedRef;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TSharedPtr;
template <typename U> requires (CObject<U> && !CBoundedArray<U>) friend class TWeakPtr;
friend struct NAMESPACE_PRIVATE::FSharedHelper;
};
/** Constructs an object of type T and wraps it in a TSharedRef or TSharedPtr. */
template <typename T, typename... Ts> requires (CObject<T> && !CArray<T> && CConstructibleFrom<T, Ts...> && CDestructible<T>)
NODISCARD FORCEINLINE NAMESPACE_PRIVATE::TSharedProxy<T> MakeShared(Ts&&... Args)
{
const auto Controller = new NAMESPACE_PRIVATE::TSharedControllerWithObject<T>(Forward<Ts>(Args)...);
return NAMESPACE_PRIVATE::TSharedProxy<T>(Controller->GetPointer(), Controller);
}
/** Constructs an array of type T and wraps it in a TSharedRef or TSharedPtr. */
template <typename T> requires (CUnboundedArray<T> && CDefaultConstructible<TRemoveExtent<T>> && CDestructible<TRemoveExtent<T>>)
NODISCARD FORCEINLINE NAMESPACE_PRIVATE::TSharedProxy<T> MakeShared(size_t N)
{
const auto Controller = NAMESPACE_PRIVATE::TSharedControllerWithArray<TRemoveExtent<T>>::New(N);
return NAMESPACE_PRIVATE::TSharedProxy<T>(Controller->GetPointer(), Controller);
}
/** Construction of arrays of known bound is disallowed. */
template <typename T, typename... Ts> requires (CBoundedArray<T>)
void MakeShared(Ts&&...) = delete;
/** Creates a new instance of TSharedRef whose stored pointer is obtained from stored pointer of 'InValue' using a static_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { static_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedRef<T> StaticCast(const TSharedRef<U>& InValue)
{
return TSharedRef<T>(InValue, static_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedRef whose stored pointer is obtained from stored pointer of 'InValue' using a static_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { static_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedRef<T> StaticCast(TSharedRef<U>&& InValue)
{
return TSharedRef<T>(MoveTemp(InValue), static_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedRef whose stored pointer is obtained from stored pointer of 'InValue' using a dynamic_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { dynamic_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedRef<T> DynamicCast(const TSharedRef<U>& InValue)
{
return TSharedRef<T>(InValue, dynamic_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedRef whose stored pointer is obtained from stored pointer of 'InValue' using a dynamic_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { dynamic_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedRef<T> DynamicCast(TSharedRef<U>&& InValue)
{
return TSharedRef<T>(MoveTemp(InValue), dynamic_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedRef whose stored pointer is obtained from stored pointer of 'InValue' using a const_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { const_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedRef<T> ConstCast(const TSharedRef<U>& InValue)
{
return TSharedRef<T>(InValue, const_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedRef whose stored pointer is obtained from stored pointer of 'InValue' using a const_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { const_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedRef<T> ConstCast(TSharedRef<U>&& InValue)
{
return TSharedRef<T>(MoveTemp(InValue), const_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedRef whose stored pointer is obtained from stored pointer of 'InValue' using a reinterpret_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { reinterpret_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedRef<T> ReinterpretCast(const TSharedRef<U>& InValue)
{
return TSharedRef<T>(InValue, reinterpret_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedRef whose stored pointer is obtained from stored pointer of 'InValue' using a reinterpret_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { reinterpret_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedRef<T> ReinterpretCast(TSharedRef<U>&& InValue)
{
return TSharedRef<T>(MoveTemp(InValue), reinterpret_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedPtr whose stored pointer is obtained from stored pointer of 'InValue' using a static_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { static_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedPtr<T> StaticCast(const TSharedPtr<U>& InValue)
{
return TSharedPtr<T>(InValue, static_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedPtr whose stored pointer is obtained from stored pointer of 'InValue' using a static_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { static_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedPtr<T> StaticCast(TSharedPtr<U>&& InValue)
{
return TSharedPtr<T>(MoveTemp(InValue), static_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedPtr whose stored pointer is obtained from stored pointer of 'InValue' using a dynamic_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { dynamic_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedPtr<T> DynamicCast(const TSharedPtr<U>& InValue)
{
return TSharedPtr<T>(InValue, dynamic_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedPtr whose stored pointer is obtained from stored pointer of 'InValue' using a dynamic_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { dynamic_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedPtr<T> DynamicCast(TSharedPtr<U>&& InValue)
{
return TSharedPtr<T>(MoveTemp(InValue), dynamic_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedPtr whose stored pointer is obtained from stored pointer of 'InValue' using a const_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { const_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedPtr<T> ConstCast(const TSharedPtr<U>& InValue)
{
return TSharedPtr<T>(InValue, const_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedPtr whose stored pointer is obtained from stored pointer of 'InValue' using a const_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { const_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedPtr<T> ConstCast(TSharedPtr<U>&& InValue)
{
return TSharedPtr<T>(MoveTemp(InValue), const_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedPtr whose stored pointer is obtained from stored pointer of 'InValue' using a reinterpret_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { reinterpret_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedPtr<T> ReinterpretCast(const TSharedPtr<U>& InValue)
{
return TSharedPtr<T>(InValue, reinterpret_cast<T*>(InValue.Get()));
}
/** Creates a new instance of TSharedPtr whose stored pointer is obtained from stored pointer of 'InValue' using a reinterpret_cast expression. */
template <typename T, typename U> requires (requires(U* InPtr) { reinterpret_cast<T*>(InPtr); })
NODISCARD FORCEINLINE TSharedPtr<T> ReinterpretCast(TSharedPtr<U>&& InValue)
{
return TSharedPtr<T>(MoveTemp(InValue), reinterpret_cast<T*>(InValue.Get()));
}
DEFINE_TPointerTraits(TSharedRef);
DEFINE_TPointerTraits(TSharedPtr);
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END