feat(memory): add TObserverPtr and the corresponding testing

This commit is contained in:
_Redstone_c_ 2023-01-20 22:40:54 +08:00
parent 1b2ea5c2a6
commit 0d99fad3f0
3 changed files with 219 additions and 0 deletions

View File

@ -6,6 +6,7 @@
#include "Memory/UniquePointer.h"
#include "Memory/SharedPointer.h"
#include "Memory/MemoryOperator.h"
#include "Memory/ObserverPointer.h"
#include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN
@ -23,6 +24,7 @@ void TestMemory()
TestPointerTraits();
TestUniquePointer();
TestSharedPointer();
TestObserverPointer();
}
void TestAlignment()
@ -1031,6 +1033,71 @@ void TestSharedPointer()
}
void TestObserverPointer()
{
{
int32 IntA;
int32 IntB;
TObserverPtr<int32> TempA;
TObserverPtr<int32> TempB = nullptr;
TObserverPtr<int32> TempC(&IntA);
TObserverPtr<int32> TempD(TempC);
TempA = TempC;
TempB = MakeObserver<int32>(&IntB);
always_check(TempA == TempC);
always_check(TempB == &IntB);
always_check(TempB.IsValid());
always_check(TempA.Release() == &IntA);
always_check(!TempA.IsValid());
TempA.Reset(&IntA);
always_check(TempA == &IntA);
always_check(GetTypeHash(TempA) == GetTypeHash(&IntA));
Swap(TempA, TempB);
always_check(TempA == &IntB);
always_check(TempB == &IntA);
}
{
int32 IntA[4];
int32 IntB[4];
TObserverPtr<int32[]> TempA;
TObserverPtr<int32[]> TempB = nullptr;
TObserverPtr<int32[]> TempC(IntA);
TObserverPtr<int32[]> TempD(TempC);
TempA = TempC;
TempB = MakeObserver<int32[]>(IntB);
always_check(TempA == TempC);
always_check(TempB == IntB);
always_check(TempB.IsValid());
always_check(TempA.Release() == IntA);
always_check(!TempA.IsValid());
TempA.Reset(IntA);
always_check(TempA == IntA);
always_check(GetTypeHash(TempA) == GetTypeHash(&IntA));
Swap(TempA, TempB);
always_check(TempA == IntB);
always_check(TempB == IntA);
}
}
NAMESPACE_END(Testing)
NAMESPACE_MODULE_END(Utility)

View File

