xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__sender_adaptor_closure.hpp (revision 6269157344064457b7e1241d4efe59c6c51c7a59)
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 "__concepts.hpp"
19  #include "__execution_fwd.hpp"
20  #include "__senders_core.hpp"
21  #include "__tuple.hpp"
22  #include "__type_traits.hpp"
23  
24  namespace stdexec
25  {
26  // NOT TO SPEC:
27  namespace __closure
28  {
29  template <__class _Dp>
30  struct sender_adaptor_closure;
31  } // namespace __closure
32  
33  using __closure::sender_adaptor_closure;
34  
35  template <class _Tp>
36  concept __sender_adaptor_closure =
37      derived_from<__decay_t<_Tp>, sender_adaptor_closure<__decay_t<_Tp>>> &&
38      move_constructible<__decay_t<_Tp>> //
39      && constructible_from<__decay_t<_Tp>, _Tp>;
40  
41  template <class _Tp, class _Sender>
42  concept __sender_adaptor_closure_for =     //
43      __sender_adaptor_closure<_Tp>          //
44      && sender<__decay_t<_Sender>>          //
45      && __callable<_Tp, __decay_t<_Sender>> //
46      && sender<__call_result_t<_Tp, __decay_t<_Sender>>>;
47  
48  namespace __closure
49  {
50  template <class _T0, class _T1>
51  struct __compose : sender_adaptor_closure<__compose<_T0, _T1>>
52  {
53      STDEXEC_ATTRIBUTE((no_unique_address))
54      _T0 __t0_;
55      STDEXEC_ATTRIBUTE((no_unique_address))
56      _T1 __t1_;
57  
58      template <sender _Sender>
59          requires __callable<_T0, _Sender> &&
60                   __callable<_T1, __call_result_t<_T0, _Sender>>
61      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__closure::__compose62      __call_result_t<_T1, __call_result_t<_T0, _Sender>> operator()(
63          _Sender&& __sndr) &&
64      {
65          return static_cast<_T1&&>(__t1_)(
66              static_cast<_T0&&>(__t0_)(static_cast<_Sender&&>(__sndr)));
67      }
68  
69      template <sender _Sender>
70          requires __callable<const _T0&, _Sender> &&
71                   __callable<const _T1&, __call_result_t<const _T0&, _Sender>>
72      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__closure::__compose73      __call_result_t<_T1, __call_result_t<_T0, _Sender>> operator()(
74          _Sender&& __sndr) const&
75      {
76          return __t1_(__t0_(static_cast<_Sender&&>(__sndr)));
77      }
78  };
79  
80  template <__class _Dp>
81  struct sender_adaptor_closure
82  {};
83  
84  template <sender _Sender, __sender_adaptor_closure_for<_Sender> _Closure>
85  STDEXEC_ATTRIBUTE((always_inline))
operator |(_Sender && __sndr,_Closure && __clsur)86  __call_result_t<_Closure, _Sender> operator|(_Sender&& __sndr,
87                                               _Closure&& __clsur)
88  {
89      return static_cast<_Closure&&>(__clsur)(static_cast<_Sender&&>(__sndr));
90  }
91  
92  template <__sender_adaptor_closure _T0, __sender_adaptor_closure _T1>
93  STDEXEC_ATTRIBUTE((always_inline))
operator |(_T0 && __t0,_T1 && __t1)94  __compose<__decay_t<_T0>, __decay_t<_T1>> operator|(_T0&& __t0, _T1&& __t1)
95  {
96      return {{}, static_cast<_T0&&>(__t0), static_cast<_T1&&>(__t1)};
97  }
98  
99  template <class _Fun, class... _As>
100  struct __binder_back :
101      __tuple_for<_As...>,
102      sender_adaptor_closure<__binder_back<_Fun, _As...>>
103  {
104      STDEXEC_ATTRIBUTE((no_unique_address))
105      _Fun __fun_{};
106  
107  #if STDEXEC_INTELLISENSE()
108      // MSVCBUG
109      // https://developercommunity.visualstudio.com/t/rejects-valid-EDG-invocation-of-lambda/10786020
110  
111      template <class _Sender>
112      struct __lambda_rvalue
113      {
114          __binder_back& __self_;
115          _Sender& __sndr_;
116  
117          STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back::__lambda_rvalue118          auto operator()(_As&... __as) const //
119              noexcept(__nothrow_callable<_Fun, _Sender, _As...>)
120                  -> __call_result_t<_Fun, _Sender, _As...>
121          {
122              return static_cast<_Fun&&>(__self_.__fun_)(
123                  static_cast<_Sender&&>(__sndr_), static_cast<_As&&>(__as)...);
124          }
125      };
126  
127      template <class _Sender>
128      struct __lambda_lvalue
129      {
130          const __binder_back& __self_;
131          _Sender& __sndr_;
132  
133          STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back::__lambda_lvalue134          auto operator()(const _As&... __as) const //
135              noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
136                  -> __call_result_t<const _Fun&, _Sender, const _As&...>
137          {
138              return __self_.__fun_(static_cast<_Sender&&>(__sndr_), __as...);
139          }
140      };
141  #endif
142  
143      template <sender _Sender>
144          requires __callable<_Fun, _Sender, _As...>
145      STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back146      auto operator()(_Sender&& __sndr) && //
147          noexcept(__nothrow_callable<_Fun, _Sender, _As...>)
148              -> __call_result_t<_Fun, _Sender, _As...>
149      {
150  #if STDEXEC_INTELLISENSE()
151          return this->apply(__lambda_rvalue<_Sender>{*this, __sndr}, *this);
152  #else
153          return this->apply(
154              [&__sndr, this](_As&... __as) //
155              noexcept(__nothrow_callable<_Fun, _Sender, _As...>)
156                  -> __call_result_t<_Fun, _Sender, _As...> {
157                  return static_cast<_Fun&&>(
158                      __fun_)(static_cast<_Sender&&>(__sndr),
159                              static_cast<_As&&>(__as)...);
160              },
161              *this);
162  #endif
163      }
164  
165      template <sender _Sender>
166          requires __callable<const _Fun&, _Sender, const _As&...>
167      STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__closure::__binder_back168      auto operator()(_Sender&& __sndr) const& //
169          noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
170              -> __call_result_t<const _Fun&, _Sender, const _As&...>
171      {
172  #if STDEXEC_INTELLISENSE()
173          return this->apply(__lambda_lvalue<_Sender>{*this, __sndr}, *this);
174  #else
175          return this->apply(
176              [&__sndr, this](const _As&... __as) //
177              noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
178                  -> __call_result_t<const _Fun&, _Sender, const _As&...> {
179                  return __fun_(static_cast<_Sender&&>(__sndr), __as...);
180              },
181              *this);
182  #endif
183      }
184  };
185  } // namespace __closure
186  
187  using __closure::__binder_back;
188  } // namespace stdexec
189