@@ -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,46 @@ 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 -> __behavior
74+ {
75+ return __behavior (std::uint8_t (__left) | std::uint8_t (__right));
76+ }
77+
78+ STDEXEC_ATTRIBUTE (always_inline, host, device)
79+ friend constexpr auto operator |=(__behavior& __left, __behavior __right) noexcept -> __behavior&
80+ {
81+ return (__left = (__left | __right));
82+ }
83+
84+ // For use when computing the completion behavior of two senders when run in sequence.
85+ STDEXEC_ATTRIBUTE (nodiscard, always_inline, host, device)
86+ friend constexpr auto operator &(__behavior __left, __behavior __right) noexcept -> __behavior
87+ {
88+ // Two senders in sequence can only complete inline if both senders can complete
89+ // inline.
90+ auto const __possibly_inline = std::uint8_t (__left) & std::uint8_t (__right) & __inline_;
91+ // Two senders in sequence can complete in a different context if either sender can
92+ // complete in a different context.
93+ auto const __not_affine = (std::uint8_t (__left) | std::uint8_t (__right)) & __not_affine_;
94+ // Two senders in sequence can complete asynchronously if either sender can complete
95+ // asynchronously.
96+ auto const __possibly_async = (std::uint8_t (__left) | std::uint8_t (__right)) & __async_;
97+
98+ return __behavior (__possibly_inline | __not_affine | __possibly_async);
99+ }
100+
101+ STDEXEC_ATTRIBUTE (always_inline, host, device)
102+ friend constexpr auto operator &=(__behavior& __left, __behavior __right) noexcept -> __behavior&
103+ {
104+ return (__left = (__left & __right));
105+ }
106+
66107 template <__behavior _CB>
67108 using __constant_t = std::integral_constant<__behavior, _CB>;
68109
@@ -81,15 +122,37 @@ namespace STDEXEC
81122 static constexpr __asynchronous_affine_t __asynchronous_affine{};
82123 static constexpr __inline_completion_t __inline_completion{};
83124
84- // __asynchronous | __asynchronous_affine => __async_ (aka __asynchronous)
85- // __asynchronous | __inline_completion => __async_ | __inline_ | __not_affine (aka __unknown)
86- // __asynchronous_affine | __inline_completion => __async_ | __inline_
125+ // private:
126+ template <__behavior _CB>
127+ static constexpr auto __reify () noexcept
128+ {
129+ if constexpr (_CB == __behavior::__asynchronous)
130+ return __asynchronous;
131+ else if constexpr (_CB == __behavior::__asynchronous_affine)
132+ return __asynchronous_affine;
133+ else if constexpr (_CB == __behavior::__inline_completion)
134+ return __inline_completion;
135+ else if constexpr (_CB == __behavior::__unknown)
136+ return __unknown;
137+ else
138+ return __constant_t <_CB>{};
139+ }
140+
141+ public:
142+ // For use when computing the completion behavior of two senders when run in parallel.
87143 template <__behavior _Left, __behavior _Right>
88144 STDEXEC_ATTRIBUTE (nodiscard, always_inline, host, device)
89145 friend constexpr auto operator |(__constant_t <_Left>, __constant_t <_Right>) noexcept
90146 {
91- return __constant_t <static_cast <__behavior>(static_cast <std::uint8_t >(_Left)
92- | static_cast <std::uint8_t >(_Right))>();
147+ return __reify<_Left | _Right>();
148+ }
149+
150+ // For use when computing the completion behavior of two senders when run in sequence.
151+ template <__behavior _Left, __behavior _Right>
152+ STDEXEC_ATTRIBUTE (nodiscard, always_inline, host, device)
153+ friend constexpr auto operator &(__constant_t <_Left>, __constant_t <_Right>) noexcept
154+ {
155+ return __reify<_Left & _Right>();
93156 }
94157
95158 template <__behavior _Left, __behavior _Right>
@@ -123,11 +186,10 @@ namespace STDEXEC
123186 struct __common_t
124187 {
125188 template <__behavior... _CSs>
126- requires (sizeof ...(_CSs) > 0 )
127189 STDEXEC_ATTRIBUTE (nodiscard, host, device)
128190 constexpr auto operator ()(__constant_t <_CSs>... __cbs) const noexcept
129191 {
130- return (__cbs | ...);
192+ return (__cbs | ... | __constant_t < __behavior ( 0 )>() );
131193 }
132194 };
133195
0 commit comments