|
629 | 629 | struct @\libglobal{let_error_t}@ { @\unspec@ }; |
630 | 630 | struct @\libglobal{let_stopped_t}@ { @\unspec@ }; |
631 | 631 | struct @\libglobal{bulk_t}@ { @\unspec@ }; |
632 | | - struct @\libglobal{split_t}@ { @\unspec@ }; |
633 | 632 | struct @\libglobal{when_all_t}@ { @\unspec@ }; |
634 | 633 | struct @\libglobal{when_all_with_variant_t}@ { @\unspec@ }; |
635 | 634 | struct @\libglobal{into_variant_t}@ { @\unspec@ }; |
|
647 | 646 | inline constexpr let_error_t @\libglobal{let_error}@{}; |
648 | 647 | inline constexpr let_stopped_t @\libglobal{let_stopped}@{}; |
649 | 648 | inline constexpr bulk_t @\libglobal{bulk}@{}; |
650 | | - inline constexpr split_t @\libglobal{split}@{}; |
651 | 649 | inline constexpr when_all_t @\libglobal{when_all}@{}; |
652 | 650 | inline constexpr when_all_with_variant_t @\libglobal{when_all_with_variant}@{}; |
653 | 651 | inline constexpr into_variant_t @\libglobal{into_variant}@{}; |
|
3695 | 3693 | propagates all completion operations sent by \tcode{sndr}. |
3696 | 3694 | \end{itemize} |
3697 | 3695 |
|
3698 | | -\rSec3[exec.split]{\tcode{execution::split}} |
3699 | | - |
3700 | | -\pnum |
3701 | | -\tcode{split} adapts an arbitrary sender |
3702 | | -into a sender that can be connected multiple times. |
3703 | | - |
3704 | | -\pnum |
3705 | | -Let \exposid{split-env} be the type of an environment |
3706 | | -such that, given an instance \tcode{env}, |
3707 | | -the expression \tcode{get_stop_token(env)} is well-formed and |
3708 | | -has type \tcode{inplace_stop_token.} |
3709 | | - |
3710 | | -\pnum |
3711 | | -The name \tcode{split} denotes a pipeable sender adaptor object. |
3712 | | -For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. |
3713 | | -If \tcode{\libconcept{sender_in}<Sndr, \exposid{split-env}>} is \tcode{false}, |
3714 | | -\tcode{split(sndr)} is ill-formed. |
3715 | | - |
3716 | | -\pnum |
3717 | | -Otherwise, the expression \tcode{split(sndr)} is expression-equivalent to: |
3718 | | -\begin{codeblock} |
3719 | | -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(split, {}, sndr)) |
3720 | | -\end{codeblock} |
3721 | | -except that \tcode{sndr} is evaluated only once. |
3722 | | -\begin{note} |
3723 | | -The default implementation of \tcode{transform_sender} |
3724 | | -will have the effect of connecting the sender to a receiver. |
3725 | | -It will return a sender with a different tag type. |
3726 | | -\end{note} |
3727 | | - |
3728 | | -\pnum |
3729 | | -Let \exposid{local-state} denote the following exposition-only class template: |
3730 | | - |
3731 | | -\begin{codeblock} |
3732 | | -namespace std::execution { |
3733 | | - struct @\exposid{local-state-base}@ { // \expos |
3734 | | - virtual ~@\exposid{local-state-base}@() = default; |
3735 | | - virtual void @\exposid{notify}@() noexcept = 0; // \expos |
3736 | | - }; |
3737 | | - |
3738 | | - template<class Sndr, class Rcvr> |
3739 | | - struct @\exposid{local-state}@ : @\exposid{local-state-base}@ { // \expos |
3740 | | - using @\exposid{on-stop-callback}@ = // \expos |
3741 | | - stop_callback_for_t<stop_token_of_t<env_of_t<Rcvr>>, @\exposid{on-stop-request}@>; |
3742 | | - |
3743 | | - @\exposid{local-state}@(Sndr&& sndr, Rcvr& rcvr) noexcept; |
3744 | | - ~@\exposid{local-state}@(); |
3745 | | - |
3746 | | - void @\exposid{notify}@() noexcept override; |
3747 | | - |
3748 | | - private: |
3749 | | - optional<@\exposid{on-stop-callback}@> @\exposid{on_stop}@; // \expos |
3750 | | - @\exposid{shared-state}@<Sndr>* @\exposid{sh_state}@; // \expos |
3751 | | - Rcvr* @\exposid{rcvr}@; // \expos |
3752 | | - }; |
3753 | | -} |
3754 | | -\end{codeblock} |
3755 | | - |
3756 | | -\begin{itemdecl} |
3757 | | -@\exposid{local-state}@(Sndr&& sndr, Rcvr& rcvr) noexcept; |
3758 | | -\end{itemdecl} |
3759 | | - |
3760 | | -\begin{itemdescr} |
3761 | | -\pnum |
3762 | | -\effects |
3763 | | -Equivalent to: |
3764 | | -\begin{codeblock} |
3765 | | -auto& [_, data, _] = sndr; |
3766 | | -this->@\exposid{sh_state}@ = data.sh_state.get(); |
3767 | | -this->@\exposid{sh_state}@->@\exposid{inc-ref}@(); |
3768 | | -this->@\exposid{rcvr}@ = addressof(rcvr); |
3769 | | -\end{codeblock} |
3770 | | -\end{itemdescr} |
3771 | | - |
3772 | | -\begin{itemdecl} |
3773 | | -~@\exposid{local-state}@(); |
3774 | | -\end{itemdecl} |
3775 | | - |
3776 | | -\begin{itemdescr} |
3777 | | -\pnum |
3778 | | -\effects |
3779 | | -Equivalent to: |
3780 | | -\begin{codeblock} |
3781 | | -sh_state->@\exposid{dec-ref}@(); |
3782 | | -\end{codeblock} |
3783 | | -\end{itemdescr} |
3784 | | - |
3785 | | -\begin{itemdecl} |
3786 | | -void @\exposid{notify}@() noexcept override; |
3787 | | -\end{itemdecl} |
3788 | | - |
3789 | | -\begin{itemdescr} |
3790 | | -\pnum |
3791 | | -\effects |
3792 | | -Equivalent to: |
3793 | | -\begin{codeblock} |
3794 | | -@\exposid{on_stop}@.reset(); |
3795 | | -visit( |
3796 | | - [this](const auto& tupl) noexcept -> void { |
3797 | | - apply( |
3798 | | - [this](auto tag, const auto&... args) noexcept -> void { |
3799 | | - tag(std::move(*@\exposid{rcvr}@), args...); |
3800 | | - }, |
3801 | | - tupl); |
3802 | | - }, |
3803 | | - @\exposid{sh_state}@->result); |
3804 | | -\end{codeblock} |
3805 | | -\end{itemdescr} |
3806 | | - |
3807 | | -\pnum |
3808 | | -Let \exposid{split-receiver} denote |
3809 | | -the following exposition-only class template: |
3810 | | -\begin{codeblock} |
3811 | | -namespace std::execution { |
3812 | | - template<class Sndr> |
3813 | | - struct @\exposid{split-receiver}@ { // \expos |
3814 | | - using receiver_concept = receiver_t; |
3815 | | - |
3816 | | - template<class Tag, class... Args> |
3817 | | - void @\exposid{complete}@(Tag, Args&&... args) noexcept { // \expos |
3818 | | - using tuple_t = @\exposid{decayed-tuple}@<Tag, Args...>; |
3819 | | - try { |
3820 | | - @\exposid{sh_state}@->result.template emplace<tuple_t>(Tag(), std::forward<Args>(args)...); |
3821 | | - } catch (...) { |
3822 | | - using tuple_t = tuple<set_error_t, exception_ptr>; |
3823 | | - @\exposid{sh_state}@->result.template emplace<tuple_t>(set_error, current_exception()); |
3824 | | - } |
3825 | | - @\exposid{sh_state}@->notify(); |
3826 | | - } |
3827 | | - |
3828 | | - template<class... Args> |
3829 | | - void set_value(Args&&... args) && noexcept { |
3830 | | - @\exposid{complete}@(execution::set_value, std::forward<Args>(args)...); |
3831 | | - } |
3832 | | - |
3833 | | - template<class Error> |
3834 | | - void set_error(Error&& err) && noexcept { |
3835 | | - @\exposid{complete}@(execution::set_error, std::forward<Error>(err)); |
3836 | | - } |
3837 | | - |
3838 | | - void set_stopped() && noexcept { |
3839 | | - @\exposid{complete}@(execution::set_stopped); |
3840 | | - } |
3841 | | - |
3842 | | - struct @\exposid{env}@ { // \expos |
3843 | | - @\exposid{shared-state}@<Sndr>* @\exposid{sh-state}@; // \expos |
3844 | | - |
3845 | | - inplace_stop_token query(get_stop_token_t) const noexcept { |
3846 | | - return @\exposid{sh-state}@->stop_src.get_token(); |
3847 | | - } |
3848 | | - }; |
3849 | | - |
3850 | | - @\exposid{env}@ get_env() const noexcept { |
3851 | | - return @\exposid{env}@{@\exposid{sh_state}@}; |
3852 | | - } |
3853 | | - |
3854 | | - @\exposid{shared-state}@<Sndr>* @\exposid{sh_state}@; // \expos |
3855 | | - }; |
3856 | | -} |
3857 | | -\end{codeblock} |
3858 | | - |
3859 | | -\pnum |
3860 | | -Let \exposid{shared-state} denote the following exposition-only class template: |
3861 | | -\begin{codeblock} |
3862 | | -namespace std::execution { |
3863 | | - template<class Sndr> |
3864 | | - struct @\exposid{shared-state}@ { |
3865 | | - using @\exposid{variant-type}@ = @\seebelow@; // \expos |
3866 | | - using @\exposid{state-list-type}@ = @\seebelow@; // \expos |
3867 | | - |
3868 | | - explicit @\exposid{shared-state}@(Sndr&& sndr); |
3869 | | - |
3870 | | - void @\exposid{start-op}@() noexcept; // \expos |
3871 | | - void @\exposid{notify}@() noexcept; // \expos |
3872 | | - void @\exposid{inc-ref}@() noexcept; // \expos |
3873 | | - void @\exposid{dec-ref}@() noexcept; // \expos |
3874 | | - |
3875 | | - inplace_stop_source @\exposid{stop_src}@{}; // \expos |
3876 | | - @\exposid{variant-type}@ @\exposid{result}@{}; // \expos |
3877 | | - @\exposid{state-list-type}@ @\exposid{waiting_states}@; // \expos |
3878 | | - atomic<bool> @\exposid{completed}@{false}; // \expos |
3879 | | - atomic<size_t> @\exposid{ref_count}@{1}; // \expos |
3880 | | - connect_result_t<Sndr, @\exposid{split-receiver}@<Sndr>> @\exposid{op_state}@; // \expos |
3881 | | - }; |
3882 | | -} |
3883 | | -\end{codeblock} |
3884 | | - |
3885 | | -\pnum |
3886 | | -Let \tcode{Sigs} be a pack of the arguments |
3887 | | -to the \tcode{completion_signatures} specialization |
3888 | | -named by \tcode{completion_signatures_of_t<Sndr>}. |
3889 | | -For type \tcode{Tag} and pack \tcode{Args}, |
3890 | | -let \exposid{as-tuple} be an alias template |
3891 | | -such that \tcode{\exposid{as-tuple}<Tag(Args...)>} denotes |
3892 | | -the type \tcode{\exposid{decayed-tuple}<Tag, Args...>}. |
3893 | | -Then \exposid{variant-type} denotes the type |
3894 | | -\begin{codeblock} |
3895 | | -variant<tuple<set_stopped_t>, tuple<set_error_t, exception_ptr>, @\exposid{as-tuple}@<Sigs>...> |
3896 | | -\end{codeblock} |
3897 | | -but with duplicate types removed. |
3898 | | - |
3899 | | -\pnum |
3900 | | -Let \exposid{state-list-type} be a type |
3901 | | -that stores a list of pointers to \exposid{local-state-base} objects and |
3902 | | -that permits atomic insertion. |
3903 | | - |
3904 | | -\begin{itemdecl} |
3905 | | -explicit @\exposid{shared-state}@(Sndr&& sndr); |
3906 | | -\end{itemdecl} |
3907 | | - |
3908 | | -\begin{itemdescr} |
3909 | | -\pnum |
3910 | | -\effects |
3911 | | -Initializes \exposid{op_state} with the result of |
3912 | | -\tcode{connect(std::forward<Sndr>(sndr), \exposid{split-re\-ceiver}\{this\})}. |
3913 | | - |
3914 | | -\pnum |
3915 | | -\ensures |
3916 | | -\exposid{waiting_states} is empty, and \exposid{completed} is \tcode{false}. |
3917 | | -\end{itemdescr} |
3918 | | - |
3919 | | -\begin{itemdecl} |
3920 | | -void @\exposid{start-op}@() noexcept; |
3921 | | -\end{itemdecl} |
3922 | | - |
3923 | | -\begin{itemdescr} |
3924 | | -\pnum |
3925 | | -\effects |
3926 | | -Evaluates \tcode{\exposid{inc-ref}()}. |
3927 | | -If \tcode{stop_src.stop_requested()} is \tcode{true}, |
3928 | | -evaluates \tcode{\exposid{notify}()}; |
3929 | | -otherwise, evaluates \tcode{start(\exposid{op_state})}. |
3930 | | -\end{itemdescr} |
3931 | | - |
3932 | | -\begin{itemdecl} |
3933 | | -void @\exposid{notify}@() noexcept; |
3934 | | -\end{itemdecl} |
3935 | | - |
3936 | | -\begin{itemdescr} |
3937 | | -\pnum |
3938 | | -\effects |
3939 | | -Atomically does the following: |
3940 | | -\begin{itemize} |
3941 | | -\item |
3942 | | -Sets \tcode{completed} to \tcode{true}, and |
3943 | | -\item |
3944 | | -Exchanges \tcode{waiting_states} with an empty list, |
3945 | | -storing the old value in a local \tcode{prior_states}. |
3946 | | -\end{itemize} |
3947 | | -Then, for each pointer \tcode{p} in \tcode{prior_states}, |
3948 | | -evaluates \tcode{p->\exposid{notify}()}. |
3949 | | -Finally, evaluates \tcode{\exposid{dec-ref}()}. |
3950 | | -\end{itemdescr} |
3951 | | - |
3952 | | -\begin{itemdecl} |
3953 | | -void @\exposid{inc-ref}@() noexcept; |
3954 | | -\end{itemdecl} |
3955 | | - |
3956 | | -\begin{itemdescr} |
3957 | | -\pnum |
3958 | | -\effects |
3959 | | -Increments \exposid{ref_count}. |
3960 | | -\end{itemdescr} |
3961 | | - |
3962 | | -\begin{itemdecl} |
3963 | | -void @\exposid{dec-ref}@() noexcept; |
3964 | | -\end{itemdecl} |
3965 | | - |
3966 | | -\begin{itemdescr} |
3967 | | -\pnum |
3968 | | -\effects |
3969 | | -Decrements \exposid{ref_count}. |
3970 | | -If the new value of \exposid{ref_count} is \tcode{0}, |
3971 | | -calls \tcode{delete this}. |
3972 | | - |
3973 | | -\pnum |
3974 | | -\sync |
3975 | | -If an evaluation of \tcode{\exposid{dec-ref}()} does not |
3976 | | -decrement the \tcode{ref_count} to \tcode{0} then |
3977 | | -synchronizes with the evaluation of \tcode{dec-ref()} |
3978 | | -that decrements \tcode{ref_count} to \tcode{0}. |
3979 | | -\end{itemdescr} |
3980 | | - |
3981 | | -\pnum |
3982 | | -Let \exposid{split-impl-tag} be an empty exposition-only class type. |
3983 | | -Given an expression \tcode{sndr}, |
3984 | | -the expression \tcode{split.transform_sender(sndr)} is equivalent to: |
3985 | | -\begin{codeblock} |
3986 | | -auto&& [tag, _, child] = sndr; |
3987 | | -auto* sh_state = new @\exposid{shared-state}@{std::forward_like<decltype((sndr))>(child)}; |
3988 | | -return @\exposid{make-sender}@(@\exposid{split-impl-tag}@(), @\exposid{shared-wrapper}@{sh_state, tag}); |
3989 | | -\end{codeblock} |
3990 | | -where \exposid{shared-wrapper} is an exposition-only class |
3991 | | -that manages the reference count of the \exposid{shared-state} object |
3992 | | -pointed to by sh_state. |
3993 | | -\exposid{shared-wrapper} models \libconcept{copyable} |
3994 | | -with move operations nulling out the moved-from object, |
3995 | | -copy operations incrementing the reference count |
3996 | | -by calling \tcode{sh_state->\exposid{inc-ref}()}, and |
3997 | | -assignment operations performing a copy-and-swap operation. |
3998 | | -The destructor has no effect if sh_state is null; |
3999 | | -otherwise, it decrements the reference count |
4000 | | -by evaluating \tcode{sh_state->\exposid{dec-ref}()}. |
4001 | | - |
4002 | | -\pnum |
4003 | | -The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} |
4004 | | -is specialized for \exposid{split-impl-tag} as follows: |
4005 | | -\begin{codeblock} |
4006 | | -namespace std::execution { |
4007 | | - template<> |
4008 | | - struct @\exposid{impls-for}@<@\exposid{split-impl-tag}@> : @\exposid{default-impls}@ { |
4009 | | - static constexpr auto @\exposid{get-state}@ = @\seebelow@; |
4010 | | - static constexpr auto @\exposid{start}@ = @\seebelow@; |
4011 | | - }; |
4012 | | -} |
4013 | | -\end{codeblock} |
4014 | | - |
4015 | | -\pnum |
4016 | | -The member |
4017 | | -\tcode{\exposid{impls-for}<\exposid{split-impl-tag}>::\exposid{get-state}} |
4018 | | -is initialized with a callable object equivalent to |
4019 | | -the following lambda expression: |
4020 | | -\begin{codeblock} |
4021 | | -[]<class Sndr>(Sndr&& sndr, auto& rcvr) noexcept { |
4022 | | - return @\exposid{local-state}@{std::forward<Sndr>(sndr), rcvr}; |
4023 | | -} |
4024 | | -\end{codeblock} |
4025 | | - |
4026 | | -\pnum |
4027 | | -The member |
4028 | | -\tcode{\exposid{impls-for}<\exposid{split-impl-tag}>::\exposid{start}} |
4029 | | -is initialized with a callable object |
4030 | | -that has a function call operator equivalent to the following: |
4031 | | -\begin{codeblock} |
4032 | | -template<class Sndr, class Rcvr> |
4033 | | -void operator()(@\exposid{local-state}@<Sndr, Rcvr>& state, Rcvr& rcvr) const noexcept; |
4034 | | -\end{codeblock} |
4035 | | - |
4036 | | -\effects |
4037 | | -If \tcode{state.\exposid{sh_state}->\exposid{completed}} is \tcode{true}, |
4038 | | -evaluates \tcode{state.\exposid{notify}()} and returns. |
4039 | | -Otherwise, does the following in order: |
4040 | | -\begin{itemize} |
4041 | | -\item |
4042 | | -Evaluates |
4043 | | -\begin{codeblock} |
4044 | | -state.@\exposid{on_stop}@.emplace( |
4045 | | - get_stop_token(get_env(rcvr)), |
4046 | | - @\exposid{on-stop-request}@{state.@\exposid{sh_state}@->@\exposid{stop_src}@}); |
4047 | | -\end{codeblock} |
4048 | | -\item |
4049 | | -Then atomically does the following: |
4050 | | -\begin{itemize} |
4051 | | -\item |
4052 | | -Reads the value \tcode{c} of |
4053 | | -\tcode{state.\exposid{sh_state}->\exposid{completed}}, and |
4054 | | -\item |
4055 | | -Inserts \tcode{addressof(state)} into |
4056 | | -\tcode{state.\exposid{sh_state}->\exposid{waiting_states}} |
4057 | | -if \tcode{c} is \tcode{false}. |
4058 | | -\end{itemize} |
4059 | | -\item |
4060 | | -If \tcode{c} is \tcode{true}, |
4061 | | -calls \tcode{state.\exposid{notify}()} and returns. |
4062 | | -\item |
4063 | | -Otherwise, |
4064 | | -if \tcode{addressof(state)} is the first item added to |
4065 | | -\tcode{state.\exposid{sh_state}->\exposid{waiting_states}}, |
4066 | | -evaluates \tcode{state.\exposid{sh_state}->\exposid{start-op}()}. |
4067 | | -\end{itemize} |
4068 | | - |
4069 | 3696 | \rSec3[exec.when.all]{\tcode{execution::when_all}} |
4070 | 3697 |
|
4071 | 3698 | \pnum |
|
0 commit comments