Skip to content

Commit 138e0e1

Browse files
committed
fix the attributes of the let_ senders
1 parent 6d7ad68 commit 138e0e1

12 files changed

Lines changed: 468 additions & 372 deletions

include/stdexec/__detail/__completion_behavior.hpp

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

include/stdexec/__detail/__completion_info.hpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "__completion_behavior.hpp"
2222
#include "__completion_signatures.hpp"
2323
#include "__meta.hpp"
24+
#include "__ranges.hpp"
2425
#include "__static_vector.hpp"
2526
#include "__typeinfo.hpp"
2627

@@ -126,6 +127,17 @@ namespace STDEXEC
126127
}
127128
}();
128129

130+
template <std::ranges::forward_range auto _Range, class _Fn, class... _Args>
131+
constexpr auto __range_apply(_Fn &&__fn, _Args &&...args) noexcept
132+
{
133+
auto __impl = [&]<std::size_t... _Is>(__indices<_Is...>)
134+
{
135+
return static_cast<_Fn &&>(__fn).template
136+
operator()<(*std::ranges::next(_Range.begin(), _Is))...>(std::forward<_Args>(args)...);
137+
};
138+
return __impl(__make_indices<std::ranges::size(_Range)>());
139+
}
140+
129141
template <class _GetComplInfo>
130142
consteval auto __completion_sigs_from(_GetComplInfo) noexcept
131143
{
@@ -142,13 +154,31 @@ namespace STDEXEC
142154

143155
template <class... _Sigs>
144156
[[nodiscard]]
145-
consteval auto __to_array(completion_signatures<_Sigs...>) noexcept
157+
consteval auto __reflect(completion_signatures<_Sigs...>) noexcept
146158
{
147159
using __array_t = __static_vector<__completion_info, sizeof...(_Sigs)>;
148160
auto __compls = __array_t{__completion_info(__signature<_Sigs>)...};
149161
std::ranges::sort(__compls);
150162
return __compls;
151163
}
164+
165+
template <auto>
166+
extern int __splice_v;
167+
168+
template <auto _Info>
169+
using __splice_t = decltype(__splice_v<_Info>);
170+
171+
template <__same_as<__completion_info> auto _Info>
172+
extern __fn_ptr_t<__tuple<__msplice<_Info.__signature>,
173+
__msplice<_Info.__domain>,
174+
__mconstant<_Info.__behavior>>>
175+
__splice_v<_Info>;
176+
177+
template <std::ranges::forward_range auto _Info>
178+
requires __same_as<std::ranges::range_value_t<decltype(_Info)>, __completion_info>
179+
constexpr auto __splice_v<_Info> = __with_indices<_Info.size()>()(
180+
[]<std::size_t... _Is>() { return __fn_ptr_t<__tuple<__splice_t<_Info[_Is]>...>>(); });
181+
152182
} // namespace __cmplsigs
153183
} // namespace STDEXEC
154184

include/stdexec/__detail/__execution_fwd.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ namespace STDEXEC
174174
using scheduler_t = scheduler_tag;
175175
using receiver_t = receiver_tag;
176176

177+
struct __completion_info;
178+
177179
template <class _Tag, class _Sndr, class... _Env>
178180
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
179181
constexpr auto __get_completion_behavior() noexcept;

include/stdexec/__detail/__get_completion_signatures.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ namespace STDEXEC
431431
auto __cmplsigs = STDEXEC::get_completion_signatures<_Sender, _Env...>();
432432
STDEXEC_IF_OK(__cmplsigs)
433433
{
434-
auto __cmplinfo = STDEXEC::__cmplsigs::__to_array(__cmplsigs);
434+
auto __cmplinfo = STDEXEC::__cmplsigs::__reflect(__cmplsigs);
435435
std::ranges::for_each(__cmplinfo, &__completion_info::__populate<_Sender, _Env...>);
436436
return __cmplinfo;
437437
}

0 commit comments

Comments
 (0)