diff --git a/Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp b/Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp index 8f0cc00..519d6b9 100644 --- a/Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp @@ -18,6 +18,7 @@ NAMESPACE_BEGIN(Testing) void TestMemory() { + TestAddress(); TestAlignment(); TestMemoryBuffer(); TestMemoryMalloc(); @@ -29,6 +30,41 @@ void TestMemory() TestInOutPointer(); } +NAMESPACE_UNNAMED_BEGIN + +template +struct TTestStructA +{ + T* Pad; + T* Data; + + TTestStructA(T* InData) : Pad(nullptr), Data(InData) { } + ~TTestStructA() { delete Data; } + T** operator&() { return &Data; } +}; + +template +int32 TestFunctionB(TTestStructA*) +{ + return 0; +} + +template +int32 TestFunctionB(T**) +{ + return 1; +} + +NAMESPACE_UNNAMED_END + +void TestAddress() +{ + TTestStructA ObjectA(new int32(3)); + always_check(TestFunctionB(&ObjectA) == 1); + always_check(TestFunctionB(AddressOf(ObjectA)) == 0); + always_check(AddressOf(TestAddress) == &TestAddress); +} + void TestAlignment() { int32 Unaligned = 0xAAAA; @@ -47,7 +83,7 @@ void TestAlignment() int32 AlignedArbitrary16 = Memory::AlignArbitrary(Unaligned, 16); int32 AlignedArbitrary32 = Memory::AlignArbitrary(Unaligned, 32); int32 AlignedArbitrary64 = Memory::AlignArbitrary(Unaligned, 64); - + always_check((Memory::IsAligned(Aligned8, 8) && Aligned8 > Unaligned)); always_check((Memory::IsAligned(Aligned16, 16) && Aligned16 > Unaligned)); always_check((Memory::IsAligned(Aligned32, 32) && Aligned32 > Unaligned)); @@ -75,7 +111,7 @@ void TestMemoryBuffer() uint8* PtrB = reinterpret_cast(&TempB); uint8* PtrC = reinterpret_cast(&TempC); uint8* PtrD = reinterpret_cast(&TempD); - + TempA = 0x0123456789ABCDEF; TempB = 0x0123456789AB0000; Memory::Memmove(PtrA, PtrA + 2, 6); @@ -295,7 +331,7 @@ void TestUniquePointer() always_check(TempC != TempB); always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempC <=> TempB) != strong_ordering::equal); - + int32 TempNum; TempNum = FCounter::Num; @@ -310,7 +346,7 @@ void TestUniquePointer() FCounter* PtrX = TempB.ReleaseAndReset(new FCounter); always_check(FCounter::Num == TempNum + 1); delete PtrX; - + TempNum = FCounter::Num; FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter()); always_check(FCounter::Num == TempNum + 1); @@ -331,7 +367,7 @@ void TestUniquePointer() Temp[0] = 15; always_check(Temp.Get()[0] = 15); } - + FCounter::Num = 0; FArrayDeleter::Num = 0; @@ -348,7 +384,7 @@ void TestUniquePointer() always_check(TempC != TempB); always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempC <=> TempB) != strong_ordering::equal); - + int32 TempNum; TempNum = FCounter::Num; @@ -363,7 +399,7 @@ void TestUniquePointer() FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]); always_check(FCounter::Num == TempNum + 4); delete [] PtrX; - + TempNum = FCounter::Num; FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter()); always_check(FCounter::Num == TempNum + 4); @@ -378,7 +414,7 @@ void TestUniquePointer() always_check( FCounter::Num == 0); always_check(FArrayDeleter::Num == 4); - + { TUniquePtr Temp = MakeUnique(); *Temp = 15; @@ -401,7 +437,7 @@ void TestUniquePointer() always_check(TempC != TempB); always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempC <=> TempB) != strong_ordering::equal); - + int32 TempNum; TempNum = FCounter::Num; @@ -416,7 +452,7 @@ void TestUniquePointer() FCounter* PtrX = TempB.ReleaseAndReset(new FCounter); always_check(FCounter::Num == TempNum + 1); delete PtrX; - + TempNum = FCounter::Num; FCounter* PtrY = TempB.ReleaseAndReset(new FCounter, FDeleter()); always_check(FCounter::Num == TempNum + 1); @@ -466,7 +502,7 @@ void TestUniquePointer() always_check(TempC != TempB); always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempC <=> TempB) != strong_ordering::equal); - + int32 TempNum; TempNum = FCounter::Num; @@ -481,7 +517,7 @@ void TestUniquePointer() FCounter* PtrX = TempB.ReleaseAndReset(new FCounter[4]); always_check(FCounter::Num == TempNum + 4); delete [] PtrX; - + TempNum = FCounter::Num; FCounter* PtrY = TempB.ReleaseAndReset(new FCounter[4], FArrayDeleter()); always_check(FCounter::Num == TempNum + 4); @@ -544,13 +580,13 @@ void TestSharedPointer() always_check(TempC != TempB); always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempC <=> TempB) != strong_ordering::equal); - + int32 TempNum; TempNum = FCounter::Num; TempB.Reset(new FCounter, FDeleter()); always_check(FCounter::Num == TempNum); - + TempNum = FCounter::Num; TempC.Reset(new FCounter, FDeleter()); always_check(FCounter::Num == TempNum); @@ -562,7 +598,7 @@ void TestSharedPointer() always_check(TempA.GetDeleter() == nullptr); always_check(TempC.GetDeleter() != nullptr); always_check(TempC.GetDeleter()->Num == 2); - + TSharedRef TempD(MoveTemp(TempB)); } @@ -591,7 +627,7 @@ void TestSharedPointer() always_check(TempC != TempB); always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempC <=> TempB) != strong_ordering::equal); - + int32 TempNum; TempNum = FCounter::Num; @@ -632,7 +668,7 @@ void TestSharedPointer() always_check(TempC != TempB); always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempC <=> TempB) != strong_ordering::equal); - + int32 TempNum; TempNum = FCounter::Num; @@ -688,7 +724,7 @@ void TestSharedPointer() always_check(TempC != TempB); always_check((TempA <=> nullptr) == strong_ordering::greater); always_check((TempC <=> TempB) != strong_ordering::equal); - + int32 TempNum; TempNum = FCounter::Num; @@ -1080,12 +1116,12 @@ void TestInOutPointer() { { TUniquePtr Temp; - + [](int64** InPtr) { *InPtr = new int64; } (OutPtr(Temp)); always_check(Temp.IsValid()); Temp.Reset(); - + [](int64** InPtr) { *InPtr = new int64; } (OutPtr(Temp, TDefaultDelete())); always_check(Temp.IsValid()); } diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index 0d68e86..85b91bf 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -70,7 +70,7 @@ void TestReferenceWrapper() always_check(TempB(1, 1, 1) == 1); TempB.Get() = &TestFunctionA; always_check(TempA(1, 1, 1) == 3); - + int32 ArrayA[3] = { 1, 2, 3 }; TReferenceWrapper ArrayB[3] = { ArrayA[1], ArrayA[0], ArrayA[2] }; always_check(ArrayB[0] == 2); @@ -164,7 +164,7 @@ void TestOptional() always_check(GetTypeHash(MakeOptional(114)) == GetTypeHash(MakeOptional(114))); always_check(GetTypeHash(MakeOptional(114)) != GetTypeHash(MakeOptional(514))); } - + { TOptional TempA = Invalid; TOptional TempB = 16; @@ -257,7 +257,7 @@ void TestVariant() { using VariantType = TVariant; VariantType TempArray[] = { 10, 15ll, 1.5 }; - + for(auto&& TempA : TempArray) { Visit( @@ -273,7 +273,7 @@ void TestVariant() ); VariantType TempB = Visit([](auto&& A) -> VariantType { return A + A; }, TempA); - + Visit( [](auto&& A, auto&& B) { @@ -287,7 +287,7 @@ void TestVariant() ); Visit([](auto&& A) { A *= 2; }, TempA); - + Visit( [](auto&& A) { @@ -300,7 +300,7 @@ void TestVariant() TempA ); } - + for (auto&& TempA : TempArray) { Visit( TOverloaded @@ -414,7 +414,7 @@ void TestVariant() auto ReturnRD = Visit(TestQualifiers, MoveTemp(TempRD)); always_check((CSameAs)); } - + { always_check(GetTypeHash(TVariant(114)) == GetTypeHash(TVariant(114))); always_check(GetTypeHash(TVariant(114)) != GetTypeHash(TVariant(514))); @@ -569,16 +569,16 @@ void TestAny() FAny TempD(InPlaceType, 0.0); FAny TempG(TempA); FAny TempH(TempC); - + FAny TempK, TempL, TempM, TempN; TempK = TempA; TempL = TempD; TempM = FAny(FFloating(0.0)); TempN = FAny(Invalid); - + TempL = FFloating(303.0); TempM = FFloating(404.0); - + FAny TempO; TempO.Emplace(202.0); TempO.Emplace(404.0); @@ -692,7 +692,7 @@ void TestTuple() always_check((CSameAs&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs&&>().GetValue<0>()), const volatile int32&&>)); always_check((CSameAs&&>().GetValue<0>()), const volatile int32&&>)); - + always_check((CSameAs&>().GetValue<0>()), int32&>)); always_check((CSameAs&>().GetValue<0>()), const int32&>)); always_check((CSameAs&>().GetValue<0>()), volatile int32&>)); @@ -773,7 +773,7 @@ void TestTuple() always_check((CSameAs>, const volatile double>)); always_check((CSameAs>, float&>)); always_check((CSameAs>, char&&>)); - + always_check((TTupleIndex> == 0)); always_check((TTupleIndex> == 1)); always_check((TTupleIndex> == 2)); @@ -816,7 +816,7 @@ void TestTuple() Temp.Fourteenth = 0; Temp.Fifteenth = 0; Temp.Sixteenth = 0; - + always_check(CDefaultConstructible); always_check(CTriviallyDefaultConstructible); always_check(CConstructibleFrom); @@ -906,7 +906,7 @@ void TestTuple() { int32 TempO = 15; TTuple TempA = { MoveTemp(TempO), 514 }; - + TempA.Apply( [](auto&& A, auto&& B) { @@ -916,7 +916,7 @@ void TestTuple() always_check((CSameAs)); } ); - + MoveTemp(TempA).Apply( [](auto&& A, auto&& B) { @@ -943,7 +943,7 @@ void TestTuple() ); VisitTuple([](auto&& A) { A++; }, TempB); - + VisitTuple( [] (T&& A) { @@ -1146,7 +1146,7 @@ void TestFunction() // TFunction ObjectG = MoveTemp(UniqueA); TUniqueFunction UniqueG = MoveTemp(UniqueA); } - + { TFunctionRef RefA = [] { }; TFunction ObjectA = [] { }; @@ -1163,7 +1163,7 @@ void TestFunction() // TFunctionRef RefD; RefD = UniqueA; // TFunction ObjectD; ObjectD = UniqueA; // TUniqueFunction UniqueD; UniqueD = UniqueA; - + // TFunctionRef RefE; RefE = MoveTemp(RefA); // TFunction ObjectE; ObjectE = MoveTemp(RefA); // TUniqueFunction UniqueE; UniqueE = MoveTemp(RefA); @@ -1279,7 +1279,7 @@ void TestAtomic() { { TAtomic TempA; - + always_check(TempA.bIsAlwaysLockFree); always_check((TempA = 11) == 11); TempA.Store(12); @@ -1510,42 +1510,10 @@ void TestPropagateConst() } } -NAMESPACE_UNNAMED_BEGIN - -template -struct TTestStructA -{ - T* Pad; - T* Data; - - TTestStructA(T* InData) : Pad(nullptr), Data(InData) { } - ~TTestStructA() { delete Data; } - T** operator&() { return &Data; } -}; - -template -int32 TestFunctionB(TTestStructA* Ptr) -{ - return 0; -} - -template -int32 TestFunctionB(T** Ptr) -{ - return 1; -} - -NAMESPACE_UNNAMED_END - void TestMiscTemplates() { - TTestStructA ObjectA(new int32(3)); - always_check(TestFunctionB(&ObjectA) == 1); - always_check(TestFunctionB(AddressOf(ObjectA)) == 0); - always_check(AddressOf(TestMiscTemplates) == &TestMiscTemplates); - struct FTestRetainedRef { explicit FTestRetainedRef(TRetainedRef InRef) { } }; - + int64 IntA; FTestRetainedRef TempA(IntA); // FTestRetainedRef TempB(114514); diff --git a/Redcraft.Utility/Source/Public/Containers/ArrayView.h b/Redcraft.Utility/Source/Public/Containers/ArrayView.h index 26e4112..9c4630c 100644 --- a/Redcraft.Utility/Source/Public/Containers/ArrayView.h +++ b/Redcraft.Utility/Source/Public/Containers/ArrayView.h @@ -1,6 +1,7 @@ #pragma once #include "CoreTypes.h" +#include "Memory/Address.h" #include "Memory/Allocator.h" #include "Containers/Array.h" #include "Templates/Utility.h" @@ -58,7 +59,7 @@ public: { checkf(Extent == DynamicExtent || Extent == InCount, TEXT("Illegal range count. Please check InCount.")); - Impl.Pointer = AddressOf(*InFirst); + Impl.Pointer = ToAddress(InFirst); if constexpr (Extent == DynamicExtent) { @@ -72,7 +73,7 @@ public: { checkf(Extent == DynamicExtent || Extent == InLast - InFirst, TEXT("Illegal range iterator. Please check InLast - InFirst.")); - Impl.Pointer = AddressOf(*InFirst); + Impl.Pointer = ToAddress(InFirst); if constexpr (Extent == DynamicExtent) { @@ -84,7 +85,8 @@ public: template requires (Extent == DynamicExtent || N == Extent) FORCEINLINE constexpr TArrayView(ElementType(&InArray)[N]) { - Impl.Pointer = AddressOf(InArray[0]); + // @TODO: Refactor this to use the GetData() function. + Impl.Pointer = InArray; if constexpr (Extent == DynamicExtent) { @@ -114,7 +116,8 @@ public: { checkf(Extent == DynamicExtent || Extent == InValue.Num(), TEXT("Illegal view extent. Please check InValue.Num().")); - Impl.Pointer = AddressOf(InValue[0]); + // @TODO: Refactor this to use the GetData() function. + Impl.Pointer = InValue.GetData().Get(); if constexpr (Extent == DynamicExtent) { diff --git a/Redcraft.Utility/Source/Public/Containers/Iterator.h b/Redcraft.Utility/Source/Public/Containers/Iterator.h index 93429c8..9e9f08a 100644 --- a/Redcraft.Utility/Source/Public/Containers/Iterator.h +++ b/Redcraft.Utility/Source/Public/Containers/Iterator.h @@ -1,6 +1,7 @@ #pragma once #include "CoreTypes.h" +#include "Memory/Address.h" #include "Templates/Invoke.h" #include "Templates/Utility.h" #include "Templates/Noncopyable.h" @@ -128,7 +129,7 @@ concept CContiguousIterator = CRandomAccessIterator && CLValueReference, TRemoveCVRef>> && requires(I& Iter) { - { AddressOf(*Iter) } -> CSameAs>>; + { ToAddress(Iter) } -> CSameAs>>; }; static_assert(CContiguousIterator); @@ -173,8 +174,8 @@ public: template requires (CSizedSentinelFor) NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult operator<=>(const TReverseIterator& LHS, const TReverseIterator& RHS) { return RHS.GetBase() <=> LHS.GetBase(); } - NODISCARD FORCEINLINE constexpr TIteratorReferenceType operator*() const { IteratorType Temp = GetBase(); return *--Temp; } - NODISCARD FORCEINLINE constexpr TIteratorPointerType operator->() const { return AddressOf(operator*()); } + NODISCARD FORCEINLINE constexpr TIteratorReferenceType operator*() const { IteratorType Temp = GetBase(); return *--Temp; } + NODISCARD FORCEINLINE constexpr TIteratorPointerType operator->() const { IteratorType Temp = GetBase(); return ToAddress(--Temp); } NODISCARD FORCEINLINE constexpr TIteratorReferenceType operator[](ptrdiff Index) const requires (CRandomAccessIterator) { return GetBase()[-Index - 1]; } @@ -402,7 +403,7 @@ public: NODISCARD FORCEINLINE constexpr TIteratorReferenceType operator*() const requires (CDereferenceable) { CheckThis(true); return *Current; } - NODISCARD FORCEINLINE constexpr TIteratorPointerType operator->() const requires (CContiguousIterator) { CheckThis(true); return AddressOf(operator*()); } + NODISCARD FORCEINLINE constexpr TIteratorPointerType operator->() const requires (CContiguousIterator) { CheckThis(true); return ToAddress(Current); } NODISCARD FORCEINLINE constexpr TIteratorReferenceType operator[](ptrdiff Index) const requires (CRandomAccessIterator) { TCountedIterator Temp = *this + Index; return *Temp; } diff --git a/Redcraft.Utility/Source/Public/Memory/Address.h b/Redcraft.Utility/Source/Public/Memory/Address.h new file mode 100644 index 0000000..1849d19 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Memory/Address.h @@ -0,0 +1,43 @@ +#pragma once + +#include "CoreTypes.h" +#include "Memory/PointerTraits.h" +#include "TypeTraits/TypeTraits.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +/** Obtains a raw pointer from a pointer-like type. */ +template requires (TPointerTraits::bIsPointer || requires(const T& Ptr) { Ptr.operator->(); }) +constexpr auto ToAddress(const T& Ptr) noexcept +{ + if constexpr (TPointerTraits::bIsPointer) { + return TPointerTraits::ToAddress(Ptr); + } + else { + return ToAddress(Ptr.operator->()); + } +} + +/** Obtains the actual address of the object or function arg, even in presence of overloaded operator&. */ +template requires (CObject) +FORCEINLINE constexpr T* AddressOf(T& Object) +{ + return reinterpret_cast(&const_cast(reinterpret_cast(Object))); +} + +/** Obtains the actual address of the object or function arg, even in presence of overloaded operator&. */ +template requires (!CObject) +FORCEINLINE constexpr T* AddressOf(T& Object) +{ + return &Object; +} + +/** Rvalue overload is deleted to prevent taking the address of const rvalues. */ +template +const T* AddressOf(const T&&) = delete; + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Memory/PointerTraits.h b/Redcraft.Utility/Source/Public/Memory/PointerTraits.h index 7d1b8ec..433789f 100644 --- a/Redcraft.Utility/Source/Public/Memory/PointerTraits.h +++ b/Redcraft.Utility/Source/Public/Memory/PointerTraits.h @@ -7,7 +7,7 @@ NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) /** The class template provides the standardized way to access certain properties of pointer-like types. */ -template +template struct TPointerTraits { static constexpr bool bIsPointer = false; @@ -21,7 +21,7 @@ struct TPointerTraits using PointerType = T*; using ElementType = T; - + static FORCEINLINE constexpr ElementType* ToAddress(PointerType InPtr) { return InPtr; diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/ConstantIterator.h b/Redcraft.Utility/Source/Public/Miscellaneous/ConstantIterator.h index 1bd99ab..40d0066 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/ConstantIterator.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/ConstantIterator.h @@ -1,6 +1,7 @@ #pragma once #include "CoreTypes.h" +#include "Memory/Address.h" #include "Templates/Utility.h" #include "Containers/Iterator.h" #include "Miscellaneous/Compare.h" @@ -45,7 +46,8 @@ public: FORCEINLINE constexpr TConstantIterator& operator=(TConstantIterator&&) requires (CMoveAssignable) = default; - NODISCARD FORCEINLINE constexpr const T& operator*() const { return Value; } + NODISCARD FORCEINLINE constexpr const T& operator*() const { return Value; } + NODISCARD FORCEINLINE constexpr const T* operator->() const { return AddressOf(Value); } FORCEINLINE constexpr TConstantIterator& operator++() { return *this; } @@ -89,7 +91,8 @@ public: template requires (CConvertibleTo) FORCEINLINE constexpr TConstantIterator& operator=(const TConstantIterator& InValue) { Ptr = InValue.Ptr; return *this; } - NODISCARD FORCEINLINE constexpr const T& operator*() const { return *Ptr; } + NODISCARD FORCEINLINE constexpr const T& operator*() const { return *Ptr; } + NODISCARD FORCEINLINE constexpr const T* operator->() const { return Ptr; } FORCEINLINE constexpr TConstantIterator& operator++() { return *this; } @@ -154,8 +157,8 @@ public: NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(FDefaultSentinel) const& { return static_cast(0) <=> Length; } - NODISCARD FORCEINLINE constexpr const TRemoveReference& operator*() const { CheckThis(true); return *Current; } - NODISCARD FORCEINLINE constexpr const TRemoveReference* operator->() const { CheckThis(true); return AddressOf(operator*()); } + NODISCARD FORCEINLINE constexpr const TRemoveReference& operator*() const { CheckThis(true); return *Current; } + NODISCARD FORCEINLINE constexpr const TRemoveReference* operator->() const { CheckThis(true); return ToAddress(Current); } NODISCARD FORCEINLINE constexpr const TRemoveReference& operator[](ptrdiff) const { return *this; } diff --git a/Redcraft.Utility/Source/Public/String/String.h b/Redcraft.Utility/Source/Public/String/String.h index 322489c..30c4bce 100644 --- a/Redcraft.Utility/Source/Public/String/String.h +++ b/Redcraft.Utility/Source/Public/String/String.h @@ -117,22 +117,22 @@ public: FORCEINLINE TString& operator=(TString&& InValue) { NativeData = MoveTemp(InValue.NativeData); InValue.NativeData.PushBack(LITERAL(ElementType, '\0')); return *this; } /** Compares the contents of two strings. */ - FORCEINLINE NODISCARD friend bool operator==(const TString& LHS, const TString& RHS) { return TStringView(LHS) == TStringView(RHS); } + NODISCARD friend FORCEINLINE bool operator==(const TString& LHS, const TString& RHS) { return TStringView(LHS) == TStringView(RHS); } /** Compares the contents of a string and a character. */ - FORCEINLINE NODISCARD friend bool operator==(const TString& LHS, ElementType RHS) { return TStringView(LHS) == RHS; } - FORCEINLINE NODISCARD friend bool operator==(const TString& LHS, const ElementType* RHS) { return TStringView(LHS) == RHS; } - FORCEINLINE NODISCARD friend bool operator==( ElementType LHS, const TString& RHS) { return LHS == TStringView(RHS); } - FORCEINLINE NODISCARD friend bool operator==(const ElementType* LHS, const TString& RHS) { return LHS == TStringView(RHS); } + NODISCARD friend FORCEINLINE bool operator==(const TString& LHS, ElementType RHS) { return TStringView(LHS) == RHS; } + NODISCARD friend FORCEINLINE bool operator==(const TString& LHS, const ElementType* RHS) { return TStringView(LHS) == RHS; } + NODISCARD friend FORCEINLINE bool operator==( ElementType LHS, const TString& RHS) { return LHS == TStringView(RHS); } + NODISCARD friend FORCEINLINE bool operator==(const ElementType* LHS, const TString& RHS) { return LHS == TStringView(RHS); } /** Compares the contents of 'LHS' and 'RHS' lexicographically. */ - FORCEINLINE NODISCARD friend auto operator<=>(const TString& LHS, const TString& RHS) { return TStringView(LHS) <=> TStringView(RHS); } + NODISCARD friend FORCEINLINE auto operator<=>(const TString& LHS, const TString& RHS) { return TStringView(LHS) <=> TStringView(RHS); } /** Compares the contents of 'LHS' and 'RHS' lexicographically. */ - FORCEINLINE NODISCARD friend auto operator<=>(const TString& LHS, ElementType RHS) { return TStringView(LHS) <=> RHS; } - FORCEINLINE NODISCARD friend auto operator<=>(const TString& LHS, const ElementType* RHS) { return TStringView(LHS) <=> RHS; } - FORCEINLINE NODISCARD friend auto operator<=>( ElementType LHS, const TString& RHS) { return LHS <=> TStringView(RHS); } - FORCEINLINE NODISCARD friend auto operator<=>(const ElementType* LHS, const TString& RHS) { return LHS <=> TStringView(RHS); } + NODISCARD friend FORCEINLINE auto operator<=>(const TString& LHS, ElementType RHS) { return TStringView(LHS) <=> RHS; } + NODISCARD friend FORCEINLINE auto operator<=>(const TString& LHS, const ElementType* RHS) { return TStringView(LHS) <=> RHS; } + NODISCARD friend FORCEINLINE auto operator<=>(ElementType LHS, const TString& RHS) { return LHS <=> TStringView(RHS); } + NODISCARD friend FORCEINLINE auto operator<=>(const ElementType* LHS, const TString& RHS) { return LHS <=> TStringView(RHS); } /** Inserts 'InValue' before 'Index' in the string. */ FORCEINLINE Iterator Insert(size_t Index, ElementType InValue) diff --git a/Redcraft.Utility/Source/Public/Templates/Function.h b/Redcraft.Utility/Source/Public/Templates/Function.h index 6e3a0e3..4a7440c 100644 --- a/Redcraft.Utility/Source/Public/Templates/Function.h +++ b/Redcraft.Utility/Source/Public/Templates/Function.h @@ -2,6 +2,7 @@ #include "CoreTypes.h" #include "Memory/Memory.h" +#include "Memory/Address.h" #include "Templates/Meta.h" #include "Templates/Invoke.h" #include "Templates/Utility.h" @@ -96,7 +97,7 @@ class alignas(16) TFunctionStorage public: FORCEINLINE constexpr TFunctionStorage() = default; - + TFunctionStorage(const TFunctionStorage& InValue) requires (!bIsUnique) : RTTI(InValue.RTTI) { @@ -151,7 +152,7 @@ public: { Destroy(); } - + TFunctionStorage& operator=(const TFunctionStorage& InValue) requires (!bIsUnique) { if (&InValue == this) UNLIKELY return *this; @@ -322,7 +323,7 @@ private: using FMoveConstruct = void(*)(void*, void*); using FDestruct = void(*)(void* ); - + const FMoveConstruct MoveConstruct; const FDestruct Destruct; @@ -343,7 +344,7 @@ private: ) { } }; - + struct FCopyableRTTI : public FMovableRTTI { using FCopyConstruct = void(*)(void*, const void*); @@ -363,7 +364,7 @@ private: }; using FRTTI = TConditional; - + static_assert(alignof(FRTTI) >= 4); static constexpr uintptr_t RepresentationMask = 3; @@ -375,7 +376,7 @@ private: Small = 2, // InternalStorage Big = 3, // ExternalStorage }; - + union { uint8 InternalStorage[64 - sizeof(uintptr) - sizeof(uintptr)]; @@ -387,7 +388,7 @@ private: FORCEINLINE constexpr ERepresentation GetRepresentation() const { return static_cast(RTTI & RepresentationMask); } FORCEINLINE constexpr const FRTTI& GetRTTI() const { return *reinterpret_cast(RTTI & ~RepresentationMask); } - + FORCEINLINE constexpr void* GetStorage() { switch (GetRepresentation()) @@ -399,7 +400,7 @@ private: default: check_no_entry(); return nullptr; } } - + FORCEINLINE constexpr const void* GetStorage() const { switch (GetRepresentation()) @@ -461,7 +462,7 @@ public: using ResultType = Ret; using ArgumentType = TTypeSequence; - + FORCEINLINE constexpr TFunctionImpl() = default; FORCEINLINE constexpr TFunctionImpl(const TFunctionImpl&) = default; FORCEINLINE constexpr TFunctionImpl(TFunctionImpl&&) = default; @@ -648,7 +649,7 @@ public: { Impl::template Emplace(Forward(Args)...); } - + /** * Constructs an TFunction with initial content an function object of type TDecay, * direct-non-list-initialized from IL, Forward(Args).... @@ -694,7 +695,7 @@ public: Impl::Destroy(); return Impl::template Emplace(Forward(Args)...); } - + /** * Changes the function object to one of type TDecay constructed from the arguments. * First destroys the current function object (if any) by Reset(), then constructs an object of type @@ -790,7 +791,7 @@ public: if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Impl::Invalidate(); else Impl::template Emplace(Forward(InValue)); } - + /** * Constructs an TUniqueFunction with initial content an function object of type TDecay, * direct-non-list-initialized from Forward(Args).... @@ -801,7 +802,7 @@ public: { Impl::template Emplace(Forward(Args)...); } - + /** * Constructs an TUniqueFunction with initial content an function object of type TDecay, * direct-non-list-initialized from IL, Forward(Args).... @@ -844,7 +845,7 @@ public: using DecayedType = TDecay; return Impl::template Emplace(Forward(Args)...); } - + /** * Changes the function object to one of type TDecay constructed from the arguments. * First destroys the current function object (if any) by Reset(), then constructs an object of type diff --git a/Redcraft.Utility/Source/Public/Templates/ReferenceWrapper.h b/Redcraft.Utility/Source/Public/Templates/ReferenceWrapper.h index 43684f8..404fcbf 100644 --- a/Redcraft.Utility/Source/Public/Templates/ReferenceWrapper.h +++ b/Redcraft.Utility/Source/Public/Templates/ReferenceWrapper.h @@ -1,6 +1,7 @@ #pragma once #include "CoreTypes.h" +#include "Memory/Address.h" #include "Templates/Invoke.h" #include "Templates/Utility.h" #include "Templates/Optional.h" @@ -31,7 +32,7 @@ public: /** Copies content of other into a new instance. */ FORCEINLINE constexpr TReferenceWrapper(const TReferenceWrapper&) = default; - + /** Converting copy constructor. */ template requires (CConvertibleTo) FORCEINLINE constexpr TReferenceWrapper(const TReferenceWrapper& InValue) diff --git a/Redcraft.Utility/Source/Public/Templates/Utility.h b/Redcraft.Utility/Source/Public/Templates/Utility.h index 793bab5..29ff1b0 100644 --- a/Redcraft.Utility/Source/Public/Templates/Utility.h +++ b/Redcraft.Utility/Source/Public/Templates/Utility.h @@ -89,24 +89,6 @@ FORCEINLINE constexpr T Exchange(T& A, U&& B) template TAddRValueReference DeclVal(); -/** Obtains the actual address of the object or function arg, even in presence of overloaded operator&. */ -template requires (CObject) -FORCEINLINE constexpr T* AddressOf(T& Object) -{ - return reinterpret_cast(&const_cast(reinterpret_cast(Object))); -} - -/** Obtains the actual address of the object or function arg, even in presence of overloaded operator&. */ -template requires (!CObject) -FORCEINLINE constexpr T* AddressOf(T& Object) -{ - return &Object; -} - -/** Rvalue overload is deleted to prevent taking the address of const rvalues. */ -template -const T* AddressOf(const T&&) = delete; - struct FIgnore final { template @@ -116,7 +98,7 @@ struct FIgnore final /** * An object of unspecified type such that any value can be assigned to it with no effect. * Intended for use with Tie when unpacking a TTuple, as placeholders for unused arguments - * or using Ignore to avoid warnings about unused return values ​​from NODISCARD functions. + * or using Ignore to avoid warnings about unused return values from NODISCARD functions. */ inline constexpr FIgnore Ignore; @@ -137,7 +119,7 @@ inline constexpr FIgnore Ignore; /** * This class is used to create a set of overloaded functions. - * + * * Visit(TOverloaded { * [](auto A) { ... }, * [](double A) { ... }, diff --git a/Redcraft.Utility/Source/Public/Testing/MemoryTesting.h b/Redcraft.Utility/Source/Public/Testing/MemoryTesting.h index f4fb660..156a760 100644 --- a/Redcraft.Utility/Source/Public/Testing/MemoryTesting.h +++ b/Redcraft.Utility/Source/Public/Testing/MemoryTesting.h @@ -9,6 +9,7 @@ NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_BEGIN(Testing) REDCRAFTUTILITY_API void TestMemory(); +REDCRAFTUTILITY_API void TestAddress(); REDCRAFTUTILITY_API void TestAlignment(); REDCRAFTUTILITY_API void TestMemoryBuffer(); REDCRAFTUTILITY_API void TestMemoryMalloc();