From 1ac82dc83eb364e25de8e24a0d0bbd8fdc0bd304 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 19 Dec 2025 08:26:07 +0000 Subject: [PATCH] Updated invoke.h from the code in the inplace_function branch --- include/etl/invoke.h | 339 +++++++++++++++++++++++++++++++------------ 1 file changed, 250 insertions(+), 89 deletions(-) diff --git a/include/etl/invoke.h b/include/etl/invoke.h index 67606e26..3f86350c 100644 --- a/include/etl/invoke.h +++ b/include/etl/invoke.h @@ -36,113 +36,274 @@ SOFTWARE. #include "function_traits.h" #include "type_traits.h" #include "utility.h" +#include "type_list.h" -namespace etl { - template struct logical_not_t : etl::integral_constant {}; +#if ETL_USING_CPP11 - /// is T a function -- a function cannot be const qualified like a variable - template struct is_function : public etl::integral_constant::value> { }; - template struct is_function : public etl::false_type { }; - template struct is_function : public etl::false_type { }; +namespace etl +{ + //**************************************************************************** + // invoke implementation + //**************************************************************************** - /// is T a member pointer - template struct is_member_pointer_helper : etl::false_type {}; - template struct is_member_pointer_helper : etl::true_type {}; - template struct is_member_pointer : is_member_pointer_helper> {}; - - /// is T a member function pointer - template struct is_member_function_pointer_helper : etl::false_type {}; - template struct is_member_function_pointer_helper : public etl::is_function::type {}; - template struct is_member_function_pointer : public is_member_function_pointer_helper>::type {}; - - /// is T a member object pointer - template struct is_member_object_pointer_helper : public etl::false_type { }; - template struct is_member_object_pointer_helper : public logical_not_t>::type { }; - template struct is_member_object_pointer : public is_member_object_pointer_helper>::type {}; - - template < - typename F, - typename ... TArgs, - typename = typename etl::enable_if< - !etl::is_member_pointer>::value>::type - > - ETL_CONSTEXPR auto invoke(F&& f, TArgs&& ... args) - -> decltype(etl::forward(f)(etl::forward(args)...)) { - return etl::forward(f)(etl::forward(args)...); - } - - template < - typename F, - typename T, - typename... TArgs, - typename = typename etl::enable_if< - etl::is_member_function_pointer>::value && - !etl::is_pointer>::value - >::type - > - ETL_CONSTEXPR auto invoke(F&& f, T&& t, TArgs&&... args) - -> decltype((etl::forward(t).*f)(etl::forward(args)...)) + //**************************************************************************** + /// Pointer to member function + reference_wrapper + template >::value && + etl::is_reference_wrapper>::value>> + ETL_CONSTEXPR auto invoke(TFunction&& f, TRefWrapper&& ref_wrapper, TArgs&&... args) + -> decltype((ref_wrapper.get().*f)(etl::forward(args)...)) { - return (etl::forward(t).*f)(etl::forward(args)...); + return (ref_wrapper.get().*f)(etl::forward(args)...); } - template < - typename F, - typename T, - typename ... TArgs, - typename = typename etl::enable_if< - etl::is_member_function_pointer>::value && - etl::is_pointer>::value - >::type - > - ETL_CONSTEXPR auto invoke(F&& f, T&& t, TArgs&&... args) - -> decltype(((*etl::forward(t)).*f)(etl::forward(args)...)) + //**************************************************************************** + /// Pointer to member function + pointer to object + template >::value && + etl::is_pointer>::value>> + ETL_CONSTEXPR auto invoke(TFunction&& f, TPtr&& ptr, TArgs&&... args) + -> decltype(((*etl::forward(ptr)).*f)(etl::forward(args)...)) { - return ((*etl::forward(t)).*f)(etl::forward(args)...); + return ((*etl::forward(ptr)).*f)(etl::forward(args)...); } - template < - typename F, - typename T, - typename = typename etl::enable_if< - etl::is_member_object_pointer>::value && - !etl::is_pointer>::value - >::type - > - ETL_CONSTEXPR auto invoke(F&& f, T&& t) - -> decltype(etl::forward(t).*f) + //**************************************************************************** + /// Pointer to member function + object (or derived) reference + template >::value && + !etl::is_pointer>::value && + !is_reference_wrapper>::value>> + ETL_CONSTEXPR auto invoke(TFunction&& f, TObject&& obj, TArgs&&... args) + -> decltype((etl::forward(obj).*f)(etl::forward(args)...)) { - return etl::forward(t).*f; + return (etl::forward(obj).*f)(etl::forward(args)...); } - template < - typename F, - typename T, - typename = typename etl::enable_if< - etl::is_member_object_pointer>::value && - etl::is_pointer>::value - >::type - > - ETL_CONSTEXPR auto invoke(F&& f, T&& t) - -> decltype(((*etl::forward(t)).*f)) + //**************************************************************************** + /// Pointer to member object + reference_wrapper + template >::value && + etl::is_reference_wrapper>::value>> + ETL_CONSTEXPR auto invoke(TFunction&& f, TRefWrapper&& ref_wrapper) + -> decltype(ref_wrapper.get().*f) { - return ((*etl::forward(t)).*f); + return ref_wrapper.get().*f; } - template struct invoke_result; + //**************************************************************************** + /// Pointer to member object + pointer to object + template >::value && + etl::is_pointer>::value>> + ETL_CONSTEXPR auto invoke(TFunction&& f, TPtr&& ptr) + -> decltype(((*etl::forward(ptr)).*f)) + { + return ((*etl::forward(ptr)).*f); + } - template - struct invoke_result< - F, - etl::void_t(), etl::declval()...))>, - Us... - > { - using type = decltype(etl::invoke(etl::declval(), etl::declval()...)); + //**************************************************************************** + /// Pointer to member object + object (or derived) reference + template >::value && + !etl::is_pointer>::value && + !is_reference_wrapper>::value>> + ETL_CONSTEXPR auto invoke(TFunction&& f, TObject&& obj) + -> decltype(etl::forward(obj).*f) + { + return etl::forward(obj).*f; + } + + //**************************************************************************** + /// General callable (function object / lambda / function pointer) + template >::value>> + ETL_CONSTEXPR auto invoke(TFunction&& f, TArgs&&... args) + -> decltype(etl::forward(f)(etl::forward(args)...)) + { + return etl::forward(f)(etl::forward(args)...); + } + + //**************************************************************************** + // is_invocable implementation + //**************************************************************************** + namespace private_invoke + { + //******************************************* + // Core detection of invocability. + // Succeeds if the invocation expression is well-formed. + template + struct is_invocable_expr + { + template + static auto test(int) -> decltype((void)etl::invoke(etl::declval(), etl::declval()...), etl::true_type{}); + + template + static etl::false_type test(...); + + using type = decltype(test(0)); + + static ETL_CONSTANT bool value = type::value; + }; + + //******************************************* + // Core detection of invocability. + // Succeeds if the invocation expression is well-formed. + // Using etl::type_list for the argument list. + template + struct is_invocable_expr> + { + template + static auto test(int) -> decltype((void)etl::invoke(etl::declval(), etl::declval()...), etl::true_type{}); + + template + static etl::false_type test(...); + + using type = decltype(test(0)); + + static ETL_CONSTANT bool value = type::value; + }; + + //******************************************* + // Map raw function type to pointer. + template + using effective_callable_t = etl::conditional_t>::value, + etl::add_pointer_t>, + TFunction>; + } + + //**************************************************************************** + /// invoke_result + template + struct invoke_result; + + template + struct invoke_result(), etl::declval()...))>, + TArgs...> + { + using type = decltype(etl::invoke(etl::declval(), etl::declval()...)); }; - template - using invoke_result_t = typename invoke_result::type; + template + using invoke_result_t = typename invoke_result::type; + + //**************************************************************************** + /// is_invocable + template + struct is_invocable + : etl::bool_constant, TArgs...>::value> + { + }; + + //**************************************************************************** + // Specialization to allow `etl::type_list<...>` as the second template parameter. + template + struct is_invocable> + : is_invocable + { + }; + + //**************************************************************************** + // is_invocable_r + template + struct is_invocable_r + : etl::conditional_t::value, + etl::is_invocable, + etl::conditional_t::value, + etl::bool_constant, TReturn>::value>, + etl::false_type>> + { + }; + + //**************************************************************************** + // Specialization to allow `etl::type_list<...>` as the second template parameter. + template + struct is_invocable_r> + : is_invocable_r + { + }; + + //**************************************************************************** + // Specialization to allow `etl::type_list<...>` when there is a preceding object argument. + template + struct is_invocable> + : is_invocable + { + }; + + //**************************************************************************** + // Specialization for is_invocable_r with a preceding object argument. + template + struct is_invocable_r> + : is_invocable_r + { + }; + +#if ETL_USING_CPP17 + //**************************************************************************** + /// is_nothrow_invocable + template + struct is_nothrow_invocable + : etl::bool_constant::value && + etl::function_traits>::is_noexcept> + { + }; + + //**************************************************************************** + /// is_nothrow_invocable_r + template + struct is_nothrow_invocable_r + : etl::bool_constant::value && + etl::function_traits>::is_noexcept && + (etl::is_same::value || + etl::is_nothrow_convertible, TReturn>::value)> + { + }; + + //**************************************************************************** + /// is_nothrow_invocable_r> + template + struct is_nothrow_invocable_r> + : etl::bool_constant::value && + etl::function_traits>::is_noexcept && + (etl::is_same::value || + etl::is_nothrow_convertible, TReturn>::value)> + { + }; + + //**************************************************************************** + // Specialization to allow `etl::type_list<...>` when there is a preceding object argument + // for the nothrow-with-return trait. + template + struct is_nothrow_invocable_r> + : is_nothrow_invocable_r + {}; +#endif + +#if ETL_USING_CPP17 + template + inline constexpr bool is_invocable_v = is_invocable::value; + + template + inline constexpr bool is_invocable_r_v = is_invocable_r::value; + template + inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable::value; + + template + inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r::value; +#endif } -#endif +#endif // ETL_USING_CPP11 +#endif // ETL_INVOKE_INCLUDED