2626
2727namespace async {
2828namespace _then {
29- template <stdx::ct_string Name, typename HandleTag , typename CompleteTag,
29+ template <stdx::ct_string Name, typename HandleTags , typename CompleteTag,
3030 typename S, typename R, typename ... Fs>
3131struct receiver {
3232 using is_receiver = void ;
@@ -53,7 +53,7 @@ struct receiver {
5353 private:
5454 template <typename T, typename ... Args>
5555 auto handle (Args &&...args) -> void {
56- if constexpr (std::same_as<HandleTag , T>) {
56+ if constexpr (boost::mp11::mp_contains<HandleTags , T>::value ) {
5757 auto results = stdx::call_by_need (
5858 std::move (fs),
5959 stdx::tuple<Args &&...>{std::forward<Args>(args)...});
@@ -76,15 +76,15 @@ template <typename Tag> struct as_signature {
7676};
7777} // namespace detail
7878
79- template <stdx::ct_string Name, typename HandleTag , typename CompleteTag,
79+ template <stdx::ct_string Name, typename HandleTags , typename CompleteTag,
8080 typename S, typename ... Fs>
8181struct sender {
8282 template <async::receiver R>
8383 [[nodiscard]] constexpr auto connect (R &&r) && {
8484 check_connect<sender &&, R>();
8585 return async::connect (
8686 std::move (s),
87- receiver<Name, HandleTag , CompleteTag, S, std::remove_cvref_t <R>,
87+ receiver<Name, HandleTags , CompleteTag, S, std::remove_cvref_t <R>,
8888 Fs...>{std::forward<R>(r), std::move (fs)});
8989 }
9090
@@ -95,8 +95,8 @@ struct sender {
9595 [[nodiscard]] constexpr auto connect (R &&r) const & {
9696 check_connect<sender const &, R>();
9797 return async::connect (
98- s, receiver<Name, HandleTag , CompleteTag, S, std:: remove_cvref_t <R> ,
99- Fs...>{std::forward<R>(r), fs});
98+ s, receiver<Name, HandleTags , CompleteTag, S,
99+ std:: remove_cvref_t <R>, Fs...>{std::forward<R>(r), fs});
100100 }
101101
102102 template <typename ... Ts>
@@ -107,31 +107,23 @@ struct sender {
107107 std::declval<stdx::tuple<Ts...>>()))>;
108108
109109 template <typename Env>
110- requires std::same_as<HandleTag, set_value_t >
111110 [[nodiscard]] constexpr static auto get_completion_signatures (Env const &) {
112- return transform_completion_signatures_of<
113- S, Env, completion_signatures<>, signatures>{};
114- }
115-
116- template <typename Env>
117- requires std::same_as<HandleTag, set_error_t >
118- [[nodiscard]] constexpr static auto get_completion_signatures (Env const &) {
119- return transform_completion_signatures_of<
120- S, Env, completion_signatures<>, ::async::detail::default_set_value,
121- signatures>{};
122- }
123-
124- template <typename Env>
125- requires std::same_as<HandleTag, set_stopped_t >
126- [[nodiscard]] constexpr static auto get_completion_signatures (Env const &) {
127- if constexpr (not sends_stopped<S, Env>) {
128- return completion_signatures_of_t <S, Env>{};
129- } else {
130- return transform_completion_signatures_of<
131- S, Env, completion_signatures<signatures<>>,
132- ::async::detail::default_set_value,
133- ::async::detail::default_set_error, completion_signatures<>>{};
134- }
111+ using tag_pred =
112+ boost::mp11::mp_apply<::async::detail::with_any_tag, HandleTags>;
113+ using raw_completions =
114+ boost::mp11::mp_partition_q<completion_signatures_of_t <S, Env>,
115+ tag_pred>;
116+
117+ using upstream_completions = boost::mp11::mp_first<raw_completions>;
118+ using dependent_completions =
119+ boost::mp11::mp_flatten<::async::detail::gather_signatures<
120+ tag_pred, upstream_completions, signatures,
121+ completion_signatures>>;
122+
123+ using unchanged_completions = boost::mp11::mp_second<raw_completions>;
124+
125+ return boost::mp11::mp_unique<boost::mp11::mp_append<
126+ dependent_completions, unchanged_completions>>{};
135127 }
136128
137129 using is_sender = void ;
@@ -144,15 +136,15 @@ struct sender {
144136 }
145137};
146138
147- template <stdx::ct_string Name, typename HandleTag , typename CompleteTag,
139+ template <stdx::ct_string Name, typename HandleTags , typename CompleteTag,
148140 typename ... Fs>
149141struct pipeable {
150142 [[no_unique_address]] stdx::tuple<Fs...> fs;
151143
152144 private:
153145 template <async::sender S, stdx::same_as_unqualified<pipeable> Self>
154146 friend constexpr auto operator |(S &&s, Self &&self) -> async::sender auto {
155- return sender<Name, HandleTag , CompleteTag, std::remove_cvref_t <S>,
147+ return sender<Name, HandleTags , CompleteTag, std::remove_cvref_t <S>,
156148 Fs...>{std::forward<S>(s), std::forward<Self>(self).fs };
157149 }
158150};
@@ -161,7 +153,7 @@ struct pipeable {
161153template <stdx::ct_string Name = " then" , stdx::callable... Fs>
162154[[nodiscard]] constexpr auto then (Fs &&...fs) {
163155 return compose (
164- _then::pipeable<Name, set_value_t , set_value_t ,
156+ _then::pipeable<Name, stdx::type_list< set_value_t > , set_value_t ,
165157 std::remove_cvref_t <Fs>...>{std::forward<Fs>(fs)...});
166158}
167159
@@ -173,8 +165,8 @@ template <stdx::ct_string Name = "then", sender S, stdx::callable... Fs>
173165template <stdx::ct_string Name = " upon_error" , stdx::callable F>
174166[[nodiscard]] constexpr auto upon_error (F &&f) {
175167 return compose (
176- _then::pipeable<Name, set_error_t , set_value_t , std:: remove_cvref_t <F>>{
177- std::forward<F>(f)});
168+ _then::pipeable<Name, stdx::type_list< set_error_t > , set_value_t ,
169+ std:: remove_cvref_t <F>>{ std::forward<F>(f)});
178170}
179171
180172template <stdx::ct_string Name = " upon_error" , sender S, stdx::callable F>
@@ -184,8 +176,9 @@ template <stdx::ct_string Name = "upon_error", sender S, stdx::callable F>
184176
185177template <stdx::ct_string Name = " upon_stopped" , stdx::callable F>
186178[[nodiscard]] constexpr auto upon_stopped (F &&f) {
187- return compose (_then::pipeable<Name, set_stopped_t , set_value_t ,
188- std::remove_cvref_t <F>>{std::forward<F>(f)});
179+ return compose (
180+ _then::pipeable<Name, stdx::type_list<set_stopped_t >, set_value_t ,
181+ std::remove_cvref_t <F>>{std::forward<F>(f)});
189182}
190183
191184template <stdx::ct_string Name = " upon_stopped" , sender S, stdx::callable F>
@@ -196,7 +189,7 @@ template <stdx::ct_string Name = "upon_stopped", sender S, stdx::callable F>
196189template <stdx::ct_string Name = " then_error" , stdx::callable... Fs>
197190[[nodiscard]] constexpr auto then_error (Fs &&...fs) {
198191 return compose (
199- _then::pipeable<Name, set_value_t , set_error_t ,
192+ _then::pipeable<Name, stdx::type_list< set_value_t > , set_error_t ,
200193 std::remove_cvref_t <Fs>...>{std::forward<Fs>(fs)...});
201194}
202195
@@ -208,7 +201,7 @@ template <stdx::ct_string Name = "then_error", sender S, stdx::callable... Fs>
208201template <stdx::ct_string Name = " transform_error" , stdx::callable... Fs>
209202[[nodiscard]] constexpr auto transform_error (Fs &&...fs) {
210203 return compose (
211- _then::pipeable<Name, set_error_t , set_error_t ,
204+ _then::pipeable<Name, stdx::type_list< set_error_t > , set_error_t ,
212205 std::remove_cvref_t <Fs>...>{std::forward<Fs>(fs)...});
213206}
214207
@@ -218,46 +211,93 @@ template <stdx::ct_string Name = "transform_error", sender S,
218211 return std::forward<S>(s) | transform_error<Name>(std::forward<Fs>(fs)...);
219212}
220213
214+ template <
215+ auto Channels = stdx::type_list<set_value_t , set_error_t , set_stopped_t >{},
216+ stdx::ct_string Name = " multithen" , stdx::callable... Fs>
217+ [[nodiscard]] constexpr auto multithen (Fs &&...fs) {
218+ return compose (
219+ _then::pipeable<Name, std::remove_cvref_t <decltype (Channels)>,
220+ set_value_t , std::remove_cvref_t <Fs>...>{
221+ std::forward<Fs>(fs)...});
222+ }
223+
224+ template <
225+ auto Channels = stdx::type_list<set_value_t , set_error_t , set_stopped_t >{},
226+ stdx::ct_string Name = " multithen" , sender S, stdx::callable... Fs>
227+ [[nodiscard]] constexpr auto multithen (S &&s, Fs &&...fs) -> sender auto {
228+ return std::forward<S>(s) |
229+ multithen<Channels, Name>(std::forward<Fs>(fs)...);
230+ }
231+
232+ template <channel_tag T, channel_tag U>
233+ [[nodiscard]] consteval auto operator |(T, U)
234+ -> boost::mp11::mp_unique<stdx::type_list<T, U>> {
235+ return {};
236+ }
237+
238+ template <channel_tag T, channel_tag... Us>
239+ [[nodiscard]] consteval auto operator |(T, stdx::type_list<Us...>)
240+ -> boost::mp11::mp_unique<stdx::type_list<T, Us...>> {
241+ return {};
242+ }
243+
244+ template <channel_tag T, channel_tag... Us>
245+ [[nodiscard]] consteval auto operator |(stdx::type_list<Us...>, T)
246+ -> boost::mp11::mp_unique<stdx::type_list<T, Us...>> {
247+ return {};
248+ }
249+
250+ template <channel_tag... Ts, channel_tag... Us>
251+ [[nodiscard]] consteval auto operator |(stdx::type_list<Ts...>,
252+ stdx::type_list<Us...>)
253+ -> boost::mp11::mp_unique<stdx::type_list<Ts..., Us...>> {
254+ return {};
255+ }
256+
221257struct then_t ;
222258struct upon_error_t ;
223259struct upon_stopped_t ;
224260
225261struct then_error_t ;
226262struct transform_error_t ;
227263
264+ struct multithen_t ;
265+
228266namespace _then {
229267namespace detail {
230- template <typename HandleTag, typename CompleteTag> struct debug_tag ;
268+ template <typename HandleTags, typename CompleteTag> struct debug_tag {
269+ using type = multithen_t ;
270+ };
231271
232- template <> struct debug_tag <set_value_t , set_value_t > {
272+ template <> struct debug_tag <stdx::type_list< set_value_t > , set_value_t > {
233273 using type = then_t ;
234274};
235- template <> struct debug_tag <set_error_t , set_value_t > {
275+ template <> struct debug_tag <stdx::type_list< set_error_t > , set_value_t > {
236276 using type = upon_error_t ;
237277};
238- template <> struct debug_tag <set_stopped_t , set_value_t > {
278+ template <> struct debug_tag <stdx::type_list< set_stopped_t > , set_value_t > {
239279 using type = upon_stopped_t ;
240280};
241281
242- template <> struct debug_tag <set_value_t , set_error_t > {
282+ template <> struct debug_tag <stdx::type_list< set_value_t > , set_error_t > {
243283 using type = then_error_t ;
244284};
245- template <> struct debug_tag <set_error_t , set_error_t > {
285+ template <> struct debug_tag <stdx::type_list< set_error_t > , set_error_t > {
246286 using type = transform_error_t ;
247287};
248288
249- template <typename HandleTag , typename CompleteTag>
250- using debug_tag_t = typename debug_tag<HandleTag , CompleteTag>::type;
289+ template <typename HandleTags , typename CompleteTag>
290+ using debug_tag_t = typename debug_tag<HandleTags , CompleteTag>::type;
251291} // namespace detail
252292} // namespace _then
253293
254- template <stdx::ct_string Name, typename HandleTag , typename CompleteTag,
294+ template <stdx::ct_string Name, typename HandleTags , typename CompleteTag,
255295 typename ... Ts>
256296struct debug ::context_for<
257- _then::receiver<Name, HandleTag , CompleteTag, Ts...>> {
258- using tag = _then::detail::debug_tag_t <HandleTag , CompleteTag>;
297+ _then::receiver<Name, HandleTags , CompleteTag, Ts...>> {
298+ using tag = _then::detail::debug_tag_t <HandleTags , CompleteTag>;
259299 constexpr static auto name = Name;
260- using type = _then::receiver<Name, HandleTag , CompleteTag, Ts...>;
300+ using type = _then::receiver<Name, HandleTags , CompleteTag, Ts...>;
261301 using children = stdx::type_list<debug::erased_context_for<
262302 connect_result_t <typename type::sender_t &&, type &&>>>;
263303};
0 commit comments