Skip to content

Commit c6890f9

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

11 files changed

Lines changed: 491 additions & 364 deletions

include/stdexec/__detail/__completion_behavior.hpp

Lines changed: 70 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,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

include/stdexec/__detail/__completion_info.hpp

Lines changed: 68 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,54 @@ namespace STDEXEC
126127
}
127128
}();
128129

130+
template <class _Iterator>
131+
struct __subrange
132+
{
133+
template <std::ranges::range Range>
134+
constexpr __subrange(Range &&rng)
135+
: __begin_(std::ranges::begin(rng))
136+
, __end_(std::ranges::end(rng))
137+
{}
138+
139+
constexpr auto begin() const noexcept -> _Iterator
140+
{
141+
return __begin_;
142+
}
143+
144+
constexpr auto end() const noexcept -> _Iterator
145+
{
146+
return __end_;
147+
}
148+
149+
[[nodiscard]]
150+
constexpr auto size() const noexcept -> std::size_t
151+
{
152+
return std::size_t(std::distance(__begin_, __end_));
153+
}
154+
155+
constexpr auto operator[](std::size_t __i) const noexcept -> std::iter_reference_t<_Iterator>
156+
{
157+
return *std::next(__begin_, __i);
158+
}
159+
160+
_Iterator __begin_, __end_;
161+
};
162+
163+
template <class Range>
164+
STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE
165+
__subrange(Range &&) -> __subrange<std::ranges::iterator_t<Range>>;
166+
167+
template <std::ranges::forward_range auto _Range, class _Fn, class... _Args>
168+
constexpr auto __range_apply(_Fn &&__fn, _Args &&...args) noexcept
169+
{
170+
auto __impl = [&]<std::size_t... _Is>(__indices<_Is...>)
171+
{
172+
return static_cast<_Fn &&>(__fn).template
173+
operator()<(*std::ranges::next(_Range.begin(), _Is))...>(std::forward<_Args>(args)...);
174+
};
175+
return __impl(__make_indices<std::ranges::size(_Range)>());
176+
}
177+
129178
template <class _GetComplInfo>
130179
consteval auto __completion_sigs_from(_GetComplInfo) noexcept
131180
{
@@ -142,13 +191,31 @@ namespace STDEXEC
142191

143192
template <class... _Sigs>
144193
[[nodiscard]]
145-
consteval auto __to_array(completion_signatures<_Sigs...>) noexcept
194+
consteval auto __reflection_of(completion_signatures<_Sigs...>) noexcept
146195
{
147196
using __array_t = __static_vector<__completion_info, sizeof...(_Sigs)>;
148197
auto __compls = __array_t{__completion_info(__signature<_Sigs>)...};
149198
std::ranges::sort(__compls);
150199
return __compls;
151200
}
201+
202+
template <auto>
203+
extern int __splice_v;
204+
205+
template <auto _Info>
206+
using __splice_t = decltype(__splice_v<_Info>);
207+
208+
template <__same_as<__completion_info> auto _Info>
209+
extern __fn_ptr_t<__tuple<__msplice<_Info.__signature>,
210+
__msplice<_Info.__domain>,
211+
__mconstant<_Info.__behavior>>>
212+
__splice_v<_Info>;
213+
214+
template <std::ranges::forward_range auto _Info>
215+
requires __same_as<std::ranges::range_value_t<decltype(_Info)>, __completion_info>
216+
constexpr auto __splice_v<_Info> = __with_indices<_Info.size()>()(
217+
[]<std::size_t... _Is>() { return __fn_ptr_t<__tuple<__splice_t<_Info[_Is]>...>>(); });
218+
152219
} // namespace __cmplsigs
153220
} // namespace STDEXEC
154221

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::__reflection_of(__cmplsigs);
435435
std::ranges::for_each(__cmplinfo, &__completion_info::__populate<_Sender, _Env...>);
436436
return __cmplinfo;
437437
}

0 commit comments

Comments
 (0)