@@ -34,9 +34,10 @@ namespace STDEXEC
3434 // __get_completion_behavior
3535 struct __completion_behavior
3636 {
37- // private:
37+ // private:
3838 template <__completion_tag _Tag>
3939 friend struct __get_completion_behavior_t ;
40+ friend struct __completion_info ;
4041
4142 enum __flag : std::uint8_t
4243 {
@@ -63,6 +64,50 @@ namespace STDEXEC
6364 __unknown = __not_affine_ | __async_ | __inline_
6465 };
6566
67+ // For use when computing the completion behavior of two senders when run in parallel.
68+ //
69+ // __asynchronous | __asynchronous_affine => __async_ (aka __asynchronous)
70+ // __asynchronous | __inline_completion => __async_ | __inline_ | __not_affine (aka __unknown)
71+ // __asynchronous_affine | __inline_completion => __async_ | __inline_
72+ STDEXEC_ATTRIBUTE (nodiscard, always_inline, host, device)
73+ friend constexpr auto operator |(__behavior __left, __behavior __right) noexcept //
74+ -> __behavior
75+ {
76+ return __behavior (std::uint8_t (__left) | std::uint8_t (__right));
77+ }
78+
79+ STDEXEC_ATTRIBUTE (always_inline, host, device)
80+ friend constexpr auto operator |=(__behavior &__left, __behavior __right) noexcept //
81+ -> __behavior &
82+ {
83+ return (__left = (__left | __right));
84+ }
85+
86+ // For use when computing the completion behavior of two senders when run in sequence.
87+ STDEXEC_ATTRIBUTE (nodiscard, always_inline, host, device)
88+ friend constexpr auto operator &(__behavior __left, __behavior __right) noexcept //
89+ -> __behavior
90+ {
91+ // Two senders in sequence can only complete inline if both senders can complete
92+ // inline.
93+ auto const __possibly_inline = std::uint8_t (__left) & std::uint8_t (__right) & __inline_;
94+ // Two senders in sequence can complete in a different context if either sender can
95+ // complete in a different context.
96+ auto const __not_affine = (std::uint8_t (__left) | std::uint8_t (__right)) & __not_affine_;
97+ // Two senders in sequence can complete asynchronously if either sender can complete
98+ // asynchronously.
99+ auto const __possibly_async = (std::uint8_t (__left) | std::uint8_t (__right)) & __async_;
100+
101+ return __behavior (__possibly_inline | __not_affine | __possibly_async);
102+ }
103+
104+ STDEXEC_ATTRIBUTE (always_inline, host, device)
105+ friend constexpr auto operator &=(__behavior &__left, __behavior __right) noexcept //
106+ -> __behavior &
107+ {
108+ return (__left = (__left & __right));
109+ }
110+
66111 template <__behavior _CB>
67112 using __constant_t = std::integral_constant<__behavior, _CB>;
68113
@@ -81,15 +126,37 @@ namespace STDEXEC
81126 static constexpr __asynchronous_affine_t __asynchronous_affine{};
82127 static constexpr __inline_completion_t __inline_completion{};
83128
84- // __asynchronous | __asynchronous_affine => __async_ (aka __asynchronous)
85- // __asynchronous | __inline_completion => __async_ | __inline_ | __not_affine (aka __unknown)
86- // __asynchronous_affine | __inline_completion => __async_ | __inline_
129+ // private:
130+ template <__behavior _CB>
131+ static constexpr auto __reify () noexcept
132+ {
133+ if constexpr (_CB == __behavior::__asynchronous)
134+ return __asynchronous;
135+ else if constexpr (_CB == __behavior::__asynchronous_affine)
136+ return __asynchronous_affine;
137+ else if constexpr (_CB == __behavior::__inline_completion)
138+ return __inline_completion;
139+ else if constexpr (_CB == __behavior::__unknown)
140+ return __unknown;
141+ else
142+ return __constant_t <_CB>{};
143+ }
144+
145+ public:
146+ // For use when computing the completion behavior of two senders when run in parallel.
87147 template <__behavior _Left, __behavior _Right>
88148 STDEXEC_ATTRIBUTE (nodiscard, always_inline, host, device)
89149 friend constexpr auto operator |(__constant_t <_Left>, __constant_t <_Right>) noexcept
90150 {
91- return __constant_t <static_cast <__behavior>(static_cast <std::uint8_t >(_Left)
92- | static_cast <std::uint8_t >(_Right))>();
151+ return __reify<_Left | _Right>();
152+ }
153+
154+ // For use when computing the completion behavior of two senders when run in sequence.
155+ template <__behavior _Left, __behavior _Right>
156+ STDEXEC_ATTRIBUTE (nodiscard, always_inline, host, device)
157+ friend constexpr auto operator &(__constant_t <_Left>, __constant_t <_Right>) noexcept
158+ {
159+ return __reify<_Left & _Right>();
93160 }
94161
95162 template <__behavior _Left, __behavior _Right>
@@ -123,11 +190,10 @@ namespace STDEXEC
123190 struct __common_t
124191 {
125192 template <__behavior... _CSs>
126- requires (sizeof ...(_CSs) > 0 )
127193 STDEXEC_ATTRIBUTE (nodiscard, host, device)
128194 constexpr auto operator ()(__constant_t <_CSs>... __cbs) const noexcept
129195 {
130- return (__cbs | ...);
196+ return (__cbs | ... | __constant_t < __behavior ( 0 )>() );
131197 }
132198 };
133199
0 commit comments