1892 lines
80 KiB
C++
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
|