Skip to content

Commit 5157bd4

Browse files
committed
Implement execution::on adaptor
1 parent 97c05d6 commit 5157bd4

5 files changed

Lines changed: 570 additions & 113 deletions

File tree

stl/inc/execution

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5341,6 +5341,25 @@ namespace execution {
53415341
template <class _Sender>
53425342
struct sender_traits : decltype(_Get_sender_traits_base<_Sender>()) {};
53435343

5344+
template <class _Sender>
5345+
_NODISCARD _CONSTEVAL auto _Get_sender_traits_derived() noexcept {
5346+
if constexpr (_Has_sender_types<sender_traits<_Sender>>) {
5347+
return _Typed_sender<sender_traits<_Sender>>{};
5348+
} else if constexpr (derived_from<_Sender, sender_base>) {
5349+
return _Sender_traits_base{};
5350+
#if 0 // TRANSITION: coroutine support
5351+
} else if constexpr (_Is_awaitable<_Sender>) {
5352+
if constexpr (is_void_v<_Await_result_t<_Sender>>) {
5353+
return _Void_sender<false>{};
5354+
} else {
5355+
return _Sender_of<false, _Await_result_t<_Sender>>{};
5356+
}
5357+
#endif // 0 TRANSITION: coroutine support
5358+
} else {
5359+
return _No_sender_traits{};
5360+
}
5361+
}
5362+
53445363
template <class _Sender>
53455364
concept sender = move_constructible<remove_cvref_t<_Sender>> && !requires {
53465365
typename sender_traits<remove_cvref_t<_Sender>>::_Unspecialized;
@@ -5543,6 +5562,134 @@ namespace execution {
55435562
_NODISCARD constexpr _Just_done_sender just_done() noexcept {
55445563
return {};
55455564
};
5565+
5566+
template <class _Tag, class... _Args>
5567+
concept _Tag_invocable_to_sender = tag_invocable<_Tag, _Args...> && sender<tag_invoke_result_t<_Tag, _Args...>>;
5568+
5569+
namespace _On {
5570+
template <scheduler _Scheduler, receiver _InputReceiver>
5571+
struct _WrappedReceiver {
5572+
_Scheduler _Sched;
5573+
_InputReceiver _Input_receiver;
5574+
5575+
friend constexpr void tag_invoke(set_done_t, _WrappedReceiver _Wrapped_receiver) noexcept {
5576+
_EXEC set_done(_STD move(_Wrapped_receiver._Input_receiver));
5577+
}
5578+
template <class _Error>
5579+
friend constexpr void tag_invoke(set_error_t, _WrappedReceiver _Wrapped_receiver, _Error&& _Err) noexcept {
5580+
_EXEC set_error(_STD move(_Wrapped_receiver._Input_receiver), _STD forward<_Error>(_Err));
5581+
}
5582+
template <class... _ArgTys>
5583+
friend constexpr void tag_invoke(
5584+
set_value_t, _WrappedReceiver _Wrapped_receiver, _ArgTys&&... _Args) noexcept {
5585+
_EXEC set_value(_STD move(_Wrapped_receiver._Input_receiver), _STD forward<_ArgTys>(_Args)...);
5586+
}
5587+
_NODISCARD friend constexpr auto tag_invoke(
5588+
get_scheduler_t, const _WrappedReceiver& _Wrapped_receiver) noexcept {
5589+
return _Wrapped_receiver._Sched;
5590+
}
5591+
};
5592+
5593+
template <scheduler _Scheduler, sender _InputSender, receiver _InputReceiver>
5594+
struct _InnerReceiver {
5595+
using _WrappedReceiver_t = _WrappedReceiver<_Scheduler, _InputReceiver>;
5596+
5597+
// Clang complains about incomplete type, so for now no _OutputSenderState*
5598+
_WrappedReceiver_t* _Wrapped_receiver;
5599+
_InputSender* _Input_sender;
5600+
invoke_result_t<connect_t, _InputSender, _WrappedReceiver_t>* _Op_state3;
5601+
5602+
friend constexpr void tag_invoke(set_done_t, _InnerReceiver _Inner_receiver) noexcept {
5603+
_EXEC set_done(_STD move(_Inner_receiver._Wrapped_receiver->_Input_receiver));
5604+
}
5605+
template <class _Error>
5606+
friend constexpr void tag_invoke(set_error_t, _InnerReceiver _Inner_receiver, _Error&& _Err) noexcept {
5607+
_EXEC set_error(
5608+
_STD move(_Inner_receiver._Wrapped_receiver->_Input_receiver), _STD forward<_Error>(_Err));
5609+
}
5610+
friend constexpr void tag_invoke(set_value_t, _InnerReceiver _Inner_receiver) noexcept {
5611+
auto* _Wrapped_receiver = _Inner_receiver._Wrapped_receiver;
5612+
_TRY_BEGIN
5613+
// *this is stored inside of `_Op_state2` so the call below will invalidate it. store the members
5614+
auto* _Input_sender = _Inner_receiver._Input_sender;
5615+
auto* _Op_state3 = _Inner_receiver._Op_state3;
5616+
_STD construct_at(_Op_state3, _EXEC connect(_STD move(*_Input_sender), _STD move(*_Wrapped_receiver)));
5617+
_EXEC start(*_Op_state3);
5618+
_CATCH_ALL
5619+
_EXEC set_error(_STD move(_Wrapped_receiver->_Input_receiver), _STD current_exception());
5620+
_CATCH_END
5621+
}
5622+
};
5623+
5624+
template <scheduler _Scheduler, sender _InputSender, receiver _InputReceiver>
5625+
struct _OutputSenderState {
5626+
using _WrappedReceiver_t = _WrappedReceiver<_Scheduler, _InputReceiver>;
5627+
using _InnerReceiver_t = _InnerReceiver<_Scheduler, _InputSender, _InputReceiver>;
5628+
5629+
_WrappedReceiver_t _Wrapped_receiver;
5630+
_InputSender _Input_sender;
5631+
union {
5632+
invoke_result_t<connect_t, invoke_result_t<schedule_t, _Scheduler>, _InnerReceiver_t> _Op_state2;
5633+
invoke_result_t<connect_t, _InputSender, _WrappedReceiver_t> _Op_state3;
5634+
};
5635+
5636+
explicit constexpr _OutputSenderState(_WrappedReceiver_t _Wrapped_receiver_, _InputSender _Input_sender_)
5637+
: _Wrapped_receiver(_STD move(_Wrapped_receiver_)), _Input_sender(_STD move(_Input_sender_)),
5638+
_Op_state2(_EXEC connect(_EXEC schedule(_Wrapped_receiver._Sched),
5639+
_InnerReceiver_t{_STD addressof(_Wrapped_receiver), _STD addressof(_Input_sender),
5640+
_STD addressof(_Op_state3)})) {}
5641+
5642+
friend constexpr void tag_invoke(start_t, _OutputSenderState& _State) noexcept {
5643+
_EXEC start(_State._Op_state2);
5644+
}
5645+
};
5646+
5647+
template <scheduler _Scheduler, sender _InputSender>
5648+
struct _OutputSender {
5649+
_Scheduler _Sched;
5650+
_InputSender _Input_sender;
5651+
5652+
template <receiver _InputReceiver>
5653+
_NODISCARD friend constexpr auto
5654+
tag_invoke(connect_t, _OutputSender _Output_sender, _InputReceiver&& _Input_receiver) noexcept(
5655+
is_nothrow_move_constructible_v<_Scheduler>&& is_nothrow_move_constructible_v<_InputSender>&&
5656+
is_nothrow_constructible_v<remove_cvref_t<_InputReceiver>, _InputReceiver>) {
5657+
return _OutputSenderState<_Scheduler, _InputSender, _InputReceiver>{
5658+
_WrappedReceiver<_Scheduler, _InputReceiver>{
5659+
_STD move(_Output_sender._Sched), _STD forward<_InputReceiver>(_Input_receiver)},
5660+
_STD move(_Output_sender._Input_sender)};
5661+
}
5662+
5663+
template <_One_of<set_value_t, set_error_t, set_done_t> _Target>
5664+
_NODISCARD friend constexpr auto tag_invoke(
5665+
get_completion_scheduler_t<_Target>, const _OutputSender& _Output_sender) noexcept requires
5666+
tag_observable<get_completion_scheduler_t<_Target>, _InputSender> {
5667+
return tag_invoke(get_completion_scheduler<_Target>, _Output_sender._Input_sender);
5668+
}
5669+
};
5670+
5671+
struct _Cpo {
5672+
template <scheduler _Scheduler, sender _InputSender>
5673+
_NODISCARD constexpr auto operator()(_Scheduler&& _Sched, _InputSender&& _Input_sender) const noexcept {
5674+
if constexpr (_Tag_invocable_to_sender<_Cpo, _Scheduler, _InputSender>) {
5675+
return tag_invoke(
5676+
*this, _STD forward<_Scheduler>(_Sched), _STD forward<_InputSender>(_Input_sender));
5677+
} else {
5678+
return _OutputSender<_Scheduler, _InputSender>{
5679+
_STD forward<_Scheduler>(_Sched), _STD forward<_InputSender>(_Input_sender)};
5680+
}
5681+
}
5682+
};
5683+
} // namespace _On
5684+
using on_t = _On::_Cpo;
5685+
5686+
inline namespace _Cpos {
5687+
inline constexpr _On::_Cpo on;
5688+
}
5689+
5690+
template <scheduler _Scheduler, sender _InputSender>
5691+
struct sender_traits<_On::_OutputSender<_Scheduler, _InputSender>>
5692+
: decltype(_Get_sender_traits_derived<_InputSender>()) {};
55465693
} // namespace execution
55475694
#endif // __cpp_lib_executors
55485695
_STD_END

stl/inc/ranges

Lines changed: 0 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -60,119 +60,6 @@ namespace ranges {
6060
template <bool _IsWrapped, class _Ty>
6161
using _Maybe_wrapped = conditional_t<_IsWrapped, _Ty, _Unwrapped_t<_Ty>>;
6262

63-
namespace _Pipe {
64-
// clang-format off
65-
template <class _Left, class _Right>
66-
concept _Can_pipe = requires(_Left&& __l, _Right&& __r) {
67-
static_cast<_Right&&>(__r)(static_cast<_Left&&>(__l));
68-
};
69-
70-
template <class _Left, class _Right>
71-
concept _Can_compose = constructible_from<remove_cvref_t<_Left>, _Left>
72-
&& constructible_from<remove_cvref_t<_Right>, _Right>;
73-
// clang-format on
74-
75-
template <class, class>
76-
struct _Pipeline;
77-
78-
template <class _Derived>
79-
struct _Base {
80-
// clang-format off
81-
template <class _Other>
82-
requires _Can_compose<_Derived, _Other>
83-
constexpr auto operator|(_Base<_Other>&& __r) && noexcept(
84-
noexcept(_Pipeline{static_cast<_Derived&&>(*this), static_cast<_Other&&>(__r)})) {
85-
// clang-format on
86-
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
87-
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
88-
return _Pipeline{static_cast<_Derived&&>(*this), static_cast<_Other&&>(__r)};
89-
}
90-
91-
// clang-format off
92-
template <class _Other>
93-
requires _Can_compose<_Derived, const _Other&>
94-
constexpr auto operator|(const _Base<_Other>& __r) && noexcept(
95-
noexcept(_Pipeline{static_cast<_Derived&&>(*this), static_cast<const _Other&>(__r)})) {
96-
// clang-format on
97-
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
98-
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
99-
return _Pipeline{static_cast<_Derived&&>(*this), static_cast<const _Other&>(__r)};
100-
}
101-
102-
// clang-format off
103-
template <class _Other>
104-
requires _Can_compose<const _Derived&, _Other>
105-
constexpr auto operator|(_Base<_Other>&& __r) const& noexcept(
106-
noexcept(_Pipeline{static_cast<const _Derived&>(*this), static_cast<_Other&&>(__r)})) {
107-
// clang-format on
108-
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
109-
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
110-
return _Pipeline{static_cast<const _Derived&>(*this), static_cast<_Other&&>(__r)};
111-
}
112-
113-
// clang-format off
114-
template <class _Other>
115-
requires _Can_compose<const _Derived&, const _Other&>
116-
constexpr auto operator|(const _Base<_Other>& __r) const& noexcept(
117-
noexcept(_Pipeline{static_cast<const _Derived&>(*this), static_cast<const _Other&>(__r)})) {
118-
// clang-format on
119-
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
120-
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
121-
return _Pipeline{static_cast<const _Derived&>(*this), static_cast<const _Other&>(__r)};
122-
}
123-
124-
template <_Can_pipe<const _Derived&> _Left>
125-
friend constexpr auto operator|(_Left&& __l, const _Base& __r)
126-
#ifdef __EDG__ // TRANSITION, VSO-1222776
127-
noexcept(noexcept(_STD declval<const _Derived&>()(_STD forward<_Left>(__l))))
128-
#else // ^^^ workaround / no workaround vvv
129-
noexcept(noexcept(static_cast<const _Derived&>(__r)(_STD forward<_Left>(__l))))
130-
#endif // TRANSITION, VSO-1222776
131-
{
132-
return static_cast<const _Derived&>(__r)(_STD forward<_Left>(__l));
133-
}
134-
135-
template <_Can_pipe<_Derived> _Left>
136-
friend constexpr auto operator|(_Left&& __l, _Base&& __r)
137-
#ifdef __EDG__ // TRANSITION, VSO-1222776
138-
noexcept(noexcept(_STD declval<_Derived>()(_STD forward<_Left>(__l))))
139-
#else // ^^^ workaround / no workaround vvv
140-
noexcept(noexcept(static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l))))
141-
#endif // TRANSITION, VSO-1222776
142-
{
143-
return static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l));
144-
}
145-
};
146-
147-
template <class _Left, class _Right>
148-
struct _Pipeline : _Base<_Pipeline<_Left, _Right>> {
149-
/* [[no_unique_address]] */ _Left __l;
150-
/* [[no_unique_address]] */ _Right __r;
151-
152-
template <class _Ty1, class _Ty2>
153-
constexpr explicit _Pipeline(_Ty1&& _Val1, _Ty2&& _Val2) noexcept(
154-
is_nothrow_convertible_v<_Ty1, _Left>&& is_nothrow_convertible_v<_Ty2, _Right>)
155-
: __l(_STD forward<_Ty1>(_Val1)), __r(_STD forward<_Ty2>(_Val2)) {}
156-
157-
template <class _Ty>
158-
_NODISCARD constexpr auto operator()(_Ty&& _Val) noexcept(
159-
noexcept(__r(__l(_STD forward<_Ty>(_Val))))) requires requires {
160-
__r(__l(static_cast<_Ty&&>(_Val)));
161-
}
162-
{ return __r(__l(_STD forward<_Ty>(_Val))); }
163-
164-
template <class _Ty>
165-
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
166-
noexcept(noexcept(__r(__l(_STD forward<_Ty>(_Val))))) requires requires {
167-
__r(__l(static_cast<_Ty&&>(_Val)));
168-
}
169-
{ return __r(__l(_STD forward<_Ty>(_Val))); }
170-
};
171-
172-
template <class _Ty1, class _Ty2>
173-
_Pipeline(_Ty1, _Ty2) -> _Pipeline<_Ty1, _Ty2>;
174-
} // namespace _Pipe
175-
17663
template <range _Rng, class _Derived>
17764
class _Cached_position : public view_interface<_Derived> {
17865
static_assert(_Always_false<_Rng>, "A range must be at least forward for position caching to be worthwhile.");

0 commit comments

Comments
 (0)