Compare commits

...

6 Commits

10 changed files with 483 additions and 35 deletions

View File

@ -24,6 +24,7 @@ void TestTemplates()
TestTuple();
TestFunction();
TestAtomic();
TestScopeHelper();
TestMiscTemplates();
}
@ -173,6 +174,13 @@ void TestOptional()
always_check(TempB <= TempC);
always_check(TempA <=> TempB == partial_ordering::unordered);
}
{
struct FTest { FTest(initializer_list<int32>, int32) { } };
TOptional<FTest> Temp(InPlace, { 0, 1, 2 }, 3);
Temp.Emplace({ 0, 1, 2 }, 3);
}
}
void TestVariant()
@ -186,8 +194,8 @@ void TestVariant()
// TVariant<int32> TempF(0.0);
TVariant<int32> TempG(TempA);
TVariant<int32> TempH(TempD);
TVariant<int32> TempI(TVariant<int32>(0));
TVariant<int32> TempJ(TVariant<int32>(Invalid));
TVariant<int32> TempI = TVariant<int32>(0);
TVariant<int32> TempJ = TVariant<int32>(Invalid);
TVariant<int32> TempK, TempL, TempM, TempN;
TempK = TempA;
@ -423,6 +431,16 @@ void TestVariant()
always_check(TempD >= TempC);
always_check(TempA <=> TempB == partial_ordering::unordered);
}
{
struct FTest { FTest(initializer_list<int32>, int32) { } };
TVariant<FTest> TempA(InPlaceIndex<0>, { 0, 1, 2 }, 3);
TempA.Emplace<0>({ 0, 1, 2 }, 3);
TVariant<FTest> TempB(InPlaceType<FTest>, { 0, 1, 2 }, 3);
TempB.Emplace<FTest>({ 0, 1, 2 }, 3);
}
}
void TestAny()
@ -630,6 +648,12 @@ void TestAny()
TempZ = FTracker();
}
{
struct FTest { FTest(initializer_list<int32>, int32) { } };
FAny Temp(InPlaceType<FTest>, { 0, 1, 2 }, 3);
Temp.Emplace<FTest>({ 0, 1, 2 }, 3);
}
}
void TestTuple()
@ -1235,6 +1259,19 @@ void TestFunction()
always_check(NotIdentity(false));
}
{
struct FTest
{
FTest(initializer_list<int32>, int32) { }
void operator()() { }
};
TFunction<void()> TempA(InPlaceType<FTest>, { 0, 1, 2 }, 3);
TempA.Emplace<FTest>({ 0, 1, 2 }, 3);
TUniqueFunction<void()> TempB(InPlaceType<FTest>, { 0, 1, 2 }, 3);
TempB.Emplace<FTest>({ 0, 1, 2 }, 3);
}
}
void TestAtomic()
@ -1345,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>

View File

@ -106,6 +106,13 @@ public:
{
EmplaceImpl<T>(Forward<Ts>(Args)...);
}
/** Constructs an object with initial content an object of type TDecay<T>, direct-non-list-initialized from IL, Forward<Ts>(Args).... */
template <typename T, typename U, typename... Ts> requires (NAMESPACE_PRIVATE::CFAnyPlaceable<T> && CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts&&...>)
FORCEINLINE explicit FAny(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args)
{
EmplaceImpl<T>(IL, Forward<Ts>(Args)...);
}
/** Destroys the contained object, if any, as if by a call to Reset(). */
FORCEINLINE ~FAny()
@ -275,7 +282,7 @@ public:
* First destroys the current contained object (if any) by Reset(), then constructs an object of type
* TDecay<T>, direct-non-list-initialized from Forward<Ts>(Args)..., as the contained object.
*
* @param Args - The arguments to be passed to the constructor of the contained object.
* @param Args - The arguments to be passed to the constructor of the contained object.
*
* @return A reference to the new contained object.
*/
@ -287,6 +294,23 @@ public:
return GetValue<TDecay<T>>();
}
/**
* Changes the contained object to one of type TDecay<T> constructed from the arguments.
* First destroys the current contained object (if any) by Reset(), then constructs an object of type
* TDecay<T>, direct-non-list-initialized from IL, Forward<Ts>(Args)..., as the contained object.
*
* @param IL, Args - The arguments to be passed to the constructor of the contained object.
*
* @return A reference to the new contained object.
*/
template <typename T, typename U, typename... Ts> requires (NAMESPACE_PRIVATE::CFAnyPlaceable<T> && CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts&&...>)
FORCEINLINE TDecay<T>& Emplace(initializer_list<U> IL, Ts&&... Args)
{
Destroy();
EmplaceImpl<T>(IL, Forward<Ts>(Args)...);
return GetValue<TDecay<T>>();
}
/** @return The typeid of the contained value if instance is non-empty, otherwise typeid(void). */
NODISCARD FORCEINLINE constexpr const type_info& GetTypeInfo() const { return IsValid() ? GetTypeInfoImpl() : typeid(void); }

