From 6f80a34e10708f05847ffba3065ecb5aabbbfed8 Mon Sep 17 00:00:00 2001 From: Alexander Taepper Date: Wed, 29 Jul 2026 19:03:33 +0200 Subject: [PATCH 1/2] remove `call_traits::argument_count` in favor of type_traits --- cpp/src/arrow/util/async_generator.h | 10 +++-- cpp/src/arrow/util/functional.h | 13 ------ cpp/src/arrow/util/future.h | 59 +++++++++++----------------- cpp/src/arrow/util/thread_pool.h | 16 ++++---- 4 files changed, 37 insertions(+), 61 deletions(-) diff --git a/cpp/src/arrow/util/async_generator.h b/cpp/src/arrow/util/async_generator.h index 056b842bb730..01eebc6c9997 100644 --- a/cpp/src/arrow/util/async_generator.h +++ b/cpp/src/arrow/util/async_generator.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "arrow/util/async_generator_fwd.h" #include "arrow/util/async_util.h" @@ -266,7 +267,7 @@ class MappingGenerator { /// /// If the source generator is async-reentrant then this generator will be also template , + typename Mapped = std::invoke_result_t, typename V = typename EnsureFuture::type::ValueType> AsyncGenerator MakeMappedGenerator(AsyncGenerator source_generator, MapFn map) { auto map_callback = [map = std::move(map)](const T& val) mutable -> Future { @@ -286,7 +287,7 @@ AsyncGenerator MakeMappedGenerator(AsyncGenerator source_generator, MapFn /// /// If the source generator is async-reentrant then this generator will be also template , + typename Mapped = std::invoke_result_t, typename V = typename EnsureFuture::type::ValueType> AsyncGenerator MakeFlatMappedGenerator(AsyncGenerator source_generator, MapFn map) { return MakeConcatenatedGenerator( @@ -1439,8 +1440,9 @@ class MergedGenerator { immediate_inner(next_item.result()); if (immediate_inner.was_empty) { Future> next_source = state->PullSource(); - if (next_source.TryAddCallback( - [this] { return OuterCallback{state, index}; })) { + if (next_source.TryAddCallback([this] { + return OuterCallback{state, index}; + })) { // We hit an unfinished future so we can stop looping return; } diff --git a/cpp/src/arrow/util/functional.h b/cpp/src/arrow/util/functional.h index 14e09b6f8a69..4444b747c837 100644 --- a/cpp/src/arrow/util/functional.h +++ b/cpp/src/arrow/util/functional.h @@ -52,23 +52,10 @@ struct call_traits { static typename std::tuple_element>::type argument_type_impl( R (F::*)(A...) &&); - template - static std::integral_constant argument_count_impl(R (F::*)(A...)); - - template - static std::integral_constant argument_count_impl(R (F::*)(A...) - const); - - template - static std::integral_constant argument_count_impl(R (F::*)(A...) &&); - /// 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())); - - template - using argument_count = decltype(argument_count_impl(&std::decay::type::operator())); }; /// A type erased callable object which may only be invoked once. diff --git a/cpp/src/arrow/util/future.h b/cpp/src/arrow/util/future.h index 0aa284270371..fa45427a9d3d 100644 --- a/cpp/src/arrow/util/future.h +++ b/cpp/src/arrow/util/future.h @@ -50,18 +50,6 @@ struct is_future : std::false_type {}; template struct is_future> : std::true_type {}; -template -struct result_of; - -template -struct result_of()(std::declval()...))>> { - using type = decltype(std::declval()(std::declval()...)); -}; - -template -using result_of_t = typename result_of::type; - // Helper to find the synchronous counterpart for a Future template struct SyncType { @@ -75,12 +63,15 @@ struct SyncType { template using first_arg_is_status = - std::is_same>::type, - Status>; + std::is_same>, Status>; -template > -using if_has_no_args = typename std::conditional::type; +template +using if_has_no_args = std::conditional_t, Then, Else>; + +template +using continuation_result_t = + typename if_has_no_args, + std::invoke_result>::type; /// Creates a callback that can be added to a future to mark a `dest` future finished template using ForReturn = typename ForReturnImpl::type; - template - using ForSignature = ForReturn>; - // If the callback returns void then we return Future<> that always finishes OK. template , + typename ContinueResult = std::invoke_result_t, typename NextFuture = ForReturn> typename std::enable_if::value>::type operator()( NextFuture next, ContinueFunc&& f, Args&&... a) const { @@ -141,7 +129,7 @@ struct ContinueFuture { /// If the callback returns Status and we return Future<> then also send the callback /// result as-is to the destination future. template , + typename ContinueResult = std::invoke_result_t, typename NextFuture = ForReturn> typename std::enable_if< !std::is_void::value && !is_future::value && @@ -158,7 +146,7 @@ struct ContinueFuture { /// OnSuccess callback is void/Status (e.g. you would get this calling the one-arg /// version of Then with an OnSuccess callback that returns void) template , + typename ContinueResult = std::invoke_result_t, typename NextFuture = ForReturn> typename std::enable_if::value && !is_future::value && NextFuture::is_empty && @@ -171,7 +159,7 @@ struct ContinueFuture { /// future and add a callback to the future given to us by the user that forwards the /// result to the future we just created template , + typename ContinueResult = std::invoke_result_t, typename NextFuture = ForReturn> typename std::enable_if::value>::type operator()( NextFuture next, ContinueFunc&& f, Args&&... a) const { @@ -507,7 +495,7 @@ class [[nodiscard]] Future { /// Returns true if a callback was actually added and false if the callback failed /// to add because the future was marked complete. template , + typename OnComplete = std::invoke_result_t, typename Callback = WrapOnComplete> bool TryAddCallback(CallbackFactory callback_factory, CallbackOptions opts = CallbackOptions::Defaults()) const { @@ -516,16 +504,15 @@ class [[nodiscard]] Future { template struct ThenOnComplete { - static constexpr bool has_no_args = - internal::call_traits::argument_count::value == 0; + static constexpr bool has_no_args = std::is_invocable_v; - using ContinuedFuture = detail::ContinueFuture::ForSignature< - detail::if_has_no_args>; + using ContinuedFuture = + detail::ContinueFuture::ForReturn>; - static_assert( - std::is_same, - ContinuedFuture>::value, - "OnSuccess and OnFailure must continue with the same future type"); + static_assert(std::is_same>, + ContinuedFuture>::value, + "OnSuccess and OnFailure must continue with the same future type"); struct DummyOnSuccess { void operator()(const T&); @@ -558,8 +545,8 @@ class [[nodiscard]] Future { template struct PassthruOnFailure { - using ContinuedFuture = detail::ContinueFuture::ForSignature< - detail::if_has_no_args>; + using ContinuedFuture = + detail::ContinueFuture::ForReturn>; Result operator()(const Status& s) { return s; } }; @@ -803,7 +790,7 @@ using ControlFlow = std::optional; /// \return A future which will complete when a Future returned by iterate completes with /// a Break template ::ValueType, + typename Control = typename std::invoke_result_t::ValueType, typename BreakValueType = typename Control::value_type> Future Loop(Iterate iterate) { struct Callback { diff --git a/cpp/src/arrow/util/thread_pool.h b/cpp/src/arrow/util/thread_pool.h index 201b8cef790d..ce33c4c201bc 100644 --- a/cpp/src/arrow/util/thread_pool.h +++ b/cpp/src/arrow/util/thread_pool.h @@ -139,8 +139,8 @@ class ARROW_EXPORT Executor { // will return the callable's result value once. // The callable's arguments are copied before execution. template > + typename FutureType = ::arrow::detail::ContinueFuture::ForReturn< + std::invoke_result_t>> Result Submit(TaskHints hints, StopToken stop_token, Function&& func, Args&&... args) { using ValueType = typename FutureType::ValueType; @@ -165,24 +165,24 @@ class ARROW_EXPORT Executor { } template > + typename FutureType = ::arrow::detail::ContinueFuture::ForReturn< + std::invoke_result_t>> Result Submit(StopToken stop_token, Function&& func, Args&&... args) { return Submit(TaskHints{}, stop_token, std::forward(func), std::forward(args)...); } template > + typename FutureType = ::arrow::detail::ContinueFuture::ForReturn< + std::invoke_result_t>> Result Submit(TaskHints hints, Function&& func, Args&&... args) { return Submit(std::move(hints), StopToken::Unstoppable(), std::forward(func), std::forward(args)...); } template > + typename FutureType = ::arrow::detail::ContinueFuture::ForReturn< + std::invoke_result_t>> Result Submit(Function&& func, Args&&... args) { return Submit(TaskHints{}, StopToken::Unstoppable(), std::forward(func), std::forward(args)...); From 6c95106eba35d1e68f38b72bdaa36be2bc787857 Mon Sep 17 00:00:00 2001 From: Alexander Taepper Date: Fri, 31 Jul 2026 09:14:01 +0200 Subject: [PATCH 2/2] missed file formatting --- cpp/src/arrow/util/async_generator.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp/src/arrow/util/async_generator.h b/cpp/src/arrow/util/async_generator.h index 01eebc6c9997..63cb01a9fe49 100644 --- a/cpp/src/arrow/util/async_generator.h +++ b/cpp/src/arrow/util/async_generator.h @@ -1440,9 +1440,8 @@ class MergedGenerator { immediate_inner(next_item.result()); if (immediate_inner.was_empty) { Future> next_source = state->PullSource(); - if (next_source.TryAddCallback([this] { - return OuterCallback{state, index}; - })) { + if (next_source.TryAddCallback( + [this] { return OuterCallback{state, index}; })) { // We hit an unfinished future so we can stop looping return; }