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.ensure_started]
37 namespace __ensure_started
38 {
39 using namespace __shared;
40 
41 struct __ensure_started_t
42 {};
43 
44 struct ensure_started_t
45 {
46     template <sender _Sender, class _Env = empty_env>
47         requires sender_in<_Sender, _Env> && __decay_copyable<env_of_t<_Sender>>
operator ()stdexec::__ensure_started::ensure_started_t48     [[nodiscard]] auto operator()(_Sender&& __sndr, _Env&& __env = {}) const
49         -> __well_formed_sender auto
50     {
51         if constexpr (sender_expr_for<_Sender, __ensure_started_t>)
52         {
53             return static_cast<_Sender&&>(__sndr);
54         }
55         else
56         {
57             auto __domain = __get_late_domain(__sndr, __env);
58             return stdexec::transform_sender(
59                 __domain,
60                 __make_sexpr<ensure_started_t>(static_cast<_Env&&>(__env),
61                                                static_cast<_Sender&&>(__sndr)));
62         }
63     }
64 
65     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__ensure_started::ensure_started_t66     auto operator()() const noexcept -> __binder_back<ensure_started_t>
67     {
68         return {{}, {}, {}};
69     }
70 
71     using _Sender = __1;
72     using __legacy_customizations_t = //
73         __types<tag_invoke_t(ensure_started_t,
74                              get_completion_scheduler_t<set_value_t>(
75                                  get_env_t(const _Sender&)),
76                              _Sender),
77                 tag_invoke_t(ensure_started_t, _Sender)>;
78 
79     template <class _CvrefSender, class _Env>
80     using __receiver_t =
81         __t<__meval<__receiver, __cvref_id<_CvrefSender>, __id<_Env>>>;
82 
83     template <class _Sender>
transform_senderstdexec::__ensure_started::ensure_started_t84     static auto transform_sender(_Sender&& __sndr)
85     {
86         using _Receiver =
87             __receiver_t<__child_of<_Sender>, __decay_t<__data_of<_Sender>>>;
88         static_assert(sender_to<__child_of<_Sender>, _Receiver>);
89 
90         return __sexpr_apply(
91             static_cast<_Sender&&>(__sndr),
92             [&]<class _Env, class _Child>(__ignore, _Env&& __env,
93                                           _Child&& __child) {
94                 // The shared state starts life with a ref-count of one.
95                 auto __sh_state =
96                     __make_intrusive<__shared_state<_Child, __decay_t<_Env>>,
97                                      2>(static_cast<_Child&&>(__child),
98                                         static_cast<_Env&&>(__env));
99 
100                 // Eagerly start the work:
101                 __sh_state->__try_start();
102 
103                 return __make_sexpr<__ensure_started_t>(
104                     __box{__ensure_started_t(), std::move(__sh_state)});
105             });
106     }
107 };
108 } // namespace __ensure_started
109 
110 using __ensure_started::ensure_started_t;
111 inline constexpr ensure_started_t ensure_started{};
112 
113 template <>
114 struct __sexpr_impl<__ensure_started::__ensure_started_t> :
115     __shared::__shared_impl<__ensure_started::__ensure_started_t>
116 {};
117 
118 template <>
119 struct __sexpr_impl<ensure_started_t> : __sexpr_defaults
120 {
121     static constexpr auto get_completion_signatures = //
122         []<class _Sender>(_Sender&&) noexcept         //
123         -> __completion_signatures_of_t<              //
124             transform_sender_result_t<default_domain, _Sender, empty_env>> {};
125 };
126 } // namespace stdexec
127