diff --git a/Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp b/Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp index eba4618..d849f92 100644 --- a/Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/MemoryTesting.cpp @@ -7,6 +7,7 @@ #include "Memory/SharedPointer.h" #include "Memory/MemoryOperator.h" #include "Memory/ObserverPointer.h" +#include "Memory/InOutPointer.h" #include "Miscellaneous/AssertionMacros.h" NAMESPACE_REDCRAFT_BEGIN @@ -25,6 +26,7 @@ void TestMemory() TestUniquePointer(); TestSharedPointer(); TestObserverPointer(); + TestInOutPointer(); } void TestAlignment() @@ -1098,6 +1100,33 @@ void TestObserverPointer() } } +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()); + } + + { + TUniquePtr Temp = MakeUnique(2485800585); + + [](int64** InPtr) { always_check(**InPtr == 2485800585); delete* InPtr; *InPtr = new int64; } (InOutPtr(Temp)); + always_check(Temp.IsValid()); + + Temp = MakeUnique(2821859274); + + [](int64** InPtr) { always_check(**InPtr == 2821859274); delete* InPtr; *InPtr = new int64; } (InOutPtr(Temp, TDefaultDelete())); + always_check(Temp.IsValid()); + } +} + NAMESPACE_END(Testing) NAMESPACE_MODULE_END(Utility) diff --git a/Redcraft.Utility/Source/Public/Memory/InOutPointer.h b/Redcraft.Utility/Source/Public/Memory/InOutPointer.h new file mode 100644 index 0000000..8c10836 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Memory/InOutPointer.h @@ -0,0 +1,78 @@ +#pragma once + +#include "CoreTypes.h" +#include "Templates/Tuple.h" +#include "Templates/Utility.h" +#include "Memory/PointerTraits.h" +#include "Templates/Noncopyable.h" +#include "TypeTraits/TypeTraits.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +NAMESPACE_PRIVATE_BEGIN + +template +using TRawPointer = TConditional, typename TPointerTraits>::ElementType*, RT>; + +template +class FInOutPtr final : private FSingleton +{ +public: + + explicit FInOutPtr(ST& InPtr, Ts&&... Args) requires (!bEnableInput) + : SPointer(InPtr), Tuple(nullptr, Forward(Args)...) + { } + + explicit FInOutPtr(ST& InPtr, Ts&&... Args) requires (bEnableInput) + : SPointer(InPtr), Tuple(InPtr.Release(), Forward(Args)...) + { } + + ~FInOutPtr() + { + if constexpr (requires(RT* RPtr, ST& SPtr, Ts&&... Args) { SPtr.Reset(RPtr, Forward(Args)...); }) + { + Tuple.Apply([this](Ts&&... Args) { SPointer.Reset(Forward(Args)...); }); + } + else if constexpr (CConstructibleFrom && CMoveAssignable) + { + SPointer = Tuple.template Construct(); + } + else check_no_entry(); + } + + operator RT*() { return &Tuple.First; } + operator void**() requires (!CSameAs) { return &Tuple.First; } + +private: + + ST& SPointer; + TTuple< RT, Ts&&...> Tuple; + +}; + +NAMESPACE_PRIVATE_END + +template requires ((CVoid) || (CPointer) + && (requires(NAMESPACE_PRIVATE::TRawPointer* RPtr, ST& SPtr, Ts&&... Args) { SPtr.Reset(RPtr, Forward(Args)...); }) + || (CConstructibleFrom, Ts...> && CMoveAssignable) + && requires { typename TPointerTraits>::ElementType; }) +auto OutPtr(ST& InPtr, Ts&&... Args) +{ + return NAMESPACE_PRIVATE::FInOutPtr, ST, Ts...>(InPtr, Forward(Args)...); +} + +template requires ((CVoid) || (CPointer) + && (requires(NAMESPACE_PRIVATE::TRawPointer* RPtr, ST& SPtr, Ts&&... Args) { SPtr.Reset(RPtr, Forward(Args)...); }) + || (CConstructibleFrom, Ts...> && CMoveAssignable) + && requires(ST& SPtr) { { SPtr.Release() } -> CConvertibleTo>; } + && requires { typename TPointerTraits>::ElementType; }) +auto InOutPtr(ST& InPtr, Ts&&... Args) +{ + return NAMESPACE_PRIVATE::FInOutPtr, ST, Ts...>(InPtr, Forward(Args)...); +} + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Testing/MemoryTesting.h b/Redcraft.Utility/Source/Public/Testing/MemoryTesting.h index 344eac9..f4fb660 100644 --- a/Redcraft.Utility/Source/Public/Testing/MemoryTesting.h +++ b/Redcraft.Utility/Source/Public/Testing/MemoryTesting.h @@ -17,6 +17,7 @@ REDCRAFTUTILITY_API void TestPointerTraits(); REDCRAFTUTILITY_API void TestUniquePointer(); REDCRAFTUTILITY_API void TestSharedPointer(); REDCRAFTUTILITY_API void TestObserverPointer(); +REDCRAFTUTILITY_API void TestInOutPointer(); NAMESPACE_END(Testing)