From 0709f209c80dc0092fbc4f548752065483039d81 Mon Sep 17 00:00:00 2001 From: _Redstone_c_ Date: Sat, 31 Dec 2022 19:19:30 +0800 Subject: [PATCH] feat(templates): add initializer_list overloads to the in place constructor and emplace --- .../Private/Testing/TemplatesTesting.cpp | 40 +++++++- .../Source/Public/Templates/Any.h | 26 ++++- .../Source/Public/Templates/Function.h | 99 +++++++++++++++---- .../Source/Public/Templates/Optional.h | 36 ++++++- .../Source/Public/Templates/Variant.h | 46 ++++++++- 5 files changed, 219 insertions(+), 28 deletions(-) diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index 8a007c6..a64ace5 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -173,6 +173,13 @@ void TestOptional() always_check(TempB <= TempC); always_check(TempA <=> TempB == partial_ordering::unordered); } + + { + struct FTest { FTest(initializer_list, int32) { } }; + + TOptional Temp(InPlace, { 0, 1, 2 }, 3); + Temp.Emplace({ 0, 1, 2 }, 3); + } } void TestVariant() @@ -186,8 +193,8 @@ void TestVariant() // TVariant TempF(0.0); TVariant TempG(TempA); TVariant TempH(TempD); - TVariant TempI(TVariant(0)); - TVariant TempJ(TVariant(Invalid)); + TVariant TempI = TVariant(0); + TVariant TempJ = TVariant(Invalid); TVariant TempK, TempL, TempM, TempN; TempK = TempA; @@ -423,6 +430,16 @@ void TestVariant() always_check(TempD >= TempC); always_check(TempA <=> TempB == partial_ordering::unordered); } + + { + struct FTest { FTest(initializer_list, int32) { } }; + + TVariant TempA(InPlaceIndex<0>, { 0, 1, 2 }, 3); + TempA.Emplace<0>({ 0, 1, 2 }, 3); + + TVariant TempB(InPlaceType, { 0, 1, 2 }, 3); + TempB.Emplace({ 0, 1, 2 }, 3); + } } void TestAny() @@ -630,6 +647,12 @@ void TestAny() TempZ = FTracker(); } + { + struct FTest { FTest(initializer_list, int32) { } }; + + FAny Temp(InPlaceType, { 0, 1, 2 }, 3); + Temp.Emplace({ 0, 1, 2 }, 3); + } } void TestTuple() @@ -1235,6 +1258,19 @@ void TestFunction() always_check(NotIdentity(false)); } + { + struct FTest + { + FTest(initializer_list, int32) { } + void operator()() { } + }; + + TFunction TempA(InPlaceType, { 0, 1, 2 }, 3); + TempA.Emplace({ 0, 1, 2 }, 3); + + TUniqueFunction TempB(InPlaceType, { 0, 1, 2 }, 3); + TempB.Emplace({ 0, 1, 2 }, 3); + } } void TestAtomic() diff --git a/Redcraft.Utility/Source/Public/Templates/Any.h b/Redcraft.Utility/Source/Public/Templates/Any.h index 95af043..b27a7ad 100644 --- a/Redcraft.Utility/Source/Public/Templates/Any.h +++ b/Redcraft.Utility/Source/Public/Templates/Any.h @@ -106,6 +106,13 @@ public: { EmplaceImpl(Forward(Args)...); } + + /** Constructs an object with initial content an object of type TDecay, direct-non-list-initialized from IL, Forward(Args).... */ + template requires (NAMESPACE_PRIVATE::CFAnyPlaceable && CConstructibleFrom, initializer_list, Ts&&...>) + FORCEINLINE explicit FAny(TInPlaceType, initializer_list IL, Ts&&... Args) + { + EmplaceImpl(IL, Forward(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, direct-non-list-initialized from Forward(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>(); } + /** + * Changes the contained object to one of type TDecay constructed from the arguments. + * First destroys the current contained object (if any) by Reset(), then constructs an object of type + * TDecay, direct-non-list-initialized from IL, Forward(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 requires (NAMESPACE_PRIVATE::CFAnyPlaceable && CConstructibleFrom, initializer_list, Ts&&...>) + FORCEINLINE TDecay& Emplace(initializer_list IL, Ts&&... Args) + { + Destroy(); + EmplaceImpl(IL, Forward(Args)...); + return GetValue>(); + } + /** @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); } diff --git a/Redcraft.Utility/Source/Public/Templates/Function.h b/Redcraft.Utility/Source/Public/Templates/Function.h index 48b04eb..42a932e 100644 --- a/Redcraft.Utility/Source/Public/Templates/Function.h +++ b/Redcraft.Utility/Source/Public/Templates/Function.h @@ -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 - FORCEINLINE constexpr TDecay& Emplace(ArgTypes&&... Args) + template + FORCEINLINE constexpr TDecay& Emplace(Us&&... Args) { using DecayedType = TDecay; @@ -525,7 +525,7 @@ protected: Storage.template Emplace( reinterpret_cast(Callable), - Forward(Args)... + Forward(Args)... ); return *reinterpret_cast(Storage.GetValuePtr()); @@ -641,12 +641,24 @@ public: * Constructs an TFunction with initial content an function object of type TDecay, * direct-non-list-initialized from Forward(Args).... */ - template requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value - && CConstructibleFrom, ArgTypes...> && CCopyConstructible> + template requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value + && CConstructibleFrom, Ts...> && CCopyConstructible> && CMoveConstructible> && CDestructible>) - FORCEINLINE explicit TFunction(TInPlaceType, ArgTypes&&... Args) + FORCEINLINE explicit TFunction(TInPlaceType, Ts&&... Args) { - Impl::template Emplace(Forward(Args)...); + 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).... + */ + template requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value + && CConstructibleFrom, initializer_list, Ts...> && CCopyConstructible> + && CMoveConstructible> && CDestructible>) + FORCEINLINE explicit TFunction(TInPlaceType, initializer_list IL, Ts&&... Args) + { + Impl::template Emplace(IL, Forward(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, direct-non-list-initialized from Forward(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 requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value - && CConstructibleFrom, ArgTypes...> && CCopyConstructible> + template requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value + && CConstructibleFrom, Ts...> && CCopyConstructible> && CMoveConstructible> && CDestructible>) - FORCEINLINE TDecay& Emplace(ArgTypes&&... Args) + FORCEINLINE TDecay& Emplace(Ts&&... Args) { Impl::Destroy(); - return Impl::template Emplace(Forward(Args)...); + 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 + * TDecay, direct-non-list-initialized from IL, Forward(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 requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value + && CConstructibleFrom, initializer_list, Ts...> && CCopyConstructible> + && CMoveConstructible> && CDestructible>) + FORCEINLINE TDecay& Emplace(initializer_list IL, Ts&&... Args) + { + Impl::Destroy(); + return Impl::template Emplace(IL, Forward(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, * direct-non-list-initialized from Forward(Args).... */ - template requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value - && CConstructibleFrom, ArgTypes...> && CMoveConstructible> && CDestructible>) - FORCEINLINE explicit TUniqueFunction(TInPlaceType, ArgTypes&&... Args) + template requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value + && CConstructibleFrom, Ts...> && CMoveConstructible> && CDestructible>) + FORCEINLINE explicit TUniqueFunction(TInPlaceType, Ts&&... Args) { - Impl::template Emplace(Forward(Args)...); + 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).... + */ + template requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value + && CConstructibleFrom, initializer_list, Ts...> && CMoveConstructible> && CDestructible>) + FORCEINLINE explicit TUniqueFunction(TInPlaceType, initializer_list IL, Ts&&... Args) + { + Impl::template Emplace(IL, Forward(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 requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value - && CConstructibleFrom, ArgTypes...> && CMoveConstructible> && CDestructible>) - FORCEINLINE TDecay& Emplace(ArgTypes&&... Args) + template requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value + && CConstructibleFrom, Ts...> && CMoveConstructible> && CDestructible>) + FORCEINLINE TDecay& Emplace(Ts&&... Args) { Impl::Destroy(); using DecayedType = TDecay; - return Impl::template Emplace(Forward(Args)...); + 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 + * TDecay, direct-non-list-initialized from IL, Forward(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 requires (NAMESPACE_PRIVATE::TIsInvocableSignature>::Value + && CConstructibleFrom, initializer_list, Ts...> && CMoveConstructible> && CDestructible>) + FORCEINLINE TDecay& Emplace(initializer_list IL, Ts&&... Args) + { + Impl::Destroy(); + using DecayedType = TDecay; + return Impl::template Emplace(IL, Forward(Args)...); } /** Removes any bound callable from the TUniqueFunction, restoring it to the default empty state. */ diff --git a/Redcraft.Utility/Source/Public/Templates/Optional.h b/Redcraft.Utility/Source/Public/Templates/Optional.h index 3b7a10f..3987917 100644 --- a/Redcraft.Utility/Source/Public/Templates/Optional.h +++ b/Redcraft.Utility/Source/Public/Templates/Optional.h @@ -66,6 +66,14 @@ public: { new (&Value) OptionalType(Forward(Args)...); } + + /** Constructs an object with initial content an object, direct-non-list-initialized from IL, Forward(Args).... */ + template requires (CConstructibleFrom, Ts...>) + FORCEINLINE constexpr explicit TOptional(FInPlace, initializer_list IL, Ts&&... Args) + : bIsValid(true) + { + new (&Value) OptionalType(IL, Forward(Args)...); + } /** Copies content of other into a new instance. */ FORCEINLINE constexpr TOptional(const TOptional& InValue) requires (CTriviallyCopyConstructible) = 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(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 requires (CConstructibleFrom) - FORCEINLINE constexpr OptionalType& Emplace(ArgTypes&&... Args) + template requires (CConstructibleFrom) + FORCEINLINE constexpr OptionalType& Emplace(Ts&&... Args) { Reset(); - OptionalType* Result = new (&Value) OptionalType(Forward(Args)...); + OptionalType* Result = new (&Value) OptionalType(Forward(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(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 requires (CConstructibleFrom, Ts...>) + FORCEINLINE constexpr OptionalType& Emplace(initializer_list IL, Ts&&... Args) + { + Reset(); + + OptionalType* Result = new (&Value) OptionalType(IL, Forward(Args)...); bIsValid = true; return *Result; diff --git a/Redcraft.Utility/Source/Public/Templates/Variant.h b/Redcraft.Utility/Source/Public/Templates/Variant.h index 2eaee81..945deb2 100644 --- a/Redcraft.Utility/Source/Public/Templates/Variant.h +++ b/Redcraft.Utility/Source/Public/Templates/Variant.h @@ -142,6 +142,22 @@ public: using SelectedType = TVariantAlternative>; new (&Value) SelectedType(Forward(Args)...); } + + /** Constructs a variant with the specified alternative T and initializes the contained value with the arguments IL, Forward(Args).... */ + template requires (CConstructibleFrom, Us...>) + FORCEINLINE constexpr explicit TVariant(TInPlaceType, initializer_list IL, Us&&... Args) + : TVariant(InPlaceIndex>>, IL, Forward(Args)...) + { } + + /** Constructs a variant with the alternative T specified by the index I and initializes the contained value with the arguments IL, Forward(Args).... */ + template requires (I < sizeof...(Ts) + && CConstructibleFrom>, initializer_list, Us...>) + FORCEINLINE constexpr explicit TVariant(TInPlaceIndex, initializer_list IL, Us&&... Args) + : TypeIndex(I) + { + using SelectedType = TVariantAlternative>; + new (&Value) SelectedType(IL, Forward(Args)...); + } /** Destroys the contained object, if any, as if by a call to Reset(). */ FORCEINLINE constexpr ~TVariant() requires (true && ... && CTriviallyDestructible) = 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(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(IL, Forward(Args)...), where I is the zero-based index of T in Types.... */ + template requires (CConstructibleFrom, Us...>) + FORCEINLINE constexpr T& Emplace(initializer_list IL, Us&&... Args) + { + return Emplace>>(IL, Forward(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(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 requires (I < sizeof...(Ts) + && CConstructibleFrom>, initializer_list, Us...>) + FORCEINLINE constexpr TVariantAlternative>& Emplace(initializer_list IL, Us&&... Args) + { + Reset(); + + using SelectedType = TVariantAlternative>; + SelectedType* Result = new (&Value) SelectedType(IL, Forward(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); }