xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/functional.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 "__detail/__config.hpp"
19  #include "__detail/__meta.hpp"
20  #include "__detail/__tag_invoke.hpp"
21  #include "concepts.hpp"
22  
23  #include <cstddef>
24  #include <functional>
25  #include <tuple>
26  #include <type_traits>
27  
28  namespace stdexec
29  {
30  template <class _Fun0, class _Fun1>
31  struct __composed
32  {
33      STDEXEC_ATTRIBUTE((no_unique_address))
34      _Fun0 __t0_;
35      STDEXEC_ATTRIBUTE((no_unique_address))
36      _Fun1 __t1_;
37  
38      template <class... _Ts>
39          requires __callable<_Fun1, _Ts...> &&
40                   __callable<_Fun0, __call_result_t<_Fun1, _Ts...>>
41      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__composed42      __call_result_t<_Fun0, __call_result_t<_Fun1, _Ts...>> operator()(
43          _Ts&&... __ts) &&
44      {
45          return static_cast<_Fun0&&>(__t0_)(
46              static_cast<_Fun1&&>(__t1_)(static_cast<_Ts&&>(__ts)...));
47      }
48  
49      template <class... _Ts>
50          requires __callable<const _Fun1&, _Ts...> &&
51                   __callable<const _Fun0&, __call_result_t<const _Fun1&, _Ts...>>
52      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__composed53      __call_result_t<_Fun0, __call_result_t<_Fun1, _Ts...>> operator()(
54          _Ts&&... __ts) const&
55      {
56          return __t0_(__t1_(static_cast<_Ts&&>(__ts)...));
57      }
58  };
59  
60  inline constexpr struct __compose_t
61  {
62      template <class _Fun0, class _Fun1>
63      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__compose_t64      __composed<_Fun0, _Fun1> operator()(_Fun0 __fun0, _Fun1 __fun1) const
65      {
66          return {static_cast<_Fun0&&>(__fun0), static_cast<_Fun1&&>(__fun1)};
67      }
68  } __compose{};
69  
70  namespace __invoke_
71  {
72  template <class>
73  inline constexpr bool __is_refwrap = false;
74  template <class _Up>
75  inline constexpr bool __is_refwrap<std::reference_wrapper<_Up>> = true;
76  
77  struct __funobj
78  {
79      template <class _Fun, class... _Args>
80      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__funobj81      constexpr auto operator()(_Fun&& __fun, _Args&&... __args) const noexcept(
82          noexcept((static_cast<_Fun&&>(__fun))(static_cast<_Args&&>(__args)...)))
83          -> decltype((static_cast<_Fun&&>(__fun))(
84              static_cast<_Args&&>(__args)...))
85      {
86          return static_cast<_Fun&&>(__fun)(static_cast<_Args&&>(__args)...);
87      }
88  };
89  
90  struct __memfn
91  {
92      template <class _Memptr, class _Ty, class... _Args>
93      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__memfn94      constexpr auto operator()(_Memptr __mem_ptr, _Ty&& __ty,
95                                _Args&&... __args) const
96          noexcept(noexcept(((static_cast<_Ty&&>(__ty)).*
97                             __mem_ptr)(static_cast<_Args&&>(__args)...)))
98              -> decltype(((static_cast<_Ty&&>(__ty)).*
99                           __mem_ptr)(static_cast<_Args&&>(__args)...))
100      {
101          return ((static_cast<_Ty&&>(__ty)).*__mem_ptr)(
102              static_cast<_Args&&>(__args)...);
103      }
104  };
105  
106  struct __memfn_refwrap
107  {
108      template <class _Memptr, class _Ty, class... _Args>
109      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__memfn_refwrap110      constexpr auto operator()(_Memptr __mem_ptr, _Ty __ty,
111                                _Args&&... __args) const
112          noexcept(noexcept((__ty.get().*
113                             __mem_ptr)(static_cast<_Args&&>(__args)...)))
114              -> decltype((__ty.get().*
115                           __mem_ptr)(static_cast<_Args&&>(__args)...))
116      {
117          return (__ty.get().*__mem_ptr)(static_cast<_Args&&>(__args)...);
118      }
119  };
120  
121  struct __memfn_smartptr
122  {
123      template <class _Memptr, class _Ty, class... _Args>
124      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__memfn_smartptr125      constexpr auto operator()(_Memptr __mem_ptr, _Ty&& __ty,
126                                _Args&&... __args) const
127          noexcept(noexcept(((*static_cast<_Ty&&>(__ty)).*
128                             __mem_ptr)(static_cast<_Args&&>(__args)...)))
129              -> decltype(((*static_cast<_Ty&&>(__ty)).*
130                           __mem_ptr)(static_cast<_Args&&>(__args)...))
131      {
132          return ((*static_cast<_Ty&&>(__ty)).*__mem_ptr)(
133              static_cast<_Args&&>(__args)...);
134      }
135  };
136  
137  struct __memobj
138  {
139      template <class _Mbr, class _Class, class _Ty>
140      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__memobj141      constexpr auto operator()(_Mbr _Class::* __mem_ptr,
142                                _Ty&& __ty) const noexcept
143          -> decltype(((static_cast<_Ty&&>(__ty)).*__mem_ptr))
144      {
145          return ((static_cast<_Ty&&>(__ty)).*__mem_ptr);
146      }
147  };
148  
149  struct __memobj_refwrap
150  {
151      template <class _Mbr, class _Class, class _Ty>
152      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__memobj_refwrap153      constexpr auto operator()(_Mbr _Class::* __mem_ptr, _Ty __ty) const noexcept
154          -> decltype((__ty.get().*__mem_ptr))
155      {
156          return (__ty.get().*__mem_ptr);
157      }
158  };
159  
160  struct __memobj_smartptr
161  {
162      template <class _Mbr, class _Class, class _Ty>
163      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__memobj_smartptr164      constexpr auto operator()(_Mbr _Class::* __mem_ptr,
165                                _Ty&& __ty) const noexcept
166          -> decltype(((*static_cast<_Ty&&>(__ty)).*__mem_ptr))
167      {
168          return ((*static_cast<_Ty&&>(__ty)).*__mem_ptr);
169      }
170  };
171  
172  auto __invoke_selector(__ignore, __ignore) noexcept -> __funobj;
173  
174  template <class _Mbr, class _Class, class _Ty>
__invoke_selector(_Mbr _Class::*,const _Ty &)175  auto __invoke_selector(_Mbr _Class::*, const _Ty&) noexcept
176  {
177      if constexpr (STDEXEC_IS_CONST(_Mbr) || STDEXEC_IS_CONST(const _Mbr))
178      {
179          // member function ptr case
180          if constexpr (STDEXEC_IS_BASE_OF(_Class, _Ty))
181          {
182              return __memobj{};
183          }
184          else if constexpr (__is_refwrap<_Ty>)
185          {
186              return __memobj_refwrap{};
187          }
188          else
189          {
190              return __memobj_smartptr{};
191          }
192      }
193      else
194      {
195          // member object ptr case
196          if constexpr (STDEXEC_IS_BASE_OF(_Class, _Ty))
197          {
198              return __memfn{};
199          }
200          else if constexpr (__is_refwrap<_Ty>)
201          {
202              return __memfn_refwrap{};
203          }
204          else
205          {
206              return __memfn_smartptr{};
207          }
208      }
209  }
210  
211  struct __invoke_t
212  {
213      template <class _Fun>
214      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__invoke_t215      constexpr auto operator()(_Fun&& __fun) const
216          noexcept(noexcept((static_cast<_Fun&&>(__fun))()))
217              -> decltype((static_cast<_Fun&&>(__fun))())
218      {
219          return static_cast<_Fun&&>(__fun)();
220      }
221  
222      template <class _Fun, class _Ty, class... _Args>
223      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__invoke_::__invoke_t224      constexpr auto operator()(_Fun&& __fun, _Ty&& __ty, _Args&&... __args) const
225          noexcept(noexcept(__invoke_selector(__fun, __ty)(
226              static_cast<_Fun&&>(__fun), static_cast<_Ty&&>(__ty),
227              static_cast<_Args&&>(__args)...)))
228              -> decltype(__invoke_selector(__fun, __ty)(
229                  static_cast<_Fun&&>(__fun), static_cast<_Ty&&>(__ty),
230                  static_cast<_Args&&>(__args)...))
231      {
232          return decltype(__invoke_selector(__fun, __ty))()(
233              static_cast<_Fun&&>(__fun), static_cast<_Ty&&>(__ty),
234              static_cast<_Args&&>(__args)...);
235      }
236  };
237  } // namespace __invoke_
238  
239  inline constexpr __invoke_::__invoke_t __invoke{};
240  
241  template <class _Fun, class... _As>
242  concept __invocable = //
243      requires(_Fun&& __f, _As&&... __as) {
244          __invoke(static_cast<_Fun&&>(__f), static_cast<_As&&>(__as)...);
245      };
246  
247  template <class _Fun, class... _As>
248  concept __nothrow_invocable =    //
249      __invocable<_Fun, _As...> && //
250      requires(_Fun&& __f, _As&&... __as) {
251          {
252              __invoke(static_cast<_Fun&&>(__f), static_cast<_As&&>(__as)...)
253          } noexcept;
254      };
255  
256  template <class _Fun, class... _As>
257  using __invoke_result_t = //
258      decltype(__invoke(__declval<_Fun>(), __declval<_As>()...));
259  
260  namespace __apply_
261  {
262  using std::get;
263  
264  template <std::size_t... _Is, class _Fn, class _Tup>
265  STDEXEC_ATTRIBUTE((always_inline))
__impl(__indices<_Is...>,_Fn && __fn,_Tup && __tup)266  constexpr auto __impl(__indices<_Is...>, _Fn&& __fn, _Tup&& __tup) //
267      noexcept(noexcept(__invoke(static_cast<_Fn&&>(__fn),
268                                 get<_Is>(static_cast<_Tup&&>(__tup))...)))
269          -> decltype(__invoke(static_cast<_Fn&&>(__fn),
270                               get<_Is>(static_cast<_Tup&&>(__tup))...))
271  {
272      return __invoke(static_cast<_Fn&&>(__fn),
273                      get<_Is>(static_cast<_Tup&&>(__tup))...);
274  }
275  
276  template <class _Tup>
277  using __tuple_indices =
278      __make_indices<std::tuple_size<std::remove_cvref_t<_Tup>>::value>;
279  
280  template <class _Fn, class _Tup>
281  using __result_t = decltype(__apply_::__impl(
282      __tuple_indices<_Tup>(), __declval<_Fn>(), __declval<_Tup>()));
283  } // namespace __apply_
284  
285  template <class _Fn, class _Tup>
286  concept __applicable = __mvalid<__apply_::__result_t, _Fn, _Tup>;
287  
288  template <class _Fn, class _Tup>
289  concept __nothrow_applicable =
290      __applicable<_Fn, _Tup> //
291      &&                      //
292      noexcept(__apply_::__impl(__apply_::__tuple_indices<_Tup>(),
293                                __declval<_Fn>(), __declval<_Tup>()));
294  
295  template <class _Fn, class _Tup>
296      requires __applicable<_Fn, _Tup>
297  using __apply_result_t = __apply_::__result_t<_Fn, _Tup>;
298  
299  struct __apply_t
300  {
301      template <class _Fn, class _Tup>
302          requires __applicable<_Fn, _Tup>
303      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__apply_t304      constexpr auto operator()(_Fn&& __fn, _Tup&& __tup) const
305          noexcept(__nothrow_applicable<_Fn, _Tup>) -> __apply_result_t<_Fn, _Tup>
306      {
307          return __apply_::__impl(__apply_::__tuple_indices<_Tup>(),
308                                  static_cast<_Fn&&>(__fn),
309                                  static_cast<_Tup&&>(__tup));
310      }
311  };
312  
313  inline constexpr __apply_t __apply{};
314  
315  template <class _Tag, class _Ty>
316  struct __field
317  {
318      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__field319      _Ty operator()(_Tag) const noexcept(__nothrow_decay_copyable<const _Ty&>)
320      {
321          return __t_;
322      }
323  
324      _Ty __t_;
325  };
326  
327  template <class _Tag>
328  struct __mkfield_
329  {
330      template <class _Ty>
331      STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__mkfield_332      __field<_Tag, __decay_t<_Ty>> operator()(_Ty&& __ty) const
333          noexcept(__nothrow_decay_copyable<_Ty>)
334      {
335          return {static_cast<_Ty&&>(__ty)};
336      }
337  };
338  
339  template <class _Tag>
340  inline constexpr __mkfield_<_Tag> __mkfield{};
341  } // namespace stdexec
342