View File

@ -1,57 +1,91 @@
#pragma once
#include "CoreTypes.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/Swappable.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
template <typename T> requires (requires(T&& Container) { Container.GetData(); })
/** @return The pointer to the container element storage. */
template <typename T> requires (requires(T&& Container) { { Container.GetData() } -> CPointer; })
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; }
template <typename T> requires (requires(T&& Container) { Container.data(); })
/** Overloads the GetData algorithm for T::data(). */
template <typename T> requires (requires(T&& Container) { { Container.data() } -> CPointer; })
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)
FORCEINLINE constexpr const T* GetData(initializer_list<T> Container)
{
return Container.begin();
}
template <typename T> requires (requires(T&& Container) { Container.Num(); })
/** @return The number of elements in the container. */
template <typename T> requires (requires(T&& Container) { { Container.Num() } -> CConvertibleTo<size_t>; })
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; }
template <typename T> requires (requires(T&& Container) { Container.size(); })
/** Overloads the GetNum algorithm for T::size(). */
template <typename T> requires (requires(T&& Container) { { Container.size() } -> CConvertibleTo<size_t>; })
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)
FORCEINLINE constexpr size_t 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]);
}
}
/** Overloads the GetTypeHash algorithm for arrays. */
template <typename T, size_t N> requires (CHashable<TRemoveAllExtents<T>>)
FORCEINLINE constexpr size_t GetTypeHash(T(&A)[N])
{
size_t Result = 3516520171;
for (size_t Index = 0; Index < N; ++Index)
{
Result = HashCombine(Result, GetTypeHash(A[Index]));
}
return Result;
}
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -506,8 +506,8 @@ protected:
FORCEINLINE constexpr void Invalidate() { Storage.Invalidate(); }
// Make sure you call this function after you have destroyed the held object using Destroy().
template <typename T, typename... ArgTypes>
FORCEINLINE constexpr TDecay<T>& Emplace(ArgTypes&&... Args)
template <typename T, typename... Us>
FORCEINLINE constexpr TDecay<T>& Emplace(Us&&... Args)
{
using DecayedType = TDecay<T>;
@ -525,7 +525,7 @@ protected:
Storage.template Emplace<DecayedType>(
reinterpret_cast<uintptr>(Callable),
Forward<ArgTypes>(Args)...
Forward<Us>(Args)...
);
return *reinterpret_cast<DecayedType*>(Storage.GetValuePtr());
@ -641,12 +641,24 @@ public:
* Constructs an TFunction with initial content an function object of type TDecay<T>,
* direct-non-list-initialized from Forward<Ts>(Args)....
*/
template <typename T, typename... ArgTypes> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, ArgTypes...> && CCopyConstructible<TDecay<T>>
template <typename T, typename... Ts> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, Ts...> && CCopyConstructible<TDecay<T>>
&& CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TFunction(TInPlaceType<T>, ArgTypes&&... Args)
FORCEINLINE explicit TFunction(TInPlaceType<T>, Ts&&... Args)
{
Impl::template Emplace<T>(Forward<ArgTypes>(Args)...);
Impl::template Emplace<T>(Forward<Ts>(Args)...);
}
/**
* Constructs an TFunction with initial content an function object of type TDecay<T>,
* direct-non-list-initialized from IL, Forward<Ts>(Args)....
*/
template <typename T, typename U, typename... Ts> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts...> && CCopyConstructible<TDecay<T>>
&& CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TFunction(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args)
{
Impl::template Emplace<T>(IL, Forward<Ts>(Args)...);
}
/** Removes any bound callable from the TFunction, restoring it to the default empty state. */
@ -670,17 +682,35 @@ public:
* First destroys the current function object (if any) by Reset(), then constructs an object of type
* TDecay<T>, direct-non-list-initialized from Forward<Ts>(Args)..., as the function object.
*
* @param Args - The arguments to be passed to the constructor of the function object.
* @param Args - The arguments to be passed to the constructor of the function object.
*
* @return A reference to the new function object.
*/
template <typename T, typename... ArgTypes> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, ArgTypes...> && CCopyConstructible<TDecay<T>>
template <typename T, typename... Ts> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, Ts...> && CCopyConstructible<TDecay<T>>
&& CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(ArgTypes&&... Args)
FORCEINLINE TDecay<T>& Emplace(Ts&&... Args)
{
Impl::Destroy();
return Impl::template Emplace<T>(Forward<ArgTypes>(Args)...);
return Impl::template Emplace<T>(Forward<Ts>(Args)...);
}
/**
* Changes the function object to one of type TDecay<T> constructed from the arguments.
* First destroys the current function object (if any) by Reset(), then constructs an object of type
* TDecay<T>, direct-non-list-initialized from IL, Forward<Ts>(Args)..., as the function object.
*
* @param IL, Args - The arguments to be passed to the constructor of the function object.
*
* @return A reference to the new function object.
*/
template <typename T, typename U, typename... Ts> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts...> && CCopyConstructible<TDecay<T>>
&& CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(initializer_list<U> IL, Ts&&... Args)
{
Impl::Destroy();
return Impl::template Emplace<T>(IL, Forward<Ts>(Args)...);
}
/** Removes any bound callable from the TFunction, restoring it to the default empty state. */
@ -765,11 +795,22 @@ public:
* Constructs an TUniqueFunction with initial content an function object of type TDecay<T>,
* direct-non-list-initialized from Forward<Ts>(Args)....
*/
template <typename T, typename... ArgTypes> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, ArgTypes...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TUniqueFunction(TInPlaceType<T>, ArgTypes&&... Args)
template <typename T, typename... Ts> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TUniqueFunction(TInPlaceType<T>, Ts&&... Args)
{
Impl::template Emplace<T>(Forward<ArgTypes>(Args)...);
Impl::template Emplace<T>(Forward<Ts>(Args)...);
}
/**
* Constructs an TUniqueFunction with initial content an function object of type TDecay<T>,
* direct-non-list-initialized from IL, Forward<Ts>(Args)....
*/
template <typename T, typename U, typename... Ts> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TUniqueFunction(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args)
{
Impl::template Emplace<T>(IL, Forward<Ts>(Args)...);
}
/** Removes any bound callable from the TUniqueFunction, restoring it to the default empty state. */
@ -795,13 +836,31 @@ public:
*
* @return A reference to the new function object.
*/
template <typename T, typename... ArgTypes> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, ArgTypes...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(ArgTypes&&... Args)
template <typename T, typename... Ts> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(Ts&&... Args)
{
Impl::Destroy();
using DecayedType = TDecay<T>;
return Impl::template Emplace<T>(Forward<ArgTypes>(Args)...);
return Impl::template Emplace<T>(Forward<Ts>(Args)...);
}
/**
* Changes the function object to one of type TDecay<T> constructed from the arguments.
* First destroys the current function object (if any) by Reset(), then constructs an object of type
* TDecay<T>, direct-non-list-initialized from IL, Forward<Ts>(Args)..., as the function object.
*
* @param IL, Args - The arguments to be passed to the constructor of the function object.
*
* @return A reference to the new function object.
*/
template <typename T, typename U, typename... Ts> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(initializer_list<U> IL, Ts&&... Args)
{
Impl::Destroy();
using DecayedType = TDecay<T>;
return Impl::template Emplace<T>(IL, Forward<Ts>(Args)...);
}
/** Removes any bound callable from the TUniqueFunction, restoring it to the default empty state. */

View File

@ -66,6 +66,14 @@ public:
{
new (&Value) OptionalType(Forward<Ts>(Args)...);
}
/** Constructs an object with initial content an object, direct-non-list-initialized from IL, Forward<Ts>(Args).... */
template <typename U, typename... Ts> requires (CConstructibleFrom<OptionalType, initializer_list<U>, Ts...>)
FORCEINLINE constexpr explicit TOptional(FInPlace, initializer_list<U> IL, Ts&&... Args)
: bIsValid(true)
{
new (&Value) OptionalType(IL, Forward<Ts>(Args)...);
}
/** Copies content of other into a new instance. */
FORCEINLINE constexpr TOptional(const TOptional& InValue) requires (CTriviallyCopyConstructible<OptionalType>) = default;
@ -258,16 +266,36 @@ public:
* First destroys the current contained object (if any) by Reset(),
* then constructs an object, direct-non-list-initialized from Forward<Ts>(Args)..., as the contained object.
*
* @param Args - The arguments to be passed to the constructor of the object.
* @param Args - The arguments to be passed to the constructor of the object.
*
* @return A reference to the new object.
*/
template <typename... ArgTypes> requires (CConstructibleFrom<OptionalType, ArgTypes...>)
FORCEINLINE constexpr OptionalType& Emplace(ArgTypes&&... Args)
template <typename... Ts> requires (CConstructibleFrom<OptionalType, Ts...>)
FORCEINLINE constexpr OptionalType& Emplace(Ts&&... Args)
{
Reset();
OptionalType* Result = new (&Value) OptionalType(Forward<ArgTypes>(Args)...);
OptionalType* Result = new (&Value) OptionalType(Forward<Ts>(Args)...);
bIsValid = true;
return *Result;
}
/**
* Changes the contained object to one constructed from the arguments.
* First destroys the current contained object (if any) by Reset(),
* then constructs an object, direct-non-list-initialized from IL, Forward<Ts>(Args)..., as the contained object.
*
* @param IL, Args - The arguments to be passed to the constructor of the object.
*
* @return A reference to the new object.
*/
template <typename U, typename... Ts> requires (CConstructibleFrom<OptionalType, initializer_list<U>, Ts...>)
FORCEINLINE constexpr OptionalType& Emplace(initializer_list<U> IL, Ts&&... Args)
{
Reset();
OptionalType* Result = new (&Value) OptionalType(IL, Forward<Ts>(Args)...);
bIsValid = true;
return *Result;

View 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

View File

@ -14,3 +14,4 @@
#include "Templates/TypeHash.h"
#include "Templates/Function.h"
#include "Templates/Atomic.h"
#include "Templates/ScopeHelper.h"

View File

@ -74,7 +74,7 @@ FORCEINLINE constexpr size_t GetTypeHash(T A)
if constexpr (sizeof(T) == 2) return GetTypeHash(*reinterpret_cast<uint16*>(&A));
if constexpr (sizeof(T) == 4) return GetTypeHash(*reinterpret_cast<uint32*>(&A));
if constexpr (sizeof(T) == 8) return GetTypeHash(*reinterpret_cast<uint64*>(&A));
if constexpr (sizeof(T) == 16) return GetTypeHash(*reinterpret_cast<uint64*>(&A) + *(reinterpret_cast<uint64*>(&A) + 1));
if constexpr (sizeof(T) == 16) return GetTypeHash(*reinterpret_cast<uint64*>(&A) ^ *(reinterpret_cast<uint64*>(&A) + 1));
else check_no_entry();
return INDEX_NONE;

View File

@ -142,6 +142,22 @@ public:
using SelectedType = TVariantAlternative<I, TVariant<Ts...>>;
new (&Value) SelectedType(Forward<Us>(Args)...);
}
/** Constructs a variant with the specified alternative T and initializes the contained value with the arguments IL, Forward<Us>(Args).... */
template <typename T, typename U, typename... Us> requires (CConstructibleFrom<T, initializer_list<U>, Us...>)
FORCEINLINE constexpr explicit TVariant(TInPlaceType<T>, initializer_list<U> IL, Us&&... Args)
: TVariant(InPlaceIndex<TVariantIndex<T, TVariant<Ts...>>>, IL, Forward<Us>(Args)...)
{ }
/** Constructs a variant with the alternative T specified by the index I and initializes the contained value with the arguments IL, Forward<Us>(Args).... */
template <size_t I, typename T, typename... Us> requires (I < sizeof...(Ts)
&& CConstructibleFrom<TVariantAlternative<I, TVariant<Ts...>>, initializer_list<T>, Us...>)
FORCEINLINE constexpr explicit TVariant(TInPlaceIndex<I>, initializer_list<T> IL, Us&&... Args)
: TypeIndex(I)
{
using SelectedType = TVariantAlternative<I, TVariant<Ts...>>;
new (&Value) SelectedType(IL, Forward<Us>(Args)...);
}
/** Destroys the contained object, if any, as if by a call to Reset(). */
FORCEINLINE constexpr ~TVariant() requires (true && ... && CTriviallyDestructible<Ts>) = default;
@ -273,7 +289,7 @@ public:
* First, destroys the currently contained value if any.
* Then direct-initializes the contained value as if constructing a value of type T with the arguments Forward<Us>(Args)....
*
* @param Args - The arguments to be passed to the constructor of the contained object.
* @param Args - The arguments to be passed to the constructor of the contained object.
*
* @return A reference to the new contained object.
*/
@ -289,6 +305,34 @@ public:
return *Result;
}
/** Equivalent to Emplace<I>(IL, Forward<Us>(Args)...), where I is the zero-based index of T in Types.... */
template <typename T, typename U, typename... Us> requires (CConstructibleFrom<T, initializer_list<U>, Us...>)
FORCEINLINE constexpr T& Emplace(initializer_list<U> IL, Us&&... Args)
{
return Emplace<TVariantIndex<T, TVariant<Ts...>>>(IL, Forward<Us>(Args)...);
}
/**
* First, destroys the currently contained value if any.
* Then direct-initializes the contained value as if constructing a value of type T with the arguments IL, Forward<Us>(Args)....
*
* @param IL, Args - The arguments to be passed to the constructor of the contained object.
*
* @return A reference to the new contained object.
*/
template <size_t I, typename T, typename... Us> requires (I < sizeof...(Ts)
&& CConstructibleFrom<TVariantAlternative<I, TVariant<Ts...>>, initializer_list<T>, Us...>)
FORCEINLINE constexpr TVariantAlternative<I, TVariant<Ts...>>& Emplace(initializer_list<T> IL, Us&&... Args)
{
Reset();
using SelectedType = TVariantAlternative<I, TVariant<Ts...>>;
SelectedType* Result = new (&Value) SelectedType(IL, Forward<Us>(Args)...);
TypeIndex = I;
return *Result;
}
/** @return The typeid of the contained value if instance is non-empty, otherwise typeid(void). */
NODISCARD FORCEINLINE constexpr const type_info& GetTypeInfo() const { return IsValid() ? *TypeInfos[GetIndex()] : typeid(void); }

View File

@ -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)