1 /*
2  * Copyright (c) 2021-2024 NVIDIA Corporation
3  *
4  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5  * (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  *
8  *   https://llvm.org/LICENSE.txt
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include "__execution_fwd.hpp"
19 
20 // include these after __execution_fwd.hpp
21 #include "__basic_sender.hpp"
22 #include "__concepts.hpp"
23 #include "__intrusive_ptr.hpp"
24 #include "__meta.hpp"
25 #include "__sender_adaptor_closure.hpp"
26 #include "__senders.hpp"
27 #include "__shared.hpp"
28 #include "__transform_sender.hpp"
29 #include "__type_traits.hpp"
30 
31 #include <utility>
32 
33 namespace stdexec
34 {
35 ////////////////////////////////////////////////////////////////////////////
36 // [execution.senders.adaptors.split]
37 namespace __split
38 {
39 using namespace __shared;
40 
41 struct __split_t
42 {};
43 
44 struct split_t
45 {
46     template <sender _Sender, class _Env = empty_env>
47         requires sender_in<_Sender, _Env> && __decay_copyable<env_of_t<_Sender>>
operator ()stdexec::__split::split_t48     auto operator()(_Sender&& __sndr,
49                     _Env&& __env = {}) const -> __well_formed_sender auto
50     {
51         auto __domain = __get_late_domain(__sndr, __env);
52         return stdexec::transform_sender(
53             __domain, __make_sexpr<split_t>(static_cast<_Env&&>(__env),
54                                             static_cast<_Sender&&>(__sndr)));
55     }
56 
57     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__split::split_t58     auto operator()() const noexcept -> __binder_back<split_t>
59     {
60         return {{}, {}, {}};
61     }
62 
63     using _Sender = __1;
64     using __legacy_customizations_t = //
65         __types<tag_invoke_t(split_t,
66                              get_completion_scheduler_t<set_value_t>(
67                                  get_env_t(const _Sender&)),
68                              _Sender),
69                 tag_invoke_t(split_t, _Sender)>;
70 
71     template <class _CvrefSender, class _Env>
72     using __receiver_t =
73         __t<__meval<__receiver, __cvref_id<_CvrefSender>, __id<_Env>>>;
74 
75     template <class _Sender>
transform_senderstdexec::__split::split_t76     static auto transform_sender(_Sender&& __sndr)
77     {
78         using _Receiver =
79             __receiver_t<__child_of<_Sender>, __decay_t<__data_of<_Sender>>>;
80         static_assert(sender_to<__child_of<_Sender>, _Receiver>);
81 
82         return __sexpr_apply(
83             static_cast<_Sender&&>(__sndr),
84             [&]<class _Env, class _Child>(__ignore, _Env&& __env,
85                                           _Child&& __child) {
86                 // The shared state starts life with a ref-count of one.
87                 auto __sh_state =
88                     __make_intrusive<__shared_state<_Child, __decay_t<_Env>>,
89                                      2>(static_cast<_Child&&>(__child),
90                                         static_cast<_Env&&>(__env));
91 
92                 return __make_sexpr<__split_t>(
93                     __box{__split_t(), std::move(__sh_state)});
94             });
95     }
96 };
97 } // namespace __split
98 
99 using __split::split_t;
100 inline constexpr split_t split{};
101 
102 template <>
103 struct __sexpr_impl<__split::__split_t> :
104     __shared::__shared_impl<__split::__split_t>
105 {};
106 
107 template <>
108 struct __sexpr_impl<split_t> : __sexpr_defaults
109 {
110     static constexpr auto get_completion_signatures = //
111         []<class _Sender>(_Sender&&) noexcept         //
112         -> __completion_signatures_of_t<              //
113             transform_sender_result_t<default_domain, _Sender, empty_env>> {};
114 };
115 } // namespace stdexec
116