From 738656f035d77e10115e76a83e9357d56bbc5cfe Mon Sep 17 00:00:00 2001 From: Hyukjin Kwon Date: Tue, 20 Jan 2026 20:45:03 +0900 Subject: [PATCH] [C++] Enhance arrow::internal::call_traits to support function pointers (and maybe ...?) --- cpp/src/arrow/array/array_dict.cc | 3 +- cpp/src/arrow/type_test.cc | 10 +-- cpp/src/arrow/util/async_generator.h | 5 +- cpp/src/arrow/util/functional.h | 96 ++++++++++++++++++++++++++-- 4 files changed, 98 insertions(+), 16 deletions(-) diff --git a/cpp/src/arrow/array/array_dict.cc b/cpp/src/arrow/array/array_dict.cc index 2e54e6ec490..cad492a6efd 100644 --- a/cpp/src/arrow/array/array_dict.cc +++ b/cpp/src/arrow/array/array_dict.cc @@ -540,8 +540,7 @@ Result> DictionaryUnifier::UnifyChunkedArray( return array; } ArrayVector chunks(array->num_chunks()); - std::transform(data_chunks.begin(), data_chunks.end(), chunks.begin(), - [](const std::shared_ptr& data) { return MakeArray(data); }); + std::transform(data_chunks.begin(), data_chunks.end(), chunks.begin(), MakeArray); return std::make_shared(std::move(chunks), array->type()); } diff --git a/cpp/src/arrow/type_test.cc b/cpp/src/arrow/type_test.cc index e9b1d30e6e7..6fcb3b16aac 100644 --- a/cpp/src/arrow/type_test.cc +++ b/cpp/src/arrow/type_test.cc @@ -1950,22 +1950,24 @@ void CheckListListTypeMetadata(ListListTypeFactory list_type_factory) { } TEST(TestListType, Metadata) { - CheckListListTypeMetadata([](std::shared_ptr field) { return list(field); }); + CheckListListTypeMetadata( + static_cast (*)(std::shared_ptr)>(&list)); } TEST(TestLargeListType, Metadata) { CheckListListTypeMetadata( - [](std::shared_ptr field) { return large_list(field); }); + static_cast (*)(std::shared_ptr)>(&large_list)); } TEST(TestListViewType, Metadata) { CheckListListTypeMetadata( - [](std::shared_ptr field) { return list_view(field); }); + static_cast (*)(std::shared_ptr)>(&list_view)); } TEST(TestLargeListViewType, Metadata) { CheckListListTypeMetadata( - [](std::shared_ptr field) { return large_list_view(field); }); + static_cast (*)(std::shared_ptr)>( + &large_list_view)); } TEST(TestNestedType, Equals) { diff --git a/cpp/src/arrow/util/async_generator.h b/cpp/src/arrow/util/async_generator.h index 056b842bb73..9ef9c75d5b6 100644 --- a/cpp/src/arrow/util/async_generator.h +++ b/cpp/src/arrow/util/async_generator.h @@ -1490,9 +1490,8 @@ Result> MakeSequencedMergedGenerator( if (max_subscriptions == 1) { return Status::Invalid("Use MakeConcatenatedGenerator if max_subscriptions is 1"); } - AsyncGenerator> autostarting_source = MakeMappedGenerator( - std::move(source), - [](const AsyncGenerator& sub) { return MakeAutoStartingGenerator(sub); }); + AsyncGenerator> autostarting_source = + MakeMappedGenerator(std::move(source), MakeAutoStartingGenerator); AsyncGenerator> sub_readahead = MakeSerialReadaheadGenerator(std::move(autostarting_source), max_subscriptions - 1); return MakeConcatenatedGenerator(std::move(sub_readahead)); diff --git a/cpp/src/arrow/util/functional.h b/cpp/src/arrow/util/functional.h index 41e268852fa..a137e318e3c 100644 --- a/cpp/src/arrow/util/functional.h +++ b/cpp/src/arrow/util/functional.h @@ -36,8 +36,7 @@ struct Empty { } }; -/// Helper struct for examining lambdas and other callables. -/// TODO(ARROW-12655) support function pointers +/// Helper struct for examining lambdas, functors, and function pointers. struct call_traits { public: template @@ -49,12 +48,24 @@ struct call_traits { template static std::true_type is_overloaded_impl(...); + // Function pointer overloads for return_type_impl + template + static R return_type_impl(R (*)(A...)); + template static R return_type_impl(R (F::*)(A...)); template static R return_type_impl(R (F::*)(A...) const); + template + static R return_type_impl(R (F::*)(A...) &&); + + // Function pointer overloads for argument_type_impl + template + static typename std::tuple_element>::type argument_type_impl( + R (*)(A...)); + template static typename std::tuple_element>::type argument_type_impl( R (F::*)(A...)); @@ -67,6 +78,10 @@ struct call_traits { static typename std::tuple_element>::type argument_type_impl( R (F::*)(A...) &&); + // Function pointer overloads for argument_count_impl + template + static std::integral_constant argument_count_impl(R (*)(A...)); + template static std::integral_constant argument_count_impl(R (F::*)(A...)); @@ -77,12 +92,33 @@ struct call_traits { template static std::integral_constant argument_count_impl(R (F::*)(A...) &&); + private: + // Helper to detect function pointers + template + struct is_function_pointer { + using decayed = typename std::decay::type; + using pointee = typename std::remove_pointer::type; + static constexpr bool value = + std::is_pointer::value && std::is_function::value; + }; + + public: /// bool constant indicating whether F is a callable with more than one possible /// signature. Will be true_type for objects which define multiple operator() or which /// define a template operator() + template ::value> + struct is_overloaded_base { + using type = decltype(is_overloaded_impl::type>(NULLPTR)); + }; + + // Function pointers are never overloaded + template + struct is_overloaded_base { + using type = std::false_type; + }; + template - using is_overloaded = - decltype(is_overloaded_impl::type>(NULLPTR)); + using is_overloaded = typename is_overloaded_base::type; template using enable_if_overloaded = typename std::enable_if::value, T>::type; @@ -91,16 +127,62 @@ struct call_traits { using disable_if_overloaded = typename std::enable_if::value, T>::type; + private: + // SFINAE-friendly helpers that dispatch based on whether F is a function pointer + template ::value> + struct argument_type_helper; + + // Specialization for function pointers + template + struct argument_type_helper { + using type = + decltype(argument_type_impl(std::declval::type>())); + }; + + // Specialization for functors/lambdas + template + struct argument_type_helper { + using type = decltype(argument_type_impl(&std::decay::type::operator())); + }; + + template ::value> + struct argument_count_helper; + + template + struct argument_count_helper { + using type = + decltype(argument_count_impl(std::declval::type>())); + }; + + template + struct argument_count_helper { + using type = decltype(argument_count_impl(&std::decay::type::operator())); + }; + + template ::value> + struct return_type_helper; + + template + struct return_type_helper { + using type = decltype(return_type_impl(std::declval::type>())); + }; + + template + struct return_type_helper { + using type = decltype(return_type_impl(&std::decay::type::operator())); + }; + + public: /// If F is not overloaded, the argument types of its call operator can be /// extracted via call_traits::argument_type template - using argument_type = decltype(argument_type_impl(&std::decay::type::operator())); + using argument_type = typename argument_type_helper::type; template - using argument_count = decltype(argument_count_impl(&std::decay::type::operator())); + using argument_count = typename argument_count_helper::type; template - using return_type = decltype(return_type_impl(&std::decay::type::operator())); + using return_type = typename return_type_helper::type; template using enable_if_return =