xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/any_sender_of.hpp (revision 36137e09614746b13603b5fbae79e6f70819c46b)
1  /* Copyright (c) 2023 Maikel Nadolski
2   * Copyright (c) 2023 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 "../stdexec/concepts.hpp"
19  #include "../stdexec/execution.hpp"
20  #include "../stdexec/functional.hpp"
21  
22  #include <sdbusplus/async/stdexec/sequence_senders.hpp>
23  
24  #include <cstddef>
25  #include <utility>
26  
27  namespace exec
28  {
29  namespace __any
30  {
31  using namespace stdexec;
32  
33  struct __create_vtable_t
34  {
35      template <class _VTable, class _Tp>
36          requires __tag_invocable_r<const _VTable*, __create_vtable_t,
37                                     __mtype<_VTable>, __mtype<_Tp>>
operator ()exec::__any::__create_vtable_t38      constexpr auto operator()(__mtype<_VTable>, __mtype<_Tp>) const noexcept
39          -> const _VTable*
40      {
41          return stdexec::tag_invoke(__create_vtable_t{}, __mtype<_VTable>{},
42                                     __mtype<_Tp>{});
43      }
44  };
45  
46  inline constexpr __create_vtable_t __create_vtable{};
47  
48  template <class _Sig>
49  struct __query_vfun;
50  
51  template <class _Tag, class _Ret, class... _As>
52  struct __query_vfun<_Tag (*const)(_Ret (*)(_As...))>
53  {
54      _Ret (*__fn_)(void*, _As...);
55  
operator ()exec::__any::__query_vfun56      auto operator()(_Tag, void* __rcvr, _As&&... __as) const -> _Ret
57      {
58          return __fn_(__rcvr, static_cast<_As&&>(__as)...);
59      }
60  };
61  
62  template <class _Tag, class _Ret, class... _As>
63  struct __query_vfun<_Tag (*)(_Ret (*)(_As...))>
64  {
65      _Ret (*__fn_)(void*, _As...);
66  
operator ()exec::__any::__query_vfun67      auto operator()(_Tag, void* __rcvr, _As&&... __as) const -> _Ret
68      {
69          return __fn_(__rcvr, static_cast<_As&&>(__as)...);
70      }
71  };
72  
73  template <class _Tag, class _Ret, class... _As>
74  struct __query_vfun<_Tag (*const)(_Ret (*)(_As...) noexcept)>
75  {
76      _Ret (*__fn_)(void*, _As...) noexcept;
77  
operator ()exec::__any::__query_vfun78      auto operator()(_Tag, void* __rcvr, _As&&... __as) const noexcept -> _Ret
79      {
80          return __fn_(__rcvr, static_cast<_As&&>(__as)...);
81      }
82  };
83  
84  template <class _Tag, class _Ret, class... _As>
85  struct __query_vfun<_Tag (*)(_Ret (*)(_As...) noexcept)>
86  {
87      _Ret (*__fn_)(void*, _As...) noexcept;
88  
operator ()exec::__any::__query_vfun89      auto operator()(_Tag, void* __rcvr, _As&&... __as) const noexcept -> _Ret
90      {
91          return __fn_(__rcvr, static_cast<_As&&>(__as)...);
92      }
93  };
94  
95  template <class _Queryable, bool _IsEnvProvider = true>
96  struct __query_vfun_fn;
97  
98  template <class _EnvProvider>
99  struct __query_vfun_fn<_EnvProvider, true>
100  {
101      template <class _Tag, class _Ret, class... _As>
102          requires __callable<_Tag, env_of_t<const _EnvProvider&>, _As...>
103      constexpr _Ret (*operator()(_Tag (*)(_Ret (*)(_As...)))
104                          const noexcept)(void*, _As...)
105      {
__anon1bf2f58b0102exec::__any::__query_vfun_fn106          return +[](void* __env_provider, _As... __as) -> _Ret {
107              return _Tag{}(stdexec::get_env(*static_cast<const _EnvProvider*>(
108                                __env_provider)),
109                            static_cast<_As&&>(__as)...);
110          };
111      }
112  
113      template <class _Tag, class _Ret, class... _As>
114          requires __callable<_Tag, env_of_t<const _EnvProvider&>, _As...>
115      constexpr _Ret (*operator()(_Tag (*)(_Ret (*)(_As...) noexcept))
116                          const noexcept)(void*, _As...) noexcept
117      {
__anon1bf2f58b0202exec::__any::__query_vfun_fn118          return +[](void* __env_provider, _As... __as) noexcept -> _Ret {
119              static_assert(
120                  __nothrow_callable<_Tag, const env_of_t<_EnvProvider>&,
121                                     _As...>);
122              return _Tag{}(stdexec::get_env(*static_cast<const _EnvProvider*>(
123                                __env_provider)),
124                            static_cast<_As&&>(__as)...);
125          };
126      }
127  };
128  
129  template <class _Queryable>
130  struct __query_vfun_fn<_Queryable, false>
131  {
132      template <class _Tag, class _Ret, class... _As>
133          requires __callable<_Tag, const _Queryable&, _As...>
134      constexpr _Ret (*operator()(_Tag (*)(_Ret (*)(_As...)))
135                          const noexcept)(void*, _As...)
136      {
__anon1bf2f58b0302exec::__any::__query_vfun_fn137          return +[](void* __queryable, _As... __as) -> _Ret {
138              return _Tag{}(*static_cast<const _Queryable*>(__queryable),
139                            static_cast<_As&&>(__as)...);
140          };
141      }
142  
143      template <class _Tag, class _Ret, class... _As>
144          requires __callable<_Tag, const _Queryable&, _As...>
145      constexpr _Ret (*operator()(_Tag (*)(_Ret (*)(_As...) noexcept))
146                          const noexcept)(void*, _As...) noexcept
147      {
__anon1bf2f58b0402exec::__any::__query_vfun_fn148          return +[](void* __env_provider, _As... __as) noexcept -> _Ret {
149              static_assert(__nothrow_callable<_Tag, const _Queryable&, _As...>);
150              return _Tag{}(*static_cast<const _Queryable*>(__env_provider),
151                            static_cast<_As&&>(__as)...);
152          };
153      }
154  };
155  
156  template <class _Sig>
157  struct __storage_vfun;
158  
159  template <class _Tag, class... _As>
160  struct __storage_vfun<_Tag(void (*)(_As...))>
161  {
__anon1bf2f58b0502exec::__any::__storage_vfun162      void (*__fn_)(void*, _As...) = [](void*, _As...) {};
163  
operator ()exec::__any::__storage_vfun164      void operator()(_Tag, void* __storage, _As&&... __as) const
165      {
166          return __fn_(__storage, static_cast<_As&&>(__as)...);
167      }
168  };
169  
170  template <class _Tag, class... _As>
171  struct __storage_vfun<_Tag(void (*)(_As...) noexcept)>
172  {
__anon1bf2f58b0602exec::__any::__storage_vfun173      void (*__fn_)(void*, _As...) noexcept = [](void*, _As...) noexcept {};
174  
operator ()exec::__any::__storage_vfun175      void operator()(_Tag, void* __storage, _As&&... __as) const noexcept
176      {
177          return __fn_(__storage, static_cast<_As&&>(__as)...);
178      }
179  };
180  
181  template <class _Storage, class _Tp>
182  struct __storage_vfun_fn
183  {
184      template <class _Tag, class... _As>
185          requires __callable<_Tag, __mtype<_Tp>, _Storage&, _As...>
186      constexpr void (*operator()(_Tag (*)(void (*)(_As...)))
187                          const noexcept)(void*, _As...)
188      {
__anon1bf2f58b0702exec::__any::__storage_vfun_fn189          return +[](void* __storage, _As... __as) -> void {
190              return _Tag{}(__mtype<_Tp>{}, *static_cast<_Storage*>(__storage),
191                            static_cast<_As&&>(__as)...);
192          };
193      }
194  
195      template <class _Tag, class... _As>
196          requires __callable<_Tag, __mtype<_Tp>, _Storage&, _As...>
197      constexpr void (*operator()(_Tag (*)(void (*)(_As...) noexcept))
198                          const noexcept)(void*, _As...) noexcept
199      {
__anon1bf2f58b0802exec::__any::__storage_vfun_fn200          return +[](void* __storage, _As... __as) noexcept -> void {
201              static_assert(
202                  __nothrow_callable<_Tag, __mtype<_Tp>, _Storage&, _As...>);
203              return _Tag{}(__mtype<_Tp>{}, *static_cast<_Storage*>(__storage),
204                            static_cast<_As&&>(__as)...);
205          };
206      }
207  };
208  
209  struct __delete_t
210  {
211      template <class _Storage, class _Tp>
212          requires tag_invocable<__delete_t, __mtype<_Tp>, _Storage&>
operator ()exec::__any::__delete_t213      void operator()(__mtype<_Tp>, _Storage& __storage) noexcept
214      {
215          static_assert(
216              nothrow_tag_invocable<__delete_t, __mtype<_Tp>, _Storage&>);
217          stdexec::tag_invoke(__delete_t{}, __mtype<_Tp>{}, __storage);
218      }
219  };
220  
221  inline constexpr __delete_t __delete{};
222  
223  struct __copy_construct_t
224  {
225      template <class _Storage, class _Tp>
226          requires tag_invocable<__copy_construct_t, __mtype<_Tp>, _Storage&,
227                                 const _Storage&>
operator ()exec::__any::__copy_construct_t228      void operator()(__mtype<_Tp>, _Storage& __self, const _Storage& __from) //
229          noexcept(nothrow_tag_invocable<__copy_construct_t, __mtype<_Tp>,
230                                         _Storage&, const _Storage&>)
231      {
232          stdexec::tag_invoke(__copy_construct_t{}, __mtype<_Tp>{}, __self,
233                              __from);
234      }
235  };
236  
237  inline constexpr __copy_construct_t __copy_construct{};
238  
239  struct __move_construct_t
240  {
241      template <class _Storage, class _Tp>
242          requires tag_invocable<__move_construct_t, __mtype<_Tp>, _Storage&,
243                                 _Storage&&>
operator ()exec::__any::__move_construct_t244      void operator()(__mtype<_Tp>, _Storage& __self,
245                      __midentity<_Storage&&> __from) noexcept
246      {
247          static_assert(nothrow_tag_invocable<__move_construct_t, __mtype<_Tp>,
248                                              _Storage&, _Storage&&>);
249          stdexec::tag_invoke(__move_construct_t{}, __mtype<_Tp>{}, __self,
250                              static_cast<_Storage&&>(__from));
251      }
252  };
253  
254  inline constexpr __move_construct_t __move_construct{};
255  
256  template <class _ParentVTable, class... _StorageCPOs>
257  struct __storage_vtable;
258  
259  template <class _ParentVTable, class... _StorageCPOs>
260      requires requires { _ParentVTable::operator(); }
261  struct __storage_vtable<_ParentVTable, _StorageCPOs...> :
262      _ParentVTable,
263      __storage_vfun<_StorageCPOs>...
264  {
265      using _ParentVTable::operator();
266      using __storage_vfun<_StorageCPOs>::operator()...;
267  };
268  
269  template <class _ParentVTable, class... _StorageCPOs>
270      requires(!requires { _ParentVTable::operator(); })
271  struct __storage_vtable<_ParentVTable, _StorageCPOs...> :
272      _ParentVTable,
273      __storage_vfun<_StorageCPOs>...
274  {
275      using __storage_vfun<_StorageCPOs>::operator()...;
276  };
277  
278  template <class _ParentVTable, class... _StorageCPOs>
279  inline constexpr __storage_vtable<_ParentVTable, _StorageCPOs...>
280      __null_storage_vtbl{};
281  
282  template <class _ParentVTable, class... _StorageCPOs>
__default_storage_vtable(__storage_vtable<_ParentVTable,_StorageCPOs...> *)283  constexpr auto __default_storage_vtable(
284      __storage_vtable<_ParentVTable, _StorageCPOs...>*) noexcept
285      -> const __storage_vtable<_ParentVTable, _StorageCPOs...>*
286  {
287      return &__null_storage_vtbl<_ParentVTable, _StorageCPOs...>;
288  }
289  
290  template <class _Storage, class _Tp, class _ParentVTable, class... _StorageCPOs>
291  static const __storage_vtable<_ParentVTable, _StorageCPOs...> __storage_vtbl{
292      {*__create_vtable(__mtype<_ParentVTable>{}, __mtype<_Tp>{})},
293      {__storage_vfun_fn<_Storage, _Tp>{}(
294          static_cast<_StorageCPOs*>(nullptr))}...};
295  
296  template <class _Vtable, class _Allocator, bool _Copyable = false,
297            std::size_t _InlineSize = 3 * sizeof(void*),
298            std::size_t _Alignment = alignof(std::max_align_t)>
299  struct __storage
300  {
301      class __t;
302  };
303  
304  template <class _Vtable, class _Allocator,
305            std::size_t _InlineSize = 3 * sizeof(void*),
306            std::size_t _Alignment = alignof(std::max_align_t)>
307  struct __immovable_storage
308  {
309      class __t : __immovable
310      {
311          static constexpr std::size_t __buffer_size =
312              std::max(_InlineSize, sizeof(void*));
313          static constexpr std::size_t __alignment =
314              std::max(_Alignment, alignof(void*));
315          using __with_delete = __delete_t(void() noexcept);
316          using __vtable_t = __storage_vtable<_Vtable, __with_delete>;
317  
318          template <class _Tp>
319          static constexpr bool __is_small =
320              sizeof(_Tp) <= __buffer_size && alignof(_Tp) <= __alignment;
321  
322          template <class _Tp>
__get_vtable_of_type()323          static constexpr auto __get_vtable_of_type() noexcept
324              -> const __vtable_t*
325          {
326              return &__storage_vtbl<__t, __decay_t<_Tp>, _Vtable, __with_delete>;
327          }
328  
329        public:
330          using __id = __immovable_storage;
331  
332          __t() = default;
333  
334          template <__not_decays_to<__t> _Tp>
335              requires __callable<__create_vtable_t, __mtype<_Vtable>,
336                                  __mtype<__decay_t<_Tp>>>
__t(_Tp && __object)337          __t(_Tp&& __object) : __vtable_{__get_vtable_of_type<_Tp>()}
338          {
339              using _Dp = __decay_t<_Tp>;
340              if constexpr (__is_small<_Dp>)
341              {
342                  __construct_small<_Dp>(static_cast<_Tp&&>(__object));
343              }
344              else
345              {
346                  __construct_large<_Dp>(static_cast<_Tp&&>(__object));
347              }
348          }
349  
350          template <class _Tp, class... _Args>
351              requires __callable<__create_vtable_t, __mtype<_Vtable>,
352                                  __mtype<_Tp>>
__t(std::in_place_type_t<_Tp>,_Args &&...__args)353          __t(std::in_place_type_t<_Tp>, _Args&&... __args) :
354              __vtable_{__get_vtable_of_type<_Tp>()}
355          {
356              if constexpr (__is_small<_Tp>)
357              {
358                  __construct_small<_Tp>(static_cast<_Args&&>(__args)...);
359              }
360              else
361              {
362                  __construct_large<_Tp>(static_cast<_Args&&>(__args)...);
363              }
364          }
365  
~__t()366          ~__t()
367          {
368              __reset();
369          }
370  
__reset()371          void __reset() noexcept
372          {
373              (*__vtable_)(__delete, this);
374              __object_pointer_ = nullptr;
375              __vtable_ =
376                  __default_storage_vtable(static_cast<__vtable_t*>(nullptr));
377          }
378  
__get_vtable() const379          [[nodiscard]] auto __get_vtable() const noexcept -> const _Vtable*
380          {
381              return __vtable_;
382          }
383  
__get_object_pointer() const384          [[nodiscard]] auto __get_object_pointer() const noexcept -> void*
385          {
386              return __object_pointer_;
387          }
388  
389        private:
390          template <class _Tp, class... _As>
__construct_small(_As &&...__args)391          void __construct_small(_As&&... __args)
392          {
393              static_assert(sizeof(_Tp) <= __buffer_size &&
394                            alignof(_Tp) <= __alignment);
395              _Tp* __pointer =
396                  static_cast<_Tp*>(static_cast<void*>(&__buffer_[0]));
397              using _Alloc = typename std::allocator_traits<
398                  _Allocator>::template rebind_alloc<_Tp>;
399              _Alloc __alloc{__allocator_};
400              std::allocator_traits<_Alloc>::construct(
401                  __alloc, __pointer, static_cast<_As&&>(__args)...);
402              __object_pointer_ = __pointer;
403          }
404  
405          template <class _Tp, class... _As>
__construct_large(_As &&...__args)406          void __construct_large(_As&&... __args)
407          {
408              using _Alloc = typename std::allocator_traits<
409                  _Allocator>::template rebind_alloc<_Tp>;
410              _Alloc __alloc{__allocator_};
411              _Tp* __pointer =
412                  std::allocator_traits<_Alloc>::allocate(__alloc, 1);
413              try
414              {
415                  std::allocator_traits<_Alloc>::construct(
416                      __alloc, __pointer, static_cast<_As&&>(__args)...);
417              }
418              catch (...)
419              {
420                  std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer,
421                                                            1);
422                  throw;
423              }
424              __object_pointer_ = __pointer;
425          }
426  
427          template <class _Tp>
STDEXEC_MEMFN_DECL(void __delete)428          STDEXEC_MEMFN_DECL(void __delete)(this __mtype<_Tp>,
429                                            __t& __self) noexcept
430          {
431              if (!__self.__object_pointer_)
432              {
433                  return;
434              }
435              using _Alloc = typename std::allocator_traits<
436                  _Allocator>::template rebind_alloc<_Tp>;
437              _Alloc __alloc{__self.__allocator_};
438              _Tp* __pointer = static_cast<_Tp*>(
439                  std::exchange(__self.__object_pointer_, nullptr));
440              std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
441              if constexpr (!__is_small<_Tp>)
442              {
443                  std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer,
444                                                            1);
445              }
446          }
447  
448        private:
449          const __vtable_t* __vtable_{
450              __default_storage_vtable(static_cast<__vtable_t*>(nullptr))};
451          void* __object_pointer_{nullptr};
452          alignas(__alignment) std::byte __buffer_[__buffer_size]{};
453          STDEXEC_ATTRIBUTE((no_unique_address))
454          _Allocator __allocator_{};
455      };
456  };
457  
458  template <class _Vtable, class _Allocator, bool _Copyable,
459            std::size_t _InlineSize, std::size_t _Alignment>
460  class __storage<_Vtable, _Allocator, _Copyable, _InlineSize, _Alignment>::__t :
461      __if_c<_Copyable, __, __move_only>
462  {
463      static_assert(STDEXEC_IS_CONVERTIBLE_TO(
464          typename std::allocator_traits<_Allocator>::void_pointer, void*));
465  
466      static constexpr std::size_t __buffer_size =
467          std::max(_InlineSize, sizeof(void*));
468      static constexpr std::size_t __alignment =
469          std::max(_Alignment, alignof(void*));
470      using __with_copy = __copy_construct_t(void(const __t&));
471      using __with_move = __move_construct_t(void(__t&&) noexcept);
472      using __with_delete = __delete_t(void() noexcept);
473  
474      template <class _Tp>
475      static constexpr bool __is_small =
476          sizeof(_Tp) <= __buffer_size && alignof(_Tp) <= __alignment &&
477          std::is_nothrow_move_constructible_v<_Tp>;
478  
479      using __vtable_t = __if_c<
480          _Copyable,
481          __storage_vtable<_Vtable, __with_delete, __with_move, __with_copy>,
482          __storage_vtable<_Vtable, __with_delete, __with_move>>;
483  
484      template <class _Tp>
__get_vtable_of_type()485      static constexpr auto __get_vtable_of_type() noexcept -> const __vtable_t*
486      {
487          if constexpr (_Copyable)
488          {
489              return &__storage_vtbl<__t, __decay_t<_Tp>, _Vtable, __with_delete,
490                                     __with_move, __with_copy>;
491          }
492          else
493          {
494              return &__storage_vtbl<__t, __decay_t<_Tp>, _Vtable, __with_delete,
495                                     __with_move>;
496          }
497      }
498  
499    public:
500      using __id = __storage;
501  
502      __t() = default;
503  
504      template <__not_decays_to<__t> _Tp>
505          requires __callable<__create_vtable_t, __mtype<_Vtable>,
506                              __mtype<__decay_t<_Tp>>>
__t(_Tp && __object)507      __t(_Tp&& __object) : __vtable_{__get_vtable_of_type<_Tp>()}
508      {
509          using _Dp = __decay_t<_Tp>;
510          if constexpr (__is_small<_Dp>)
511          {
512              __construct_small<_Dp>(static_cast<_Tp&&>(__object));
513          }
514          else
515          {
516              __construct_large<_Dp>(static_cast<_Tp&&>(__object));
517          }
518      }
519  
520      template <class _Tp, class... _Args>
521          requires __callable<__create_vtable_t, __mtype<_Vtable>, __mtype<_Tp>>
__t(std::in_place_type_t<_Tp>,_Args &&...__args)522      __t(std::in_place_type_t<_Tp>, _Args&&... __args) :
523          __vtable_{__get_vtable_of_type<_Tp>()}
524      {
525          if constexpr (__is_small<_Tp>)
526          {
527              __construct_small<_Tp>(static_cast<_Args&&>(__args)...);
528          }
529          else
530          {
531              __construct_large<_Tp>(static_cast<_Args&&>(__args)...);
532          }
533      }
534  
__t(const __t & __other)535      __t(const __t& __other)
536          requires(_Copyable)
537      {
538          (*__other.__vtable_)(__copy_construct, this, __other);
539      }
540  
operator =(const __t & __other)541      auto operator=(const __t& __other)
542          -> __t& requires(_Copyable) {
543                      if (&__other != this)
544                      {
545                          __t tmp(__other);
546                          *this = std::move(tmp);
547                      }
548                      return *this;
549                  }
550  
__t(__t && __other)551      __t(__t&& __other) noexcept
552      {
553          (*__other.__vtable_)(__move_construct, this,
554                               static_cast<__t&&>(__other));
555      }
556  
operator =(__t && __other)557      auto operator=(__t&& __other) noexcept -> __t&
558      {
559          __reset();
560          (*__other.__vtable_)(__move_construct, this,
561                               static_cast<__t&&>(__other));
562          return *this;
563      }
564  
~__t()565      ~__t()
566      {
567          __reset();
568      }
569  
__reset()570      void __reset() noexcept
571      {
572          (*__vtable_)(__delete, this);
573          __object_pointer_ = nullptr;
574          __vtable_ = __default_storage_vtable(static_cast<__vtable_t*>(nullptr));
575      }
576  
__get_vtable() const577      auto __get_vtable() const noexcept -> const _Vtable*
578      {
579          return __vtable_;
580      }
581  
__get_object_pointer() const582      [[nodiscard]] auto __get_object_pointer() const noexcept -> void*
583      {
584          return __object_pointer_;
585      }
586  
587    private:
588      template <class _Tp, class... _As>
__construct_small(_As &&...__args)589      void __construct_small(_As&&... __args)
590      {
591          static_assert(sizeof(_Tp) <= __buffer_size &&
592                        alignof(_Tp) <= __alignment);
593          _Tp* __pointer = static_cast<_Tp*>(static_cast<void*>(&__buffer_[0]));
594          using _Alloc = typename std::allocator_traits<
595              _Allocator>::template rebind_alloc<_Tp>;
596          _Alloc __alloc{__allocator_};
597          std::allocator_traits<_Alloc>::construct(__alloc, __pointer,
598                                                   static_cast<_As&&>(__args)...);
599          __object_pointer_ = __pointer;
600      }
601  
602      template <class _Tp, class... _As>
__construct_large(_As &&...__args)603      void __construct_large(_As&&... __args)
604      {
605          using _Alloc = typename std::allocator_traits<
606              _Allocator>::template rebind_alloc<_Tp>;
607          _Alloc __alloc{__allocator_};
608          _Tp* __pointer = std::allocator_traits<_Alloc>::allocate(__alloc, 1);
609          try
610          {
611              std::allocator_traits<_Alloc>::construct(
612                  __alloc, __pointer, static_cast<_As&&>(__args)...);
613          }
614          catch (...)
615          {
616              std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
617              throw;
618          }
619          __object_pointer_ = __pointer;
620      }
621  
622      template <class _Tp>
STDEXEC_MEMFN_DECL(void __delete)623      STDEXEC_MEMFN_DECL(void __delete)(this __mtype<_Tp>, __t& __self) noexcept
624      {
625          if (!__self.__object_pointer_)
626          {
627              return;
628          }
629          using _Alloc = typename std::allocator_traits<
630              _Allocator>::template rebind_alloc<_Tp>;
631          _Alloc __alloc{__self.__allocator_};
632          _Tp* __pointer =
633              static_cast<_Tp*>(std::exchange(__self.__object_pointer_, nullptr));
634          std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
635          if constexpr (!__is_small<_Tp>)
636          {
637              std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
638          }
639      }
640  
641      template <class _Tp>
STDEXEC_MEMFN_DECL(void __move_construct)642      STDEXEC_MEMFN_DECL(void __move_construct)(this __mtype<_Tp>, __t& __self,
643                                                __t&& __other) noexcept
644      {
645          if (!__other.__object_pointer_)
646          {
647              return;
648          }
649          _Tp* __pointer = static_cast<_Tp*>(
650              std::exchange(__other.__object_pointer_, nullptr));
651          if constexpr (__is_small<_Tp>)
652          {
653              _Tp& __other_object = *__pointer;
654              __self.template __construct_small<_Tp>(
655                  static_cast<_Tp&&>(__other_object));
656              using _Alloc = typename std::allocator_traits<
657                  _Allocator>::template rebind_alloc<_Tp>;
658              _Alloc __alloc{__self.__allocator_};
659              std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
660          }
661          else
662          {
663              __self.__object_pointer_ = __pointer;
664          }
665          __self.__vtable_ = std::exchange(
666              __other.__vtable_,
667              __default_storage_vtable(static_cast<__vtable_t*>(nullptr)));
668      }
669  
670      template <class _Tp>
671          requires _Copyable
STDEXEC_MEMFN_DECL(void __copy_construct)672      STDEXEC_MEMFN_DECL(void __copy_construct)(this __mtype<_Tp>, __t& __self,
673                                                const __t& __other)
674      {
675          if (!__other.__object_pointer_)
676          {
677              return;
678          }
679          const _Tp& __other_object =
680              *static_cast<const _Tp*>(__other.__object_pointer_);
681          if constexpr (__is_small<_Tp>)
682          {
683              __self.template __construct_small<_Tp>(__other_object);
684          }
685          else
686          {
687              __self.template __construct_large<_Tp>(__other_object);
688          }
689          __self.__vtable_ = __other.__vtable_;
690      }
691  
692      const __vtable_t* __vtable_{
693          __default_storage_vtable(static_cast<__vtable_t*>(nullptr))};
694      void* __object_pointer_{nullptr};
695      alignas(__alignment) std::byte __buffer_[__buffer_size]{};
696      STDEXEC_ATTRIBUTE((no_unique_address))
697      _Allocator __allocator_{};
698  };
699  
700  struct __empty_vtable
701  {
702      template <class _Sender>
STDEXEC_MEMFN_DECLexec::__any::__empty_vtable703      STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__empty_vtable>,
704                                               __mtype<_Sender>) noexcept
705          -> const __empty_vtable*
706      {
707          static const __empty_vtable __vtable_{};
708          return &__vtable_;
709      }
710  };
711  
712  template <class _VTable = __empty_vtable,
713            class _Allocator = std::allocator<std::byte>>
714  using __immovable_storage_t = __t<__immovable_storage<_VTable, _Allocator>>;
715  
716  template <class _VTable, class _Allocator = std::allocator<std::byte>>
717  using __unique_storage_t = __t<__storage<_VTable, _Allocator>>;
718  
719  template <class _VTable, std::size_t _InlineSize = 3 * sizeof(void*),
720            class _Allocator = std::allocator<std::byte>>
721  using __copyable_storage_t =
722      __t<__storage<_VTable, _Allocator, true, _InlineSize>>;
723  
724  template <class _Tag, class... _As>
725  auto __tag_type(_Tag (*)(_As...)) -> _Tag;
726  
727  template <class _Tag, class... _As>
728  auto __tag_type(_Tag (*)(_As...) noexcept) -> _Tag;
729  
730  template <class _Query>
731  concept __is_stop_token_query = requires {
732                                      {
733                                          __tag_type(static_cast<_Query>(nullptr))
734                                      } -> same_as<get_stop_token_t>;
735                                  };
736  
737  template <class _Query>
738  concept __is_not_stop_token_query = !__is_stop_token_query<_Query>;
739  
740  template <class _Query>
741  using __is_not_stop_token_query_v = __mbool<__is_not_stop_token_query<_Query>>;
742  
743  namespace __rec
744  {
745  template <class _Sigs, class... _Queries>
746  struct __vtable
747  {
748      class __t;
749  };
750  
751  template <class _Sigs, class... _Queries>
752  struct __ref;
753  
754  template <class... _Sigs, class... _Queries>
755  struct __vtable<completion_signatures<_Sigs...>, _Queries...>
756  {
757      class __t :
758          public __any_::__rcvr_vfun<_Sigs>...,
759          public __query_vfun<_Queries>...
760      {
761        public:
762          using __query_vfun<_Queries>::operator()...;
763  
764        private:
765          template <class _Rcvr>
766              requires receiver_of<_Rcvr, completion_signatures<_Sigs...>> &&
767                       (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
STDEXEC_MEMFN_DECL(auto __create_vtable)768          STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__t>,
769                                                   __mtype<_Rcvr>) noexcept
770              -> const __t*
771          {
772              static const __t __vtable_{
773                  {__any_::__rcvr_vfun_fn(static_cast<_Rcvr*>(nullptr),
774                                          static_cast<_Sigs*>(nullptr))}...,
775                  {__query_vfun_fn<_Rcvr>{}(static_cast<_Queries>(nullptr))}...};
776              return &__vtable_;
777          }
778      };
779  };
780  
781  template <class... _Sigs, class... _Queries>
782      requires(__is_not_stop_token_query<_Queries> && ...)
783  struct __ref<completion_signatures<_Sigs...>, _Queries...>
784  {
785  #if !STDEXEC_MSVC()
786      // MSVCBUG
787      // https://developercommunity.visualstudio.com/t/Private-member-inaccessible-when-used-in/10448363
788  
789    private:
790  #endif
791      using __vtable_t =
792          stdexec::__t<__vtable<completion_signatures<_Sigs...>, _Queries...>>;
793  
794      struct __env_t
795      {
796          const __vtable_t* __vtable_;
797          void* __rcvr_;
798          inplace_stop_token __token_;
799  
800          template <class _Tag, class... _As>
801              requires __callable<const __vtable_t&, _Tag, void*, _As...>
queryexec::__any::__rec::__ref::__env_t802          auto query(_Tag, _As&&... __as) const //
803              noexcept(__nothrow_callable<const __vtable_t&, _Tag, void*, _As...>)
804                  -> __call_result_t<const __vtable_t&, _Tag, void*, _As...>
805          {
806              return (*__vtable_)(_Tag{}, __rcvr_, static_cast<_As&&>(__as)...);
807          }
808  
queryexec::__any::__rec::__ref::__env_t809          auto query(get_stop_token_t) const noexcept -> inplace_stop_token
810          {
811              return __token_;
812          }
813      } __env_;
814  
815    public:
816      using receiver_concept = stdexec::receiver_t;
817      using __id = __ref;
818      using __t = __ref;
819  
820      template <__none_of<__ref, const __ref, __env_t, const __env_t> _Rcvr>
821          requires receiver_of<_Rcvr, completion_signatures<_Sigs...>> &&
822                   (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
__refexec::__any::__rec::__ref823      __ref(_Rcvr& __rcvr) noexcept :
824          __env_{__create_vtable(__mtype<__vtable_t>{}, __mtype<_Rcvr>{}),
825                 &__rcvr, stdexec::get_stop_token(stdexec::get_env(__rcvr))}
826      {}
827  
828      template <class... _As>
829          requires __one_of<set_value_t(_As...), _Sigs...>
set_valueexec::__any::__rec::__ref830      void set_value(_As&&... __as) noexcept
831      {
832          const __any_::__rcvr_vfun<set_value_t(_As...)>* __vfun =
833              __env_.__vtable_;
834          (*__vfun->__complete_)(__env_.__rcvr_, static_cast<_As&&>(__as)...);
835      }
836  
837      template <class _Error>
838          requires __one_of<set_error_t(_Error), _Sigs...>
set_errorexec::__any::__rec::__ref839      void set_error(_Error&& __err) noexcept
840      {
841          const __any_::__rcvr_vfun<set_error_t(_Error)>* __vfun =
842              __env_.__vtable_;
843          (*__vfun->__complete_)(__env_.__rcvr_, static_cast<_Error&&>(__err));
844      }
845  
set_stoppedexec::__any::__rec::__ref846      void set_stopped() noexcept
847          requires __one_of<set_stopped_t(), _Sigs...>
848      {
849          const __any_::__rcvr_vfun<set_stopped_t()>* __vfun = __env_.__vtable_;
850          (*__vfun->__complete_)(__env_.__rcvr_);
851      }
852  
get_envexec::__any::__rec::__ref853      auto get_env() const noexcept -> const __env_t&
854      {
855          return __env_;
856      }
857  };
858  
859  auto __test_never_stop_token(
860      get_stop_token_t (*)(never_stop_token (*)() noexcept)) -> __mbool<true>;
861  
862  template <class _Tag, class _Ret, class... _As>
863  auto __test_never_stop_token(_Tag (*)(_Ret (*)(_As...) noexcept))
864      -> __mbool<false>;
865  
866  template <class _Tag, class _Ret, class... _As>
867  auto __test_never_stop_token(_Tag (*)(_Ret (*)(_As...))) -> __mbool<false>;
868  
869  template <class _Query>
870  using __is_never_stop_token_query =
871      decltype(__test_never_stop_token(static_cast<_Query>(nullptr)));
872  
873  template <class... _Sigs, class... _Queries>
874      requires(__is_stop_token_query<_Queries> || ...)
875  struct __ref<completion_signatures<_Sigs...>, _Queries...>
876  {
877  #if !STDEXEC_MSVC()
878      // MSVCBUG
879      // https://developercommunity.visualstudio.com/t/Private-member-inaccessible-when-used-in/10448363
880  
881    private:
882  #endif
883      using _FilteredQueries =
884          __minvoke<__mremove_if<__q<__is_never_stop_token_query>>, _Queries...>;
885      using __vtable_t = stdexec::__t<
886          __mapply<__mbind_front_q<__vtable, completion_signatures<_Sigs...>>,
887                   _FilteredQueries>>;
888  
889      struct __env_t
890      {
891          const __vtable_t* __vtable_;
892          void* __rcvr_;
893  
894          template <class _Tag, class... _As>
895              requires __callable<const __vtable_t&, _Tag, void*, _As...>
queryexec::__any::__rec::__ref::__env_t896          auto query(_Tag, _As&&... __as) const //
897              noexcept(__nothrow_callable<const __vtable_t&, _Tag, void*, _As...>)
898                  -> __call_result_t<const __vtable_t&, _Tag, void*, _As...>
899          {
900              return (*__vtable_)(_Tag{}, __rcvr_, static_cast<_As&&>(__as)...);
901          }
902      } __env_;
903  
904    public:
905      using receiver_concept = stdexec::receiver_t;
906      using __id = __ref;
907      using __t = __ref;
908  
909      template <__none_of<__ref, const __ref, __env_t, const __env_t> _Rcvr>
910          requires receiver_of<_Rcvr, completion_signatures<_Sigs...>> &&
911                   (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
__refexec::__any::__rec::__ref912      __ref(_Rcvr& __rcvr) noexcept :
913          __env_{__create_vtable(__mtype<__vtable_t>{}, __mtype<_Rcvr>{}),
914                 &__rcvr}
915      {}
916  
917      template <class... _As>
918          requires __one_of<set_value_t(_As...), _Sigs...>
set_valueexec::__any::__rec::__ref919      void set_value(_As&&... __as) noexcept
920      {
921          const __any_::__rcvr_vfun<set_value_t(_As...)>* __vfun =
922              __env_.__vtable_;
923          (*__vfun->__complete_)(__env_.__rcvr_, static_cast<_As&&>(__as)...);
924      }
925  
926      template <class _Error>
927          requires __one_of<set_error_t(_Error), _Sigs...>
set_errorexec::__any::__rec::__ref928      void set_error(_Error&& __err) noexcept
929      {
930          const __any_::__rcvr_vfun<set_error_t(_Error)>* __vfun =
931              __env_.__vtable_;
932          (*__vfun->__complete_)(__env_.__rcvr_, static_cast<_Error&&>(__err));
933      }
934  
set_stoppedexec::__any::__rec::__ref935      void set_stopped() noexcept
936          requires __one_of<set_stopped_t(), _Sigs...>
937      {
938          const __any_::__rcvr_vfun<set_stopped_t()>* __vfun = __env_.__vtable_;
939          (*__vfun->__complete_)(__env_.__rcvr_);
940      }
941  
get_envexec::__any::__rec::__ref942      auto get_env() const noexcept -> const __env_t&
943      {
944          return __env_;
945      }
946  };
947  } // namespace __rec
948  
949  class __operation_vtable
950  {
951    public:
952      void (*__start_)(void*) noexcept;
953  
954    private:
955      template <class _Op>
STDEXEC_MEMFN_DECL(auto __create_vtable)956      STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__operation_vtable>,
957                                               __mtype<_Op>) noexcept
958          -> const __operation_vtable*
959      {
960          static __operation_vtable __vtable{
961              [](void* __object_pointer) noexcept -> void {
962                  STDEXEC_ASSERT(__object_pointer);
963                  _Op& __op = *static_cast<_Op*>(__object_pointer);
964                  static_assert(operation_state<_Op>);
965                  stdexec::start(__op);
966              }};
967          return &__vtable;
968      }
969  };
970  
971  using __immovable_operation_storage = __immovable_storage_t<__operation_vtable>;
972  
973  template <class _Sigs, class _Queries>
974  using __receiver_ref =
975      __mapply<__mbind_front<__q<__rec::__ref>, _Sigs>, _Queries>;
976  
977  struct __on_stop_t
978  {
979      stdexec::inplace_stop_source& __source_;
980  
operator ()exec::__any::__on_stop_t981      void operator()() const noexcept
982      {
983          __source_.request_stop();
984      }
985  };
986  
987  template <class _Receiver>
988  struct __operation_base
989  {
990      STDEXEC_ATTRIBUTE((no_unique_address))
991      _Receiver __rcvr_;
992      stdexec::inplace_stop_source __stop_source_{};
993      using __stop_callback = typename stdexec::stop_token_of_t<
994          stdexec::env_of_t<_Receiver>>::template callback_type<__on_stop_t>;
995      std::optional<__stop_callback> __on_stop_{};
996  };
997  
998  template <class _Env>
999  using __env_t =
1000      __env::__join_t<prop<get_stop_token_t, inplace_stop_token>, _Env>;
1001  
1002  template <class _ReceiverId>
1003  struct __stoppable_receiver
1004  {
1005      using _Receiver = stdexec::__t<_ReceiverId>;
1006  
1007      struct __t
1008      {
1009          using receiver_concept = stdexec::receiver_t;
1010          __operation_base<_Receiver>* __op_;
1011  
1012          template <same_as<__t> _Self, class _Item>
1013              requires __callable<set_next_t, _Receiver&, _Item>
STDEXEC_MEMFN_DECLexec::__any::__stoppable_receiver::__t1014          STDEXEC_MEMFN_DECL(auto set_next)(this _Self& __self,
1015                                            _Item&& __item) noexcept
1016              -> __call_result_t<set_next_t, _Receiver&, _Item>
1017          {
1018              return exec::set_next(__self.__op_->__rcvr_,
1019                                    static_cast<_Item&&>(__item));
1020          }
1021  
1022          template <class... _Args>
1023              requires __callable<set_value_t, _Receiver, _Args...>
set_valueexec::__any::__stoppable_receiver::__t1024          void set_value(_Args&&... __args) noexcept
1025          {
1026              __op_->__on_stop_.reset();
1027              stdexec::set_value(static_cast<_Receiver&&>(__op_->__rcvr_),
1028                                 static_cast<_Args&&>(__args)...);
1029          }
1030  
1031          template <class _Error>
1032              requires __callable<set_error_t, _Receiver, _Error>
set_errorexec::__any::__stoppable_receiver::__t1033          void set_error(_Error&& __err) noexcept
1034          {
1035              __op_->__on_stop_.reset();
1036              stdexec::set_error(static_cast<_Receiver&&>(__op_->__rcvr_),
1037                                 static_cast<_Error&&>(__err));
1038          }
1039  
set_stoppedexec::__any::__stoppable_receiver::__t1040          void set_stopped() noexcept
1041              requires __callable<set_stopped_t, _Receiver>
1042          {
1043              __op_->__on_stop_.reset();
1044              stdexec::set_stopped(static_cast<_Receiver&&>(__op_->__rcvr_));
1045          }
1046  
get_envexec::__any::__stoppable_receiver::__t1047          auto get_env() const noexcept -> __env_t<env_of_t<_Receiver>>
1048          {
1049              return __env::__join(
1050                  prop{get_stop_token, __op_->__stop_source_.get_token()},
1051                  stdexec::get_env(__op_->__rcvr_));
1052          }
1053      };
1054  };
1055  
1056  template <class _ReceiverId>
1057  using __stoppable_receiver_t = stdexec::__t<__stoppable_receiver<_ReceiverId>>;
1058  
1059  template <class _ReceiverId, bool>
1060  struct __operation
1061  {
1062      using _Receiver = stdexec::__t<_ReceiverId>;
1063  
1064      class __t : public __operation_base<_Receiver>
1065      {
1066        public:
1067          using __id = __operation;
1068  
1069          template <class _Sender>
__t(_Sender && __sender,_Receiver && __receiver)1070          __t(_Sender&& __sender, _Receiver&& __receiver) :
1071              __operation_base<_Receiver>{static_cast<_Receiver&&>(__receiver)},
1072              __rec_{this}, __storage_{__sender.__connect(__rec_)}
1073          {}
1074  
start()1075          void start() & noexcept
1076          {
1077              this->__on_stop_.emplace(
1078                  stdexec::get_stop_token(stdexec::get_env(this->__rcvr_)),
1079                  __on_stop_t{this->__stop_source_});
1080              STDEXEC_ASSERT(__storage_.__get_vtable()->__start_);
1081              __storage_.__get_vtable()->__start_(
1082                  __storage_.__get_object_pointer());
1083          }
1084  
1085        private:
1086          __stoppable_receiver_t<_ReceiverId> __rec_;
1087          __immovable_operation_storage __storage_{};
1088      };
1089  };
1090  
1091  template <class _ReceiverId>
1092  struct __operation<_ReceiverId, false>
1093  {
1094      using _Receiver = stdexec::__t<_ReceiverId>;
1095  
1096      class __t
1097      {
1098        public:
1099          using __id = __operation;
1100  
1101          template <class _Sender>
__t(_Sender && __sender,_Receiver && __receiver)1102          __t(_Sender&& __sender, _Receiver&& __receiver) :
1103              __rec_{static_cast<_Receiver&&>(__receiver)},
1104              __storage_{__sender.__connect(__rec_)}
1105          {}
1106  
start()1107          void start() & noexcept
1108          {
1109              STDEXEC_ASSERT(__storage_.__get_vtable()->__start_);
1110              __storage_.__get_vtable()->__start_(
1111                  __storage_.__get_object_pointer());
1112          }
1113  
1114        private:
1115          STDEXEC_ATTRIBUTE((no_unique_address))
1116          _Receiver __rec_;
1117          __immovable_operation_storage __storage_{};
1118      };
1119  };
1120  
1121  template <class _Queries, bool _IsEnvProvider = true>
1122  class __query_vtable;
1123  
1124  template <template <class...> class _List, class... _Queries,
1125            bool _IsEnvProvider>
1126  class __query_vtable<_List<_Queries...>, _IsEnvProvider> :
1127      public __query_vfun<_Queries>...
1128  {
1129    public:
1130      using __query_vfun<_Queries>::operator()...;
1131  
1132    private:
1133      template <class _Queryable>
1134          requires(
1135              __callable<__query_vfun_fn<_Queryable, _IsEnvProvider>, _Queries> &&
1136              ...)
STDEXEC_MEMFN_DECL(auto __create_vtable)1137      STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__query_vtable>,
1138                                               __mtype<_Queryable>) noexcept
1139          -> const __query_vtable*
1140      {
1141          static const __query_vtable __vtable{
1142              {__query_vfun_fn<_Queryable, _IsEnvProvider>{}(
1143                  static_cast<_Queries>(nullptr))}...};
1144          return &__vtable;
1145      }
1146  };
1147  
1148  template <class _Sigs, class _SenderQueries = __types<>,
1149            class _ReceiverQueries = __types<>>
1150  struct __sender
1151  {
1152      using __receiver_ref_t = __receiver_ref<_Sigs, _ReceiverQueries>;
1153      static constexpr bool __with_inplace_stop_token =
1154          __v<__mapply<__mall_of<__q<__is_not_stop_token_query_v>>,
1155                       _ReceiverQueries>>;
1156  
1157      class __vtable : public __query_vtable<_SenderQueries>
1158      {
1159        public:
1160          using __id = __vtable;
1161  
__queries() const1162          auto __queries() const noexcept -> const __query_vtable<_SenderQueries>&
1163          {
1164              return *this;
1165          }
1166  
1167          __immovable_operation_storage (*__connect_)(void*, __receiver_ref_t);
1168  
1169        private:
1170          template <sender_to<__receiver_ref_t> _Sender>
STDEXEC_MEMFN_DECL(auto __create_vtable)1171          STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__vtable>,
1172                                                   __mtype<_Sender>) noexcept
1173              -> const __vtable*
1174          {
1175              static const __vtable __vtable_{
1176                  {*__create_vtable(__mtype<__query_vtable<_SenderQueries>>{},
1177                                    __mtype<_Sender>{})},
1178                  [](void* __object_pointer, __receiver_ref_t __receiver)
1179                      -> __immovable_operation_storage {
1180                      _Sender& __sender =
1181                          *static_cast<_Sender*>(__object_pointer);
1182                      using __op_state_t =
1183                          connect_result_t<_Sender, __receiver_ref_t>;
1184                      return __immovable_operation_storage{
1185                          std::in_place_type<__op_state_t>, __emplace_from{[&] {
1186                              return stdexec::connect(
1187                                  static_cast<_Sender&&>(__sender),
1188                                  static_cast<__receiver_ref_t&&>(__receiver));
1189                          }}};
1190                  }};
1191              return &__vtable_;
1192          }
1193      };
1194  
1195      struct __env_t
1196      {
1197          const __vtable* __vtable_;
1198          void* __sender_;
1199  
1200          template <class _Tag, class... _As>
1201              requires __callable<const __query_vtable<_SenderQueries>&, _Tag,
1202                                  void*, _As...>
queryexec::__any::__sender::__env_t1203          auto query(_Tag, _As&&... __as) const //
1204              noexcept(__nothrow_callable<const __query_vtable<_SenderQueries>&,
1205                                          _Tag, void*, _As...>)
1206                  -> __call_result_t<const __query_vtable<_SenderQueries>&, _Tag,
1207                                     void*, _As...>
1208          {
1209              return __vtable_->__queries()(_Tag{}, __sender_,
1210                                            static_cast<_As&&>(__as)...);
1211          }
1212      };
1213  
1214      struct __t
1215      {
1216          using __id = __sender;
1217          using completion_signatures = _Sigs;
1218          using sender_concept = stdexec::sender_t;
1219  
1220          __t(const __t&) = delete;
1221          auto operator=(const __t&) -> __t& = delete;
1222  
1223          __t(__t&&) = default;
1224          auto operator=(__t&&) -> __t& = default;
1225  
1226          template <__not_decays_to<__t> _Sender>
1227              requires sender_to<_Sender, __receiver_ref<_Sigs, _ReceiverQueries>>
__texec::__any::__sender::__t1228          __t(_Sender&& __sndr) : __storage_{static_cast<_Sender&&>(__sndr)}
1229          {}
1230  
__connectexec::__any::__sender::__t1231          auto __connect(__receiver_ref_t __receiver)
1232              -> __immovable_operation_storage
1233          {
1234              return __storage_.__get_vtable()->__connect_(
1235                  __storage_.__get_object_pointer(),
1236                  static_cast<__receiver_ref_t&&>(__receiver));
1237          }
1238  
operator boolexec::__any::__sender::__t1239          explicit operator bool() const noexcept
1240          {
1241              return __get_object_pointer(__storage_) != nullptr;
1242          }
1243  
get_envexec::__any::__sender::__t1244          auto get_env() const noexcept -> __env_t
1245          {
1246              return {__storage_.__get_vtable(),
1247                      __storage_.__get_object_pointer()};
1248          }
1249  
1250          template <receiver_of<_Sigs> _Rcvr>
connectexec::__any::__sender::__t1251          auto connect(_Rcvr __rcvr) && //
1252              -> stdexec::__t<
1253                  __operation<stdexec::__id<_Rcvr>, __with_inplace_stop_token>>
1254          {
1255              return {static_cast<__t&&>(*this), static_cast<_Rcvr&&>(__rcvr)};
1256          }
1257  
1258        private:
1259          __unique_storage_t<__vtable> __storage_;
1260      };
1261  };
1262  
1263  template <class _ScheduleSender, class _SchedulerQueries = __types<>>
1264  class __scheduler
1265  {
1266      static constexpr std::size_t __buffer_size = 4 * sizeof(void*);
1267      template <class _Ty>
1268      static constexpr bool __is_small =
1269          sizeof(_Ty) <= __buffer_size &&
1270          alignof(_Ty) <= alignof(std::max_align_t);
1271  
1272    public:
1273      template <class _Scheduler>
1274          requires(!__decays_to<_Scheduler, __scheduler>) && scheduler<_Scheduler>
__scheduler(_Scheduler && __scheduler)1275      __scheduler(_Scheduler&& __scheduler) :
1276          __storage_{static_cast<_Scheduler&&>(__scheduler)}
1277      {
1278          static_assert(
1279              __is_small<_Scheduler>,
1280              "any_scheduler<> must have a nothrow copy constructor, so the scheduler object must be "
1281              "small enough to be stored in the internal buffer to avoid dynamic allocation.");
1282      }
1283  
1284      __scheduler(__scheduler&&) noexcept = default;
1285      __scheduler(const __scheduler&) noexcept = default;
1286      __scheduler& operator=(__scheduler&&) noexcept = default;
1287      __scheduler& operator=(const __scheduler&) noexcept = default;
1288  
1289      using __sender_t = _ScheduleSender;
1290  
schedule() const1291      auto schedule() const noexcept -> __sender_t
1292      {
1293          STDEXEC_ASSERT(__storage_.__get_vtable()->__schedule_);
1294          return __storage_.__get_vtable()->__schedule_(
1295              __storage_.__get_object_pointer());
1296      }
1297  
1298      template <class _Tag, class... _As>
1299          requires __callable<const __query_vtable<_SchedulerQueries, false>&,
1300                              _Tag, void*, _As...>
query(_Tag,_As &&...__as) const1301      auto query(_Tag, _As&&... __as) const //
1302          noexcept(
1303              __nothrow_callable<const __query_vtable<_SchedulerQueries, false>&,
1304                                 _Tag, void*, _As...>)
1305              -> __call_result_t<const __query_vtable<_SchedulerQueries, false>&,
1306                                 _Tag, void*, _As...>
1307      {
1308          return __storage_.__get_vtable()->__queries()(
1309              _Tag{}, __storage_.__get_object_pointer(),
1310              static_cast<_As&&>(__as)...);
1311      }
1312  
1313    private:
1314      class __vtable : public __query_vtable<_SchedulerQueries, false>
1315      {
1316        public:
1317          __sender_t (*__schedule_)(void*) noexcept;
1318          bool (*__equal_to_)(const void*, const void* other) noexcept;
1319  
__queries() const1320          auto __queries() const noexcept
1321              -> const __query_vtable<_SchedulerQueries, false>&
1322          {
1323              return *this;
1324          }
1325  
1326        private:
1327          template <scheduler _Scheduler>
STDEXEC_MEMFN_DECL(auto __create_vtable)1328          STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__vtable>,
1329                                                   __mtype<_Scheduler>) noexcept
1330              -> const __vtable*
1331          {
1332              static const __vtable __vtable_{
1333                  {*__create_vtable(
1334                      __mtype<__query_vtable<_SchedulerQueries, false>>{},
1335                      __mtype<_Scheduler>{})},
1336                  [](void* __object_pointer) noexcept -> __sender_t {
1337                      const _Scheduler& __scheduler =
1338                          *static_cast<const _Scheduler*>(__object_pointer);
1339                      return __sender_t{stdexec::schedule(__scheduler)};
1340                  },
1341                  [](const void* __self, const void* __other) noexcept -> bool {
1342                      static_assert(noexcept(__declval<const _Scheduler&>() ==
1343                                             __declval<const _Scheduler&>()));
1344                      STDEXEC_ASSERT(__self && __other);
1345                      const _Scheduler& __self_scheduler =
1346                          *static_cast<const _Scheduler*>(__self);
1347                      const _Scheduler& __other_scheduler =
1348                          *static_cast<const _Scheduler*>(__other);
1349                      return __self_scheduler == __other_scheduler;
1350                  }};
1351              return &__vtable_;
1352          }
1353      };
1354  
operator ==(const __scheduler & __self,const __scheduler & __other)1355      friend auto operator==(const __scheduler& __self,
1356                             const __scheduler& __other) noexcept -> bool
1357      {
1358          if (__self.__storage_.__get_vtable() !=
1359              __other.__storage_.__get_vtable())
1360          {
1361              return false;
1362          }
1363  
1364          void* __p = __self.__storage_.__get_object_pointer();
1365          void* __o = __other.__storage_.__get_object_pointer();
1366          // if both object pointers are not null, use the virtual equal_to
1367          // function
1368          return (__p && __o &&
1369                  __self.__storage_.__get_vtable()->__equal_to_(__p, __o))
1370                 // if both object pointers are nullptrs, they are equal
1371                 || (!__p && !__o);
1372      }
1373  
operator !=(const __scheduler & __self,const __scheduler & __other)1374      friend auto operator!=(const __scheduler& __self,
1375                             const __scheduler& __other) noexcept -> bool
1376      {
1377          return !(__self == __other);
1378      }
1379  
1380      __copyable_storage_t<__vtable, __buffer_size> __storage_{};
1381  };
1382  } // namespace __any
1383  
1384  template <auto... _Sigs>
1385  using queries = stdexec::__types<decltype(_Sigs)...>;
1386  
1387  template <class _Completions, auto... _ReceiverQueries>
1388  class any_receiver_ref
1389  {
1390      using __receiver_base =
1391          __any::__rec::__ref<_Completions, decltype(_ReceiverQueries)...>;
1392      using __env_t = stdexec::env_of_t<__receiver_base>;
1393      __receiver_base __receiver_;
1394  
1395    public:
1396      using receiver_concept = stdexec::receiver_t;
1397      using __t = any_receiver_ref;
1398      using __id = any_receiver_ref;
1399  
1400      template <stdexec::__none_of<any_receiver_ref, const any_receiver_ref,
1401                                   __env_t, const __env_t>
1402                    _Receiver>
1403          requires stdexec::receiver_of<_Receiver, _Completions>
any_receiver_ref(_Receiver & __receiver)1404      any_receiver_ref(_Receiver& __receiver) //
1405          noexcept(
1406              stdexec::__nothrow_constructible_from<__receiver_base, _Receiver>) :
1407          __receiver_(__receiver)
1408      {}
1409  
1410      template <class... _As>
1411          requires stdexec::tag_invocable<stdexec::set_value_t, __receiver_base,
1412                                          _As...>
set_value(_As &&...__as)1413      void set_value(_As&&... __as) noexcept
1414      {
1415          stdexec::tag_invoke(stdexec::set_value,
1416                              static_cast<__receiver_base&&>(__receiver_),
1417                              static_cast<_As&&>(__as)...);
1418      }
1419  
1420      template <class _Error>
1421          requires stdexec::tag_invocable<stdexec::set_error_t, __receiver_base,
1422                                          _Error>
set_error(_Error && __err)1423      void set_error(_Error&& __err) noexcept
1424      {
1425          stdexec::tag_invoke(stdexec::set_error,
1426                              static_cast<__receiver_base&&>(__receiver_),
1427                              static_cast<_Error&&>(__err));
1428      }
1429  
set_stopped()1430      void set_stopped() noexcept
1431          requires stdexec::tag_invocable<stdexec::set_stopped_t, __receiver_base>
1432      {
1433          stdexec::tag_invoke(stdexec::set_stopped,
1434                              static_cast<__receiver_base&&>(__receiver_));
1435      }
1436  
get_env() const1437      auto get_env() const noexcept -> stdexec::env_of_t<__receiver_base>
1438      {
1439          return stdexec::get_env(__receiver_);
1440      }
1441  
1442      template <auto... _SenderQueries>
1443      class any_sender
1444      {
1445          using __sender_base = stdexec::__t<
1446              __any::__sender<_Completions, queries<_SenderQueries...>,
1447                              queries<_ReceiverQueries...>>>;
1448          __sender_base __sender_;
1449  
1450          template <class _Tag, stdexec::__decays_to<any_sender> Self,
1451                    class... _As>
1452              requires stdexec::tag_invocable<
1453                  _Tag, stdexec::__copy_cvref_t<Self, __sender_base>, _As...>
tag_invoke(_Tag,Self && __self,_As &&...__as)1454          friend auto tag_invoke(_Tag, Self&& __self, _As&&... __as) //
1455              noexcept(
1456                  stdexec::nothrow_tag_invocable<
1457                      _Tag, stdexec::__copy_cvref_t<Self, __sender_base>, _As...>)
1458          {
1459              return stdexec::tag_invoke(_Tag{},
1460                                         static_cast<Self&&>(__self).__sender_,
1461                                         static_cast<_As&&>(__as)...);
1462          }
1463  
1464        public:
1465          using sender_concept = stdexec::sender_t;
1466          using completion_signatures =
1467              typename __sender_base::completion_signatures;
1468  
1469          template <stdexec::__not_decays_to<any_sender> _Sender>
1470              requires stdexec::sender_to<_Sender, __receiver_base>
any_sender(_Sender && __sender)1471          any_sender(_Sender&& __sender) //
1472              noexcept(
1473                  stdexec::__nothrow_constructible_from<__sender_base, _Sender>) :
1474              __sender_(static_cast<_Sender&&>(__sender))
1475          {}
1476  
1477          template <stdexec::receiver_of<_Completions> _Receiver>
connect(_Receiver __rcvr)1478          auto connect(_Receiver __rcvr) && -> stdexec::connect_result_t<
1479              __sender_base, _Receiver>
1480          {
1481              return static_cast<__sender_base&&>(__sender_).connect(
1482                  static_cast<_Receiver&&>(__rcvr));
1483          }
1484  
1485          template <auto... _SchedulerQueries>
1486          class any_scheduler
1487          {
1488              using __schedule_completions =
1489                  stdexec::__concat_completion_signatures<
1490                      _Completions,
1491                      stdexec::completion_signatures<stdexec::set_value_t()>>;
1492              using __schedule_receiver =
1493                  any_receiver_ref<__schedule_completions, _ReceiverQueries...>;
1494  
1495              template <typename _Tag, typename _Sig>
1496              static auto __ret_fn(_Tag (*const)(_Sig)) -> _Tag;
1497  
1498              template <class _Tag>
1499              struct __ret_equals_to
1500              {
1501                  template <class _Sig>
1502                  using __f = std::is_same<
1503                      _Tag, decltype(__ret_fn(static_cast<_Sig>(nullptr)))>;
1504              };
1505  
1506              using schedule_sender_queries = stdexec::__minvoke<
1507                  stdexec::__mremove_if<__ret_equals_to<
1508                      stdexec::get_completion_scheduler_t<stdexec::set_value_t>>>,
1509                  decltype(_SenderQueries)...>;
1510  
1511  #if STDEXEC_MSVC()
1512              // MSVCBUG
1513              // https://developercommunity.visualstudio.com/t/ICE-and-non-ICE-bug-in-NTTP-argument-w/10361081
1514  
1515              static constexpr auto __any_scheduler_noexcept_signature =
1516                  stdexec::get_completion_scheduler<stdexec::set_value_t>.signature<any_scheduler() noexcept>;
1517              template <class... _Queries>
1518              using __schedule_sender_fn =
1519                  typename __schedule_receiver::template any_sender<
1520                      __any_scheduler_noexcept_signature>;
1521  #else
1522              template <class... _Queries>
1523              using __schedule_sender_fn = typename __schedule_receiver::template any_sender<
1524                  stdexec::get_completion_scheduler<stdexec::set_value_t>.template signature<any_scheduler() noexcept>>;
1525  #endif
1526              using __schedule_sender =
1527                  stdexec::__mapply<stdexec::__q<__schedule_sender_fn>,
1528                                    schedule_sender_queries>;
1529  
1530              using __scheduler_base =
1531                  __any::__scheduler<__schedule_sender,
1532                                     queries<_SchedulerQueries...>>;
1533  
1534              __scheduler_base __scheduler_;
1535  
1536            public:
1537              using __t = any_scheduler;
1538              using __id = any_scheduler;
1539  
1540              template <stdexec::__none_of<any_scheduler> _Scheduler>
1541                  requires stdexec::scheduler<_Scheduler>
any_scheduler(_Scheduler __scheduler)1542              any_scheduler(_Scheduler __scheduler) :
1543                  __scheduler_{static_cast<_Scheduler&&>(__scheduler)}
1544              {}
1545  
schedule() const1546              auto schedule() const noexcept -> __schedule_sender
1547              {
1548                  return __scheduler_.schedule();
1549              }
1550  
1551              template <class _Tag, class... _As>
1552                  requires stdexec::tag_invocable<_Tag, const __scheduler_base&,
1553                                                  _As...>
query(_Tag,_As &&...__as) const1554              auto query(_Tag, _As&&... __as) const noexcept(
1555                  stdexec::nothrow_tag_invocable<_Tag, const __scheduler_base&,
1556                                                 _As...>)
1557                  -> stdexec::tag_invoke_result_t<_Tag, const __scheduler_base&,
1558                                                  _As...>
1559              {
1560                  return stdexec::tag_invoke(_Tag(), __scheduler_,
1561                                             static_cast<_As&&>(__as)...);
1562              }
1563  
1564              auto operator==(const any_scheduler&) const noexcept
1565                  -> bool = default;
1566          };
1567      };
1568  };
1569  } // namespace exec
1570