diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index c2793ce..a843591 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -1003,6 +1003,24 @@ void TestTuple() ); } + { + TTuple TempA = { 1, 'A' }; + + TempA.Visit([](auto&& A) { A++; }); + + TempA.Visit( + [] (T&& A) + { + if constexpr (CSameAs) always_check(A == 2); + else if constexpr (CSameAs) always_check(A == 'B'); + else always_check_no_entry(); + } + ); + + always_check(TempA.Visit([](auto A) { return A; }, 0) == 2 ); + always_check(TempA.Visit([](auto A) { return A; }, 1) == 'B'); + } + { TTuple TempA = { 1, 'A' }; TTuple TempB = TempA.Transform([](auto&& InValue) { return InValue + 1; }); diff --git a/Redcraft.Utility/Source/Public/Templates/Tuple.h b/Redcraft.Utility/Source/Public/Templates/Tuple.h index 6f4b10e..e004ffe 100644 --- a/Redcraft.Utility/Source/Public/Templates/Tuple.h +++ b/Redcraft.Utility/Source/Public/Templates/Tuple.h @@ -56,7 +56,7 @@ template struct TTupleConvertCopy : FTrue { }; template -struct TTupleConvertCopy +struct TTupleConvertCopy : TBoolConstant&, T> || CConstructibleFrom&> || CSameAs)> @@ -93,7 +93,7 @@ public: FORCEINLINE constexpr TTupleBasicElement& operator=(const TTupleBasicElement&) = default; FORCEINLINE constexpr TTupleBasicElement& operator=(TTupleBasicElement&&) = default; FORCEINLINE constexpr ~TTupleBasicElement() = default; - + FORCEINLINE constexpr T& GetValue() & { return static_cast< T& >(Value); } FORCEINLINE constexpr const T& GetValue() const & { return static_cast(Value); } FORCEINLINE constexpr volatile T& GetValue() volatile& { return static_cast< volatile T& >(Value); } @@ -203,7 +203,7 @@ public: static_assert(sizeof...(Indices) == TTupleArityImpl>::Value && TTupleArityImpl>::Value == TTupleArityImpl>::Value, "Cannot assign tuple from different size"); - + ((LHS.template GetValue() = Forward(RHS).template GetValue()), ...); } @@ -278,6 +278,31 @@ struct TTTupleSynthThreeWayComparable, TTypeSequence<>> : FTrue template concept CTTupleSynthThreeWayComparable = TTTupleSynthThreeWayComparable::Value; +template +struct TTupleVisitElementByIndex; + +template +struct TTupleVisitElementByIndex> +{ + template + FORCEINLINE static constexpr decltype(auto) Do(F&& Func, TTupleType&& Arg, size_t Index) + { + if (Index == I) return InvokeResult(Forward(Func), Forward(Arg).template GetValue()); + return TTupleVisitElementByIndex>::Do(Forward(Func), Forward(Arg), Index); + } +}; + +template +struct TTupleVisitElementByIndex> +{ + template + FORCEINLINE static constexpr decltype(auto) Do(F&& Func, TTupleType&& Arg, size_t) + { + checkf(false, "Read access violation. Please check Index."); + return InvokeResult(Forward(Func), Forward(Arg).template GetValue<0>()); + } +}; + NAMESPACE_PRIVATE_END template @@ -297,21 +322,21 @@ class TTuple final : public NAMESPACE_PRIVATE::TTupleImpl, Ts...>; + using Super = NAMESPACE_PRIVATE::TTupleImpl, Ts...>; using Helper = NAMESPACE_PRIVATE::TTupleHelper>; public: /** Default constructor. Value-initializes all elements, if any. */ FORCEINLINE constexpr TTuple() = default; - + /** Converting constructor. Initializes each element of the tuple with the corresponding value in Forward(Args). */ template requires (sizeof...(Ts) >= 1 && sizeof...(Us) == sizeof...(Ts)) && (true && ... && CConstructibleFrom) FORCEINLINE constexpr explicit (!(true && ... && CConvertibleTo)) TTuple(Us&&... Args) : Super(NAMESPACE_PRIVATE::ForwardingConstructor, Forward(Args)...) { } - + /** Converting copy constructor. Initializes each element of the tuple with the corresponding element of other. */ template requires (sizeof...(Us) == sizeof...(Ts) && (true && ... && CConstructibleFrom) @@ -353,7 +378,7 @@ public: /** Copy/move assignment operator. */ FORCEINLINE constexpr TTuple& operator=(const TTuple&) = default; FORCEINLINE constexpr TTuple& operator=(TTuple&&) = default; - + /** Compares every element of the tuple lhs with the corresponding element of the tuple rhs. */ template requires (sizeof...(Ts) == sizeof...(Us) && NAMESPACE_PRIVATE::CTTupleWeaklyEqualityComparable, TTypeSequence>) NODISCARD friend FORCEINLINE constexpr bool operator==(const TTuple& LHS, const TTuple& RHS) @@ -366,7 +391,7 @@ public: } (TMakeIndexSequence()); } - + /** Compares lhs and rhs lexicographically by synthesized three-way comparison. */ template requires (sizeof...(Ts) == sizeof...(Us) && NAMESPACE_PRIVATE::CTTupleSynthThreeWayComparable, TTypeSequence>) NODISCARD friend FORCEINLINE constexpr TCommonComparisonCategory...> operator<=>(const TTuple& LHS, const TTuple& RHS) @@ -376,26 +401,26 @@ public: } /** Extracts the Ith element from the tuple. I must be an integer value in [0, sizeof...(Ts)). */ - template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() & { return static_cast< NAMESPACE_PRIVATE::TTupleBasicElement>, I>& >(*this).GetValue(); } - template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const & { return static_cast>, I>& >(*this).GetValue(); } - template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() volatile& { return static_cast< volatile NAMESPACE_PRIVATE::TTupleBasicElement>, I>& >(*this).GetValue(); } - template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile& { return static_cast>, I>& >(*this).GetValue(); } - template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() && { return static_cast< NAMESPACE_PRIVATE::TTupleBasicElement>, I>&&>(*this).GetValue(); } - template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const && { return static_cast>, I>&&>(*this).GetValue(); } - template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() volatile&& { return static_cast< volatile NAMESPACE_PRIVATE::TTupleBasicElement>, I>&&>(*this).GetValue(); } - template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile&& { return static_cast>, I>&&>(*this).GetValue(); } + template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() & { return static_cast< NAMESPACE_PRIVATE::TTupleBasicElement, I>& >(*this).GetValue(); } + template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const & { return static_cast, I>& >(*this).GetValue(); } + template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() volatile& { return static_cast< volatile NAMESPACE_PRIVATE::TTupleBasicElement, I>& >(*this).GetValue(); } + template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile& { return static_cast, I>& >(*this).GetValue(); } + template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() && { return static_cast< NAMESPACE_PRIVATE::TTupleBasicElement, I>&&>(*this).GetValue(); } + template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const && { return static_cast, I>&&>(*this).GetValue(); } + template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() volatile&& { return static_cast< volatile NAMESPACE_PRIVATE::TTupleBasicElement, I>&&>(*this).GetValue(); } + template requires (I < sizeof...(Ts)) NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile&& { return static_cast, I>&&>(*this).GetValue(); } /** Extracts the element of the tuple whose type is T. Fails to compile unless the tuple has exactly one element of that type. */ - template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() & { return static_cast< TTuple& >(*this).GetValue>>(); } - template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const & { return static_cast(*this).GetValue>>(); } - template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() volatile& { return static_cast< volatile TTuple& >(*this).GetValue>>(); } - template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile& { return static_cast(*this).GetValue>>(); } - template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() && { return static_cast< TTuple&&>(*this).GetValue>>(); } - template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const && { return static_cast(*this).GetValue>>(); } - template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() volatile&& { return static_cast< volatile TTuple&&>(*this).GetValue>>(); } - template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile&& { return static_cast(*this).GetValue>>(); } + template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() & { return static_cast< TTuple& >(*this).GetValue>(); } + template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const & { return static_cast(*this).GetValue>(); } + template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() volatile& { return static_cast< volatile TTuple& >(*this).GetValue>(); } + template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile& { return static_cast(*this).GetValue>(); } + template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() && { return static_cast< TTuple&&>(*this).GetValue>(); } + template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const && { return static_cast(*this).GetValue>(); } + template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() volatile&& { return static_cast< volatile TTuple&&>(*this).GetValue>(); } + template NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile&& { return static_cast(*this).GetValue>(); } - /** Invoke the Callable object 'Func' with a tuple of arguments. */ + /** Invoke the callable object 'Func' with a tuple of arguments. */ template requires (CInvocable) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) & { return Helper::Apply(Forward(Func), static_cast< TTuple& >(*this)); } template requires (CInvocable) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const & { return Helper::Apply(Forward(Func), static_cast(*this)); } template requires (CInvocable) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) volatile& { return Helper::Apply(Forward(Func), static_cast< volatile TTuple& >(*this)); } @@ -405,6 +430,36 @@ public: template requires (CInvocable) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) volatile&& { return Helper::Apply(Forward(Func), static_cast< volatile TTuple&&>(*this)); } template requires (CInvocable) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const volatile&& { return Helper::Apply(Forward(Func), static_cast(*this)); } + /** Visits each element in a tuple in parallel and applies it as arguments to the function. */ + template requires (true && ... && CInvocable) FORCEINLINE constexpr void Visit(F&& Func) & { VisitTuple(Forward(Func), static_cast< TTuple& >(*this)); } + template requires (true && ... && CInvocable) FORCEINLINE constexpr void Visit(F&& Func) const & { VisitTuple(Forward(Func), static_cast(*this)); } + template requires (true && ... && CInvocable) FORCEINLINE constexpr void Visit(F&& Func) volatile& { VisitTuple(Forward(Func), static_cast< volatile TTuple& >(*this)); } + template requires (true && ... && CInvocable) FORCEINLINE constexpr void Visit(F&& Func) const volatile& { VisitTuple(Forward(Func), static_cast(*this)); } + template requires (true && ... && CInvocable) FORCEINLINE constexpr void Visit(F&& Func) && { VisitTuple(Forward(Func), static_cast< TTuple&&>(*this)); } + template requires (true && ... && CInvocable) FORCEINLINE constexpr void Visit(F&& Func) const && { VisitTuple(Forward(Func), static_cast(*this)); } + template requires (true && ... && CInvocable) FORCEINLINE constexpr void Visit(F&& Func) volatile&& { VisitTuple(Forward(Func), static_cast< volatile TTuple&&>(*this)); } + template requires (true && ... && CInvocable) FORCEINLINE constexpr void Visit(F&& Func) const volatile&& { VisitTuple(Forward(Func), static_cast(*this)); } + + /** Visits specified element in a tuple and applies it as arguments to the function. */ + template requires ((sizeof...(Ts) >= 1 && CCommonType...>) && ... && (CInvocable)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) & { return static_cast< TTuple& >(*this).Visit...>>(Forward(Func), Index); } + template requires ((sizeof...(Ts) >= 1 && CCommonType...>) && ... && (CInvocable)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const & { return static_cast(*this).Visit...>>(Forward(Func), Index); } + template requires ((sizeof...(Ts) >= 1 && CCommonType...>) && ... && (CInvocable)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) volatile& { return static_cast< volatile TTuple& >(*this).Visit...>>(Forward(Func), Index); } + template requires ((sizeof...(Ts) >= 1 && CCommonType...>) && ... && (CInvocable)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const volatile& { return static_cast(*this).Visit...>>(Forward(Func), Index); } + template requires ((sizeof...(Ts) >= 1 && CCommonType...>) && ... && (CInvocable)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) && { return static_cast< TTuple&&>(*this).Visit...>>(Forward(Func), Index); } + template requires ((sizeof...(Ts) >= 1 && CCommonType...>) && ... && (CInvocable)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const && { return static_cast(*this).Visit...>>(Forward(Func), Index); } + template requires ((sizeof...(Ts) >= 1 && CCommonType...>) && ... && (CInvocable)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) volatile&& { return static_cast< volatile TTuple&&>(*this).Visit...>>(Forward(Func), Index); } + template requires ((sizeof...(Ts) >= 1 && CCommonType...>) && ... && (CInvocable)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const volatile&& { return static_cast(*this).Visit...>>(Forward(Func), Index); } + + /** Visits specified element in a tuple and applies it as arguments to the function. */ + template requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) & { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex>::Do(Forward(Func), static_cast< TTuple& >(*this), Index); } + template requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const & { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex>::Do(Forward(Func), static_cast(*this), Index); } + template requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) volatile& { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex>::Do(Forward(Func), static_cast< volatile TTuple& >(*this), Index); } + template requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const volatile& { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex>::Do(Forward(Func), static_cast(*this), Index); } + template requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) && { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex>::Do(Forward(Func), static_cast< TTuple&&>(*this), Index); } + template requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const && { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex>::Do(Forward(Func), static_cast(*this), Index); } + template requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) volatile&& { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex>::Do(Forward(Func), static_cast< volatile TTuple&&>(*this), Index); } + template requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const volatile&& { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex>::Do(Forward(Func), static_cast(*this), Index); } + /** Transform a tuple into another tuple using the given function. */ template requires (true && ... && (CInvocable && !CSameAs>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) & { return Helper::Transform(Forward(Func), static_cast< TTuple& >(*this)); } template requires (true && ... && (CInvocable && !CSameAs>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const & { return Helper::Transform(Forward(Func), static_cast(*this)); } @@ -575,7 +630,7 @@ template <> struct TTupleVisitImpl> { template - FORCEINLINE static constexpr void Do(TupleTypes&&... Tuples) { } + FORCEINLINE static constexpr void Do(TupleTypes&&...) { } }; NAMESPACE_PRIVATE_END @@ -597,7 +652,7 @@ FORCEINLINE constexpr decltype(auto) TupleCat(TTupleTypes&&... Args) * * @param Func - The function to apply. * @param Tuples - The tuples whose elements are to be applied to the function. - * + * * void SomeFunction(const TTuple& TupleA, const TTuple& TupleB) * { * // Equivalent to: