Compare commits
2 Commits
38ec8f6571
...
c543abebfb
Author | SHA1 | Date | |
---|---|---|---|
c543abebfb | |||
e057cdc84d |
@ -24,6 +24,7 @@ void TestTemplates()
|
||||
TestTuple();
|
||||
TestFunction();
|
||||
TestAtomic();
|
||||
TestScopeHelper();
|
||||
TestMiscTemplates();
|
||||
}
|
||||
|
||||
@ -1381,6 +1382,93 @@ void TestAtomic()
|
||||
}
|
||||
}
|
||||
|
||||
void TestScopeHelper()
|
||||
{
|
||||
{
|
||||
int32 CheckNum = 0;
|
||||
{
|
||||
TScopeCallback ScopeCallback([&]() { CheckNum = 2; });
|
||||
always_check(CheckNum == 0);
|
||||
CheckNum = 1;
|
||||
always_check(CheckNum == 1);
|
||||
}
|
||||
always_check(CheckNum == 2);
|
||||
}
|
||||
|
||||
{
|
||||
int32 CheckNum = 0;
|
||||
{
|
||||
TScopeCallback ScopeCallback([&]() { CheckNum = 2; });
|
||||
always_check(CheckNum == 0);
|
||||
CheckNum = 1;
|
||||
always_check(CheckNum == 1);
|
||||
ScopeCallback.Release();
|
||||
}
|
||||
always_check(CheckNum == 1);
|
||||
}
|
||||
|
||||
{
|
||||
int32 CheckNum = 0;
|
||||
{
|
||||
TScopeCallback ScopeCallbackA([&]() { CheckNum = 2; });
|
||||
TScopeCallback ScopeCallbackB(MoveTemp(ScopeCallbackA));
|
||||
always_check(CheckNum == 0);
|
||||
CheckNum = 1;
|
||||
always_check(CheckNum == 1);
|
||||
}
|
||||
always_check(CheckNum == 2);
|
||||
}
|
||||
|
||||
{
|
||||
int32 CheckNum = 1;
|
||||
{
|
||||
TGuardValue GuardValue(CheckNum);
|
||||
CheckNum = 2;
|
||||
always_check(CheckNum == 2);
|
||||
}
|
||||
always_check(CheckNum == 1);
|
||||
}
|
||||
|
||||
{
|
||||
int32 CheckNum = 1;
|
||||
{
|
||||
TGuardValue GuardValue(CheckNum, 2);
|
||||
always_check(CheckNum == 2);
|
||||
}
|
||||
always_check(CheckNum == 1);
|
||||
}
|
||||
|
||||
{
|
||||
int32 CheckNum = 1;
|
||||
{
|
||||
TGuardValue GuardValue(CheckNum, 2);
|
||||
always_check(CheckNum == 2);
|
||||
GuardValue.Release();
|
||||
}
|
||||
always_check(CheckNum == 2);
|
||||
}
|
||||
|
||||
{
|
||||
int32 CheckNum = 1;
|
||||
{
|
||||
TGuardValue GuardValueA(CheckNum, 2);
|
||||
TGuardValue GuardValueB(MoveTemp(GuardValueA));
|
||||
always_check(CheckNum == 2);
|
||||
}
|
||||
always_check(CheckNum == 1);
|
||||
}
|
||||
|
||||
{
|
||||
int32 CheckNum = 1;
|
||||
{
|
||||
TScopeCounter GuardValue(CheckNum);
|
||||
always_check(CheckNum == 2);
|
||||
}
|
||||
always_check(CheckNum == 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NAMESPACE_UNNAMED_BEGIN
|
||||
|
||||
template <typename T>
|
||||
|
@ -1,57 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/Swappable.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
/** @return The pointer or iterator to the container element storage. */
|
||||
template <typename T> requires (requires(T&& Container) { Container.GetData(); })
|
||||
FORCEINLINE constexpr decltype(auto) GetData(T&& Container)
|
||||
{
|
||||
return Container.GetData();
|
||||
}
|
||||
|
||||
/** Overloads the GetData algorithm for arrays. */
|
||||
template <typename T, size_t N> FORCEINLINE constexpr T* GetData( T(& Container)[N]) { return Container; }
|
||||
template <typename T, size_t N> FORCEINLINE constexpr T* GetData( T(&& Container)[N]) { return Container; }
|
||||
template <typename T, size_t N> FORCEINLINE constexpr const T* GetData(const T(& Container)[N]) { return Container; }
|
||||
template <typename T, size_t N> FORCEINLINE constexpr const T* GetData(const T(&& Container)[N]) { return Container; }
|
||||
|
||||
/** Overloads the GetData algorithm for T::data(). */
|
||||
template <typename T> requires (requires(T&& Container) { Container.data(); })
|
||||
FORCEINLINE constexpr decltype(auto) GetData(T&& Container)
|
||||
{
|
||||
return Container.data();
|
||||
}
|
||||
|
||||
/** Overloads the GetData algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
FORCEINLINE constexpr decltype(auto) GetData(initializer_list<T> Container)
|
||||
{
|
||||
return Container.begin();
|
||||
}
|
||||
|
||||
/** @return The number of elements in the container. */
|
||||
template <typename T> requires (requires(T&& Container) { Container.Num(); })
|
||||
FORCEINLINE constexpr decltype(auto) GetNum(T&& Container)
|
||||
{
|
||||
return Container.Num();
|
||||
}
|
||||
|
||||
/** Overloads the GetNum algorithm for arrays. */
|
||||
template <typename T, size_t N> FORCEINLINE constexpr size_t GetNum( T(& Container)[N]) { return N; }
|
||||
template <typename T, size_t N> FORCEINLINE constexpr size_t GetNum( T(&& Container)[N]) { return N; }
|
||||
template <typename T, size_t N> FORCEINLINE constexpr size_t GetNum(const T(& Container)[N]) { return N; }
|
||||
template <typename T, size_t N> FORCEINLINE constexpr size_t GetNum(const T(&& Container)[N]) { return N; }
|
||||
|
||||
/** Overloads the GetNum algorithm for T::size(). */
|
||||
template <typename T> requires (requires(T&& Container) { Container.size(); })
|
||||
FORCEINLINE constexpr decltype(auto) GetNum(T&& Container)
|
||||
{
|
||||
return Container.size();
|
||||
}
|
||||
|
||||
/** Overloads the GetNum algorithm for initializer_list. */
|
||||
template <typename T>
|
||||
FORCEINLINE constexpr decltype(auto) GetNum(initializer_list<T> Container)
|
||||
{
|
||||
return Container.size();
|
||||
}
|
||||
|
||||
/** Overloads the Swap algorithm for arrays. */
|
||||
template <typename T, size_t N> requires (CSwappable<TRemoveAllExtents<T>>)
|
||||
FORCEINLINE constexpr void Swap(T(&A)[N], T(&B)[N])
|
||||
{
|
||||
for (size_t Index = 0; Index < N; ++Index)
|
||||
{
|
||||
Swap(A[Index], B[Index]);
|
||||
}
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
||||
|
133
Redcraft.Utility/Source/Public/Templates/ScopeHelper.h
Normal file
133
Redcraft.Utility/Source/Public/Templates/ScopeHelper.h
Normal file
@ -0,0 +1,133 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/Invocable.h"
|
||||
#include "Templates/Noncopyable.h"
|
||||
#include "TypeTraits/CompositeType.h"
|
||||
#include "TypeTraits/Miscellaneous.h"
|
||||
#include "TypeTraits/SupportedOperations.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
/** The class template is a general-purpose scope guard intended to call its callback function when a scope is exited. */
|
||||
template <CInvocable F> requires (CDestructible<F>)
|
||||
class TScopeCallback final : public FNoncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
/** Initializes the callback function with a function or function object. */
|
||||
template <typename InF> requires (!CSameAs<TRemoveCVRef<InF>, TScopeCallback> && CConstructibleFrom<F, InF>)
|
||||
FORCEINLINE constexpr explicit TScopeCallback(InF&& Func) : Storage(Forward<InF>(Func)), bIsActive(true) { }
|
||||
|
||||
/** Move constructor. Initializes the stored object with the one in other. */
|
||||
FORCEINLINE constexpr TScopeCallback(TScopeCallback&& InValue) requires (CMoveConstructible<F>)
|
||||
: Storage(MoveTemp(InValue.Storage)), bIsActive(InValue.bIsActive)
|
||||
{
|
||||
InValue.Release();
|
||||
}
|
||||
|
||||
/** Calls the callback function if the TScopeCallback is active, then destroys the stored object. */
|
||||
FORCEINLINE constexpr ~TScopeCallback()
|
||||
{
|
||||
if (bIsActive) Storage();
|
||||
}
|
||||
|
||||
/** Makes the TScopeCallback inactive. */
|
||||
FORCEINLINE constexpr void Release() { bIsActive = false; }
|
||||
|
||||
/** @return a const reference to the stored object. */
|
||||
FORCEINLINE constexpr const F& Get() const { return Storage; }
|
||||
|
||||
private:
|
||||
|
||||
F Storage;
|
||||
bool bIsActive;
|
||||
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
TScopeCallback(F) -> TScopeCallback<F>;
|
||||
|
||||
/** The class template is a general-purpose scope guard intended to make sure a value is restored when a scope is exited. */
|
||||
template <typename T> requires (CCopyConstructible<T> && CCopyAssignable<T> && CMoveAssignable<T> && CDestructible<T>)
|
||||
class TGuardValue final : public FNoncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
/** Initializes the TGuardValue with a reference. */
|
||||
FORCEINLINE constexpr TGuardValue(T& InReference) : Reference(InReference), OldValue(InReference), bIsActive(true) { }
|
||||
|
||||
/** Initializes the TGuardValue with a reference and assign a new value to the reference. */
|
||||
template <typename U> requires (CAssignableFrom<T&, U>)
|
||||
FORCEINLINE constexpr TGuardValue(T& InReference, U&& InValue) : Reference(InReference), OldValue(InReference), bIsActive(true) { InReference = InValue; }
|
||||
|
||||
/** Move constructor. Initializes the referenced value and old value with the one in other. */
|
||||
FORCEINLINE constexpr TGuardValue(TGuardValue&& InValue) requires (CMoveConstructible<T>)
|
||||
: Reference(InValue.Reference), OldValue(MoveTemp(InValue.OldValue)), bIsActive(InValue.bIsActive)
|
||||
{
|
||||
InValue.Release();
|
||||
}
|
||||
|
||||
/** Restore the referenced value if the TGuardValue is active, then destroys the old value. */
|
||||
FORCEINLINE constexpr ~TGuardValue()
|
||||
{
|
||||
if (bIsActive) Reference = MoveTemp(OldValue);
|
||||
}
|
||||
|
||||
/** Makes the TGuardValue inactive. */
|
||||
FORCEINLINE constexpr void Release() { bIsActive = false; }
|
||||
|
||||
/** @return a const reference to the old value. */
|
||||
FORCEINLINE constexpr const T& Get() const { return OldValue; }
|
||||
|
||||
private:
|
||||
|
||||
T& Reference;
|
||||
T OldValue;
|
||||
bool bIsActive;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
TGuardValue(T&) -> TGuardValue<T>;
|
||||
|
||||
template <typename T, typename U>
|
||||
TGuardValue(T&, U&&) -> TGuardValue<T>;
|
||||
|
||||
/** Commonly used to make sure a value is incremented, and then decremented when a scope is exited. */
|
||||
template <typename T> requires (requires(T& Value) { ++Value; --Value; })
|
||||
class TScopeCounter : public FNoncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
/** Initializes the TScopeCounter with a reference and increments it. */
|
||||
FORCEINLINE constexpr TScopeCounter(T& InReference)
|
||||
: Reference(InReference)
|
||||
{
|
||||
++Reference;
|
||||
}
|
||||
|
||||
/** Decrements the referenced value. */
|
||||
FORCEINLINE constexpr ~TScopeCounter()
|
||||
{
|
||||
--Reference;
|
||||
}
|
||||
|
||||
/** @return a const reference to the value. */
|
||||
FORCEINLINE constexpr const T& Get() const { return Reference; }
|
||||
|
||||
private:
|
||||
|
||||
T& Reference;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
TScopeCounter(T&) -> TScopeCounter<T>;
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -14,3 +14,4 @@
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Templates/Function.h"
|
||||
#include "Templates/Atomic.h"
|
||||
#include "Templates/ScopeHelper.h"
|
||||
|
@ -73,18 +73,6 @@ FORCEINLINE constexpr void Swap(T& A, T& B)
|
||||
B = MoveTemp(Temp);
|
||||
}
|
||||
|
||||
/** Overloads the Swap algorithm for array. */
|
||||
template <typename T, size_t N> requires (CMoveConstructible<T> && CMoveAssignable<T>)
|
||||
FORCEINLINE constexpr void Swap(T(&A)[N], T(&B)[N])
|
||||
{
|
||||
for (size_t Index = 0; Index < N; ++Index)
|
||||
{
|
||||
T Temp = MoveTemp(A[Index]);
|
||||
A[Index] = MoveTemp(B[Index]);
|
||||
B[Index] = MoveTemp(Temp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Replaces the value of 'A' with 'B' and returns the old value of 'A'. */
|
||||
template <typename T, typename U = T> requires (CMoveConstructible<T> && CAssignableFrom<T&, U>)
|
||||
FORCEINLINE constexpr T Exchange(T& A, U&& B)
|
||||
|
@ -17,6 +17,7 @@ REDCRAFTUTILITY_API void TestAny();
|
||||
REDCRAFTUTILITY_API void TestTuple();
|
||||
REDCRAFTUTILITY_API void TestFunction();
|
||||
REDCRAFTUTILITY_API void TestAtomic();
|
||||
REDCRAFTUTILITY_API void TestScopeHelper();
|
||||
REDCRAFTUTILITY_API void TestMiscTemplates();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
Loading…
Reference in New Issue
Block a user