xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/any_sender_of.hpp (revision 10d0b4b7d1498cfd5c3d37edea271a54d1984e41)
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/execution.hpp"
19 #include "../stdexec/__detail/__any_receiver_ref.hpp"
20 #include "../stdexec/__detail/__concepts.hpp"
21 #include "../stdexec/__detail/__env.hpp"
22 #include "../stdexec/__detail/__transform_completion_signatures.hpp"
23 
24 #include "sequence_senders.hpp"
25 
26 #include <cstddef>
27 #include <utility>
28 
29 namespace exec {
30   namespace __any {
31     using namespace stdexec;
32 
33     struct __create_vtable_t {
34       template <class _VTable, class _Tp>
35         requires __tag_invocable_r<const _VTable*, __create_vtable_t, __mtype<_VTable>, __mtype<_Tp>>
operator ()exec::__any::__create_vtable_t36       constexpr auto operator()(__mtype<_VTable>, __mtype<_Tp>) const noexcept -> const _VTable* {
37         return stdexec::tag_invoke(__create_vtable_t{}, __mtype<_VTable>{}, __mtype<_Tp>{});
38       }
39     };
40 
41     inline constexpr __create_vtable_t __create_vtable{};
42 
43     template <class _Sig>
44     struct __query_vfun;
45 
46     template <class _Tag, class _Ret, class... _As>
47     struct __query_vfun<_Tag (*const)(_Ret (*)(_As...))> {
48       _Ret (*__fn_)(void*, _As...);
49 
operator ()exec::__any::__query_vfun50       auto operator()(_Tag, void* __rcvr, _As&&... __as) const -> _Ret {
51         return __fn_(__rcvr, static_cast<_As&&>(__as)...);
52       }
53     };
54 
55     template <class _Tag, class _Ret, class... _As>
56     struct __query_vfun<_Tag (*)(_Ret (*)(_As...))> {
57       _Ret (*__fn_)(void*, _As...);
58 
operator ()exec::__any::__query_vfun59       auto operator()(_Tag, void* __rcvr, _As&&... __as) const -> _Ret {
60         return __fn_(__rcvr, static_cast<_As&&>(__as)...);
61       }
62     };
63 
64     template <class _Tag, class _Ret, class... _As>
65     struct __query_vfun<_Tag (*const)(_Ret (*)(_As...) noexcept)> {
66       _Ret (*__fn_)(void*, _As...) noexcept;
67 
operator ()exec::__any::__query_vfun68       auto operator()(_Tag, void* __rcvr, _As&&... __as) const noexcept -> _Ret {
69         return __fn_(__rcvr, static_cast<_As&&>(__as)...);
70       }
71     };
72 
73     template <class _Tag, class _Ret, class... _As>
74     struct __query_vfun<_Tag (*)(_Ret (*)(_As...) noexcept)> {
75       _Ret (*__fn_)(void*, _As...) noexcept;
76 
operator ()exec::__any::__query_vfun77       auto operator()(_Tag, void* __rcvr, _As&&... __as) const noexcept -> _Ret {
78         return __fn_(__rcvr, static_cast<_As&&>(__as)...);
79       }
80     };
81 
82     template <class _Queryable, bool _IsEnvProvider = true>
83     struct __query_vfun_fn;
84 
85     template <class _EnvProvider>
86     struct __query_vfun_fn<_EnvProvider, true> {
87       template <class _Tag, class _Ret, class... _As>
88         requires __callable<_Tag, env_of_t<const _EnvProvider&>, _As...>
89       constexpr auto
operator ()exec::__any::__query_vfun_fn90         operator()(_Tag (*)(_Ret (*)(_As...))) const noexcept -> _Ret (*)(void*, _As...) {
91         return +[](void* __env_provider, _As... __as) -> _Ret {
92           return _Tag{}(
93             stdexec::get_env(*static_cast<const _EnvProvider*>(__env_provider)),
94             static_cast<_As&&>(__as)...);
95         };
96       }
97 
98       template <class _Tag, class _Ret, class... _As>
99         requires __callable<_Tag, env_of_t<const _EnvProvider&>, _As...>
operator ()exec::__any::__query_vfun_fn100       constexpr auto operator()(_Tag (*)(_Ret (*)(_As...) noexcept)) const noexcept
101         -> _Ret (*)(void*, _As...) noexcept {
102         return +[](void* __env_provider, _As... __as) noexcept -> _Ret {
103           static_assert(__nothrow_callable<_Tag, const env_of_t<_EnvProvider>&, _As...>);
104           return _Tag{}(
105             stdexec::get_env(*static_cast<const _EnvProvider*>(__env_provider)),
106             static_cast<_As&&>(__as)...);
107         };
108       }
109     };
110 
111     template <class _Queryable>
112     struct __query_vfun_fn<_Queryable, false> {
113       template <class _Tag, class _Ret, class... _As>
114         requires __callable<_Tag, const _Queryable&, _As...>
115       constexpr auto
operator ()exec::__any::__query_vfun_fn116         operator()(_Tag (*)(_Ret (*)(_As...))) const noexcept -> _Ret (*)(void*, _As...) {
117         return +[](void* __queryable, _As... __as) -> _Ret {
118           return _Tag{}(*static_cast<const _Queryable*>(__queryable), static_cast<_As&&>(__as)...);
119         };
120       }
121 
122       template <class _Tag, class _Ret, class... _As>
123         requires __callable<_Tag, const _Queryable&, _As...>
operator ()exec::__any::__query_vfun_fn124       constexpr auto operator()(_Tag (*)(_Ret (*)(_As...) noexcept)) const noexcept
125         -> _Ret (*)(void*, _As...) noexcept {
126         return +[](void* __env_provider, _As... __as) noexcept -> _Ret {
127           static_assert(__nothrow_callable<_Tag, const _Queryable&, _As...>);
128           return _Tag{}(
129             *static_cast<const _Queryable*>(__env_provider), static_cast<_As&&>(__as)...);
130         };
131       }
132     };
133 
134     template <class _Sig>
135     struct __storage_vfun;
136 
137     template <class _Tag, class... _As>
138     struct __storage_vfun<_Tag(void (*)(_As...))> {
__anon1bf2f58b0502exec::__any::__storage_vfun139       void (*__fn_)(void*, _As...) = [](void*, _As...) {
140       };
141 
operator ()exec::__any::__storage_vfun142       void operator()(_Tag, void* __storage, _As&&... __as) const {
143         return __fn_(__storage, static_cast<_As&&>(__as)...);
144       }
145     };
146 
147     template <class _Tag, class... _As>
148     struct __storage_vfun<_Tag(void (*)(_As...) noexcept)> {
__anon1bf2f58b0602exec::__any::__storage_vfun149       void (*__fn_)(void*, _As...) noexcept = [](void*, _As...) noexcept {
150       };
151 
operator ()exec::__any::__storage_vfun152       void operator()(_Tag, void* __storage, _As&&... __as) const noexcept {
153         return __fn_(__storage, static_cast<_As&&>(__as)...);
154       }
155     };
156 
157     template <class _Storage, class _Tp>
158     struct __storage_vfun_fn {
159       template <class _Tag, class... _As>
160         requires __callable<_Tag, __mtype<_Tp>, _Storage&, _As...>
161       constexpr auto
operator ()exec::__any::__storage_vfun_fn162         operator()(_Tag (*)(void (*)(_As...))) const noexcept -> void (*)(void*, _As...) {
163         return +[](void* __storage, _As... __as) -> void {
164           return _Tag{}(
165             __mtype<_Tp>{}, *static_cast<_Storage*>(__storage), static_cast<_As&&>(__as)...);
166         };
167       }
168 
169       template <class _Tag, class... _As>
170         requires __callable<_Tag, __mtype<_Tp>, _Storage&, _As...>
operator ()exec::__any::__storage_vfun_fn171       constexpr auto operator()(_Tag (*)(void (*)(_As...) noexcept)) const noexcept
172         -> void (*)(void*, _As...) noexcept {
173         return +[](void* __storage, _As... __as) noexcept -> void {
174           static_assert(__nothrow_callable<_Tag, __mtype<_Tp>, _Storage&, _As...>);
175           return _Tag{}(
176             __mtype<_Tp>{}, *static_cast<_Storage*>(__storage), static_cast<_As&&>(__as)...);
177         };
178       }
179     };
180 
181     struct __delete_t {
182       template <class _Storage, class _Tp>
183         requires tag_invocable<__delete_t, __mtype<_Tp>, _Storage&>
operator ()exec::__any::__delete_t184       void operator()(__mtype<_Tp>, _Storage& __storage) noexcept {
185         static_assert(nothrow_tag_invocable<__delete_t, __mtype<_Tp>, _Storage&>);
186         stdexec::tag_invoke(__delete_t{}, __mtype<_Tp>{}, __storage);
187       }
188     };
189 
190     inline constexpr __delete_t __delete{};
191 
192     struct __copy_construct_t {
193       template <class _Storage, class _Tp>
194         requires tag_invocable<__copy_construct_t, __mtype<_Tp>, _Storage&, const _Storage&>
operator ()exec::__any::__copy_construct_t195       void operator()(__mtype<_Tp>, _Storage& __self, const _Storage& __from) noexcept(
196         nothrow_tag_invocable<__copy_construct_t, __mtype<_Tp>, _Storage&, const _Storage&>) {
197         stdexec::tag_invoke(__copy_construct_t{}, __mtype<_Tp>{}, __self, __from);
198       }
199     };
200 
201     inline constexpr __copy_construct_t __copy_construct{};
202 
203     struct __move_construct_t {
204       template <class _Storage, class _Tp>
205         requires tag_invocable<__move_construct_t, __mtype<_Tp>, _Storage&, _Storage&&>
operator ()exec::__any::__move_construct_t206       void operator()(__mtype<_Tp>, _Storage& __self, __midentity<_Storage&&> __from) noexcept {
207         static_assert(
208           nothrow_tag_invocable<__move_construct_t, __mtype<_Tp>, _Storage&, _Storage&&>);
209         stdexec::tag_invoke(
210           __move_construct_t{}, __mtype<_Tp>{}, __self, static_cast<_Storage&&>(__from));
211       }
212     };
213 
214     inline constexpr __move_construct_t __move_construct{};
215 
216     template <class _ParentVTable, class... _StorageCPOs>
217     struct __storage_vtable;
218 
219     template <class _ParentVTable, class... _StorageCPOs>
220       requires requires { _ParentVTable::operator(); }
221     struct __storage_vtable<_ParentVTable, _StorageCPOs...>
222       : _ParentVTable
223       , __storage_vfun<_StorageCPOs>... {
224       using _ParentVTable::operator();
225       using __storage_vfun<_StorageCPOs>::operator()...;
226     };
227 
228     template <class _ParentVTable, class... _StorageCPOs>
229       requires(!requires { _ParentVTable::operator(); })
230     struct __storage_vtable<_ParentVTable, _StorageCPOs...>
231       : _ParentVTable
232       , __storage_vfun<_StorageCPOs>... {
233       using __storage_vfun<_StorageCPOs>::operator()...;
234     };
235 
236     template <class _ParentVTable, class... _StorageCPOs>
237     inline constexpr __storage_vtable<_ParentVTable, _StorageCPOs...> __null_storage_vtbl{};
238 
239     template <class _ParentVTable, class... _StorageCPOs>
240     constexpr auto
__default_storage_vtable(__storage_vtable<_ParentVTable,_StorageCPOs...> *)241       __default_storage_vtable(__storage_vtable<_ParentVTable, _StorageCPOs...>*) noexcept
242       -> const __storage_vtable<_ParentVTable, _StorageCPOs...>* {
243       return &__null_storage_vtbl<_ParentVTable, _StorageCPOs...>;
244     }
245 
246     template <class _Storage, class _Tp, class _ParentVTable, class... _StorageCPOs>
247     static const __storage_vtable<_ParentVTable, _StorageCPOs...> __storage_vtbl{
248       {*__create_vtable(__mtype<_ParentVTable>{}, __mtype<_Tp>{})},
249       {__storage_vfun_fn<_Storage, _Tp>{}(static_cast<_StorageCPOs*>(nullptr))}...};
250 
251     template <
252       class _Vtable,
253       class _Allocator,
254       bool _Copyable = false,
255       std::size_t _InlineSize = 3 * sizeof(void*),
256       std::size_t _Alignment = alignof(std::max_align_t)
257     >
258     struct __storage {
259       class __t;
260     };
261 
262     template <
263       class _Vtable,
264       class _Allocator,
265       std::size_t _InlineSize = 3 * sizeof(void*),
266       std::size_t _Alignment = alignof(std::max_align_t)
267     >
268     struct __immovable_storage {
269       class __t : __immovable {
270         static constexpr std::size_t __buffer_size = std::max(_InlineSize, sizeof(void*));
271         static constexpr std::size_t __alignment = std::max(_Alignment, alignof(void*));
272         using __with_delete = __delete_t(void() noexcept);
273         using __vtable_t = __storage_vtable<_Vtable, __with_delete>;
274 
275         template <class _Tp>
276         static constexpr bool __is_small = sizeof(_Tp) <= __buffer_size
277                                         && alignof(_Tp) <= __alignment;
278 
279         template <class _Tp>
__get_vtable_of_type()280         static constexpr auto __get_vtable_of_type() noexcept -> const __vtable_t* {
281           return &__storage_vtbl<__t, __decay_t<_Tp>, _Vtable, __with_delete>;
282         }
283        public:
284         using __id = __immovable_storage;
285 
286         __t() = default;
287 
288         template <__not_decays_to<__t> _Tp>
289           requires __callable<__create_vtable_t, __mtype<_Vtable>, __mtype<__decay_t<_Tp>>>
__t(_Tp && __object)290         __t(_Tp&& __object)
291           : __vtable_{__get_vtable_of_type<_Tp>()} {
292           using _Dp = __decay_t<_Tp>;
293           if constexpr (__is_small<_Dp>) {
294             __construct_small<_Dp>(static_cast<_Tp&&>(__object));
295           } else {
296             __construct_large<_Dp>(static_cast<_Tp&&>(__object));
297           }
298         }
299 
300         template <class _Tp, class... _Args>
301           requires __callable<__create_vtable_t, __mtype<_Vtable>, __mtype<_Tp>>
__t(std::in_place_type_t<_Tp>,_Args &&...__args)302         __t(std::in_place_type_t<_Tp>, _Args&&... __args)
303           : __vtable_{__get_vtable_of_type<_Tp>()} {
304           if constexpr (__is_small<_Tp>) {
305             __construct_small<_Tp>(static_cast<_Args&&>(__args)...);
306           } else {
307             __construct_large<_Tp>(static_cast<_Args&&>(__args)...);
308           }
309         }
310 
~__t()311         ~__t() {
312           __reset();
313         }
314 
__reset()315         void __reset() noexcept {
316           (*__vtable_)(__delete, this);
317           __object_pointer_ = nullptr;
318           __vtable_ = __default_storage_vtable(static_cast<__vtable_t*>(nullptr));
319         }
320 
321         [[nodiscard]]
__get_vtable() const322         auto __get_vtable() const noexcept -> const _Vtable* {
323           return __vtable_;
324         }
325 
326         [[nodiscard]]
__get_object_pointer() const327         auto __get_object_pointer() const noexcept -> void* {
328           return __object_pointer_;
329         }
330 
331        private:
332         template <class _Tp, class... _As>
__construct_small(_As &&...__args)333         void __construct_small(_As&&... __args) {
334           static_assert(sizeof(_Tp) <= __buffer_size && alignof(_Tp) <= __alignment);
335           _Tp* __pointer = reinterpret_cast<_Tp*>(&__buffer_[0]);
336           using _Alloc = std::allocator_traits<_Allocator>::template rebind_alloc<_Tp>;
337           _Alloc __alloc{__allocator_};
338           std::allocator_traits<_Alloc>::construct(
339             __alloc, __pointer, static_cast<_As&&>(__args)...);
340           __object_pointer_ = __pointer;
341         }
342 
343         template <class _Tp, class... _As>
__construct_large(_As &&...__args)344         void __construct_large(_As&&... __args) {
345           using _Alloc = std::allocator_traits<_Allocator>::template rebind_alloc<_Tp>;
346           _Alloc __alloc{__allocator_};
347           _Tp* __pointer = std::allocator_traits<_Alloc>::allocate(__alloc, 1);
348           STDEXEC_TRY {
349             std::allocator_traits<_Alloc>::construct(
350               __alloc, __pointer, static_cast<_As&&>(__args)...);
351           }
352           STDEXEC_CATCH_ALL {
353             std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
354             STDEXEC_THROW();
355           }
356           __object_pointer_ = __pointer;
357         }
358 
359         template <class _Tp>
STDEXEC_MEMFN_DECL(void __delete)360         STDEXEC_MEMFN_DECL(void __delete)(this __mtype<_Tp>, __t& __self) noexcept {
361           if (!__self.__object_pointer_) {
362             return;
363           }
364           using _Alloc = std::allocator_traits<_Allocator>::template rebind_alloc<_Tp>;
365           _Alloc __alloc{__self.__allocator_};
366           _Tp* __pointer = static_cast<_Tp*>(std::exchange(__self.__object_pointer_, nullptr));
367           std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
368           if constexpr (!__is_small<_Tp>) {
369             std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
370           }
371         }
372        private:
373         const __vtable_t* __vtable_{__default_storage_vtable(static_cast<__vtable_t*>(nullptr))};
374         void* __object_pointer_{nullptr};
375         alignas(__alignment) std::byte __buffer_[__buffer_size]{};
STDEXEC_ATTRIBUTE(no_unique_address)376         STDEXEC_ATTRIBUTE(no_unique_address) _Allocator __allocator_ { };
377       };
378     };
379 
380     template <
381       class _Vtable,
382       class _Allocator,
383       bool _Copyable,
384       std::size_t _InlineSize,
385       std::size_t _Alignment
386     >
387     class __storage<_Vtable, _Allocator, _Copyable, _InlineSize, _Alignment>::__t
388       : __if_c<_Copyable, __, __move_only> {
389       static_assert(
390         STDEXEC_IS_CONVERTIBLE_TO(typename std::allocator_traits<_Allocator>::void_pointer, void*));
391 
392       static constexpr std::size_t __buffer_size = std::max(_InlineSize, sizeof(void*));
393       static constexpr std::size_t __alignment = std::max(_Alignment, alignof(void*));
394       using __with_copy = __copy_construct_t(void(const __t&));
395       using __with_move = __move_construct_t(void(__t&&) noexcept);
396       using __with_delete = __delete_t(void() noexcept);
397 
398       template <class _Tp>
399       static constexpr bool __is_small = sizeof(_Tp) <= __buffer_size && alignof(_Tp) <= __alignment
400                                       && std::is_nothrow_move_constructible_v<_Tp>;
401 
402       using __vtable_t = __if_c<
403         _Copyable,
404         __storage_vtable<_Vtable, __with_delete, __with_move, __with_copy>,
405         __storage_vtable<_Vtable, __with_delete, __with_move>
406       >;
407 
408       template <class _Tp>
__get_vtable_of_type()409       static constexpr auto __get_vtable_of_type() noexcept -> const __vtable_t* {
410         if constexpr (_Copyable) {
411           return &__storage_vtbl<
412             __t,
413             __decay_t<_Tp>,
414             _Vtable,
415             __with_delete,
416             __with_move,
417             __with_copy
418           >;
419         } else {
420           return &__storage_vtbl<__t, __decay_t<_Tp>, _Vtable, __with_delete, __with_move>;
421         }
422       }
423 
424      public:
425       using __id = __storage;
426 
427       __t() = default;
428 
429       template <__not_decays_to<__t> _Tp>
430         requires __callable<__create_vtable_t, __mtype<_Vtable>, __mtype<__decay_t<_Tp>>>
__t(_Tp && __object)431       __t(_Tp&& __object)
432         : __vtable_{__get_vtable_of_type<_Tp>()} {
433         using _Dp = __decay_t<_Tp>;
434         if constexpr (__is_small<_Dp>) {
435           __construct_small<_Dp>(static_cast<_Tp&&>(__object));
436         } else {
437           __construct_large<_Dp>(static_cast<_Tp&&>(__object));
438         }
439       }
440 
441       template <class _Tp, class... _Args>
442         requires __callable<__create_vtable_t, __mtype<_Vtable>, __mtype<_Tp>>
__t(std::in_place_type_t<_Tp>,_Args &&...__args)443       __t(std::in_place_type_t<_Tp>, _Args&&... __args)
444         : __vtable_{__get_vtable_of_type<_Tp>()} {
445         if constexpr (__is_small<_Tp>) {
446           __construct_small<_Tp>(static_cast<_Args&&>(__args)...);
447         } else {
448           __construct_large<_Tp>(static_cast<_Args&&>(__args)...);
449         }
450       }
451 
__t(const __t & __other)452       __t(const __t& __other)
453         requires(_Copyable)
454         : __vtable_(__other.__vtable_) {
455         (*__other.__vtable_)(__copy_construct, this, __other);
456       }
457 
operator =(const __t & __other)458       auto operator=(const __t& __other) -> __t&
459         requires(_Copyable)
460       {
461         if (&__other != this) {
462           __t tmp(__other);
463           *this = std::move(tmp);
464         }
465         return *this;
466       }
467 
__t(__t && __other)468       __t(__t&& __other) noexcept
469         : __vtable_(__other.__vtable_) {
470         (*__other.__vtable_)(__move_construct, this, static_cast<__t&&>(__other));
471       }
472 
operator =(__t && __other)473       auto operator=(__t&& __other) noexcept -> __t& {
474         __reset();
475         (*__other.__vtable_)(__move_construct, this, static_cast<__t&&>(__other));
476         return *this;
477       }
478 
~__t()479       ~__t() {
480         __reset();
481       }
482 
__reset()483       void __reset() noexcept {
484         (*__vtable_)(__delete, this);
485         __object_pointer_ = nullptr;
486         __vtable_ = __default_storage_vtable(static_cast<__vtable_t*>(nullptr));
487       }
488 
__get_vtable() const489       auto __get_vtable() const noexcept -> const _Vtable* {
490         return __vtable_;
491       }
492 
493       [[nodiscard]]
__get_object_pointer() const494       auto __get_object_pointer() const noexcept -> void* {
495         return __object_pointer_;
496       }
497 
498      private:
499       template <class _Tp, class... _As>
__construct_small(_As &&...__args)500       void __construct_small(_As&&... __args) {
501         static_assert(sizeof(_Tp) <= __buffer_size && alignof(_Tp) <= __alignment);
502         _Tp* __pointer = reinterpret_cast<_Tp*>(&__buffer_[0]);
503         using _Alloc = std::allocator_traits<_Allocator>::template rebind_alloc<_Tp>;
504         _Alloc __alloc{__allocator_};
505         std::allocator_traits<_Alloc>::construct(__alloc, __pointer, static_cast<_As&&>(__args)...);
506         __object_pointer_ = __pointer;
507       }
508 
509       template <class _Tp, class... _As>
__construct_large(_As &&...__args)510       void __construct_large(_As&&... __args) {
511         using _Alloc = std::allocator_traits<_Allocator>::template rebind_alloc<_Tp>;
512         _Alloc __alloc{__allocator_};
513         _Tp* __pointer = std::allocator_traits<_Alloc>::allocate(__alloc, 1);
514         STDEXEC_TRY {
515           std::allocator_traits<_Alloc>::construct(
516             __alloc, __pointer, static_cast<_As&&>(__args)...);
517         }
518         STDEXEC_CATCH_ALL {
519           std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
520           STDEXEC_THROW();
521         }
522         __object_pointer_ = __pointer;
523       }
524 
525       template <class _Tp>
STDEXEC_MEMFN_DECL(void __delete)526       STDEXEC_MEMFN_DECL(void __delete)(this __mtype<_Tp>, __t& __self) noexcept {
527         if (!__self.__object_pointer_) {
528           return;
529         }
530         using _Alloc = std::allocator_traits<_Allocator>::template rebind_alloc<_Tp>;
531         _Alloc __alloc{__self.__allocator_};
532         _Tp* __pointer = static_cast<_Tp*>(std::exchange(__self.__object_pointer_, nullptr));
533         std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
534         if constexpr (!__is_small<_Tp>) {
535           std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
536         }
537       }
538 
539       template <class _Tp>
STDEXEC_MEMFN_DECL(void __move_construct)540       STDEXEC_MEMFN_DECL(
541         void __move_construct)(this __mtype<_Tp>, __t& __self, __t&& __other) noexcept {
542         if (!__other.__object_pointer_) {
543           return;
544         }
545         _Tp* __pointer = static_cast<_Tp*>(std::exchange(__other.__object_pointer_, nullptr));
546         if constexpr (__is_small<_Tp>) {
547           _Tp& __other_object = *__pointer;
548           __self.template __construct_small<_Tp>(static_cast<_Tp&&>(__other_object));
549           using _Alloc = std::allocator_traits<_Allocator>::template rebind_alloc<_Tp>;
550           _Alloc __alloc{__self.__allocator_};
551           std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
552         } else {
553           __self.__object_pointer_ = __pointer;
554         }
555         __self.__vtable_ = std::exchange(
556           __other.__vtable_, __default_storage_vtable(static_cast<__vtable_t*>(nullptr)));
557       }
558 
559       template <class _Tp>
560         requires _Copyable
STDEXEC_MEMFN_DECL(void __copy_construct)561       STDEXEC_MEMFN_DECL(
562         void __copy_construct)(this __mtype<_Tp>, __t& __self, const __t& __other) {
563         if (!__other.__object_pointer_) {
564           return;
565         }
566         const _Tp& __other_object = *static_cast<const _Tp*>(__other.__object_pointer_);
567         if constexpr (__is_small<_Tp>) {
568           __self.template __construct_small<_Tp>(__other_object);
569         } else {
570           __self.template __construct_large<_Tp>(__other_object);
571         }
572         __self.__vtable_ = __other.__vtable_;
573       }
574 
575       const __vtable_t* __vtable_{__default_storage_vtable(static_cast<__vtable_t*>(nullptr))};
576       void* __object_pointer_{nullptr};
577       alignas(__alignment) std::byte __buffer_[__buffer_size]{};
STDEXEC_ATTRIBUTE(no_unique_address)578       STDEXEC_ATTRIBUTE(no_unique_address) _Allocator __allocator_ { };
579     };
580 
581     struct __empty_vtable {
582       template <class _Sender>
STDEXEC_MEMFN_DECLexec::__any::__empty_vtable583       STDEXEC_MEMFN_DECL(
584         auto __create_vtable)(this __mtype<__empty_vtable>, __mtype<_Sender>) noexcept
585         -> const __empty_vtable* {
586         static const __empty_vtable __vtable_{};
587         return &__vtable_;
588       }
589     };
590 
591     template <
592       class _VTable = __empty_vtable,
593       class _Allocator = std::allocator<std::byte>,
594       std::size_t _InlineSize = 3 * sizeof(void*),
595       std::size_t _Alignment = alignof(std::max_align_t)
596     >
597     using __immovable_storage_t =
598       __t<__immovable_storage<_VTable, _Allocator, _InlineSize, _Alignment>>;
599 
600     template <class _VTable, class _Allocator = std::allocator<std::byte>>
601     using __unique_storage_t = __t<__storage<_VTable, _Allocator>>;
602 
603     template <
604       class _VTable,
605       std::size_t _InlineSize = 3 * sizeof(void*),
606       class _Allocator = std::allocator<std::byte>
607     >
608     using __copyable_storage_t = __t<__storage<_VTable, _Allocator, true, _InlineSize>>;
609 
610     template <class _Tag, class... _As>
611     auto __tag_type(_Tag (*)(_As...)) -> _Tag;
612 
613     template <class _Tag, class... _As>
614     auto __tag_type(_Tag (*)(_As...) noexcept) -> _Tag;
615 
616     template <class _Query>
617     using __tag_type_t = decltype(__tag_type(static_cast<_Query>(nullptr)));
618 
619     template <class _Query>
620     concept __is_stop_token_query = __same_as<__tag_type_t<_Query>, get_stop_token_t>;
621 
622     template <class _Query>
623     concept __is_not_stop_token_query = !__is_stop_token_query<_Query>;
624 
625     template <class _Query>
626     using __is_not_stop_token_query_t = __mbool<__is_not_stop_token_query<_Query>>;
627 
628     auto __test_never_stop_token(get_stop_token_t (*)(never_stop_token (*)() noexcept))
629       -> __mbool<true>;
630 
631     template <class _Tag, class _Ret, class... _As>
632     auto __test_never_stop_token(_Tag (*)(_Ret (*)(_As...) noexcept)) -> __mbool<false>;
633 
634     template <class _Tag, class _Ret, class... _As>
635     auto __test_never_stop_token(_Tag (*)(_Ret (*)(_As...))) -> __mbool<false>;
636 
637     template <class _Query>
638     using __is_never_stop_token_query_t = decltype(__test_never_stop_token(
639       static_cast<_Query>(nullptr)));
640 
641     template <class _Query>
642     concept __is_never_stop_token_query = __is_never_stop_token_query_t<_Query>::value;
643 
644     template <class _Query, class _Env>
645     concept __satisfies_receiver_stop_token_query =
646       __same_as<__decay_t<__query_result_t<_Env, __tag_type_t<_Query>>>, stop_token_of_t<_Env>>;
647 
648     template <class _Query, class... _Env>
649     concept __satisfies_receiver_query = !__is_stop_token_query<_Query>
650                                       || __is_never_stop_token_query<_Query>
651                                       || (__satisfies_receiver_stop_token_query<_Query, _Env> || ...);
652 
653     namespace __rec {
654       template <class _Sigs, class... _Queries>
655       struct __vtable {
656         class __t;
657       };
658 
659       template <class _Sigs, class... _Queries>
660       struct __ref;
661 
662       template <class... _Sigs, class... _Queries>
663       struct __vtable<completion_signatures<_Sigs...>, _Queries...> {
664         struct __t
665           : __overload<__any_::__rcvr_vfun<_Sigs>...>
666           , __query_vfun<_Queries>... {
667           using __query_vfun<_Queries>::operator()...;
668 
669           template <class _Tag, class... _As>
670             requires __one_of<_Tag(_As...), _Sigs...>
671                   || __callable<__overload<__any_::__rcvr_vfun<_Sigs>...>, void*, _Tag, _As...>
672           void operator()(void* __rcvr, _Tag, _As&&... __as) const noexcept {
673             if constexpr (__one_of<_Tag(_As...), _Sigs...>) {
674               const __any_::__rcvr_vfun<_Tag(_As...)>& __vfun = *this;
675               __vfun(__rcvr, _Tag(), static_cast<_As&&>(__as)...);
676             } else {
677               const __overload<__any_::__rcvr_vfun<_Sigs>...>& __vfun = *this;
678               __vfun(__rcvr, _Tag(), static_cast<_As&&>(__as)...);
679             }
680           }
681 
682          private:
683           template <class _Rcvr>
684             requires receiver_of<_Rcvr, completion_signatures<_Sigs...>>
685                   && (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
STDEXEC_MEMFN_DECLexec::__any::__rec::__vtable::__t686           STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__t>, __mtype<_Rcvr>) noexcept
687             -> const __t* {
688             static const __t __vtable_{
689               {{__any_::__rcvr_vfun_fn(
690                 static_cast<_Rcvr*>(nullptr), static_cast<_Sigs*>(nullptr))}...},
691               {__query_vfun_fn<_Rcvr>{}(static_cast<_Queries>(nullptr))}...};
692             return &__vtable_;
693           }
694         };
695       };
696 
697       template <class... _Sigs, class... _Queries>
698         requires(__is_not_stop_token_query<_Queries> && ...)
699       struct __ref<completion_signatures<_Sigs...>, _Queries...> {
700 #if !STDEXEC_MSVC()
701         // MSVCBUG https://developercommunity.visualstudio.com/t/Private-member-inaccessible-when-used-in/10448363
702        private:
703 #endif
704         using __vtable_t = stdexec::__t<__vtable<completion_signatures<_Sigs...>, _Queries...>>;
705 
706         struct __env_t {
707           const __vtable_t* __vtable_;
708           void* __rcvr_;
709           inplace_stop_token __token_;
710 
711           template <class _Tag, class... _As>
712             requires __callable<const __vtable_t&, _Tag, void*, _As...>
queryexec::__any::__rec::__ref::__env_t713           auto query(_Tag, _As&&... __as) const
714             noexcept(__nothrow_callable<const __vtable_t&, _Tag, void*, _As...>)
715               -> __call_result_t<const __vtable_t&, _Tag, void*, _As...> {
716             return (*__vtable_)(_Tag{}, __rcvr_, static_cast<_As&&>(__as)...);
717           }
718 
719           [[nodiscard]]
queryexec::__any::__rec::__ref::__env_t720           auto query(get_stop_token_t) const noexcept -> inplace_stop_token {
721             return __token_;
722           }
723         } __env_;
724        public:
725         using receiver_concept = stdexec::receiver_t;
726         using __id = __ref;
727         using __t = __ref;
728 
729         template <__none_of<__ref, const __ref, __env_t, const __env_t> _Rcvr>
730           requires receiver_of<_Rcvr, completion_signatures<_Sigs...>>
731                 && (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
__refexec::__any::__rec::__ref732         __ref(_Rcvr& __rcvr) noexcept
733           : __env_{
734               __create_vtable(__mtype<__vtable_t>{}, __mtype<_Rcvr>{}),
735               &__rcvr,
736               stdexec::get_stop_token(stdexec::get_env(__rcvr))} {
737         }
738 
739         template <class... _As>
740           requires __callable<__vtable_t, void*, set_value_t, _As...>
set_valueexec::__any::__rec::__ref741         void set_value(_As&&... __as) noexcept {
742           (*__env_.__vtable_)(__env_.__rcvr_, set_value_t(), static_cast<_As&&>(__as)...);
743         }
744 
745         template <class _Error>
746           requires __callable<__vtable_t, void*, set_error_t, _Error>
set_errorexec::__any::__rec::__ref747         void set_error(_Error&& __err) noexcept {
748           (*__env_.__vtable_)(__env_.__rcvr_, set_error_t(), static_cast<_Error&&>(__err));
749         }
750 
set_stoppedexec::__any::__rec::__ref751         void set_stopped() noexcept
752           requires __callable<__vtable_t, void*, set_stopped_t>
753         {
754           (*__env_.__vtable_)(__env_.__rcvr_, set_stopped_t());
755         }
756 
get_envexec::__any::__rec::__ref757         auto get_env() const noexcept -> const __env_t& {
758           return __env_;
759         }
760       };
761 
762       template <class... _Sigs, class... _Queries>
763         requires(__is_stop_token_query<_Queries> || ...)
764       struct __ref<completion_signatures<_Sigs...>, _Queries...> {
765 #if !STDEXEC_MSVC()
766         // MSVCBUG https://developercommunity.visualstudio.com/t/Private-member-inaccessible-when-used-in/10448363
767 
768        private:
769 #endif
770         using _FilteredQueries =
771           __minvoke<__mremove_if<__q<__is_never_stop_token_query_t>>, _Queries...>;
772         using __vtable_t = stdexec::__t<
773           __mapply<__mbind_front_q<__vtable, completion_signatures<_Sigs...>>, _FilteredQueries>
774         >;
775 
776         struct __env_t {
777           const __vtable_t* __vtable_;
778           void* __rcvr_;
779 
780           template <class _Tag, class... _As>
781             requires __callable<const __vtable_t&, _Tag, void*, _As...>
queryexec::__any::__rec::__ref::__env_t782           auto query(_Tag, _As&&... __as) const
783             noexcept(__nothrow_callable<const __vtable_t&, _Tag, void*, _As...>)
784               -> __call_result_t<const __vtable_t&, _Tag, void*, _As...> {
785             return (*__vtable_)(_Tag{}, __rcvr_, static_cast<_As&&>(__as)...);
786           }
787         } __env_;
788        public:
789         using receiver_concept = stdexec::receiver_t;
790         using __id = __ref;
791         using __t = __ref;
792 
793         template <__none_of<__ref, const __ref, __env_t, const __env_t> _Rcvr>
794           requires receiver_of<_Rcvr, completion_signatures<_Sigs...>>
795                 && (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
__refexec::__any::__rec::__ref796         __ref(_Rcvr& __rcvr) noexcept
797           : __env_{__create_vtable(__mtype<__vtable_t>{}, __mtype<_Rcvr>{}), &__rcvr} {
798         }
799 
800         template <class... _As>
801           requires __one_of<set_value_t(_As...), _Sigs...>
802                 || __callable<__overload<__any_::__rcvr_vfun<_Sigs>...>, void*, set_value_t, _As...>
803         void set_value(_As&&... __as) noexcept {
804           if constexpr (__one_of<set_value_t(_As...), _Sigs...>) {
805             const __any_::__rcvr_vfun<set_value_t(_As...)>& __vfun = *__env_.__vtable_;
806             __vfun(__env_.__rcvr_, set_value_t(), static_cast<_As&&>(__as)...);
807           } else {
808             const __overload<__any_::__rcvr_vfun<_Sigs>...>& __vfun = *__env_.__vtable_;
809             __vfun(__env_.__rcvr_, set_value_t(), static_cast<_As&&>(__as)...);
810           }
811         }
812 
813         template <class _Error>
814           requires __one_of<set_error_t(_Error), _Sigs...>
815                 || __callable<__overload<__any_::__rcvr_vfun<_Sigs>...>, void*, set_error_t, _Error>
816         void set_error(_Error&& __err) noexcept {
817           if constexpr (__one_of<set_error_t(_Error), _Sigs...>) {
818             const __any_::__rcvr_vfun<set_error_t(_Error)>& __vfun = *__env_.__vtable_;
819             __vfun(__env_.__rcvr_, set_error_t(), static_cast<_Error&&>(__err));
820           } else {
821             const __overload<__any_::__rcvr_vfun<_Sigs>...>& __vfun = *__env_.__vtable_;
822             __vfun(__env_.__rcvr_, set_error_t(), static_cast<_Error&&>(__err));
823           }
824         }
825 
set_stoppedexec::__any::__rec::__ref826         void set_stopped() noexcept
827           requires __one_of<set_stopped_t(), _Sigs...>
828         {
829           const __any_::__rcvr_vfun<set_stopped_t()>& __vfun = *__env_.__vtable_;
830           __vfun(__env_.__rcvr_, set_stopped_t());
831         }
832 
get_envexec::__any::__rec::__ref833         auto get_env() const noexcept -> const __env_t& {
834           return __env_;
835         }
836       };
837     } // namespace __rec
838 
839     class __operation_vtable {
840      public:
841       void (*__start_)(void*) noexcept;
842 
843      private:
844       template <class _Op>
STDEXEC_MEMFN_DECL(auto __create_vtable)845       STDEXEC_MEMFN_DECL(
846         auto __create_vtable)(this __mtype<__operation_vtable>, __mtype<_Op>) noexcept
847         -> const __operation_vtable* {
848         static __operation_vtable __vtable{[](void* __object_pointer) noexcept -> void {
849           STDEXEC_ASSERT(__object_pointer);
850           _Op& __op = *static_cast<_Op*>(__object_pointer);
851           static_assert(operation_state<_Op>);
852           stdexec::start(__op);
853         }};
854         return &__vtable;
855       }
856     };
857 
858     using __immovable_operation_storage =
859       __immovable_storage_t<__operation_vtable, std::allocator<std::byte>, 6 * sizeof(void*)>;
860 
861     template <class _Sigs, class _Queries>
862     using __receiver_ref = __mapply<__mbind_front_q<__rec::__ref, _Sigs>, _Queries>;
863 
864     struct __on_stop_t {
865       stdexec::inplace_stop_source& __source_;
866 
operator ()exec::__any::__on_stop_t867       void operator()() const noexcept {
868         __source_.request_stop();
869       }
870     };
871 
872     template <class _Receiver>
873     struct __operation_base {
874       STDEXEC_ATTRIBUTE(no_unique_address) _Receiver __rcvr_;
875       stdexec::inplace_stop_source __stop_source_{};
876       using __stop_callback =
877         stdexec::stop_token_of_t<stdexec::env_of_t<_Receiver>>::template callback_type<__on_stop_t>;
878       std::optional<__stop_callback> __on_stop_{};
879     };
880 
881     template <class _Env>
882     using __env_t = __join_env_t<prop<get_stop_token_t, inplace_stop_token>, _Env>;
883 
884     template <class _ReceiverId>
885     struct __stoppable_receiver {
886       using _Receiver = stdexec::__t<_ReceiverId>;
887 
888       struct __t {
889         using receiver_concept = stdexec::receiver_t;
890         __operation_base<_Receiver>* __op_;
891 
892         template <class _Item>
893           requires __callable<set_next_t, _Receiver&, _Item>
894         [[nodiscard]]
set_nextexec::__any::__stoppable_receiver::__t895         auto set_next(_Item&& __item) & noexcept(__nothrow_callable<set_next_t, _Receiver&, _Item>)
896           -> __call_result_t<set_next_t, _Receiver&, _Item> {
897           return exec::set_next(__op_->__rcvr_, static_cast<_Item&&>(__item));
898         }
899 
900         template <class... _Args>
901           requires __callable<set_value_t, _Receiver, _Args...>
set_valueexec::__any::__stoppable_receiver::__t902         void set_value(_Args&&... __args) noexcept {
903           __op_->__on_stop_.reset();
904           stdexec::set_value(
905             static_cast<_Receiver&&>(__op_->__rcvr_), static_cast<_Args&&>(__args)...);
906         }
907 
908         template <class _Error>
909           requires __callable<set_error_t, _Receiver, _Error>
set_errorexec::__any::__stoppable_receiver::__t910         void set_error(_Error&& __err) noexcept {
911           __op_->__on_stop_.reset();
912           stdexec::set_error(
913             static_cast<_Receiver&&>(__op_->__rcvr_), static_cast<_Error&&>(__err));
914         }
915 
set_stoppedexec::__any::__stoppable_receiver::__t916         void set_stopped() noexcept
917           requires __callable<set_stopped_t, _Receiver>
918         {
919           __op_->__on_stop_.reset();
920           stdexec::set_stopped(static_cast<_Receiver&&>(__op_->__rcvr_));
921         }
922 
get_envexec::__any::__stoppable_receiver::__t923         auto get_env() const noexcept -> __env_t<env_of_t<_Receiver>> {
924           return __env::__join(
925             prop{get_stop_token, __op_->__stop_source_.get_token()},
926             stdexec::get_env(__op_->__rcvr_));
927         }
928       };
929     };
930 
931     template <class _ReceiverId>
932     using __stoppable_receiver_t = stdexec::__t<__stoppable_receiver<_ReceiverId>>;
933 
934     template <class _ReceiverId, bool>
935     struct __operation {
936       using _Receiver = stdexec::__t<_ReceiverId>;
937 
938       class __t : public __operation_base<_Receiver> {
939        public:
940         using __id = __operation;
941 
942         template <class _Sender>
__t(_Sender && __sender,_Receiver && __receiver)943         __t(_Sender&& __sender, _Receiver&& __receiver)
944           : __operation_base<_Receiver>{static_cast<_Receiver&&>(__receiver)}
945           , __rec_{this}
946           , __storage_{__sender.__connect(__rec_)} {
947         }
948 
start()949         void start() & noexcept {
950           this->__on_stop_.emplace(
951             stdexec::get_stop_token(stdexec::get_env(this->__rcvr_)),
952             __on_stop_t{this->__stop_source_});
953           STDEXEC_ASSERT(__storage_.__get_vtable()->__start_);
954           __storage_.__get_vtable()->__start_(__storage_.__get_object_pointer());
955         }
956 
957        private:
958         __stoppable_receiver_t<_ReceiverId> __rec_;
959         __immovable_operation_storage __storage_{};
960       };
961     };
962 
963     template <class _ReceiverId>
964     struct __operation<_ReceiverId, false> {
965       using _Receiver = stdexec::__t<_ReceiverId>;
966 
967       class __t {
968        public:
969         using __id = __operation;
970 
971         template <class _Sender>
__t(_Sender && __sender,_Receiver && __receiver)972         __t(_Sender&& __sender, _Receiver&& __receiver)
973           : __rec_{static_cast<_Receiver&&>(__receiver)}
974           , __storage_{__sender.__connect(__rec_)} {
975         }
976 
start()977         void start() & noexcept {
978           STDEXEC_ASSERT(__storage_.__get_vtable()->__start_);
979           __storage_.__get_vtable()->__start_(__storage_.__get_object_pointer());
980         }
981 
982        private:
983         STDEXEC_ATTRIBUTE(no_unique_address) _Receiver __rec_;
984         __immovable_operation_storage __storage_{};
985       };
986     };
987 
988     template <class _Queries, bool _IsEnvProvider = true>
989     class __query_vtable;
990 
991     template <template <class...> class _List, class... _Queries, bool _IsEnvProvider>
992     class __query_vtable<_List<_Queries...>, _IsEnvProvider> : public __query_vfun<_Queries>... {
993      public:
994       using __query_vfun<_Queries>::operator()...;
995      private:
996       template <class _Queryable>
997         requires(__callable<__query_vfun_fn<_Queryable, _IsEnvProvider>, _Queries> && ...)
STDEXEC_MEMFN_DECL(auto __create_vtable)998       STDEXEC_MEMFN_DECL(
999         auto __create_vtable)(this __mtype<__query_vtable>, __mtype<_Queryable>) noexcept
1000         -> const __query_vtable* {
1001         static const __query_vtable __vtable{
1002           {__query_vfun_fn<_Queryable, _IsEnvProvider>{}(static_cast<_Queries>(nullptr))}...};
1003         return &__vtable;
1004       }
1005     };
1006 
1007     template <class _Sigs, class _SenderQueries = __types<>, class _ReceiverQueries = __types<>>
1008     struct __sender {
1009       using __receiver_ref_t = __receiver_ref<_Sigs, _ReceiverQueries>;
1010       static constexpr bool __with_inplace_stop_token =
1011         __v<__mapply<__mall_of<__q<__is_not_stop_token_query_t>>, _ReceiverQueries>>;
1012 
1013       class __vtable : public __query_vtable<_SenderQueries> {
1014        public:
1015         using __id = __vtable;
1016 
__queries() const1017         auto __queries() const noexcept -> const __query_vtable<_SenderQueries>& {
1018           return *this;
1019         }
1020 
1021         __immovable_operation_storage (*__connect_)(void*, __receiver_ref_t);
1022        private:
1023         template <sender_to<__receiver_ref_t> _Sender>
STDEXEC_MEMFN_DECL(auto __create_vtable)1024         STDEXEC_MEMFN_DECL(auto __create_vtable)(this __mtype<__vtable>, __mtype<_Sender>) noexcept
1025           -> const __vtable* {
1026           static const __vtable __vtable_{
1027             {*__create_vtable(__mtype<__query_vtable<_SenderQueries>>{}, __mtype<_Sender>{})},
1028             [](void* __object_pointer, __receiver_ref_t __receiver)
1029               -> __immovable_operation_storage {
1030               _Sender& __sender = *static_cast<_Sender*>(__object_pointer);
1031               using __op_state_t = connect_result_t<_Sender, __receiver_ref_t>;
1032               return __immovable_operation_storage{
1033                 std::in_place_type<__op_state_t>, __emplace_from{[&] {
1034                   return stdexec::connect(
1035                     static_cast<_Sender&&>(__sender), static_cast<__receiver_ref_t&&>(__receiver));
1036                 }}};
1037             }};
1038           return &__vtable_;
1039         }
1040       };
1041 
1042       struct __env_t {
1043         const __vtable* __vtable_;
1044         void* __sender_;
1045 
1046         template <class _Tag, class... _As>
1047           requires __callable<const __query_vtable<_SenderQueries>&, _Tag, void*, _As...>
queryexec::__any::__sender::__env_t1048         auto query(_Tag, _As&&... __as) const
1049           noexcept(__nothrow_callable<const __query_vtable<_SenderQueries>&, _Tag, void*, _As...>)
1050             -> __call_result_t<const __query_vtable<_SenderQueries>&, _Tag, void*, _As...> {
1051           return __vtable_->__queries()(_Tag{}, __sender_, static_cast<_As&&>(__as)...);
1052         }
1053       };
1054 
1055       struct __t {
1056         using __id = __sender;
1057         using completion_signatures = _Sigs;
1058         using sender_concept = stdexec::sender_t;
1059 
1060         __t(const __t&) = delete;
1061         auto operator=(const __t&) -> __t& = delete;
1062 
1063         __t(__t&&) = default;
1064         auto operator=(__t&&) -> __t& = default;
1065 
1066         template <__not_decays_to<__t> _Sender>
1067           requires sender_to<_Sender, __receiver_ref<_Sigs, _ReceiverQueries>>
__texec::__any::__sender::__t1068         __t(_Sender&& __sndr)
1069           : __storage_{static_cast<_Sender&&>(__sndr)} {
1070         }
1071 
__connectexec::__any::__sender::__t1072         auto __connect(__receiver_ref_t __receiver) -> __immovable_operation_storage {
1073           return __storage_.__get_vtable()->__connect_(
1074             __storage_.__get_object_pointer(), static_cast<__receiver_ref_t&&>(__receiver));
1075         }
1076 
get_envexec::__any::__sender::__t1077         auto get_env() const noexcept -> __env_t {
1078           return {__storage_.__get_vtable(), __storage_.__get_object_pointer()};
1079         }
1080 
1081         template <receiver_of<_Sigs> _Rcvr>
connectexec::__any::__sender::__t1082         auto connect(_Rcvr __rcvr) && -> stdexec::__t<
1083           __operation<stdexec::__id<_Rcvr>, __with_inplace_stop_token>
1084         > {
1085           return {static_cast<__t&&>(*this), static_cast<_Rcvr&&>(__rcvr)};
1086         }
1087 
1088        private:
1089         __unique_storage_t<__vtable> __storage_;
1090       };
1091     };
1092 
1093     template <class _ScheduleSender, class _SchedulerQueries = __types<>>
1094     class __scheduler {
1095       static constexpr std::size_t __buffer_size = 4 * sizeof(void*);
1096       template <class _Ty>
1097       static constexpr bool __is_small = sizeof(_Ty) <= __buffer_size
1098                                       && alignof(_Ty) <= alignof(std::max_align_t);
1099 
1100      public:
1101       template <class _Scheduler>
1102         requires(!__decays_to<_Scheduler, __scheduler>) && scheduler<_Scheduler>
__scheduler(_Scheduler && __scheduler)1103       __scheduler(_Scheduler&& __scheduler)
1104         : __storage_{static_cast<_Scheduler&&>(__scheduler)} {
1105         static_assert(
1106           __is_small<_Scheduler>,
1107           "any_scheduler<> must have a nothrow copy constructor, so the scheduler object must be "
1108           "small enough to be stored in the internal buffer to avoid dynamic allocation.");
1109       }
1110 
1111       __scheduler(__scheduler&&) noexcept = default;
1112       __scheduler(const __scheduler&) noexcept = default;
1113       auto operator=(__scheduler&&) noexcept -> __scheduler& = default;
1114       auto operator=(const __scheduler&) noexcept -> __scheduler& = default;
1115 
1116       using __sender_t = _ScheduleSender;
1117 
schedule() const1118       auto schedule() const noexcept -> __sender_t {
1119         STDEXEC_ASSERT(__storage_.__get_vtable()->__schedule_);
1120         return __storage_.__get_vtable()->__schedule_(__storage_.__get_object_pointer());
1121       }
1122 
1123       template <class _Tag, class... _As>
1124         requires __callable<const __query_vtable<_SchedulerQueries, false>&, _Tag, void*, _As...>
query(_Tag,_As &&...__as) const1125       auto query(_Tag, _As&&... __as) const noexcept(
1126         __nothrow_callable<const __query_vtable<_SchedulerQueries, false>&, _Tag, void*, _As...>)
1127         -> __call_result_t<const __query_vtable<_SchedulerQueries, false>&, _Tag, void*, _As...> {
1128         return __storage_.__get_vtable()
1129           ->__queries()(_Tag{}, __storage_.__get_object_pointer(), static_cast<_As&&>(__as)...);
1130       }
1131 
1132      private:
1133       class __vtable : public __query_vtable<_SchedulerQueries, false> {
1134        public:
1135         __sender_t (*__schedule_)(void*) noexcept;
1136         bool (*__equal_to_)(const void*, const void* other) noexcept;
1137 
__queries() const1138         auto __queries() const noexcept -> const __query_vtable<_SchedulerQueries, false>& {
1139           return *this;
1140         }
1141        private:
1142         template <scheduler _Scheduler>
STDEXEC_MEMFN_DECL(auto __create_vtable)1143         STDEXEC_MEMFN_DECL(
1144           auto __create_vtable)(this __mtype<__vtable>, __mtype<_Scheduler>) noexcept
1145           -> const __vtable* {
1146           static const __vtable __vtable_{
1147             {*__create_vtable(
1148               __mtype<__query_vtable<_SchedulerQueries, false>>{}, __mtype<_Scheduler>{})},
1149             [](void* __object_pointer) noexcept -> __sender_t {
1150               const _Scheduler& __scheduler = *static_cast<const _Scheduler*>(__object_pointer);
1151               return __sender_t{stdexec::schedule(__scheduler)};
1152             },
1153             [](const void* __self, const void* __other) noexcept -> bool {
1154               static_assert(
1155                 noexcept(__declval<const _Scheduler&>() == __declval<const _Scheduler&>()));
1156               STDEXEC_ASSERT(__self && __other);
1157               const _Scheduler& __self_scheduler = *static_cast<const _Scheduler*>(__self);
1158               const _Scheduler& __other_scheduler = *static_cast<const _Scheduler*>(__other);
1159               return __self_scheduler == __other_scheduler;
1160             }};
1161           return &__vtable_;
1162         }
1163       };
1164 
1165       friend auto
operator ==(const __scheduler & __self,const __scheduler & __other)1166         operator==(const __scheduler& __self, const __scheduler& __other) noexcept -> bool {
1167         if (__self.__storage_.__get_vtable() != __other.__storage_.__get_vtable()) {
1168           return false;
1169         }
1170 
1171         void* __p = __self.__storage_.__get_object_pointer();
1172         void* __o = __other.__storage_.__get_object_pointer();
1173         // if both object pointers are not null, use the virtual equal_to function
1174         return (__p && __o && __self.__storage_.__get_vtable()->__equal_to_(__p, __o))
1175             // if both object pointers are nullptrs, they are equal
1176             || (!__p && !__o);
1177       }
1178 
1179       friend auto
operator !=(const __scheduler & __self,const __scheduler & __other)1180         operator!=(const __scheduler& __self, const __scheduler& __other) noexcept -> bool {
1181         return !(__self == __other);
1182       }
1183 
1184       __copyable_storage_t<__vtable, __buffer_size> __storage_{};
1185     };
1186   } // namespace __any
1187 
1188   template <auto... _Sigs>
1189   using queries = stdexec::__types<decltype(_Sigs)...>;
1190 
1191   template <class _Completions, auto... _ReceiverQueries>
1192   class any_receiver_ref {
1193     using __receiver_base = __any::__rec::__ref<_Completions, decltype(_ReceiverQueries)...>;
1194     using __env_t = stdexec::env_of_t<__receiver_base>;
1195     __receiver_base __receiver_;
1196 
1197    public:
1198     using receiver_concept = stdexec::receiver_t;
1199     using __t = any_receiver_ref;
1200     using __id = any_receiver_ref;
1201 
1202     template <stdexec::__none_of<any_receiver_ref, const any_receiver_ref, __env_t, const __env_t>
1203                 _Receiver>
1204       requires stdexec::receiver_of<_Receiver, _Completions>
any_receiver_ref(_Receiver & __receiver)1205     any_receiver_ref(_Receiver& __receiver)
1206       noexcept(stdexec::__nothrow_constructible_from<__receiver_base, _Receiver>)
1207       : __receiver_(__receiver) {
1208     }
1209 
1210     template <class... _As>
1211       requires stdexec::__callable<stdexec::set_value_t, __receiver_base, _As...>
set_value(_As &&...__as)1212     void set_value(_As&&... __as) noexcept {
1213       stdexec::set_value(static_cast<__receiver_base&&>(__receiver_), static_cast<_As&&>(__as)...);
1214     }
1215 
1216     template <class _Error>
1217       requires stdexec::__callable<stdexec::set_error_t, __receiver_base, _Error>
set_error(_Error && __err)1218     void set_error(_Error&& __err) noexcept {
1219       stdexec::set_error(static_cast<__receiver_base&&>(__receiver_), static_cast<_Error&&>(__err));
1220     }
1221 
set_stopped()1222     void set_stopped() noexcept
1223       requires stdexec::__callable<stdexec::set_stopped_t, __receiver_base>
1224     {
1225       stdexec::set_stopped(static_cast<__receiver_base&&>(__receiver_));
1226     }
1227 
get_env() const1228     auto get_env() const noexcept -> stdexec::env_of_t<__receiver_base> {
1229       return stdexec::get_env(__receiver_);
1230     }
1231 
1232     template <auto... _SenderQueries>
1233     class any_sender {
1234       using __sender_base = stdexec::__t<
1235         __any::__sender<_Completions, queries<_SenderQueries...>, queries<_ReceiverQueries...>>
1236       >;
1237       __sender_base __sender_;
1238 
1239      public:
1240       using sender_concept = stdexec::sender_t;
1241       using __t = any_sender;
1242       using __id = any_sender;
1243 
1244       template <stdexec::__not_decays_to<any_sender> _Sender>
1245         requires stdexec::sender_to<_Sender, __receiver_base>
any_sender(_Sender && __sender)1246       any_sender(_Sender&& __sender)
1247         noexcept(stdexec::__nothrow_constructible_from<__sender_base, _Sender>)
1248         : __sender_(static_cast<_Sender&&>(__sender)) {
1249       }
1250 
1251       template <stdexec::__decays_to<any_sender> _Self, class... _Env>
1252         requires(__any::__satisfies_receiver_query<decltype(_ReceiverQueries), _Env...> && ...)
get_completion_signatures(_Self &&,_Env &&...)1253       static auto get_completion_signatures(_Self&&, _Env&&...) noexcept
1254         -> __sender_base::completion_signatures {
1255         return {};
1256       }
1257 
1258       template <stdexec::receiver_of<_Completions> _Receiver>
connect(_Receiver __rcvr)1259       auto connect(_Receiver __rcvr) && -> stdexec::connect_result_t<__sender_base, _Receiver> {
1260         return static_cast<__sender_base&&>(__sender_).connect(static_cast<_Receiver&&>(__rcvr));
1261       }
1262 
get_env() const1263       auto get_env() const noexcept -> stdexec::env_of_t<__sender_base> {
1264         return static_cast<const __sender_base&>(__sender_).get_env();
1265       }
1266 
1267       template <auto... _SchedulerQueries>
1268       class any_scheduler {
1269         // Add the required set_value_t() completions to the schedule-sender.
1270         using __schedule_completions = stdexec::__concat_completion_signatures<
1271           _Completions,
1272           stdexec::completion_signatures<stdexec::set_value_t()>
1273         >;
1274         using __schedule_receiver = any_receiver_ref<__schedule_completions, _ReceiverQueries...>;
1275 
1276         template <typename _Tag, typename _Sig>
1277         static auto __ret_fn(_Tag (*const)(_Sig)) -> _Tag;
1278 
1279         template <class _Tag>
1280         struct __ret_equals_to {
1281           template <class _Sig>
1282           using __f =
1283             stdexec::__mbool<STDEXEC_IS_SAME(_Tag, decltype(__ret_fn(static_cast<_Sig>(nullptr))))>;
1284         };
1285 
1286         using __schedule_sender_queries = stdexec::__minvoke<
1287           stdexec::__mremove_if<
1288             __ret_equals_to<stdexec::get_completion_scheduler_t<stdexec::set_value_t>>
1289           >,
1290           decltype(_SenderQueries)...
1291         >;
1292 
1293 #if STDEXEC_MSVC()
1294         // MSVCBUG https://developercommunity.visualstudio.com/t/ICE-and-non-ICE-bug-in-NTTP-argument-w/10361081
1295 
1296         static constexpr auto __any_scheduler_noexcept_signature =
1297           stdexec::get_completion_scheduler<stdexec::set_value_t>.signature<any_scheduler() noexcept>;
1298         template <class... _Queries>
1299         using __schedule_sender_fn =
1300           __schedule_receiver::template any_sender<__any_scheduler_noexcept_signature>;
1301 #else
1302         template <class... _Queries>
1303         using __schedule_sender_fn = __schedule_receiver::template any_sender<
1304           stdexec::get_completion_scheduler<stdexec::set_value_t>.template signature<any_scheduler() noexcept>
1305         >;
1306 #endif
1307         using __schedule_sender =
1308           stdexec::__mapply<stdexec::__q<__schedule_sender_fn>, __schedule_sender_queries>;
1309 
1310         using __scheduler_base =
1311           __any::__scheduler<__schedule_sender, queries<_SchedulerQueries...>>;
1312 
1313         __scheduler_base __scheduler_;
1314 
1315        public:
1316         using scheduler_concept = stdexec::scheduler_t;
1317         using __t = any_scheduler;
1318         using __id = any_scheduler;
1319 
1320         template <stdexec::__none_of<any_scheduler> _Scheduler>
1321           requires stdexec::scheduler<_Scheduler>
any_scheduler(_Scheduler __scheduler)1322         any_scheduler(_Scheduler __scheduler)
1323           : __scheduler_{static_cast<_Scheduler&&>(__scheduler)} {
1324         }
1325 
schedule() const1326         auto schedule() const noexcept -> __schedule_sender {
1327           return __scheduler_.schedule();
1328         }
1329 
1330         template <class _Tag, class... _As>
1331           requires stdexec::__queryable_with<const __scheduler_base&, _Tag, _As...>
query(_Tag,_As &&...__as) const1332         auto query(_Tag, _As&&... __as) const
1333           noexcept(stdexec::__nothrow_queryable_with<const __scheduler_base&, _Tag, _As...>)
1334             -> stdexec::__query_result_t<const __scheduler_base&, _Tag, _As...> {
1335           return __scheduler_.query(_Tag{}, static_cast<_As&&>(__as)...);
1336         }
1337 
1338         auto operator==(const any_scheduler&) const noexcept -> bool = default;
1339       };
1340     };
1341   };
1342 } // namespace exec
1343