Skip to content

Commit 4468684

Browse files
Deduce function signature for sender to ensure proper completion
1 parent 9e789a3 commit 4468684

File tree

2 files changed

+96
-22
lines changed

2 files changed

+96
-22
lines changed

include/beman/execution/detail/bulk.hpp

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -87,30 +87,107 @@ struct print_type {
8787
static_assert(sizeof(T) == 0, "Debugging type...");
8888
};
8989

90-
/*template <typename, typename, typename, typename,typename>
91-
struct fixed_completions_helper;
92-
template <typename F, typename Shape,typename Sender,typename Env, typename... Args>
93-
struct fixed_completions_helper<F, Shape,Sender, Env, completion_signatures<Args...>> {
94-
using completions = ::beman::execution::value_types_of_t<Sender,Env>;
95-
static_assert(std::is_invocable_v<F, completions>,"Error: The function is not callable with the given arguments.");
96-
using type = std::conditional_t<::beman::execution::detail::nothrow_callable<F, Args ...>,
97-
completion_signatures<Args...>,
98-
completion_signatures<Args..., set_error_t(std::exception_ptr)>>;
90+
template <typename T>
91+
concept function_constraint = std::is_function_v<T>;
92+
93+
template <typename T, typename... Args>
94+
struct function_type;
95+
96+
template <typename T, typename... Args>
97+
using function_type_t = typename function_type<T, Args...>::type;
98+
99+
template <typename>
100+
struct function_type_basis {};
101+
102+
template <typename T, typename...>
103+
struct function_type : function_type_basis<std::remove_cv_t<T>> {};
104+
105+
template <function_constraint T>
106+
struct function_type_basis<T> {
107+
using type = T;
99108
};
100109

101-
template <typename F, typename Shape, typename Sender , typename Env, typename completions>
102-
using fixed_completions = typename fixed_completions_helper<F, Shape, Sender , Env, completions>::type;*/
110+
template <function_constraint T>
111+
struct function_type_basis<T*> {
112+
using type = T;
113+
};
103114

115+
template <function_constraint T>
116+
struct function_type_basis<T&> {
117+
using type = T;
118+
};
104119

120+
template <function_constraint T>
121+
struct function_type_basis<T&&> {
122+
using type = T;
123+
};
105124

125+
template <function_constraint T, typename C>
126+
struct function_type_basis<T C::*> {
127+
using type = T;
128+
};
129+
130+
template <typename, typename...>
131+
struct function_object_type {};
132+
133+
template <typename C, typename... Args>
134+
requires(bool(&C::operator()))
135+
struct function_object_type<C, Args...> : function_type_basis<decltype(&C::operator())> {};
136+
137+
template <typename F, typename... Args>
138+
requires std::is_class<std::remove_cvref_t<F>>::value
139+
struct function_type<F, Args...> : function_object_type<F, Args...> {};
140+
141+
template <typename>
142+
struct function_traits;
143+
144+
// Specialization for function types
145+
template <typename R, typename... Args, bool NoExcept>
146+
struct function_traits<R(Args...) noexcept(NoExcept)> {
147+
// The return type
148+
using return_type = R;
149+
// A tuple containing all argument types
150+
using argument_types = std::tuple<Args...>;
151+
152+
// The number of arguments
153+
static constexpr std::size_t arity = sizeof...(Args);
154+
};
155+
156+
template <typename R, typename... Args, bool NoExcept>
157+
struct function_traits<R(Args...) const noexcept(NoExcept)> {
158+
// The return type
159+
using return_type = R;
160+
// A tuple containing all argument types
161+
using argument_types = std::tuple<Args...>;
162+
// The number of arguments
163+
static constexpr std::size_t arity = sizeof...(Args);
164+
};
165+
166+
template <typename F, typename FunctionType>
167+
struct is_invocable_with;
168+
169+
template <typename F, typename... Args>
170+
struct is_invocable_with<F, std::tuple<Args...>> {
171+
static constexpr bool is_invocable = std::is_invocable_v<F, Args...>;
172+
static constexpr bool is_no_throw = ::beman::execution::detail::nothrow_callable<F, Args...>;
173+
};
106174

107175
template <typename, typename, typename>
108176
struct fixed_completions_helper;
109177

110178
template <typename F, typename Shape, typename... Args>
111179
struct fixed_completions_helper<F, Shape, completion_signatures<Args...>> {
112-
//static_assert(std::is_invocable_v<F, Shape, Args...>,"Error: The function is not callable with the given arguments.");
113-
using type = std::conditional_t<::beman::execution::detail::nothrow_callable<F, Args ...>,
180+
// get function signature
181+
using signature = function_type_t<F>;
182+
// break apart return type and args types
183+
using signature_helper = function_traits<signature>;
184+
// get arg types
185+
using function_args_type = signature_helper::argument_types;
186+
// print_type<function_args_type> debug;
187+
// check if function is well form
188+
static_assert(is_invocable_with<F, function_args_type>::is_invocable,
189+
"Error: The function is not callable with the given arguments.");
190+
using type = std::conditional_t<is_invocable_with<F, function_args_type>::is_no_throw,
114191
completion_signatures<Args...>,
115192
completion_signatures<Args..., set_error_t(std::exception_ptr)>>;
116193
};
@@ -123,11 +200,10 @@ struct completion_signatures_for_impl<
123200
::beman::execution::detail::
124201
basic_sender<::beman::execution::detail::bulk_t, ::beman::execution::detail::product_type<Shape, F>, Sender>,
125202
Env> {
126-
127203

128204
using completions = decltype(get_completion_signatures(std::declval<Sender>(), std::declval<Env>()));
129205
using type = fixed_completions<F, Shape, completions>;
130-
//print_type<type> debug;
206+
// print_type<F> debug;
131207
};
132208

133209
} // namespace beman::execution::detail

tests/beman/execution/exec-bulk.test.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ auto test_bulk() {
4343
std::vector<int> results(a.size(), 0);
4444

4545
auto b2 = test_std::bulk(test_std::just(a), a.size(), [&](std::size_t index, const std::vector<int>& vec) {
46-
results[index] = vec[index] * b[index];
46+
results[index] = vec[index] * b[index];
4747
});
4848
static_assert(test_std::sender<decltype(b2)>);
4949
auto b2_env = test_std::get_env(b2);
@@ -58,20 +58,18 @@ auto test_bulk() {
5858
// Expected results: element-wise multiplication of a and b
5959
std::vector<int> expected{9, 20, 33, 52, 70, 90, 112, 136};
6060

61-
6261
for (size_t i = 0; i < results.size(); ++i) {
6362
ASSERT(results[i] == expected[i]);
6463
}
6564
}
6665

6766
auto test_bulk_noexept() {
68-
auto b0 = test_std::bulk(test_std::just(), 1, [](int) noexcept {});
67+
auto b0 = test_std::bulk(test_std::just(), 1, [](int) noexcept {});
6968
auto b0_env = test_std::get_env(b0);
7069
auto b0_completions = test_std::get_completion_signatures(b0, b0_env);
71-
/*static_assert(
72-
std::is_same_v<decltype(b0_completions),
73-
beman::execution::completion_signatures<beman::execution::set_value_t()> >,
74-
"Completion signatures do not match!");*/
70+
static_assert(std::is_same_v<decltype(b0_completions),
71+
beman::execution::completion_signatures<beman::execution::set_value_t()> >,
72+
"Completion signatures do not match!");
7573
static_assert(test_std::sender<decltype(b0)>);
7674
}
7775

0 commit comments

Comments
 (0)