xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/any_sender_of.hpp (revision a23d26bd8cd0cc40ff6311e86e0de2c7f43f55ea)
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) -> __t&
542         requires(_Copyable)
543     {
544         if (&__other != this)
545         {
546             __t tmp(__other);
547             *this = std::move(tmp);
548         }
549         return *this;
550     }
551 
__t(__t && __other)552     __t(__t&& __other) noexcept
553     {
554         (*__other.__vtable_)(__move_construct, this,
555                              static_cast<__t&&>(__other));
556     }
557 
operator =(__t && __other)558     auto operator=(__t&& __other) noexcept -> __t&
559     {
560         __reset();
561         (*__other.__vtable_)(__move_construct, this,
562                              static_cast<__t&&>(__other));
563         return *this;
564     }
565 
~__t()566     ~__t()
567     {
568         __reset();
569     }
570 
__reset()571     void __reset() noexcept
572     {
573         (*__vtable_)(__delete, this);
574         __object_pointer_ = nullptr;
575         __vtable_ = __default_storage_vtable(static_cast<__vtable_t*>(nullptr));
576     }
577 
__get_vtable() const578     auto __get_vtable() const noexcept -> const _Vtable*
579     {
580         return __vtable_;
581     }
582 
__get_object_pointer() const583     [[nodiscard]] auto __get_object_pointer() const noexcept -> void*
584     {
585         return __object_pointer_;
586     }
587 
588   private:
589     template <class _Tp, class... _As>
__construct_small(_As &&...__args)590     void __construct_small(_As&&... __args)
591     {
592         static_assert(sizeof(_Tp) <= __buffer_size &&
593                       alignof(_Tp) <= __alignment);
594         _Tp* __pointer = static_cast<_Tp*>(static_cast<void*>(&__buffer_[0]));
595         using _Alloc = typename std::allocator_traits<
596             _Allocator>::template rebind_alloc<_Tp>;
597         _Alloc __alloc{__allocator_};
598         std::allocator_traits<_Alloc>::construct(__alloc, __pointer,
599                                                  static_cast<_As&&>(__args)...);
600         __object_pointer_ = __pointer;
601     }
602 
603     template <class _Tp, class... _As>
__construct_large(_As &&...__args)604     void __construct_large(_As&&... __args)
605     {
606         using _Alloc = typename std::allocator_traits<
607             _Allocator>::template rebind_alloc<_Tp>;
608         _Alloc __alloc{__allocator_};
609         _Tp* __pointer = std::allocator_traits<_Alloc>::allocate(__alloc, 1);
610         try
611         {
612             std::allocator_traits<_Alloc>::construct(
613                 __alloc, __pointer, static_cast<_As&&>(__args)...);
614         }
615         catch (...)
616         {
617             std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
618             throw;
619         }
620         __object_pointer_ = __pointer;
621     }
622 
623     template <class _Tp>
STDEXEC_MEMFN_DECL(void __delete)624     STDEXEC_MEMFN_DECL(void __delete)(this __mtype<_Tp>, __t& __self) noexcept
625     {
626         if (!__self.__object_pointer_)
627         {
628             return;
629         }
630         using _Alloc = typename std::allocator_traits<
631             _Allocator>::template rebind_alloc<_Tp>;
632         _Alloc __alloc{__self.__allocator_};
633         _Tp* __pointer =
634             static_cast<_Tp*>(std::exchange(__self.__object_pointer_, nullptr));
635         std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
636         if constexpr (!__is_small<_Tp>)
637         {
638             std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
639         }
640     }
641 
642     template <class _Tp>
STDEXEC_MEMFN_DECL(void __move_construct)643     STDEXEC_MEMFN_DECL(void __move_construct)(this __mtype<_Tp>, __t& __self,
644                                               __t&& __other) noexcept
645     {
646         if (!__other.__object_pointer_)
647         {
648             return;
649         }
650         _Tp* __pointer = static_cast<_Tp*>(
651             std::exchange(__other.__object_pointer_, nullptr));
652         if constexpr (__is_small<_Tp>)
653         {
654             _Tp& __other_object = *__pointer;
655             __self.template __construct_small<_Tp>(
656                 static_cast<_Tp&&>(__other_object));
657             using _Alloc = typename std::allocator_traits<
658                 _Allocator>::template rebind_alloc<_Tp>;
659             _Alloc __alloc{__self.__allocator_};
660             std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
661         }
662         else
663         {
664             __self.__object_pointer_ = __pointer;
665         }
666         __self.__vtable_ = std::exchange(
667             __other.__vtable_,
668             __default_storage_vtable(static_cast<__vtable_t*>(nullptr)));
669     }
670 
671     template <class _Tp>
672         requires _Copyable
STDEXEC_MEMFN_DECL(void __copy_construct)673     STDEXEC_MEMFN_DECL(void __copy_construct)(this __mtype<_Tp>, __t& __self,
674                                               const __t& __other)
675     {
676         if (!__other.__object_pointer_)
677         {
678             return;
679         }
680         const _Tp& __other_object =
681             *static_cast<const _Tp*>(__other.__object_pointer_);
682         if constexpr (__is_small<_Tp>)
683         {
684             __self.template __construct_small<_Tp>(__other_object);
685         }
686         else
687         {
688             __self.template __construct_large<_Tp>(__other_object);
689         }
690         __self.__vtable_ = __other.__vtable_;
691     }
692 
693     const __vtable_t* __vtable_{
694         __default_storage_vtable(static_cast<__vtable_t*>(nullptr))};
695     void* __object_pointer_{nullptr};
696     alignas(__alignment) std::byte __buffer_[__buffer_size]{};
697     STDEXEC_ATTRIBUTE((no_unique_address))
698     _Allocator __allocator_{};
699 };
700 
701 struct __empty_vtable
702 {
703     template <class _Sender>
STDEXEC_MEMFN_DECLexec::__any::__empty_vtable704     STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__empty_vtable>,
705                                              __mtype<_Sender>) noexcept
706         -> const __empty_vtable*
707     {
708         static const __empty_vtable __vtable_{};
709         return &__vtable_;
710     }
711 };
712 
713 template <class _VTable = __empty_vtable,
714           class _Allocator = std::allocator<std::byte>>
715 using __immovable_storage_t = __t<__immovable_storage<_VTable, _Allocator>>;
716 
717 template <class _VTable, class _Allocator = std::allocator<std::byte>>
718 using __unique_storage_t = __t<__storage<_VTable, _Allocator>>;
719 
720 template <class _VTable, std::size_t _InlineSize = 3 * sizeof(void*),
721           class _Allocator = std::allocator<std::byte>>
722 using __copyable_storage_t =
723     __t<__storage<_VTable, _Allocator, true, _InlineSize>>;
724 
725 template <class _Tag, class... _As>
726 auto __tag_type(_Tag (*)(_As...)) -> _Tag;
727 
728 template <class _Tag, class... _As>
729 auto __tag_type(_Tag (*)(_As...) noexcept) -> _Tag;
730 
731 template <class _Query>
732 concept __is_stop_token_query = requires {
733                                     {
734                                         __tag_type(static_cast<_Query>(nullptr))
735                                     } -> same_as<get_stop_token_t>;
736                                 };
737 
738 template <class _Query>
739 concept __is_not_stop_token_query = !__is_stop_token_query<_Query>;
740 
741 template <class _Query>
742 using __is_not_stop_token_query_v = __mbool<__is_not_stop_token_query<_Query>>;
743 
744 namespace __rec
745 {
746 template <class _Sigs, class... _Queries>
747 struct __vtable
748 {
749     class __t;
750 };
751 
752 template <class _Sigs, class... _Queries>
753 struct __ref;
754 
755 template <class... _Sigs, class... _Queries>
756 struct __vtable<completion_signatures<_Sigs...>, _Queries...>
757 {
758     class __t :
759         public __any_::__rcvr_vfun<_Sigs>...,
760         public __query_vfun<_Queries>...
761     {
762       public:
763         using __query_vfun<_Queries>::operator()...;
764 
765       private:
766         template <class _Rcvr>
767             requires receiver_of<_Rcvr, completion_signatures<_Sigs...>> &&
768                      (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
STDEXEC_MEMFN_DECL(auto __create_vtable)769         STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__t>,
770                                                  __mtype<_Rcvr>) noexcept
771             -> const __t*
772         {
773             static const __t __vtable_{
774                 {__any_::__rcvr_vfun_fn(static_cast<_Rcvr*>(nullptr),
775                                         static_cast<_Sigs*>(nullptr))}...,
776                 {__query_vfun_fn<_Rcvr>{}(static_cast<_Queries>(nullptr))}...};
777             return &__vtable_;
778         }
779     };
780 };
781 
782 template <class... _Sigs, class... _Queries>
783     requires(__is_not_stop_token_query<_Queries> && ...)
784 struct __ref<completion_signatures<_Sigs...>, _Queries...>
785 {
786 #if !STDEXEC_MSVC()
787     // MSVCBUG
788     // https://developercommunity.visualstudio.com/t/Private-member-inaccessible-when-used-in/10448363
789 
790   private:
791 #endif
792     using __vtable_t =
793         stdexec::__t<__vtable<completion_signatures<_Sigs...>, _Queries...>>;
794 
795     struct __env_t
796     {
797         const __vtable_t* __vtable_;
798         void* __rcvr_;
799         inplace_stop_token __token_;
800 
801         template <class _Tag, class... _As>
802             requires __callable<const __vtable_t&, _Tag, void*, _As...>
queryexec::__any::__rec::__ref::__env_t803         auto query(_Tag, _As&&... __as) const //
804             noexcept(__nothrow_callable<const __vtable_t&, _Tag, void*, _As...>)
805                 -> __call_result_t<const __vtable_t&, _Tag, void*, _As...>
806         {
807             return (*__vtable_)(_Tag{}, __rcvr_, static_cast<_As&&>(__as)...);
808         }
809 
queryexec::__any::__rec::__ref::__env_t810         auto query(get_stop_token_t) const noexcept -> inplace_stop_token
811         {
812             return __token_;
813         }
814     } __env_;
815 
816   public:
817     using receiver_concept = stdexec::receiver_t;
818     using __id = __ref;
819     using __t = __ref;
820 
821     template <__none_of<__ref, const __ref, __env_t, const __env_t> _Rcvr>
822         requires receiver_of<_Rcvr, completion_signatures<_Sigs...>> &&
823                  (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
__refexec::__any::__rec::__ref824     __ref(_Rcvr& __rcvr) noexcept :
825         __env_{__create_vtable(__mtype<__vtable_t>{}, __mtype<_Rcvr>{}),
826                &__rcvr, stdexec::get_stop_token(stdexec::get_env(__rcvr))}
827     {}
828 
829     template <class... _As>
830         requires __one_of<set_value_t(_As...), _Sigs...>
set_valueexec::__any::__rec::__ref831     void set_value(_As&&... __as) noexcept
832     {
833         const __any_::__rcvr_vfun<set_value_t(_As...)>* __vfun =
834             __env_.__vtable_;
835         (*__vfun->__complete_)(__env_.__rcvr_, static_cast<_As&&>(__as)...);
836     }
837 
838     template <class _Error>
839         requires __one_of<set_error_t(_Error), _Sigs...>
set_errorexec::__any::__rec::__ref840     void set_error(_Error&& __err) noexcept
841     {
842         const __any_::__rcvr_vfun<set_error_t(_Error)>* __vfun =
843             __env_.__vtable_;
844         (*__vfun->__complete_)(__env_.__rcvr_, static_cast<_Error&&>(__err));
845     }
846 
set_stoppedexec::__any::__rec::__ref847     void set_stopped() noexcept
848         requires __one_of<set_stopped_t(), _Sigs...>
849     {
850         const __any_::__rcvr_vfun<set_stopped_t()>* __vfun = __env_.__vtable_;
851         (*__vfun->__complete_)(__env_.__rcvr_);
852     }
853 
get_envexec::__any::__rec::__ref854     auto get_env() const noexcept -> const __env_t&
855     {
856         return __env_;
857     }
858 };
859 
860 auto __test_never_stop_token(
861     get_stop_token_t (*)(never_stop_token (*)() noexcept)) -> __mbool<true>;
862 
863 template <class _Tag, class _Ret, class... _As>
864 auto __test_never_stop_token(_Tag (*)(_Ret (*)(_As...) noexcept))
865     -> __mbool<false>;
866 
867 template <class _Tag, class _Ret, class... _As>
868 auto __test_never_stop_token(_Tag (*)(_Ret (*)(_As...))) -> __mbool<false>;
869 
870 template <class _Query>
871 using __is_never_stop_token_query =
872     decltype(__test_never_stop_token(static_cast<_Query>(nullptr)));
873 
874 template <class... _Sigs, class... _Queries>
875     requires(__is_stop_token_query<_Queries> || ...)
876 struct __ref<completion_signatures<_Sigs...>, _Queries...>
877 {
878 #if !STDEXEC_MSVC()
879     // MSVCBUG
880     // https://developercommunity.visualstudio.com/t/Private-member-inaccessible-when-used-in/10448363
881 
882   private:
883 #endif
884     using _FilteredQueries =
885         __minvoke<__mremove_if<__q<__is_never_stop_token_query>>, _Queries...>;
886     using __vtable_t = stdexec::__t<
887         __mapply<__mbind_front_q<__vtable, completion_signatures<_Sigs...>>,
888                  _FilteredQueries>>;
889 
890     struct __env_t
891     {
892         const __vtable_t* __vtable_;
893         void* __rcvr_;
894 
895         template <class _Tag, class... _As>
896             requires __callable<const __vtable_t&, _Tag, void*, _As...>
queryexec::__any::__rec::__ref::__env_t897         auto query(_Tag, _As&&... __as) const //
898             noexcept(__nothrow_callable<const __vtable_t&, _Tag, void*, _As...>)
899                 -> __call_result_t<const __vtable_t&, _Tag, void*, _As...>
900         {
901             return (*__vtable_)(_Tag{}, __rcvr_, static_cast<_As&&>(__as)...);
902         }
903     } __env_;
904 
905   public:
906     using receiver_concept = stdexec::receiver_t;
907     using __id = __ref;
908     using __t = __ref;
909 
910     template <__none_of<__ref, const __ref, __env_t, const __env_t> _Rcvr>
911         requires receiver_of<_Rcvr, completion_signatures<_Sigs...>> &&
912                  (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
__refexec::__any::__rec::__ref913     __ref(_Rcvr& __rcvr) noexcept :
914         __env_{__create_vtable(__mtype<__vtable_t>{}, __mtype<_Rcvr>{}),
915                &__rcvr}
916     {}
917 
918     template <class... _As>
919         requires __one_of<set_value_t(_As...), _Sigs...>
set_valueexec::__any::__rec::__ref920     void set_value(_As&&... __as) noexcept
921     {
922         const __any_::__rcvr_vfun<set_value_t(_As...)>* __vfun =
923             __env_.__vtable_;
924         (*__vfun->__complete_)(__env_.__rcvr_, static_cast<_As&&>(__as)...);
925     }
926 
927     template <class _Error>
928         requires __one_of<set_error_t(_Error), _Sigs...>
set_errorexec::__any::__rec::__ref929     void set_error(_Error&& __err) noexcept
930     {
931         const __any_::__rcvr_vfun<set_error_t(_Error)>* __vfun =
932             __env_.__vtable_;
933         (*__vfun->__complete_)(__env_.__rcvr_, static_cast<_Error&&>(__err));
934     }
935 
set_stoppedexec::__any::__rec::__ref936     void set_stopped() noexcept
937         requires __one_of<set_stopped_t(), _Sigs...>
938     {
939         const __any_::__rcvr_vfun<set_stopped_t()>* __vfun = __env_.__vtable_;
940         (*__vfun->__complete_)(__env_.__rcvr_);
941     }
942 
get_envexec::__any::__rec::__ref943     auto get_env() const noexcept -> const __env_t&
944     {
945         return __env_;
946     }
947 };
948 } // namespace __rec
949 
950 class __operation_vtable
951 {
952   public:
953     void (*__start_)(void*) noexcept;
954 
955   private:
956     template <class _Op>
STDEXEC_MEMFN_DECL(auto __create_vtable)957     STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__operation_vtable>,
958                                              __mtype<_Op>) noexcept
959         -> const __operation_vtable*
960     {
961         static __operation_vtable __vtable{
962             [](void* __object_pointer) noexcept -> void {
963                 STDEXEC_ASSERT(__object_pointer);
964                 _Op& __op = *static_cast<_Op*>(__object_pointer);
965                 static_assert(operation_state<_Op>);
966                 stdexec::start(__op);
967             }};
968         return &__vtable;
969     }
970 };
971 
972 using __immovable_operation_storage = __immovable_storage_t<__operation_vtable>;
973 
974 template <class _Sigs, class _Queries>
975 using __receiver_ref =
976     __mapply<__mbind_front<__q<__rec::__ref>, _Sigs>, _Queries>;
977 
978 struct __on_stop_t
979 {
980     stdexec::inplace_stop_source& __source_;
981 
operator ()exec::__any::__on_stop_t982     void operator()() const noexcept
983     {
984         __source_.request_stop();
985     }
986 };
987 
988 template <class _Receiver>
989 struct __operation_base
990 {
991     STDEXEC_ATTRIBUTE((no_unique_address))
992     _Receiver __rcvr_;
993     stdexec::inplace_stop_source __stop_source_{};
994     using __stop_callback = typename stdexec::stop_token_of_t<
995         stdexec::env_of_t<_Receiver>>::template callback_type<__on_stop_t>;
996     std::optional<__stop_callback> __on_stop_{};
997 };
998 
999 template <class _Env>
1000 using __env_t =
1001     __env::__join_t<prop<get_stop_token_t, inplace_stop_token>, _Env>;
1002 
1003 template <class _ReceiverId>
1004 struct __stoppable_receiver
1005 {
1006     using _Receiver = stdexec::__t<_ReceiverId>;
1007 
1008     struct __t
1009     {
1010         using receiver_concept = stdexec::receiver_t;
1011         __operation_base<_Receiver>* __op_;
1012 
1013         template <same_as<__t> _Self, class _Item>
1014             requires __callable<set_next_t, _Receiver&, _Item>
STDEXEC_MEMFN_DECLexec::__any::__stoppable_receiver::__t1015         STDEXEC_MEMFN_DECL(auto set_next)(this _Self& __self,
1016                                           _Item&& __item) noexcept
1017             -> __call_result_t<set_next_t, _Receiver&, _Item>
1018         {
1019             return exec::set_next(__self.__op_->__rcvr_,
1020                                   static_cast<_Item&&>(__item));
1021         }
1022 
1023         template <class... _Args>
1024             requires __callable<set_value_t, _Receiver, _Args...>
set_valueexec::__any::__stoppable_receiver::__t1025         void set_value(_Args&&... __args) noexcept
1026         {
1027             __op_->__on_stop_.reset();
1028             stdexec::set_value(static_cast<_Receiver&&>(__op_->__rcvr_),
1029                                static_cast<_Args&&>(__args)...);
1030         }
1031 
1032         template <class _Error>
1033             requires __callable<set_error_t, _Receiver, _Error>
set_errorexec::__any::__stoppable_receiver::__t1034         void set_error(_Error&& __err) noexcept
1035         {
1036             __op_->__on_stop_.reset();
1037             stdexec::set_error(static_cast<_Receiver&&>(__op_->__rcvr_),
1038                                static_cast<_Error&&>(__err));
1039         }
1040 
set_stoppedexec::__any::__stoppable_receiver::__t1041         void set_stopped() noexcept
1042             requires __callable<set_stopped_t, _Receiver>
1043         {
1044             __op_->__on_stop_.reset();
1045             stdexec::set_stopped(static_cast<_Receiver&&>(__op_->__rcvr_));
1046         }
1047 
get_envexec::__any::__stoppable_receiver::__t1048         auto get_env() const noexcept -> __env_t<env_of_t<_Receiver>>
1049         {
1050             return __env::__join(
1051                 prop{get_stop_token, __op_->__stop_source_.get_token()},
1052                 stdexec::get_env(__op_->__rcvr_));
1053         }
1054     };
1055 };
1056 
1057 template <class _ReceiverId>
1058 using __stoppable_receiver_t = stdexec::__t<__stoppable_receiver<_ReceiverId>>;
1059 
1060 template <class _ReceiverId, bool>
1061 struct __operation
1062 {
1063     using _Receiver = stdexec::__t<_ReceiverId>;
1064 
1065     class __t : public __operation_base<_Receiver>
1066     {
1067       public:
1068         using __id = __operation;
1069 
1070         template <class _Sender>
__t(_Sender && __sender,_Receiver && __receiver)1071         __t(_Sender&& __sender, _Receiver&& __receiver) :
1072             __operation_base<_Receiver>{static_cast<_Receiver&&>(__receiver)},
1073             __rec_{this}, __storage_{__sender.__connect(__rec_)}
1074         {}
1075 
start()1076         void start() & noexcept
1077         {
1078             this->__on_stop_.emplace(
1079                 stdexec::get_stop_token(stdexec::get_env(this->__rcvr_)),
1080                 __on_stop_t{this->__stop_source_});
1081             STDEXEC_ASSERT(__storage_.__get_vtable()->__start_);
1082             __storage_.__get_vtable()->__start_(
1083                 __storage_.__get_object_pointer());
1084         }
1085 
1086       private:
1087         __stoppable_receiver_t<_ReceiverId> __rec_;
1088         __immovable_operation_storage __storage_{};
1089     };
1090 };
1091 
1092 template <class _ReceiverId>
1093 struct __operation<_ReceiverId, false>
1094 {
1095     using _Receiver = stdexec::__t<_ReceiverId>;
1096 
1097     class __t
1098     {
1099       public:
1100         using __id = __operation;
1101 
1102         template <class _Sender>
__t(_Sender && __sender,_Receiver && __receiver)1103         __t(_Sender&& __sender, _Receiver&& __receiver) :
1104             __rec_{static_cast<_Receiver&&>(__receiver)},
1105             __storage_{__sender.__connect(__rec_)}
1106         {}
1107 
start()1108         void start() & noexcept
1109         {
1110             STDEXEC_ASSERT(__storage_.__get_vtable()->__start_);
1111             __storage_.__get_vtable()->__start_(
1112                 __storage_.__get_object_pointer());
1113         }
1114 
1115       private:
1116         STDEXEC_ATTRIBUTE((no_unique_address))
1117         _Receiver __rec_;
1118         __immovable_operation_storage __storage_{};
1119     };
1120 };
1121 
1122 template <class _Queries, bool _IsEnvProvider = true>
1123 class __query_vtable;
1124 
1125 template <template <class...> class _List, class... _Queries,
1126           bool _IsEnvProvider>
1127 class __query_vtable<_List<_Queries...>, _IsEnvProvider> :
1128     public __query_vfun<_Queries>...
1129 {
1130   public:
1131     using __query_vfun<_Queries>::operator()...;
1132 
1133   private:
1134     template <class _Queryable>
1135         requires(
1136             __callable<__query_vfun_fn<_Queryable, _IsEnvProvider>, _Queries> &&
1137             ...)
STDEXEC_MEMFN_DECL(auto __create_vtable)1138     STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__query_vtable>,
1139                                              __mtype<_Queryable>) noexcept
1140         -> const __query_vtable*
1141     {
1142         static const __query_vtable __vtable{
1143             {__query_vfun_fn<_Queryable, _IsEnvProvider>{}(
1144                 static_cast<_Queries>(nullptr))}...};
1145         return &__vtable;
1146     }
1147 };
1148 
1149 template <class _Sigs, class _SenderQueries = __types<>,
1150           class _ReceiverQueries = __types<>>
1151 struct __sender
1152 {
1153     using __receiver_ref_t = __receiver_ref<_Sigs, _ReceiverQueries>;
1154     static constexpr bool __with_inplace_stop_token =
1155         __v<__mapply<__mall_of<__q<__is_not_stop_token_query_v>>,
1156                      _ReceiverQueries>>;
1157 
1158     class __vtable : public __query_vtable<_SenderQueries>
1159     {
1160       public:
1161         using __id = __vtable;
1162 
__queries() const1163         auto __queries() const noexcept -> const __query_vtable<_SenderQueries>&
1164         {
1165             return *this;
1166         }
1167 
1168         __immovable_operation_storage (*__connect_)(void*, __receiver_ref_t);
1169 
1170       private:
1171         template <sender_to<__receiver_ref_t> _Sender>
STDEXEC_MEMFN_DECL(auto __create_vtable)1172         STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__vtable>,
1173                                                  __mtype<_Sender>) noexcept
1174             -> const __vtable*
1175         {
1176             static const __vtable __vtable_{
1177                 {*__create_vtable(__mtype<__query_vtable<_SenderQueries>>{},
1178                                   __mtype<_Sender>{})},
1179                 [](void* __object_pointer, __receiver_ref_t __receiver)
1180                     -> __immovable_operation_storage {
1181                     _Sender& __sender =
1182                         *static_cast<_Sender*>(__object_pointer);
1183                     using __op_state_t =
1184                         connect_result_t<_Sender, __receiver_ref_t>;
1185                     return __immovable_operation_storage{
1186                         std::in_place_type<__op_state_t>, __emplace_from{[&] {
1187                             return stdexec::connect(
1188                                 static_cast<_Sender&&>(__sender),
1189                                 static_cast<__receiver_ref_t&&>(__receiver));
1190                         }}};
1191                 }};
1192             return &__vtable_;
1193         }
1194     };
1195 
1196     struct __env_t
1197     {
1198         const __vtable* __vtable_;
1199         void* __sender_;
1200 
1201         template <class _Tag, class... _As>
1202             requires __callable<const __query_vtable<_SenderQueries>&, _Tag,
1203                                 void*, _As...>
queryexec::__any::__sender::__env_t1204         auto query(_Tag, _As&&... __as) const //
1205             noexcept(__nothrow_callable<const __query_vtable<_SenderQueries>&,
1206                                         _Tag, void*, _As...>)
1207                 -> __call_result_t<const __query_vtable<_SenderQueries>&, _Tag,
1208                                    void*, _As...>
1209         {
1210             return __vtable_->__queries()(_Tag{}, __sender_,
1211                                           static_cast<_As&&>(__as)...);
1212         }
1213     };
1214 
1215     struct __t
1216     {
1217         using __id = __sender;
1218         using completion_signatures = _Sigs;
1219         using sender_concept = stdexec::sender_t;
1220 
1221         __t(const __t&) = delete;
1222         auto operator=(const __t&) -> __t& = delete;
1223 
1224         __t(__t&&) = default;
1225         auto operator=(__t&&) -> __t& = default;
1226 
1227         template <__not_decays_to<__t> _Sender>
1228             requires sender_to<_Sender, __receiver_ref<_Sigs, _ReceiverQueries>>
__texec::__any::__sender::__t1229         __t(_Sender&& __sndr) : __storage_{static_cast<_Sender&&>(__sndr)}
1230         {}
1231 
__connectexec::__any::__sender::__t1232         auto __connect(__receiver_ref_t __receiver)
1233             -> __immovable_operation_storage
1234         {
1235             return __storage_.__get_vtable()->__connect_(
1236                 __storage_.__get_object_pointer(),
1237                 static_cast<__receiver_ref_t&&>(__receiver));
1238         }
1239 
operator boolexec::__any::__sender::__t1240         explicit operator bool() const noexcept
1241         {
1242             return __get_object_pointer(__storage_) != nullptr;
1243         }
1244 
get_envexec::__any::__sender::__t1245         auto get_env() const noexcept -> __env_t
1246         {
1247             return {__storage_.__get_vtable(),
1248                     __storage_.__get_object_pointer()};
1249         }
1250 
1251         template <receiver_of<_Sigs> _Rcvr>
connectexec::__any::__sender::__t1252         auto connect(_Rcvr __rcvr) && //
1253             -> stdexec::__t<
1254                 __operation<stdexec::__id<_Rcvr>, __with_inplace_stop_token>>
1255         {
1256             return {static_cast<__t&&>(*this), static_cast<_Rcvr&&>(__rcvr)};
1257         }
1258 
1259       private:
1260         __unique_storage_t<__vtable> __storage_;
1261     };
1262 };
1263 
1264 template <class _ScheduleSender, class _SchedulerQueries = __types<>>
1265 class __scheduler
1266 {
1267     static constexpr std::size_t __buffer_size = 4 * sizeof(void*);
1268     template <class _Ty>
1269     static constexpr bool __is_small =
1270         sizeof(_Ty) <= __buffer_size &&
1271         alignof(_Ty) <= alignof(std::max_align_t);
1272 
1273   public:
1274     template <class _Scheduler>
1275         requires(!__decays_to<_Scheduler, __scheduler>) && scheduler<_Scheduler>
__scheduler(_Scheduler && __scheduler)1276     __scheduler(_Scheduler&& __scheduler) :
1277         __storage_{static_cast<_Scheduler&&>(__scheduler)}
1278     {
1279         static_assert(
1280             __is_small<_Scheduler>,
1281             "any_scheduler<> must have a nothrow copy constructor, so the scheduler object must be "
1282             "small enough to be stored in the internal buffer to avoid dynamic allocation.");
1283     }
1284 
1285     __scheduler(__scheduler&&) noexcept = default;
1286     __scheduler(const __scheduler&) noexcept = default;
1287     __scheduler& operator=(__scheduler&&) noexcept = default;
1288     __scheduler& operator=(const __scheduler&) noexcept = default;
1289 
1290     using __sender_t = _ScheduleSender;
1291 
schedule() const1292     auto schedule() const noexcept -> __sender_t
1293     {
1294         STDEXEC_ASSERT(__storage_.__get_vtable()->__schedule_);
1295         return __storage_.__get_vtable()->__schedule_(
1296             __storage_.__get_object_pointer());
1297     }
1298 
1299     template <class _Tag, class... _As>
1300         requires __callable<const __query_vtable<_SchedulerQueries, false>&,
1301                             _Tag, void*, _As...>
query(_Tag,_As &&...__as) const1302     auto query(_Tag, _As&&... __as) const //
1303         noexcept(
1304             __nothrow_callable<const __query_vtable<_SchedulerQueries, false>&,
1305                                _Tag, void*, _As...>)
1306             -> __call_result_t<const __query_vtable<_SchedulerQueries, false>&,
1307                                _Tag, void*, _As...>
1308     {
1309         return __storage_.__get_vtable()->__queries()(
1310             _Tag{}, __storage_.__get_object_pointer(),
1311             static_cast<_As&&>(__as)...);
1312     }
1313 
1314   private:
1315     class __vtable : public __query_vtable<_SchedulerQueries, false>
1316     {
1317       public:
1318         __sender_t (*__schedule_)(void*) noexcept;
1319         bool (*__equal_to_)(const void*, const void* other) noexcept;
1320 
__queries() const1321         auto __queries() const noexcept
1322             -> const __query_vtable<_SchedulerQueries, false>&
1323         {
1324             return *this;
1325         }
1326 
1327       private:
1328         template <scheduler _Scheduler>
STDEXEC_MEMFN_DECL(auto __create_vtable)1329         STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__vtable>,
1330                                                  __mtype<_Scheduler>) noexcept
1331             -> const __vtable*
1332         {
1333             static const __vtable __vtable_{
1334                 {*__create_vtable(
1335                     __mtype<__query_vtable<_SchedulerQueries, false>>{},
1336                     __mtype<_Scheduler>{})},
1337                 [](void* __object_pointer) noexcept -> __sender_t {
1338                     const _Scheduler& __scheduler =
1339                         *static_cast<const _Scheduler*>(__object_pointer);
1340                     return __sender_t{stdexec::schedule(__scheduler)};
1341                 },
1342                 [](const void* __self, const void* __other) noexcept -> bool {
1343                     static_assert(noexcept(__declval<const _Scheduler&>() ==
1344                                            __declval<const _Scheduler&>()));
1345                     STDEXEC_ASSERT(__self && __other);
1346                     const _Scheduler& __self_scheduler =
1347                         *static_cast<const _Scheduler*>(__self);
1348                     const _Scheduler& __other_scheduler =
1349                         *static_cast<const _Scheduler*>(__other);
1350                     return __self_scheduler == __other_scheduler;
1351                 }};
1352             return &__vtable_;
1353         }
1354     };
1355 
operator ==(const __scheduler & __self,const __scheduler & __other)1356     friend auto operator==(const __scheduler& __self,
1357                            const __scheduler& __other) noexcept -> bool
1358     {
1359         if (__self.__storage_.__get_vtable() !=
1360             __other.__storage_.__get_vtable())
1361         {
1362             return false;
1363         }
1364 
1365         void* __p = __self.__storage_.__get_object_pointer();
1366         void* __o = __other.__storage_.__get_object_pointer();
1367         // if both object pointers are not null, use the virtual equal_to
1368         // function
1369         return (__p && __o &&
1370                 __self.__storage_.__get_vtable()->__equal_to_(__p, __o))
1371                // if both object pointers are nullptrs, they are equal
1372                || (!__p && !__o);
1373     }
1374 
operator !=(const __scheduler & __self,const __scheduler & __other)1375     friend auto operator!=(const __scheduler& __self,
1376                            const __scheduler& __other) noexcept -> bool
1377     {
1378         return !(__self == __other);
1379     }
1380 
1381     __copyable_storage_t<__vtable, __buffer_size> __storage_{};
1382 };
1383 } // namespace __any
1384 
1385 template <auto... _Sigs>
1386 using queries = stdexec::__types<decltype(_Sigs)...>;
1387 
1388 template <class _Completions, auto... _ReceiverQueries>
1389 class any_receiver_ref
1390 {
1391     using __receiver_base =
1392         __any::__rec::__ref<_Completions, decltype(_ReceiverQueries)...>;
1393     using __env_t = stdexec::env_of_t<__receiver_base>;
1394     __receiver_base __receiver_;
1395 
1396   public:
1397     using receiver_concept = stdexec::receiver_t;
1398     using __t = any_receiver_ref;
1399     using __id = any_receiver_ref;
1400 
1401     template <stdexec::__none_of<any_receiver_ref, const any_receiver_ref,
1402                                  __env_t, const __env_t>
1403                   _Receiver>
1404         requires stdexec::receiver_of<_Receiver, _Completions>
any_receiver_ref(_Receiver & __receiver)1405     any_receiver_ref(_Receiver& __receiver) //
1406         noexcept(
1407             stdexec::__nothrow_constructible_from<__receiver_base, _Receiver>) :
1408         __receiver_(__receiver)
1409     {}
1410 
1411     template <class... _As>
1412         requires stdexec::tag_invocable<stdexec::set_value_t, __receiver_base,
1413                                         _As...>
set_value(_As &&...__as)1414     void set_value(_As&&... __as) noexcept
1415     {
1416         stdexec::tag_invoke(stdexec::set_value,
1417                             static_cast<__receiver_base&&>(__receiver_),
1418                             static_cast<_As&&>(__as)...);
1419     }
1420 
1421     template <class _Error>
1422         requires stdexec::tag_invocable<stdexec::set_error_t, __receiver_base,
1423                                         _Error>
set_error(_Error && __err)1424     void set_error(_Error&& __err) noexcept
1425     {
1426         stdexec::tag_invoke(stdexec::set_error,
1427                             static_cast<__receiver_base&&>(__receiver_),
1428                             static_cast<_Error&&>(__err));
1429     }
1430 
set_stopped()1431     void set_stopped() noexcept
1432         requires stdexec::tag_invocable<stdexec::set_stopped_t, __receiver_base>
1433     {
1434         stdexec::tag_invoke(stdexec::set_stopped,
1435                             static_cast<__receiver_base&&>(__receiver_));
1436     }
1437 
get_env() const1438     auto get_env() const noexcept -> stdexec::env_of_t<__receiver_base>
1439     {
1440         return stdexec::get_env(__receiver_);
1441     }
1442 
1443     template <auto... _SenderQueries>
1444     class any_sender
1445     {
1446         using __sender_base = stdexec::__t<
1447             __any::__sender<_Completions, queries<_SenderQueries...>,
1448                             queries<_ReceiverQueries...>>>;
1449         __sender_base __sender_;
1450 
1451         template <class _Tag, stdexec::__decays_to<any_sender> Self,
1452                   class... _As>
1453             requires stdexec::tag_invocable<
1454                 _Tag, stdexec::__copy_cvref_t<Self, __sender_base>, _As...>
tag_invoke(_Tag,Self && __self,_As &&...__as)1455         friend auto tag_invoke(_Tag, Self&& __self, _As&&... __as) //
1456             noexcept(
1457                 stdexec::nothrow_tag_invocable<
1458                     _Tag, stdexec::__copy_cvref_t<Self, __sender_base>, _As...>)
1459         {
1460             return stdexec::tag_invoke(_Tag{},
1461                                        static_cast<Self&&>(__self).__sender_,
1462                                        static_cast<_As&&>(__as)...);
1463         }
1464 
1465       public:
1466         using sender_concept = stdexec::sender_t;
1467         using completion_signatures =
1468             typename __sender_base::completion_signatures;
1469 
1470         template <stdexec::__not_decays_to<any_sender> _Sender>
1471             requires stdexec::sender_to<_Sender, __receiver_base>
any_sender(_Sender && __sender)1472         any_sender(_Sender&& __sender) //
1473             noexcept(
1474                 stdexec::__nothrow_constructible_from<__sender_base, _Sender>) :
1475             __sender_(static_cast<_Sender&&>(__sender))
1476         {}
1477 
1478         template <stdexec::receiver_of<_Completions> _Receiver>
connect(_Receiver __rcvr)1479         auto connect(_Receiver __rcvr) && -> stdexec::connect_result_t<
1480             __sender_base, _Receiver>
1481         {
1482             return static_cast<__sender_base&&>(__sender_).connect(
1483                 static_cast<_Receiver&&>(__rcvr));
1484         }
1485 
1486         template <auto... _SchedulerQueries>
1487         class any_scheduler
1488         {
1489             using __schedule_completions =
1490                 stdexec::__concat_completion_signatures<
1491                     _Completions,
1492                     stdexec::completion_signatures<stdexec::set_value_t()>>;
1493             using __schedule_receiver =
1494                 any_receiver_ref<__schedule_completions, _ReceiverQueries...>;
1495 
1496             template <typename _Tag, typename _Sig>
1497             static auto __ret_fn(_Tag (*const)(_Sig)) -> _Tag;
1498 
1499             template <class _Tag>
1500             struct __ret_equals_to
1501             {
1502                 template <class _Sig>
1503                 using __f = std::is_same<
1504                     _Tag, decltype(__ret_fn(static_cast<_Sig>(nullptr)))>;
1505             };
1506 
1507             using schedule_sender_queries = stdexec::__minvoke<
1508                 stdexec::__mremove_if<__ret_equals_to<
1509                     stdexec::get_completion_scheduler_t<stdexec::set_value_t>>>,
1510                 decltype(_SenderQueries)...>;
1511 
1512 #if STDEXEC_MSVC()
1513             // MSVCBUG
1514             // https://developercommunity.visualstudio.com/t/ICE-and-non-ICE-bug-in-NTTP-argument-w/10361081
1515 
1516             static constexpr auto __any_scheduler_noexcept_signature =
1517                 stdexec::get_completion_scheduler<stdexec::set_value_t>.signature<any_scheduler() noexcept>;
1518             template <class... _Queries>
1519             using __schedule_sender_fn =
1520                 typename __schedule_receiver::template any_sender<
1521                     __any_scheduler_noexcept_signature>;
1522 #else
1523             template <class... _Queries>
1524             using __schedule_sender_fn = typename __schedule_receiver::template any_sender<
1525                 stdexec::get_completion_scheduler<stdexec::set_value_t>.template signature<any_scheduler() noexcept>>;
1526 #endif
1527             using __schedule_sender =
1528                 stdexec::__mapply<stdexec::__q<__schedule_sender_fn>,
1529                                   schedule_sender_queries>;
1530 
1531             using __scheduler_base =
1532                 __any::__scheduler<__schedule_sender,
1533                                    queries<_SchedulerQueries...>>;
1534 
1535             __scheduler_base __scheduler_;
1536 
1537           public:
1538             using __t = any_scheduler;
1539             using __id = any_scheduler;
1540 
1541             template <stdexec::__none_of<any_scheduler> _Scheduler>
1542                 requires stdexec::scheduler<_Scheduler>
any_scheduler(_Scheduler __scheduler)1543             any_scheduler(_Scheduler __scheduler) :
1544                 __scheduler_{static_cast<_Scheduler&&>(__scheduler)}
1545             {}
1546 
schedule() const1547             auto schedule() const noexcept -> __schedule_sender
1548             {
1549                 return __scheduler_.schedule();
1550             }
1551 
1552             template <class _Tag, class... _As>
1553                 requires stdexec::tag_invocable<_Tag, const __scheduler_base&,
1554                                                 _As...>
query(_Tag,_As &&...__as) const1555             auto query(_Tag, _As&&... __as) const noexcept(
1556                 stdexec::nothrow_tag_invocable<_Tag, const __scheduler_base&,
1557                                                _As...>)
1558                 -> stdexec::tag_invoke_result_t<_Tag, const __scheduler_base&,
1559                                                 _As...>
1560             {
1561                 return stdexec::tag_invoke(_Tag(), __scheduler_,
1562                                            static_cast<_As&&>(__as)...);
1563             }
1564 
1565             auto operator==(const any_scheduler&) const noexcept
1566                 -> bool = default;
1567         };
1568     };
1569 };
1570 } // namespace exec
1571