Skip to content
Open
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
9 changes: 6 additions & 3 deletions docs/implementation-status.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<!--
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->
# Implementation Status

Meaning of the status indicators (in order best to worst):
Expand All @@ -15,13 +18,13 @@ The indicators come in groups of threes:
Each section containing subelements reflects the state of the "worst" element.

# &#x1F534;&#x1F534;&#x1F534; [exec](https://wg21.link/exec) Execution control library
## &#x1F6A7;&#x2705;&#x2705; [exec.general](https://wg21.link/exec.general) General
## &#x2705;&#x2705;&#x2705; [exec.general](https://wg21.link/exec.general) General

- &#x1F6A7;&#x274E;&#x274E; [<code><i>MANDATE-NOTHROW</i>(expr)</code>](https://wg21.link/exec.general#5) &#x21d2; <code>noexcept(<i>expr</i>)</code> is `true`
- &#x274E;&#x274E;&#x274E; [<code><i>MANDATE-NOTHROW</i>(expr)</code>](https://wg21.link/exec.general#5) &#x21d2; <code>noexcept(<i>expr</i>)</code> is `true`
- &#x2705;&#x2705;&#x2705; [<code><i>movable-value</i>&lt;T&gt;</code>](https://wg21.link/exec.general#6): [`movable_value.hpp`](https://github.com/bemanproject/execution/blob/main/include/beman/execution/detail/movable_value.hpp)
- &#x2705;&#x2705;&#x2705; [<code><i>MATCHING-SIG</i>&lt;F1, F2&gt;</code>](https://wg21.link/exec.general#7): [`matching_sig.hpp`](https://github.com/bemanproject/execution/blob/main/include/beman/execution/detail/matching_sig.hpp)
- &#x2705;&#x2705;&#x2705; [<code><i>AS-EXCEPT-PTR</i>(error)</code>](https://wg21.link/exec.general#8): [`as_except_ptr.hpp`](https://github.com/bemanproject/execution/blob/main/include/beman/execution/detail/as_except_ptr.hpp)
- &#x1F6A7;&#x274E;&#x274E; [<code><i>as-const</i>(error)</code>](https://wg21.link/exec.general#9): <code>[std::as_const](https://wg21.link/utility.as.const)(error)</code>
- &#x274E;&#x274E;&#x274E; [<code><i>as-const</i>(error)</code>](https://wg21.link/exec.general#9): <code>[std::as_const](https://wg21.link/utility.as.const)(error)</code>

## &#x1F6A7;&#x2705;&#x2705; [exec.queryable](https://wg21.link/exec.queryable) Query and queryables
### &#x1F6A7;&#x274E;&#x274E; [exec.queryable.general](https://wg21.link/exec.queryable.general) General
Expand Down
3 changes: 2 additions & 1 deletion docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -821,10 +821,11 @@ tries the following transformations:
<li><code><i>sender-awaitable</i>{<i>adapt-for-await-completion</i>(transform_sender(<i>expr</i>, get_env(<i>promise</i>))), <i>promise</i>}</code> if this expression is well-formed; otherwise</li>
<li><code><i>expr</i></code></li>
</ol>

</details>

- `with_awaitable_sender`
- `apply_sender`