@ -0,0 +1,151 @@
#pragma once
#include "CoreTypes.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "Memory/PointerTraits.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TObserverPtr;
NAMESPACE_PRIVATE_BEGIN
template <typename T> struct TIsTObserverPtr : FFalse { };
template <typename T> struct TIsTObserverPtr<TObserverPtr<T>> : FTrue { };
NAMESPACE_PRIVATE_END
template <typename T>
concept CTObserverPtr = NAMESPACE_PRIVATE::TIsTObserverPtr<TRemoveCV<T>>::Value;
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
class TObserverPtr
{
public:
using ElementType = T;
FORCEINLINE constexpr TObserverPtr() : Pointer(nullptr) { }
FORCEINLINE constexpr TObserverPtr(nullptr_t) : TObserverPtr() { }
FORCEINLINE constexpr explicit TObserverPtr(T* InPtr) : Pointer(InPtr) { }
FORCEINLINE constexpr TObserverPtr(const TObserverPtr&) = default;
FORCEINLINE constexpr TObserverPtr(TObserverPtr&&) = default;
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE constexpr TObserverPtr(TObserverPtr<U> InValue) : Pointer(InValue.Pointer) { }
FORCEINLINE constexpr ~TObserverPtr() = default;
FORCEINLINE constexpr TObserverPtr& operator=(const TObserverPtr&) = default;
FORCEINLINE constexpr TObserverPtr& operator=(TObserverPtr&&) = default;
NODISCARD friend FORCEINLINE constexpr bool operator==(const TObserverPtr& LHS, const TObserverPtr& RHS) { return LHS.Get() == RHS.Get(); }
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TObserverPtr& LHS, const TObserverPtr& RHS) { return LHS.Get() <=> RHS.Get(); }
NODISCARD FORCEINLINE constexpr bool operator==(T* InPtr) const& { return Get() == InPtr; }
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(T* InPtr) const& { return Get() <=> InPtr; }
NODISCARD FORCEINLINE constexpr T* Release() { return Exchange(Pointer, nullptr); }
FORCEINLINE constexpr void Reset(T* InPtr = nullptr) { Pointer = InPtr; }
NODISCARD FORCEINLINE constexpr T* Get() const { return Pointer; }
NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; }
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(); }
NODISCARD FORCEINLINE constexpr operator ElementType*() { return Get(); }
NODISCARD FORCEINLINE constexpr operator const ElementType*() const { return Get(); }
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TObserverPtr& A) { return GetTypeHash(A.Get()); }
friend FORCEINLINE constexpr void Swap(TObserverPtr& A, TObserverPtr& B) { Swap(A.Pointer, B.Pointer); }
private:
T* Pointer;
};
template <typename T>
class TObserverPtr<T[]>
{
public:
using ElementType = T;
FORCEINLINE constexpr TObserverPtr() : Pointer(nullptr) { }
FORCEINLINE constexpr TObserverPtr(nullptr_t) : TObserverPtr() { }
template <typename U = T*> requires (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>)
FORCEINLINE constexpr explicit TObserverPtr(U InPtr) : Pointer(InPtr) { }
FORCEINLINE constexpr TObserverPtr(const TObserverPtr&) = default;
FORCEINLINE constexpr TObserverPtr(TObserverPtr&&) = default;
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE constexpr TObserverPtr(TObserverPtr<U> InValue) : Pointer(InValue.Pointer) { }
FORCEINLINE constexpr ~TObserverPtr() = default;
FORCEINLINE constexpr TObserverPtr& operator=(const TObserverPtr&) = default;
FORCEINLINE constexpr TObserverPtr& operator=(TObserverPtr&&) = default;
NODISCARD friend FORCEINLINE constexpr bool operator==(const TObserverPtr& LHS, const TObserverPtr& RHS) { return LHS.Get() == RHS.Get(); }
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TObserverPtr& LHS, const TObserverPtr& RHS) { return LHS.Get() <=> RHS.Get(); }
template <typename U = T*> requires (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>))
NODISCARD FORCEINLINE constexpr bool operator==(U InPtr) const& { return Get() == InPtr; }
template <typename U = T*> requires (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>))
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(U InPtr) const& { return Get() <=> InPtr; }
NODISCARD FORCEINLINE constexpr T* Release() { return Exchange(Pointer, nullptr); }
template <typename U = T*> requires (CNullPointer<U> || (CPointer<U> && CConvertibleTo<TRemovePointer<U>(*)[], T(*)[]>))
FORCEINLINE constexpr void Reset(U InPtr = nullptr) { Pointer = InPtr; }
NODISCARD FORCEINLINE constexpr T* Get() const { return Pointer; }
NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr T& operator[](size_t Index) const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; }
NODISCARD FORCEINLINE constexpr operator ElementType*() { return Get(); }
NODISCARD FORCEINLINE constexpr operator const ElementType*() const { return Get(); }
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TObserverPtr& A) { return GetTypeHash(A.Get()); }
friend FORCEINLINE constexpr void Swap(TObserverPtr& A, TObserverPtr& B) { Swap(A.Pointer, B.Pointer); }
private:
T* Pointer;
};
template <typename T> requires (CObject<T> && !CBoundedArray<T>)
NODISCARD FORCEINLINE constexpr TObserverPtr<T> MakeObserver(TRemoveExtent<T>* InPtr) { return TObserverPtr<T>(InPtr); }
DEFINE_TPointerTraits(TObserverPtr);
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -16,6 +16,7 @@ REDCRAFTUTILITY_API void TestMemoryOperator();
REDCRAFTUTILITY_API void TestPointerTraits();
REDCRAFTUTILITY_API void TestUniquePointer();
REDCRAFTUTILITY_API void TestSharedPointer();
REDCRAFTUTILITY_API void TestObserverPointer();
NAMESPACE_END(Testing)