44#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_BULK
55#define INCLUDED_BEMAN_EXECUTION_DETAIL_BULK
66
7- #include " beman/execution/detail/callable .hpp"
8- #include " beman/execution/detail/get_completion_signatures .hpp"
9- #include " beman/execution/detail/nothrow_callable .hpp"
7+ #include < beman/execution/detail/get_completion_signatures .hpp>
8+ #include < beman/execution/detail/meta_combine .hpp>
9+ #include < beman/execution/detail/meta_unique .hpp>
1010#include < beman/execution/detail/basic_sender.hpp>
1111#include < beman/execution/detail/completion_signatures.hpp>
1212#include < beman/execution/detail/completion_signatures_for.hpp>
@@ -69,125 +69,35 @@ struct impls_for<bulk_t> : ::beman::execution::detail::default_impls {
6969 }();
7070
7171 } catch (...) {
72-
73- ::beman::execution::set_error (std::move(rcvr), std::current_exception());
72+ if constexpr (not nothrow) {
73+ ::beman::execution::set_error (std::move(rcvr), std::current_exception());
74+ }
7475 }
7576 } else {
7677 Tag ()(std::move (rcvr), std::forward<Args>(args)...);
7778 }
7879 };
7980};
8081
81- template <typename T>
82- struct print_type ;
83-
84- // Specialization to trigger a compile-time error and print the type
85- template <typename T>
86- struct print_type {
87- static_assert (sizeof (T) == 0 , " Debugging type..." );
88- };
89-
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;
108- };
109-
110- template <function_constraint T>
111- struct function_type_basis <T*> {
112- using type = T;
113- };
114-
115- template <function_constraint T>
116- struct function_type_basis <T&> {
117- using type = T;
118- };
119-
120- template <function_constraint T>
121- struct function_type_basis <T&&> {
122- using type = T;
123- };
124-
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- };
174-
17582template <typename , typename , typename >
17683struct fixed_completions_helper ;
17784
17885template <typename F, typename Shape, typename ... Args>
17986struct fixed_completions_helper <F, Shape, completion_signatures<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,
87+
88+ template <typename , typename >
89+ struct may_throw ;
90+ template <typename XF, typename Tag, typename ... XArgs>
91+ struct may_throw <XF, Tag(XArgs...)> {
92+ static constexpr bool value = std::same_as<Tag, ::beman::execution::set_value_t > &&
93+ not ::std::is_nothrow_invocable<XF, Shape, XArgs...>();
94+ };
95+ template <typename XF, typename ... Sigs>
96+ struct may_throw <XF, completion_signatures<Sigs...>> {
97+ static constexpr bool value = (false || ... || may_throw<XF, Sigs>::value);
98+ };
99+
100+ using type = std::conditional_t <!may_throw<F, Args...>::value,
191101 completion_signatures<Args...>,
192102 completion_signatures<Args..., set_error_t (std::exception_ptr)>>;
193103};
@@ -202,8 +112,8 @@ struct completion_signatures_for_impl<
202112 Env> {
203113
204114 using completions = decltype (get_completion_signatures(std::declval<Sender>(), std::declval<Env>()));
205- using type = fixed_completions<F, Shape, completions>;
206- // print_type<F> debug ;
115+ using type = ::beman::execution::detail::meta::unique<
116+ ::beman::execution::detail::meta::combine<fixed_completions<F, Shape, completions>>> ;
207117};
208118
209119} // namespace beman::execution::detail
0 commit comments