<details>
<summary><code>completion_signatures&lt;<i>Sig</i>...&gt;</code></summary>
The template specialization <code>completion_signatures&lt;<i>Sig</i>...&gt;</code> is a list
Expand Down
3 changes: 2 additions & 1 deletion include/beman/execution/detail/forwarding_query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ namespace beman::execution::detail {
struct forwarding_query_t {
template <typename Object>
requires requires(Object&& object, const forwarding_query_t& query) {
{ ::std::forward<Object>(object).query(query) } noexcept -> ::std::same_as<bool>;
{ ::std::forward<Object>(object).query(query) } -> ::std::same_as<bool>;
}
constexpr auto operator()(Object&& object) const noexcept -> bool {
static_assert(noexcept(::std::forward<Object>(object).query(*this)));
return ::std::forward<Object>(object).query(*this);
}
Comment on lines 25 to 32
template <typename Object>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ import beman.execution.detail.forwarding_query;
namespace beman::execution {
struct get_await_completion_adaptor_t {
template <typename Env>
requires requires(Env&& env, const get_await_completion_adaptor_t& g) {
{ ::std::as_const(env).query(g) } noexcept;
}
requires requires(Env&& env, const get_await_completion_adaptor_t& g) { ::std::as_const(env).query(g); }
auto operator()(Env&& env) const noexcept {
static_assert(noexcept(::std::as_const(env).query(*this)));
return ::std::as_const(env).query(*this);
}
Comment on lines 22 to 28
static constexpr auto query(const ::beman::execution::forwarding_query_t&) noexcept -> bool { return true; }
Expand Down
2 changes: 2 additions & 0 deletions include/beman/execution/detail/get_completion_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ template <typename Q, typename... E>
::beman::execution::scheduler<Q>
auto get_completion_scheduler_t<Tag>::operator()(const Q& q, const E&... e) const noexcept {
if constexpr (::beman::execution::detail::compl_sched_recurse_queryable<Tag, Q, E...>) {
static_assert(noexcept(
::beman::execution::detail::recurse_query(::beman::execution::detail::try_query(q, *this, e...), e...)));
return ::beman::execution::detail::recurse_query(::beman::execution::detail::try_query(q, *this, e...), e...);
} else {
static_assert(::beman::execution::scheduler<Q>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ namespace beman::execution {
struct get_delegation_scheduler_t {
template <typename Env>
requires requires(Env&& env, const get_delegation_scheduler_t& g) {
{ auto(::std::as_const(env).query(g)) } noexcept -> ::beman::execution::scheduler;
{ auto(::std::as_const(env).query(g)) } -> ::beman::execution::scheduler;
}
auto operator()(Env&& env) const noexcept {
static_assert(noexcept(::std::as_const(env).query(*this)));
return ::std::as_const(env).query(*this);
}
Comment on lines 24 to 32
constexpr auto query(const ::beman::execution::forwarding_query_t&) const noexcept -> bool { return true; }
Expand Down
19 changes: 16 additions & 3 deletions include/beman/execution/detail/get_domain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,27 @@ struct get_domain_t : ::beman::execution::forwarding_query_t {
template <typename Env>
constexpr auto operator()(Env&& env) const noexcept {
if constexpr (requires { ::std::as_const(env).query(*this); }) {
return ::std::as_const(env).query(*this);
using type = decltype(auto(::std::as_const(env).query(*this)));
static_assert(noexcept(type{}));
return type{};
} else if constexpr (requires {
Comment on lines 37 to 41
::beman::execution::get_completion_domain<::beman::execution::set_value_t>(
::beman::execution::get_scheduler(env),
::beman::execution::detail::hide_sched(env));
}) {
return ::beman::execution::get_completion_domain<::beman::execution::set_value_t>(
::beman::execution::get_scheduler(env), ::beman::execution::detail::hide_sched(env));
using type = decltype(auto(::beman::execution::get_completion_domain<::beman::execution::set_value_t>(
::beman::execution::get_scheduler(env), ::beman::execution::detail::hide_sched(env))));
static_assert(noexcept(type{}));
return type{};
} else if constexpr (requires {
::beman::execution::get_completion_domain<::beman::execution::set_value_t>(
::beman::execution::get_scheduler(env),
::beman::execution::detail::hide_sched(env));
}) {
using type = decltype(auto(::beman::execution::get_completion_domain<::beman::execution::set_value_t>(
::beman::execution::get_scheduler(env), ::beman::execution::detail::hide_sched(env))));
static_assert(noexcept(type{}));
return type{};
} else {
return ::beman::execution::default_domain{};
}
Expand Down
11 changes: 6 additions & 5 deletions include/beman/execution/detail/get_env.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ struct get_env_t {
std::remove_cvref_t<decltype(::std::declval<const ::std::remove_cvref_t<Object>&>().get_env())>>)
auto operator()(Object&& object) const noexcept -> decltype(auto) {
::std::add_const_t<::std::remove_cvref_t<Object>>& obj{object};
if constexpr (requires { obj.get_env(); }) {
static_assert(noexcept(obj.get_env()), "get_env requires the expression to be noexcept");
static_assert(::beman::execution::detail::queryable<std::remove_cvref_t<decltype(obj.get_env())>>,
"get_env requires the result type to be destructible");
return obj.get_env();
if constexpr (requires { ::std::as_const(obj).get_env(); }) {
static_assert(noexcept(::std::as_const(obj).get_env()), "get_env requires the expression to be noexcept");
static_assert(
::beman::execution::detail::queryable<std::remove_cvref_t<decltype(::std::as_const(obj).get_env())>>,
"get_env requires the result type to be destructible");
return ::std::as_const(obj).get_env();
} else {
return ::beman::execution::env<>{};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct get_forward_progress_guarantee_t {
template <beman::execution::detail::almost_scheduler Object>
requires requires(const Object& object, const get_forward_progress_guarantee_t& tag) { object.query(tag); }
auto operator()(const Object& object) const noexcept -> forward_progress_guarantee {
static_assert(noexcept(object.query(*this)));
static_assert(::std::same_as<decltype(object.query(*this)), forward_progress_guarantee>);
return object.query(*this);
}
Expand Down
2 changes: 2 additions & 0 deletions include/beman/execution/detail/get_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ struct get_scheduler_t : ::beman::execution::forwarding_query_t {
::std::as_const(env).query(self), ::beman::execution::detail::hide_sched(env));
}
auto operator()(Env&& env) const noexcept {
static_assert(noexcept(::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>(
::std::as_const(env).query(*this), ::beman::execution::detail::hide_sched(env))));
return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>(
::std::as_const(env).query(*this), ::beman::execution::detail::hide_sched(env));
}
Expand Down
5 changes: 3 additions & 2 deletions include/beman/execution/detail/get_start_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ namespace beman::execution {
struct get_start_scheduler_t : ::beman::execution::forwarding_query_t {
template <typename Env>
requires requires(const get_start_scheduler_t& self, const Env& env) {
{ auto(::std::as_const(env).query(self)) } noexcept -> beman::execution::scheduler;
{ auto(::std::as_const(env).query(self)) } -> beman::execution::scheduler;
}
auto operator()(const Env& env) const noexcept {
return env.query(*this);
static_assert(noexcept(::std::as_const(env).query(*this)));
return ::std::as_const(env).query(*this);
}
Comment on lines 25 to 32
};

Expand Down
3 changes: 2 additions & 1 deletion include/beman/execution/detail/get_stop_token.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ namespace beman::execution {
struct get_stop_token_t {
template <typename Object>
requires requires(Object&& object, const get_stop_token_t& tag) {
{ ::std::as_const(object).query(tag) } noexcept -> ::beman::execution::detail::decayed_stoppable_token;
{ ::std::as_const(object).query(tag) } -> ::beman::execution::detail::decayed_stoppable_token;
}
auto operator()(Object&& object) const noexcept {
static_assert(noexcept(::std::as_const(object).query(*this)));
return ::std::as_const(object).query(*this);
}
Comment on lines 31 to 39

Expand Down
6 changes: 2 additions & 4 deletions include/beman/execution/detail/set_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@ struct set_error_t {
::std::forward<Receiver>(receiver).set_error(::std::forward<Error>(error));
})
= BEMAN_EXECUTION_DELETE("set_error requires a suitable member overload on the receiver");
template <typename Receiver, typename Error>
requires(not noexcept(::std::declval<Receiver>().set_error(::std::declval<Error>())))
auto operator()(Receiver&&, Error&&) const
-> void = BEMAN_EXECUTION_DELETE("the call to receiver.set_error(error) has to be noexcept");

// NOLINTBEGIN(misc-no-recursion)
template <typename Receiver, typename Error>
auto operator()(Receiver&& receiver, Error&& error) const noexcept -> void {
static_assert(noexcept(::std::forward<Receiver>(receiver).set_error(::std::forward<Error>(error))),
"the call to receiver.set_error(error) has to be noexcept");
::std::forward<Receiver>(receiver).set_error(::std::forward<Error>(error));
}
Comment on lines 36 to 42
// NOLINTEND(misc-no-recursion)
Expand Down
6 changes: 2 additions & 4 deletions include/beman/execution/detail/set_stopped.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,11 @@ struct set_stopped_t {
auto operator()(Receiver&&) const -> void
requires(not requires(Receiver&& receiver) { ::std::forward<Receiver>(receiver).set_stopped(); })
= BEMAN_EXECUTION_DELETE("set_stopped requires a suitable member overload on the receiver");
template <typename Receiver>
requires(not noexcept(::std::declval<Receiver>().set_stopped()))
auto operator()(Receiver&&) const
-> void = BEMAN_EXECUTION_DELETE("the call to receiver.set_stopped() has to be noexcept");

template <typename Receiver>
auto operator()(Receiver&& receiver) const noexcept -> void {
static_assert(noexcept(::std::forward<Receiver>(receiver).set_stopped()),
"the call to receiver.set_stopped() has to be noexcept");
::std::forward<Receiver>(receiver).set_stopped();
}
Comment on lines 30 to 39
};
Expand Down
3 changes: 3 additions & 0 deletions include/beman/execution/detail/set_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ struct set_value_t {

template <typename Receiver, typename... Args>
auto operator()(Receiver&& receiver, Args&&... args) const noexcept -> void {
static_assert(noexcept(::std::forward<Receiver>(receiver).set_value(::std::forward<Args>(args)...)),
"the call to receiver.set_value(args...) has to be noexcept");

::std::forward<Receiver>(receiver).set_value(::std::forward<Args>(args)...);
}
};
Expand Down
13 changes: 2 additions & 11 deletions include/beman/execution/detail/start.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,15 @@ struct start_t {
requires(not requires(const State& state) { state.start(); })
auto operator()(const State&) const -> void = BEMAN_EXECUTION_DELETE("state needs to have a start() member");

template <typename State>
requires(not requires(State& state) {
{ state.start() } noexcept;
})
auto operator()(State&) const -> void = BEMAN_EXECUTION_DELETE("state start() member has to be noexcept");
template <typename State>
requires(not requires(const State& state) {
{ state.start() } noexcept;
})
auto operator()(const State&) const -> void = BEMAN_EXECUTION_DELETE("state start() member has to be noexcept");

template <typename State>
auto operator()(const State& state) const noexcept -> void {
static_assert(noexcept(state.start()), "state start() member has to be noexcept");
state.start();
}
// NOLINTBEGIN(misc-no-recursion)
template <typename State>
auto operator()(State& state) const noexcept -> void {
static_assert(noexcept(state.start()), "state start() member has to be noexcept");
state.start();
}
Comment on lines 23 to 33
// NOLINTEND(misc-no-recursion)
Expand Down
53 changes: 35 additions & 18 deletions include/beman/execution/detail/stop_when.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#ifdef BEMAN_HAS_IMPORT_STD
import std;
#else
#include <iostream>
#include <optional>
#include <type_traits>
#include <utility>
Expand Down Expand Up @@ -67,24 +68,32 @@ struct beman::execution::detail::stop_when_t::sender {
std::remove_cvref_t<Sndr> sndr;

template <::beman::execution::receiver Rcvr>
struct state {
struct base_state {
using rcvr_t = ::std::remove_cvref_t<Rcvr>;
rcvr_t rcvr;
::beman::execution::inplace_stop_source source{};
base_state(Rcvr&& r) : rcvr(::std::forward<Rcvr>(r)) {}
virtual ~base_state() noexcept = default;
virtual auto reset() & noexcept -> void = 0;
};
Comment on lines 70 to +78
template <::beman::execution::receiver Rcvr>
struct state : base_state<Rcvr> {
using operation_state_concept = ::beman::execution::operation_state_tag;
using rcvr_t = ::std::remove_cvref_t<Rcvr>;
using rcvr_t = base_state<Rcvr>::rcvr_t;
using token1_t = ::std::remove_cvref_t<Tok>;
using token2_t =
decltype(::beman::execution::get_stop_token(::beman::execution::get_env(::std::declval<rcvr_t>())));

struct cb_t {
::beman::execution::inplace_stop_source& source;
auto operator()() const noexcept { this->source.request_stop(); }
};
struct base_state {
rcvr_t rcvr;
::beman::execution::inplace_stop_source source{};
auto operator()() const noexcept {
::std::cout << "stop_when: stop requested\n" << ::std::flush;
this->source.request_stop();
}
Comment on lines +89 to +92
};
struct env {
base_state* st;
auto query(const ::beman::execution::get_stop_token_t&) const noexcept {
base_state<Rcvr>* st;
auto query(const ::beman::execution::get_stop_token_t&) const noexcept {
return this->st->source.get_token();
}
template <typename Q, typename... A>
Expand All @@ -98,40 +107,48 @@ struct beman::execution::detail::stop_when_t::sender {

struct receiver {
using receiver_concept = ::beman::execution::receiver_tag;
base_state* st;
base_state<Rcvr>* st;

auto get_env() const noexcept -> env { return env{this->st}; }
template <typename... A>
auto set_value(A&&... a) const noexcept -> void {
this->st->reset();
::beman::execution::set_value(::std::move(this->st->rcvr), ::std::forward<A>(a)...);
}
template <typename E>
auto set_error(E&& e) const noexcept -> void {
this->st->reset();
::beman::execution::set_error(::std::move(this->st->rcvr), ::std::forward<E>(e));
}
auto set_stopped() const noexcept -> void { ::beman::execution::set_stopped(::std::move(this->st->rcvr)); }
auto set_stopped() const noexcept -> void {
this->st->reset();
::beman::execution::set_stopped(::std::move(this->st->rcvr));
}
};
using inner_state_t =
decltype(::beman::execution::connect(::std::declval<Sndr>(), ::std::declval<receiver>()));

token1_t tok;
base_state base;
std::optional<::beman::execution::stop_callback_for_t<token1_t, cb_t>> cb1;
std::optional<::beman::execution::stop_callback_for_t<token2_t, cb_t>> cb2;
inner_state_t inner_state;

template <::beman::execution::sender S, ::beman::execution::stoppable_token T, ::beman::execution::receiver R>
state(S&& s, T&& t, R&& r)
: tok(::std::forward<T>(t)),
base{::std::forward<R>(r)},
inner_state(::beman::execution::connect(::std::forward<S>(s), receiver{&this->base})) {}
: base_state<Rcvr>{::std::forward<R>(r)},
tok(::std::forward<T>(t)),
inner_state(::beman::execution::connect(::std::forward<S>(s), receiver{this})) {}

auto start() & noexcept {
this->cb1.emplace(this->tok, cb_t{this->base.source});
this->cb2.emplace(::beman::execution::get_stop_token(::beman::execution::get_env(this->base.rcvr)),
cb_t{this->base.source});
this->cb1.emplace(this->tok, cb_t{this->source});
this->cb2.emplace(::beman::execution::get_stop_token(::beman::execution::get_env(this->rcvr)),
cb_t{this->source});
::beman::execution::start(this->inner_state);
}
auto reset() & noexcept -> void override {
this->cb1.reset();
this->cb2.reset();
}
};

template <typename, typename... E>
Expand Down
3 changes: 2 additions & 1 deletion tests/beman/execution/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ if(BEMAN_USE_MODULES)
list(APPEND execution_tests execution-module.test stop-token-module.test)
endif()

list(APPEND unsupported_execution_tests exec-split.test exec-spawn-future.test)
list(APPEND unsupported_execution_tests exec-split.test)

list(
APPEND execution_tests
Expand Down Expand Up @@ -64,6 +64,7 @@ list(
exec-snd-expos.test
exec-snd-transform.test
exec-spawn.test
exec-spawn-future.test
exec-starts-on.test
exec-stop-when.test
exec-stopped-err.test
Expand Down
Loading