#pragma once #include "CoreTypes.h" #include "Templates/Invoke.h" #include "Templates/Utility.h" #include "Templates/TypeHash.h" #include "Memory/PointerTraits.h" #include "Templates/Noncopyable.h" #include "TypeTraits/TypeTraits.h" #include "Miscellaneous/Compare.h" NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_PRIVATE_BEGIN template && !CFinal> class TUniqueStorage; template class TUniqueStorage : private E { public: FORCEINLINE constexpr TUniqueStorage() = delete; FORCEINLINE constexpr TUniqueStorage(T* InPtr) : E(), Pointer(InPtr) { } template FORCEINLINE constexpr TUniqueStorage(T* InPtr, U&& InDeleter) : E(Forward(InDeleter)), Pointer(InPtr) { } FORCEINLINE constexpr TUniqueStorage(const TUniqueStorage&) = delete; FORCEINLINE constexpr TUniqueStorage(TUniqueStorage&& InValue) = default; FORCEINLINE constexpr TUniqueStorage& operator=(const TUniqueStorage&) = delete; FORCEINLINE constexpr TUniqueStorage& operator=(TUniqueStorage&&) = default; FORCEINLINE constexpr T*& GetPointer() { return Pointer; } FORCEINLINE constexpr T* GetPointer() const { return Pointer; } FORCEINLINE constexpr E& GetDeleter() { return *this; } FORCEINLINE constexpr const E& GetDeleter() const { 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 class TUniqueStorage { public: FORCEINLINE constexpr TUniqueStorage() = delete; FORCEINLINE constexpr TUniqueStorage(T* InPtr) : E(), Pointer(InPtr) { } template FORCEINLINE constexpr TUniqueStorage(T* InPtr, U&& InDeleter) : Pointer(InPtr), Deleter(Forward(InDeleter)) { } FORCEINLINE constexpr TUniqueStorage(const TUniqueStorage&) = delete; FORCEINLINE constexpr TUniqueStorage(TUniqueStorage&& InValue) = default; FORCEINLINE constexpr TUniqueStorage& operator=(const TUniqueStorage&) = delete; FORCEINLINE constexpr TUniqueStorage& operator=(TUniqueStorage&&) = default; FORCEINLINE constexpr T*& GetPointer() { return Pointer; } FORCEINLINE constexpr T* GetPointer() const { return Pointer; } FORCEINLINE constexpr E& GetDeleter() { return Deleter; } FORCEINLINE constexpr const E& GetDeleter() const { return Deleter; } private: T* Pointer; E Deleter; }; NAMESPACE_PRIVATE_END /** TDefaultDelete is the default destruction policy used by TUniquePtr when no deleter is specified. */ template requires ((!CArray && requires(T* Ptr) { delete Ptr; }) || (CArray && requires(TRemoveExtent* Ptr) { delete [] Ptr; })) struct TDefaultDelete { /** Constructs a TDefaultDelete object. */ FORCEINLINE constexpr TDefaultDelete() = default; /** Constructs a TDefaultDelete object from another TDefaultDelete object. */ template requires (CConvertibleTo) FORCEINLINE constexpr TDefaultDelete(TDefaultDelete) { } /** Calls delete on ptr. */ FORCEINLINE constexpr void operator()(T* Ptr) const { static_assert(!CVoid, "Can't delete pointer to incomplete type"); static_assert(sizeof(T) > 0, "Can't delete pointer to incomplete type"); delete Ptr; } }; /** TDefaultDelete is the default destruction policy used by TUniquePtr when no deleter is specified. */ template struct TDefaultDelete { /** Constructs a TDefaultDelete object. */ FORCEINLINE constexpr TDefaultDelete() = default; /** Constructs a TDefaultDelete object from another TDefaultDelete object. */ template requires (CConvertibleTo) FORCEINLINE constexpr TDefaultDelete(TDefaultDelete) { } /** Calls delete [] on ptr. */ FORCEINLINE constexpr void operator()(T* Ptr) const { static_assert(!CVoid, "Can't delete pointer to incomplete type"); static_assert(sizeof(T) > 0, "Can't delete pointer to incomplete type"); delete [] Ptr; } }; template *> E = TDefaultDelete> requires (CObject && !CBoundedArray && (CDestructible || CLValueReference)) class TUniqueRef; template *> E = TDefaultDelete> requires (CObject && !CBoundedArray && (CDestructible || CLValueReference)) class TUniquePtr; NAMESPACE_PRIVATE_BEGIN template struct TIsTUniqueRef : FFalse { }; template struct TIsTUniqueRef> : FTrue { }; template struct TIsTUniquePtr : FFalse { }; template struct TIsTUniquePtr> : FTrue { }; NAMESPACE_PRIVATE_END template concept CTUniqueRef = NAMESPACE_PRIVATE::TIsTUniqueRef>::Value; template concept CTUniquePtr = NAMESPACE_PRIVATE::TIsTUniquePtr>::Value; NAMESPACE_PRIVATE_BEGIN template class TUniqueProxy : private FSingleton { public: FORCEINLINE TUniqueProxy(TRemoveExtent* InPtr) : Pointer(InPtr) { } # if DO_CHECK FORCEINLINE ~TUniqueProxy() { checkf(Pointer == nullptr, TEXT("The return value from MakeUnique() is incorrectly ignored.")); } # endif private: TRemoveExtent* Pointer; template *> E> requires (CObject && !CBoundedArray && (CDestructible || CLValueReference)) friend class NAMESPACE_REDCRAFT::TUniqueRef; template *> E> requires (CObject && !CBoundedArray && (CDestructible || CLValueReference)) friend class NAMESPACE_REDCRAFT::TUniquePtr; }; NAMESPACE_PRIVATE_END /** This is essentially a reference version of TUniquePtr. */ template *> E> requires (CObject && !CBoundedArray && (CDestructible || CLValueReference)) class TUniqueRef final : private FSingleton { public: using ElementType = T; using DeleterType = E; /** TUniqueRef cannot be initialized by nullptr. */ TUniqueRef() = delete; /** TUniqueRef cannot be initialized by nullptr. */ TUniqueRef(nullptr_t) = delete; /** Constructs a TUniqueRef which owns 'InPtr', initializing the stored pointer with 'InPtr' and value-initializing the stored deleter. */ FORCEINLINE constexpr explicit TUniqueRef(T* InPtr) requires(CDefaultConstructible && !CPointer) : Storage(InPtr) { checkf(InPtr != nullptr, TEXT("TUniqueRef cannot be initialized by nullptr. Please use TUniquePtr.")); } /** Constructs a TUniqueRef object which owns 'InPtr', initializing the stored pointer with 'InPtr' and initializing a deleter 'InDeleter' */ template requires (CConvertibleTo) FORCEINLINE constexpr TUniqueRef(T* InPtr, InE&& InDeleter) : Storage(InPtr, Forward(InDeleter)) { checkf(InPtr != nullptr, TEXT("TUniqueRef cannot be initialized by nullptr. Please use TUniquePtr.")); } /** Destroy the owned object. */ FORCEINLINE constexpr ~TUniqueRef() { Invoke(GetDeleter(), Get()); } /** Compares the pointer values of two TUniqueRef. */ template requires (CEqualityComparable*>) NODISCARD friend FORCEINLINE constexpr bool operator==(const TUniqueRef& LHS, const TUniqueRef& RHS) { return LHS.Get() == RHS.Get(); } /** Compares the pointer values of two TUniqueRef. */ template requires (CThreeWayComparable*>) NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TUniqueRef& LHS, const TUniqueRef& 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(nullptr); } /** TUniqueRef cannot be reset to nullptr. */ void Reset(nullptr_t) = delete; /** Replaces the managed object. */ FORCEINLINE constexpr void Reset(T* InPtr) { checkf(InPtr != nullptr, TEXT("TUniqueRef cannot be initialized by nullptr. Please use TUniquePtr.")); Invoke(GetDeleter(), Get()); Storage.GetPointer() = InPtr; } /** TUniqueRef cannot be reset to nullptr. */ template void Reset(nullptr_t, InE&&) = delete; /** Replaces the managed object. */ template requires (CConvertibleTo) FORCEINLINE constexpr void Reset(T* InPtr, InE&& InDeleter) { Reset(InPtr); GetDeleter() = Forward(InDeleter); } /** TUniqueRef cannot be reset to nullptr. */ T* ReleaseAndReset(nullptr_t) = delete; /** Equivalent to Release() then Reset(InPtr). */ FORCEINLINE constexpr T* ReleaseAndReset(T* InPtr) { checkf(InPtr != nullptr, TEXT("TUniqueRef cannot be initialized by nullptr. Please use TUniquePtr.")); return Exchange(Storage.GetPointer(), InPtr); } /** TUniqueRef cannot be reset to nullptr. */ template T* ReleaseAndReset(nullptr_t, InE&&) = delete; /** Equivalent to Release() then Reset(InPtr, Forward(InDeleter)). */ template requires (CConvertibleTo) FORCEINLINE constexpr T* ReleaseAndReset(T* InPtr, InE&& InDeleter) { GetDeleter() = Forward(InDeleter); return ReleaseAndReset(InPtr); } /** @return The pointer to the managed object. */ NODISCARD FORCEINLINE constexpr T* Get() const { return Storage.GetPointer(); } /** @return The deleter that is used for destruction of the managed object. */ NODISCARD FORCEINLINE constexpr E& GetDeleter() { return Storage.GetDeleter(); } NODISCARD FORCEINLINE constexpr const E& GetDeleter() const { return Storage.GetDeleter(); } /** @return The a 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(); } /** Overloads the GetTypeHash algorithm for TUniqueRef. */ NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TUniqueRef& A) { return GetTypeHash(A.Get()); } /** Overloads the Swap algorithm for TUniqueRef. */ friend FORCEINLINE constexpr void Swap(TUniqueRef& A, TUniqueRef& B) requires (!CReference && CSwappable) { Swap(A.Storage.GetPointer(), B.Storage.GetPointer()); Swap(A.Storage.GetDeleter(), B.Storage.GetDeleter()); } public: template requires (CConvertibleTo && !CArray && CSameAs>) FORCEINLINE TUniqueRef(NAMESPACE_PRIVATE::TUniqueProxy&& InValue) : Storage(InValue.Pointer) { check_code({ InValue.Pointer = nullptr; }); } private: NAMESPACE_PRIVATE::TUniqueStorage Storage; }; template TUniqueRef(T*) -> TUniqueRef; /** This is essentially a reference version of TUniquePtr. */ template class TUniqueRef final : private FSingleton { public: using ElementType = T; using DeleterType = E; /** TUniqueRef cannot be initialized by nullptr. */ TUniqueRef() = delete; /** TUniqueRef cannot be initialized by nullptr. */ TUniqueRef(nullptr_t) = delete; /** Constructs a TUniqueRef which owns 'InPtr', initializing the stored pointer with 'InPtr' and value-initializing the stored deleter. */ template requires (CPointer && CConvertibleTo(*)[], T(*)[]>) FORCEINLINE constexpr explicit TUniqueRef(U InPtr) requires(CDefaultConstructible && !CPointer) : Storage(InPtr) { checkf(InPtr != nullptr, TEXT("TUniqueRef cannot be initialized by nullptr. Please use TUniquePtr.")); } /** Constructs a TUniqueRef object which owns 'InPtr', initializing the stored pointer with 'InPtr' and initializing a deleter 'InDeleter' */ template requires (CConvertibleTo && (CPointer && CConvertibleTo(*)[], T(*)[]>)) FORCEINLINE constexpr TUniqueRef(U InPtr, InE&& InDeleter) : Storage(InPtr, Forward(InDeleter)) { checkf(InPtr != nullptr, TEXT("TUniqueRef cannot be initialized by nullptr. Please use TUniquePtr.")); } /** Destroy the owned array. */ FORCEINLINE constexpr ~TUniqueRef() { Invoke(GetDeleter(), Get()); } /** Compares the pointer values of two TUniqueRef. */ template requires (CEqualityComparable*>) NODISCARD friend FORCEINLINE constexpr bool operator==(const TUniqueRef& LHS, const TUniqueRef& RHS) { return LHS.Get() == RHS.Get(); } /** Compares the pointer values of two TUniqueRef. */ template requires (CThreeWayComparable*>) NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TUniqueRef& LHS, const TUniqueRef& 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(nullptr); } /** TUniqueRef cannot be reset to nullptr. */ void Reset(nullptr_t) = delete; /** Replaces the managed array. */ template requires (CPointer && CConvertibleTo(*)[], T(*)[]>) FORCEINLINE constexpr void Reset(U InPtr) { checkf(InPtr != nullptr, TEXT("TUniqueRef cannot be initialized by nullptr. Please use TUniquePtr.")); Invoke(GetDeleter(), Get()); Storage.GetPointer() = InPtr; } /** TUniqueRef cannot be reset to nullptr. */ template void Reset(nullptr_t, InE&&) = delete; /** Replaces the managed array. */ template requires (CConvertibleTo && (CPointer && CConvertibleTo(*)[], T(*)[]>)) FORCEINLINE constexpr void Reset(U InPtr, InE&& InDeleter) { Reset(InPtr); GetDeleter() = Forward(InDeleter); } /** TUniqueRef cannot be reset to nullptr. */ T* ReleaseAndReset(nullptr_t) = delete; /** Equivalent to Release() then Reset(InPtr). */ template requires (CPointer && CConvertibleTo(*)[], T(*)[]>) FORCEINLINE constexpr T* ReleaseAndReset(U InPtr) { checkf(InPtr != nullptr, TEXT("TUniqueRef cannot be initialized by nullptr. Please use TUniquePtr.")); return Exchange(Storage.GetPointer(), InPtr); } /** TUniqueRef cannot be reset to nullptr. */ template T* ReleaseAndReset(nullptr_t, InE&&) = delete; /** Equivalent to Release() then Reset(InPtr, Forward(InDeleter)). */ template requires (CConvertibleTo && (CPointer && CConvertibleTo(*)[], T(*)[]>)) FORCEINLINE constexpr T* ReleaseAndReset(U InPtr, InE&& InDeleter) { GetDeleter() = Forward(InDeleter); return ReleaseAndReset(InPtr); } /** @return The pointer to the managed array. */ NODISCARD FORCEINLINE constexpr T* Get() const { return Storage.GetPointer(); } /** @return The deleter that is used for destruction of the managed array. */ NODISCARD FORCEINLINE constexpr E& GetDeleter() { return Storage.GetDeleter(); } NODISCARD FORCEINLINE constexpr const E& GetDeleter() const { return Storage.GetDeleter(); } /** @return The element at index, i.e. Get()[Index]. */ NODISCARD FORCEINLINE constexpr T& operator[](size_t Index) const { return Get()[Index]; } /** Overloads the GetTypeHash algorithm for TUniqueRef. */ NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TUniqueRef& A) { return GetTypeHash(A.Get()); } /** Overloads the Swap algorithm for TUniqueRef. */ friend FORCEINLINE constexpr void Swap(TUniqueRef& A, TUniqueRef& B) requires (!CReference && CSwappable) { Swap(A.Storage.GetPointer(), B.Storage.GetPointer()); Swap(A.Storage.GetDeleter(), B.Storage.GetDeleter()); } public: template requires (CConvertibleTo(*)[], T(*)[]> && CArray && CSameAs>) FORCEINLINE TUniqueRef(NAMESPACE_PRIVATE::TUniqueProxy&& InValue) : Storage(InValue.Pointer) { check_code({ InValue.Pointer = nullptr; }); } private: NAMESPACE_PRIVATE::TUniqueStorage Storage; }; /** Single-ownership smart pointer. Use this when you need an object's lifetime to be strictly bound to the lifetime of a single smart pointer. */ template *> E> requires (CObject && !CBoundedArray && (CDestructible || CLValueReference)) class TUniquePtr final : private FNoncopyable { public: using ElementType = T; using DeleterType = E; /** Constructs a TUniquePtr that owns nothing. Value-initializes the stored pointer and the stored deleter. */ FORCEINLINE constexpr TUniquePtr() requires(CDefaultConstructible && !CPointer) : Storage(nullptr) { } /** Constructs a TUniquePtr that owns nothing. Value-initializes the stored pointer and the stored deleter. */ FORCEINLINE constexpr TUniquePtr(nullptr_t) requires(CDefaultConstructible && !CPointer) : TUniquePtr() { } /** Constructs a TUniquePtr which owns 'InPtr', initializing the stored pointer with 'InPtr' and value-initializing the stored deleter. */ FORCEINLINE constexpr explicit TUniquePtr(T* InPtr) requires(CDefaultConstructible && !CPointer) : Storage(InPtr) { } /** Constructs a TUniquePtr object which owns 'InPtr', initializing the stored pointer with 'InPtr' and initializing a deleter 'InDeleter' */ template requires (CConvertibleTo) FORCEINLINE constexpr TUniquePtr(T* InPtr, InE&& InDeleter) : Storage(InPtr, Forward(InDeleter)) { } /** Constructs a TUniquePtr by transferring ownership from 'InValue' to *this and stores the nullptr in 'InValue'. */ FORCEINLINE constexpr TUniquePtr(TUniquePtr&& InValue) : Storage(InValue.Release(), Forward(InValue.GetDeleter())) { } /** Constructs a TUniquePtr by transferring ownership from 'InValue' to *this and stores the nullptr in 'InValue'. */ template requires (CConvertibleTo && !CArray && ((CReference && CSameAs) || (!CReference && CConvertibleTo))) FORCEINLINE constexpr TUniquePtr(TUniquePtr&& InValue) : Storage(InValue.Release(), Forward(InValue.GetDeleter())) { } /** If !IsValid() there are no effects. Otherwise, the owned object is destroyed. */ FORCEINLINE constexpr ~TUniquePtr() { if (IsValid()) Invoke(GetDeleter(), Get()); } /** Move assignment operator. Transfers ownership from 'InValue' to *this. */ FORCEINLINE constexpr TUniquePtr& operator=(TUniquePtr&& InValue) requires (!CReference && CAssignableFrom) { Reset(InValue.Release()); GetDeleter() = Forward(InValue.GetDeleter()); return *this; } /** Move assignment operator. Transfers ownership from 'InValue' to *this. */ template requires (CConvertibleTo && !CArray && !CReference && CAssignableFrom) FORCEINLINE constexpr TUniquePtr& operator=(TUniquePtr&& InValue) { Reset(InValue.Release()); GetDeleter() = Forward(InValue.GetDeleter()); return *this; } /** Effectively the same as calling Reset(). */ FORCEINLINE constexpr TUniquePtr& operator=(nullptr_t) { Reset(); return *this; } /** Compares the pointer values of two TUniquePtr. */ template requires (CEqualityComparable*>) NODISCARD friend FORCEINLINE constexpr bool operator==(const TUniquePtr& LHS, const TUniquePtr& RHS) { return LHS.Get() == RHS.Get(); } /** Compares the pointer values of two TUniquePtr. */ template requires (CThreeWayComparable*>) NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TUniquePtr& LHS, const TUniquePtr& 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(nullptr); } /** Returns a pointer to the managed object and releases the ownership. */ NODISCARD FORCEINLINE constexpr T* Release() { return Exchange(Storage.GetPointer(), nullptr); } /** Replaces the managed object. */ FORCEINLINE constexpr void Reset(T* InPtr = nullptr) { if (IsValid()) Invoke(GetDeleter(), Get()); Storage.GetPointer() = InPtr; } /** Replaces the managed object. */ template requires (CConvertibleTo) FORCEINLINE constexpr void Reset(T* InPtr, InE&& InDeleter) { Reset(InPtr); GetDeleter() = Forward(InDeleter); } /** Equivalent to Release() then Reset(InPtr). */ FORCEINLINE constexpr T* ReleaseAndReset(T* InPtr = nullptr) { return Exchange(Storage.GetPointer(), InPtr); } /** Equivalent to Release() then Reset(InPtr, Forward(InDeleter)). */ template requires (CConvertibleTo) FORCEINLINE constexpr T* ReleaseAndReset(T* InPtr, InE&& InDeleter) { GetDeleter() = Forward(InDeleter); return ReleaseAndReset(InPtr); } /** @return The pointer to the managed object or nullptr if no object is owned. */ NODISCARD FORCEINLINE constexpr T* Get() const { return Storage.GetPointer(); } /** @return The deleter that is used for destruction of the managed object. */ NODISCARD FORCEINLINE constexpr E& GetDeleter() { return Storage.GetDeleter(); } NODISCARD FORCEINLINE constexpr const E& GetDeleter() const { return Storage.GetDeleter(); } /** @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 a 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(); } /** Overloads the GetTypeHash algorithm for TUniquePtr. */ NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TUniquePtr& A) { return GetTypeHash(A.Get()); } /** Overloads the Swap algorithm for TUniquePtr. */ friend FORCEINLINE constexpr void Swap(TUniquePtr& A, TUniquePtr& B) requires (!CReference && CSwappable) { Swap(A.Storage.GetPointer(), B.Storage.GetPointer()); Swap(A.Storage.GetDeleter(), B.Storage.GetDeleter()); } public: template requires (CConvertibleTo && !CArray && CSameAs>) FORCEINLINE TUniquePtr(NAMESPACE_PRIVATE::TUniqueProxy&& InValue) : Storage(InValue.Pointer) { check_code({ InValue.Pointer = nullptr; }); } private: NAMESPACE_PRIVATE::TUniqueStorage Storage; template *> OtherE> requires (CObject && !CBoundedArray && (CDestructible || CLValueReference)) friend class TUniquePtr; }; template TUniquePtr(T*) -> TUniquePtr; /** Single-ownership smart pointer. Use this when you need an array's lifetime to be strictly bound to the lifetime of a single smart pointer. */ template class TUniquePtr final : private FNoncopyable { public: using ElementType = T; using DeleterType = E; /** Constructs a TUniquePtr that owns nothing. Value-initializes the stored pointer and the stored deleter. */ FORCEINLINE constexpr TUniquePtr() requires(CDefaultConstructible && !CPointer) : Storage(nullptr) { } /** Constructs a TUniquePtr that owns nothing. Value-initializes the stored pointer and the stored deleter. */ FORCEINLINE constexpr TUniquePtr(nullptr_t) requires(CDefaultConstructible && !CPointer) : TUniquePtr() { } /** Constructs a TUniquePtr which owns 'InPtr', initializing the stored pointer with 'InPtr' and value-initializing the stored deleter. */ template requires (CPointer && CConvertibleTo(*)[], T(*)[]>) FORCEINLINE constexpr explicit TUniquePtr(U InPtr) requires(CDefaultConstructible && !CPointer) : Storage(InPtr) { } /** Constructs a TUniquePtr object which owns 'InPtr', initializing the stored pointer with 'InPtr' and initializing a deleter 'InDeleter' */ template requires (CConvertibleTo && (CNullPointer || (CPointer && CConvertibleTo(*)[], T(*)[]>))) FORCEINLINE constexpr TUniquePtr(U InPtr, InE&& InDeleter) : Storage(InPtr, Forward(InDeleter)) { } /** Constructs a TUniquePtr by transferring ownership from 'InValue' to *this and stores the nullptr in 'InValue'. */ FORCEINLINE constexpr TUniquePtr(TUniquePtr&& InValue) : Storage(InValue.Release(), Forward(InValue.GetDeleter())) { } /** Constructs a TUniquePtr by transferring ownership from 'InValue' to *this and stores the nullptr in 'InValue'. */ template requires (CConvertibleTo(*)[], T(*)[]> && CArray && ((CReference && CSameAs) || (!CReference && CConvertibleTo))) FORCEINLINE constexpr TUniquePtr(TUniquePtr&& InValue) : Storage(InValue.Release(), Forward(InValue.GetDeleter())) { } /** If !IsValid() there are no effects. Otherwise, the owned array is destroyed. */ FORCEINLINE constexpr ~TUniquePtr() { if (IsValid()) Invoke(GetDeleter(), Get()); } /** Move assignment operator. Transfers ownership from 'InValue' to *this. */ FORCEINLINE constexpr TUniquePtr& operator=(TUniquePtr&& InValue) requires (!CReference && CAssignableFrom) { Reset(InValue.Release()); GetDeleter() = Forward(InValue.GetDeleter()); return *this; } /** Move assignment operator. Transfers ownership from 'InValue' to *this. */ template requires (CConvertibleTo(*)[], T(*)[]> && CArray && !CReference && CAssignableFrom) FORCEINLINE constexpr TUniquePtr& operator=(TUniquePtr&& InValue) { Reset(InValue.Release()); GetDeleter() = Forward(InValue.GetDeleter()); return *this; } /** Effectively the same as calling Reset(). */ FORCEINLINE constexpr TUniquePtr& operator=(nullptr_t) { Reset(); return *this; } /** Compares the pointer values of two TUniquePtr. */ template requires (CEqualityComparable*>) NODISCARD friend FORCEINLINE constexpr bool operator==(const TUniquePtr& LHS, const TUniquePtr& RHS) { return LHS.Get() == RHS.Get(); } /** Compares the pointer values of two TUniquePtr. */ template requires (CThreeWayComparable*>) NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TUniquePtr& LHS, const TUniquePtr& 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(nullptr); } /** Returns a pointer to the managed array and releases the ownership. */ NODISCARD FORCEINLINE constexpr T* Release() { return Exchange(Storage.GetPointer(), nullptr); } /** Replaces the managed array. */ template requires (CNullPointer || (CPointer && CConvertibleTo(*)[], T(*)[]>)) FORCEINLINE constexpr void Reset(U InPtr = nullptr) { if (IsValid()) Invoke(GetDeleter(), Get()); Storage.GetPointer() = InPtr; } /** Replaces the managed array. */ template requires (CConvertibleTo && CNullPointer || (CPointer && CConvertibleTo(*)[], T(*)[]>)) FORCEINLINE constexpr void Reset(U InPtr, InE&& InDeleter) { Reset(InPtr); GetDeleter() = Forward(InDeleter); } /** Equivalent to Release() then Reset(InPtr). */ template requires (CNullPointer || (CPointer && CConvertibleTo(*)[], T(*)[]>)) FORCEINLINE constexpr T* ReleaseAndReset(U InPtr = nullptr) { return Exchange(Storage.GetPointer(), InPtr); } /** Equivalent to Release() then Reset(InPtr, Forward(InDeleter)). */ template requires (CConvertibleTo && CNullPointer || (CPointer && CConvertibleTo(*)[], T(*)[]>)) FORCEINLINE constexpr T* ReleaseAndReset(U InPtr, InE&& InDeleter) { GetDeleter() = Forward(InDeleter); return ReleaseAndReset(InPtr); } /** @return The pointer to the managed array or nullptr if no array is owned. */ NODISCARD FORCEINLINE constexpr T* Get() const { return Storage.GetPointer(); } /** @return The deleter that is used for destruction of the managed array. */ NODISCARD FORCEINLINE constexpr E& GetDeleter() { return Storage.GetDeleter(); } NODISCARD FORCEINLINE constexpr const E& GetDeleter() const { return Storage.GetDeleter(); } /** @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]; } /** Overloads the GetTypeHash algorithm for TUniquePtr. */ NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TUniquePtr& A) { return GetTypeHash(A.Get()); } /** Overloads the Swap algorithm for TUniquePtr. */ friend FORCEINLINE constexpr void Swap(TUniquePtr& A, TUniquePtr& B) requires (!CReference && CSwappable) { Swap(A.Storage.GetPointer(), B.Storage.GetPointer()); Swap(A.Storage.GetDeleter(), B.Storage.GetDeleter()); } public: template requires (CConvertibleTo(*)[], T(*)[]> && CArray && CSameAs>) FORCEINLINE TUniquePtr(NAMESPACE_PRIVATE::TUniqueProxy&& InValue) : Storage(InValue.Pointer) { check_code({ InValue.Pointer = nullptr; }); } private: NAMESPACE_PRIVATE::TUniqueStorage Storage; template *> OtherE> requires (CObject && !CBoundedArray && (CDestructible || CLValueReference)) friend class TUniquePtr; }; /** Constructs an object of type T and wraps it in a TUniquePtr. */ template requires (CObject && !CArray && CConstructibleFrom && CDestructible) NODISCARD FORCEINLINE constexpr NAMESPACE_PRIVATE::TUniqueProxy MakeUnique(Ts&&... Args) { if constexpr (sizeof...(Ts) == 0) { return NAMESPACE_PRIVATE::TUniqueProxy(new T); } else { return NAMESPACE_PRIVATE::TUniqueProxy(new T(Forward(Args)...)); } } /** Constructs an array of type T and wraps it in a TUniquePtr. */ template requires (CUnboundedArray && CDefaultConstructible> && CDestructible>) NODISCARD FORCEINLINE constexpr NAMESPACE_PRIVATE::TUniqueProxy MakeUnique(size_t N) { return NAMESPACE_PRIVATE::TUniqueProxy(new TRemoveExtent[N]); } /** Construction of arrays of known bound is disallowed. */ template requires (CBoundedArray) void MakeUnique(Ts&&...) = delete; static_assert(sizeof(TUniqueRef) == sizeof(int32*), "The byte size of TUniqueRef is unexpected"); static_assert(sizeof(TUniquePtr) == sizeof(int32*), "The byte size of TUniquePtr is unexpected"); DEFINE_TPointerTraits(TUniqueRef); DEFINE_TPointerTraits(TUniquePtr); NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END