Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/__utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ namespace std {
using __f = __t<__f_<_Args...>>;
};

template <class _T>
struct __constant {
template <class...>
using __f = _T;
};

template <class _Fn, class _Continuation = __q<__types>>
struct __transform {
template <class... _Args>
Expand Down
42 changes: 19 additions & 23 deletions include/execution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,24 +176,23 @@ namespace std::execution {
sender<_Sender> &&
__has_sender_types<sender_traits<remove_cvref_t<_Sender>>>;

template <bool>
struct __variant_ {
template <class... _Ts>
using __f = variant<_Ts...>;
};
template <>
struct __variant_<false> {
struct __not_a_variant {
__not_a_variant() = delete;
};
template <class...>
using __f = __not_a_variant;
};
struct __not_a_variant {
__not_a_variant() = delete;
};
template <class... _Ts>
using __variant = __minvoke<__variant_<sizeof...(_Ts) != 0>, _Ts...>;
using __variant =
__minvoke<
__if<
__bool<sizeof...(_Ts) != 0>,
__transform<__q1<decay_t>, __unique<__q<variant>>>,
__constant<__not_a_variant>>,
_Ts...>;

template <class... _Ts>
using __decayed_tuple = tuple<decay_t<_Ts>...>;

template <typed_sender _Sender,
template <class...> class _Tuple = tuple,
template <class...> class _Tuple = __decayed_tuple,
template <class...> class _Variant = __variant>
using value_types_of_t =
typename sender_traits<decay_t<_Sender>>::template
Expand Down Expand Up @@ -1514,9 +1513,6 @@ namespace std::execution {
namespace __impl {
using __nullable_variant_t = __unique<__bind_front<__q<variant>, __>>;

template <class... _Ts>
using __decayed_tuple = tuple<decay_t<_Ts>...>;

template <class... _Ts>
struct __as_tuple {
__decayed_tuple<_Ts...> operator()(_Ts...) const;
Expand Down Expand Up @@ -2107,14 +2103,14 @@ _PRAGMA_POP()
using __bound_values_t =
__value_types_of_t<
_Sender,
__transform<__q1<decay_t>, __bind_front_q<tuple, set_value_t>>,
__bind_front_q<__decayed_tuple, set_value_t>,
__q<__bind_tuples>>;

using __variant_t =
__error_types_of_t<
_Sender,
__transform<
__transform<__q1<decay_t>, __bind_front_q<tuple, set_error_t>>,
__bind_front_q<__decayed_tuple, set_error_t>,
__bound_values_t>>;

template <receiver _Receiver>
Expand Down Expand Up @@ -2196,7 +2192,7 @@ _PRAGMA_POP()
// Write the tag and the args into the operation state so that
// we can forward the completion from within the scheduler's
// execution context.
__self.__op_state_->__data_.template emplace<tuple<_Tag, decay_t<_Args>...>>(_Tag{}, (_Args&&) __args...);
__self.__op_state_->__data_.template emplace<__decayed_tuple<_Tag, _Args...>>(_Tag{}, (_Args&&) __args...);
// Schedule the completion to happen on the scheduler's
// execution context.
__self.__op_state_->__state2_.emplace(
Expand Down Expand Up @@ -2670,7 +2666,7 @@ _PRAGMA_POP()
// Could be non-atomic here and atomic_ref everywhere except __completion_fn
atomic<__state_t> __state_{__started};
error_types_of_t<__sender, variant> __errors_{};
tuple<value_types_of_t<__t<_SenderIds>, tuple, optional>...> __values_{};
tuple<value_types_of_t<__t<_SenderIds>, __decayed_tuple, optional>...> __values_{};
in_place_stop_source __stop_source_{};
optional<typename stop_token_of_t<_Receiver&>::template
callback_type<__on_stop_requested>> __on_stop_{};
Expand Down Expand Up @@ -2735,7 +2731,7 @@ namespace std::this_thread {
// What should sync_wait(just_done()) return?
template <class _Sender>
using __sync_wait_result_t =
execution::value_types_of_t<_Sender, tuple, __single_t>;
execution::value_types_of_t<_Sender, execution::__decayed_tuple, __single_t>;

template <class _Tuple>
struct __state {
Expand Down
37 changes: 22 additions & 15 deletions std_execution.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2732,11 +2732,14 @@ namespace std::execution {
template&lt;class S>
struct sender_traits;

template &lt;class... Ts>
using <i>decayed-tuple</i> = tuple&lt;decay_t&lt;Ts>...>; // exposition only

template &lt;class... Ts>
using <i>variant-or-empty</i> = <i>see below</i>; // exposition only

template&lt;typed_sender S,
template &lt;class...> class Tuple = tuple,
template &lt;class...> class Tuple = <i>decayed-tuple</i>,
template &lt;class...> class Variant = <i>variant-or-empty</i>>
using value_types_of_t =
typename sender_traits&lt;remove_cvref_t&lt;S>>::template value_types&lt;Tuple, Variant>;
Expand Down Expand Up @@ -3218,13 +3221,17 @@ enum class forward_progress_guarantee {
};
</pre>

5. The exposition-only type <code><i>variant-or-empty&lt;Ts...></i></code> names the type `variant<Ts...>` if `sizeof...(Ts)` is greater than zero; otherwise, it names an implementation defined class type equivalent to the following:
5. The exposition-only type <code><i>variant-or-empty&lt;Ts...></i></code> is defined as follows:

<pre highlight="c++">
struct <i>empty-variant</i> {
<i>empty-variant</i>() = delete;
};
</pre>
1. If `sizeof...(Ts)` is greater than zero, <code><i>variant-or-empty&lt;Ts...></i></code> names the type `variant<Us...>` where `Us...` is the pack `decay_t<Ts>...` with duplicate types removed.

2. Otherwise, <code><i>variant-or-empty&lt;Ts...></i></code> names an implementation defined class type equivalent to the following:

<pre highlight="c++">
struct <i>empty-variant</i> {
<i>empty-variant</i>() = delete;
};
</pre>

6. If `value_types_of_t<S, Tuple, Variant>` for some sender type `S` is well formed, it shall be a type <code>Variant&lt;Tuple&lt;Args<sub>0</sub>...>, Tuple&lt;Args<sub>1</sub>...>, ..., Tuple&lt;Args<sub>N</sub>...>>></code>, where the type packs <code>Args<sub>0</sub></code> through <code>Args<sub>N</sub></code> are the packs of types the sender `S` passes as
arguments to `execution::set_value` after a receiver object. If such sender `S` odr-uses ([basic.def.odr]) `execution::set_value(r, args...)` for some receiver `r`, where `decltype(args)...` is not one of the type packs <code>Args<sub>0</sub>...</code> through <code>Args<sub>N</sub>...</code>, the program is ill-formed with no
Expand Down Expand Up @@ -3328,7 +3335,7 @@ enum class forward_progress_guarantee {
template&lt;class... Ts>
struct <i>just-sender</i> // exposition only
{
std::tuple&lt;Ts...> vs_;
tuple&lt;Ts...> vs_;

template&lt;template&lt;class...> class Tuple, template&lt;class...> class Variant>
using value_types = Variant&lt;Tuple&lt;Ts...>>;
Expand All @@ -3340,7 +3347,7 @@ enum class forward_progress_guarantee {

template&lt;class R>
struct operation_state {
std::tuple&lt;Ts...> vs_;
tuple&lt;Ts...> vs_;
R r_;

friend void tag_invoke(execution::start_t, operation_state& s)
Expand Down Expand Up @@ -3373,7 +3380,7 @@ enum class forward_progress_guarantee {
<i>just-sender</i>&lt;decay_t&lt;Ts>...> just(Ts &&... ts) noexcept(<i>see-below</i>);
</pre>

1. <i>Effects</i>: Initializes `vs_` with `make_tuple(forward<Ts>(ts)...)`.
1. <i>Effects</i>: Initializes `vs_` with <code><i>decayed-tuple</i>&lt;Ts...>(std::forward&lt;Ts>(ts)...)</code>.

2. <i>Remarks</i>: The expression in the `noexcept-specifier` is equivalent to

Expand Down Expand Up @@ -3868,7 +3875,7 @@ are all well-formed.

* If the number of subexpressions <code>s<i><sub>i</sub></i>...</code> is 0, or
* If any type <code>S<i><sub>i</sub></i></code> does not satisfy `execution::typed_sender`, or
* If for any type <code>S<i><sub>i</sub></i></code>, the type <code>value_types_of_t&lt;S<i><sub>i</sub></i>, tuple, <i>zero-or-one</i>></code> is ill-formed, where <code><i>zero-or-one</i></code> is a template alias equivalent to the following:
* If for any type <code>S<i><sub>i</sub></i></code>, the type <code>value_types_of_t&lt;S<i><sub>i</sub></i>, <i>decayed-tuple</i>, <i>zero-or-one</i>></code> is ill-formed, where <code><i>zero-or-one</i></code> is a template alias equivalent to the following:
<pre highlight="c++">
template &lt;class... Ts>
requires (sizeof...(Ts) <= 1)
Expand Down Expand Up @@ -3983,7 +3990,7 @@ are all well-formed.

1. Constructs a receiver `r`:

1. If `execution::set_value(r, ts...)` is called, calls <code>execution::set_value(out_r, <i>into-variant-type</i>&lt;S>(make_tuple(ts...)))</code>.
1. If `execution::set_value(r, ts...)` is called, calls <code>execution::set_value(out_r, <i>into-variant-type</i>&lt;S>(<i>decayed-tuple</i>&lt;decltype(ts)...>(ts...)))</code>.

2. If `execution::set_error(r, e)` is called, calls `execution::set_error(out_r, e)`.

Expand Down Expand Up @@ -4110,7 +4117,7 @@ from the operation before the operation completes.
<pre highlight=c++>
template&lt;typed_sender S>
using <i>sync-wait-type</i> =
optional&lt;execution::value_types_of_t&lt;S, tuple, type_identity_t>>;
optional&lt;execution::value_types_of_t&lt;S, <i>decayed-tuple</i>, type_identity_t>>;

template&lt;typed_sender S>
using <i>sync-wait-with-variant-type</i> =
Expand All @@ -4132,9 +4139,9 @@ from the operation before the operation completes.

3. Blocks the current thread until a receiver completion-signal of `r` is called. When it is:

1. If `execution::set_value(r, ts...)` has been called, returns <code><i>sync-wait-type</i>&lt;S>(make_tuple(ts...))></code>.
1. If `execution::set_value(r, ts...)` has been called, returns <code><i>sync-wait-type</i>&lt;S>(<i>decayed-tuple</i>&lt;decltype(ts)...>(ts...))></code>.

2. If `execution::set_error(r, e...)` has been called, if `remove_cvref_t(decltype(e))` is `exception_ptr`, calls `std::rethrow_exception(e)`. Otherwise, throws `e`.
2. If `execution::set_error(r, e...)` has been called, if `decay_t<decltype(e)>` is `exception_ptr`, calls `std::rethrow_exception(e)`. Otherwise, throws `e`.

3. If `execution::set_done(r)` has been called, returns <code><i>sync-wait-type</i>&lt;S(nullopt)></code>.

Expand Down