Skip to content

Commit 7117f8a

Browse files
committed
Merge branch 'main' into async-scope
2 parents 630c20a + 9edc153 commit 7117f8a

File tree

17 files changed

+348
-32
lines changed

17 files changed

+348
-32
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
22
# Codeowners for reviews on PRs
33

4-
* @dietmarkuehl @camio @bemanproject/core-reviewers
4+
* @dietmarkuehl @camio @neatudarius

docs/overview.md

Lines changed: 115 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,6 @@ The expression <code>get_allocator(<i>env</i>)</code> returns an <code><i>alloca
446446
<li>the result of the expression satisfies <code><i>simple-allocator</i></code>.</li>
447447
</ul>
448448
Otherwise the expression is ill-formed.
449-
</details>
450449
<div>
451450
<details>
452451
<summary>Example</summary>
@@ -560,7 +559,8 @@ Otherwise the value is <code>never_stop_token{}</code>.
560559
## Customization Point Objects
561560

562561
<details>
563-
<summary><code>connect(<i>sender, receiver</i>) -> <i>operation_state</i></code></summary>
562+
<summary><code>connect(<i>sender</i>, <i>receiver</i>) -> <i>operation_state</i></code></summary>
563+
The expresion <code>connect(<i>sender</i>, <i>receiver</i>)</code> combines <code><i>sender</i></code> and <code><i>receiver</i></code> into an operation state <code><i>state</i></code>. When this <code><i>state</i></code> gets started using <code>start(<i>state</i>)</code> the operation represented by <code><i>sender</i></code> gets started and reports its completion to <code><i>receiver</i></code> or an object copied or moved from <code><i>receiver</i></code>. While the operation state <code><i>state</i></code> isn’t started it can be destroyed but once it got started it needs to stay valid until one of the completion signals is called on <code><i>receiver</i></code>.
564564
</details>
565565
<details>
566566
<summary><code>set_error(<i>receiver</i>, <i>error</i>) noexcept -> void</code></summary>
@@ -583,31 +583,122 @@ The expression <code>start(<i>state</i>)</code> starts the execution of the <cod
583583

584584
### Sender Factories
585585

586-
- <code>just(<i>value...</i>) -> <i>sender-of</i>&lt;set_value_t(<i>Value...</i>)&gt;</code>
587-
- <code>just_error(<i>error</i>) -> <i>sender-of</i>&lt;set_error_t(<i>Error</i>)&gt;</code>
588-
- <code>just_stopped() -> <i>sender-of</i>&lt;set_stopped_t()&gt;</code>
589-
- <code>read_env(<i>query</i>) -> <i>sender-of</i>&lt;set_value_t(<i>query-result</i>)&gt;</code>
590-
- <code>schedule(<i>scheduler</i>) -> <i>sender-of</i>&lt;set_value_t()&gt;</code>
586+
Sender factories create a sender which forms the start of a graph of lazy work items.
587+
588+
<details>
589+
<summary><code>just(<i>value...</i>) -> <i>sender-of</i>&lt;set_value_t(<i>Value...</i>)&gt;</code></summary>
590+
The expression <code>just(<i>value...</i>)</code> creates a sender which sends <code><i>value...</i></code> on the `set_value` (success) channel when started (note that <code><i>value...</i></code> can be empty).
591+
592+
<b>Completions</b>
593+
<ul>
594+
<li><code>set_value_t(decltype(<i>value</i>)...)</code></li>
595+
</ul>
596+
</details>
597+
<details>
598+
<summary><code>just_error(<i>error</i>) -> <i>sender-of</i>&lt;set_error_t(<i>Error</i>)&gt;</code></code></summary>
599+
The expression <code>just_error(<i>error</i>)</code> creates a sender which sends <code><i>error</i></code> on the `set_error` (failure) channel when started.
600+
601+
<b>Completions</b>
602+
<ul>
603+
<li><code>set_error_t(decltype(<i>error</i>))</code></li>
604+
</ul>
605+
</details>
606+
<details>
607+
<summary><code>just_stopped() -> <i>sender-of</i>&lt;set_stopped_t()&gt;</code></code></summary>
608+
The expression <code>just_stopped()</code> creates a sender which sends a completion on the `set_stopped` (cancellation) channel when started.
609+
610+
<b>Completions</b>
611+
<ul>
612+
<li><code>set_stopped_t()</code></li>
613+
</ul>
614+
</details>
615+
<details>
616+
<summary><code>read_env(<i>query</i>) -> <i>sender-of</i>&lt;set_value_t(<i>query-result</i>)&gt;</code></code></summary>
617+
The expression <code>read_env(<i>query</i>)</code> creates a sender which sends the result of querying <code><i>query</i></code> the environment of the <code><i>receiver</i></code> it gets connected to on the `set_value` channel when started. Put differently, it calls <code>set_value(move(<i>receiver</i>), <i>query</i>(get_env(<i>receiver</i>)))</code>. For example, in a coroutine it may be useful to extra the stop token associated with the coroutine which can be done using <code>read_env</code>:
618+
619+
```c++\
620+
auto token = co_await read_env(get_stop_token);
621+
```
622+
623+
<b>Completions</b>
624+
<ul>
625+
<li><code>set_value_t(decltype(<i>query</i>(get_env(<i>receiver</i>))))</code>
626+
</ul>
627+
</details>
628+
<details>
629+
<summary><code>schedule(<i>scheduler</i>) -> <i>sender-of</i>&lt;set_value_t()&gt;</code></code></summary>
630+
The expression <code>schedule(<i>scheduler</i>)</code> creates a sender which upon success completes on the <code>set_value</code> channel without any arguments running on the execution context associated with <code><i>scheduler</i></code>. Depending on the scheduler it is possible that the sender can complete with an error if the scheduling fails or using `set_stopped()` if the operation gets cancelled before it is successful.
631+
632+
<b>Completions</b>
633+
<ul>
634+
<li><code>set_value_t()</code> upon success</li>
635+
<li><code>set_error_t(<i>Error</i>)</code> upon failure if <code><i>scheduler</i></code> may fail</li>
636+
<li><code>set_stopped_t()</code> upon cancellation if <code><i>scheduler</i></code> supports cancellation
637+
</ul>
638+
</details>
591639

592640
### Sender Adaptors
641+
The sender adaptors take one or more senders and adapt their respective behavior to complete with a corresponding result. The description uses the informal function <code><i>completions-of</i>(<i>sender</i>)</code> to represent the completion signatures which <code><i>sender</i></code> produces. Also, completion signatures are combined using <code>+</code>: the result is the deduplicated set of the combined completion signatures.
642+
643+
<details>
644+
<summary>`bulk`</summary>
645+
</details>
646+
<details>
647+
<summary><code>continues_on(<i>sender</i>, <i>scheduler</i>) -> <i>sender-of</i><<i>completions-of</i>(<i>sender</i>) + <i>completions-of</i>(schedule(<i>scheduler</i>))></code></summary>
648+
The expression <code>continues_on(<i>sender</i>, <i>scheduler</i>)</code> creates a sender <code><i>cs</i></code> which starts <code><i>sender</i></code> when started. The results from <code><i>sender</i></code> are stored. Once that is <code><i>cs</i></code> creates a sender using <code>schedule(<i>scheduler</i>)</code> and completes itself on the execution once that sender completes.
593649

594-
- `bulk`
595-
- <code>continues_on(<i>sender</i>, <i>scheduler</i>) -> <i>sender</i></code>
596-
- <code>into_variant(<i>sender</i>) -> <i>sender-of</i>&lt;set_value_t(std::variant&lt;T...&gt;)&gt;</code>`
597-
- <code>let_error(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code>
598-
- <code>let_stopped(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code>
599-
- <code>let_value(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code>
600-
- `on`
601-
- <code>schedule_from(<i>scheduler</i>, <i>sender</i>) -> <i>sender</i></code>
602-
- `split`
603-
- <code>starts_on(<i>scheduler</i>, <i>sender</i>) -> <i>sender</i></code>
604-
- `stopped_as_error`
605-
- `stopped_as_optional`
606-
- <code>then(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code>
607-
- <code>upon_error(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code>
608-
- <code>upon_stopped(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code>
609-
- <code>when_all(<i>sender</i>...) -> <i>sender</i></code>
610-
- <code>when_all_with_variant(<i>sender</i>...) -> <i>sender</i></code>
650+
<b>Completions</b>
651+
<ul>
652+
<li><code><i>completions-of</i>(<i>sender</i>)</code></li>
653+
<li><code><i>completions-of</i>(schedule(<i>scheduler</i>))</code></li>
654+
</ul>
655+
</details>
656+
<details>
657+
<summary><code>into_variant(<i>sender</i>) -> <i>sender-of</i>&lt;set_value_t(std::variant&lt;<i>Tuple</i>...&gt;)&gt;</code></summary>
658+
The expression <code>into_variant(<i>sender</i>)</code> creates a sender which transforms the results of possibly multiple <code>set_value</code> completions of <code><i>sender</i></code> into one <code>set_value</code> completion respresenting the different upstream results as different options of a <code>variant&lt;<i>Tuple</i>...&gt;</code> where each <code><i>Tuple</i></code> is a <code>tuple</code> of values initialized with the respective arguments passed to <code>set_value</code>. The order of options in the <code>variant</code> isn’t specified.
659+
</details>
660+
<details>
661+
<summary><code>let_error(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code></summary>
662+
</details>
663+
<details>
664+
<summary><code>let_stopped(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code></summary>
665+
</details>
666+
<details>
667+
<summary><code>let_value(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code></summary>
668+
</details>
669+
<details>
670+
<summary>`on`</summary>
671+
</details>
672+
<details>
673+
<summary><code>schedule_from(<i>scheduler</i>, <i>sender</i>) -> <i>sender</i></code></summary>
674+
</details>
675+
<details>
676+
<summary>`split`</summary>
677+
</details>
678+
<details>
679+
<summary><code>starts_on(<i>scheduler</i>, <i>sender</i>) -> <i>sender</i></code></summary>
680+
</details>
681+
<details>
682+
<summary>`stopped_as_error`</summary>
683+
</details>
684+
<details>
685+
<summary>`stopped_as_optional`</summary>
686+
</details>
687+
<details>
688+
<summary><code>then(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code></summary>
689+
</details>
690+
<details>
691+
<summary><code>upon_error(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code></summary>
692+
</details>
693+
<details>
694+
<summary><code>upon_stopped(<i>upstream</i>, <i>fun</i>) -> <i>sender</i></code></summary>
695+
</details>
696+
<details>
697+
<summary><code>when_all(<i>sender</i>...) -> <i>sender</i></code></summary>
698+
</details>
699+
<details>
700+
<summary><code>when_all_with_variant(<i>sender</i>...) -> <i>sender</i></code></summary>
701+
</details>
611702

612703
### Sender Consumers
613704

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
list(
77
APPEND
88
EXAMPLES
9+
inspect
910
playground
1011
sender-demo
1112
when_all-cancel

examples/inspect.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// examples/inspectc.pp -*-C++-*-
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#include <beman/execution/execution.hpp>
5+
#include "meta.hpp"
6+
#include <iostream>
7+
#include <sstream>
8+
#include <typeinfo>
9+
10+
namespace ex = beman::execution;
11+
12+
// ----------------------------------------------------------------------------
13+
14+
namespace {
15+
struct logger_t {
16+
template <ex::sender Sndr, ex::receiver Rcvr, typename Log>
17+
struct state {
18+
using operation_state_concept = ex::operation_state_t;
19+
using inner_t = decltype(ex::connect(std::declval<Sndr>(), std::declval<Rcvr>()));
20+
21+
inner_t inner;
22+
std::remove_cvref_t<Log> log;
23+
state(Sndr&& s, Rcvr&& r, Log&& l)
24+
: inner(ex::connect(std::forward<Sndr>(s), std::forward<Rcvr>(r))), log(std::forward<Log>(l)) {}
25+
auto start() & noexcept -> void {
26+
this->log(meta::type<decltype(ex::get_completion_signatures(std::declval<Sndr>(),
27+
ex::get_env(std::declval<Rcvr>())))>::name());
28+
ex::start(this->inner);
29+
}
30+
};
31+
32+
template <ex::sender Sndr, typename Log>
33+
struct sender {
34+
using sender_concept = ex::sender_t;
35+
36+
Sndr sndr;
37+
Log log;
38+
39+
template <typename Env>
40+
auto get_completion_signatures(const Env& env) const noexcept {
41+
return ex::get_completion_signatures(this->sndr, env);
42+
}
43+
44+
template <ex::receiver Receiver>
45+
auto connect(Receiver&& receiver) && noexcept(noexcept(ex::connect(std::move(this->sndr),
46+
std::forward<Receiver>(receiver)))) {
47+
return state<Sndr, Receiver, Log>(
48+
std::move(this->sndr), std::forward<Receiver>(receiver), std::move(this->log));
49+
}
50+
};
51+
52+
template <ex::sender Sndr, typename Log>
53+
auto operator()(Sndr&& sndr, Log&& log) const {
54+
return sender<std::remove_cvref_t<Sndr>, std::remove_cvref_t<Log>>{std::forward<Sndr>(sndr),
55+
std::forward<Log>(log)};
56+
}
57+
};
58+
59+
inline constexpr logger_t logger{};
60+
} // namespace
61+
62+
// ----------------------------------------------------------------------------
63+
64+
int main() {
65+
auto log = [](std::string_view name) {
66+
return [name](std::string_view msg) { std::cout << name << " message='" << msg << "'\n"; };
67+
};
68+
69+
ex::sync_wait(logger(ex::just(), log("just()")));
70+
ex::sync_wait(logger(ex::just() | ex::then([]() {}), log("just() | then(...)")));
71+
ex::sync_wait(logger(ex::just() | ex::then([]() noexcept {}), log("just() | then(...)")));
72+
ex::sync_wait(logger(ex::just(0, 1), log("just(0, 1)")));
73+
ex::sync_wait(logger(ex::just(0, 1, 2), log("just(0, 1, 2)")));
74+
ex::sync_wait(logger(ex::just_error(0), log("just_error(0)")) | ex::upon_error([](auto) {}));
75+
ex::sync_wait(logger(ex::just_stopped(), log("just_stopped()")) | ex::upon_stopped([]() {}));
76+
}

examples/intro-1-hello-world.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ int main() {
1818
ex::when_all(
1919
ex::just("hello, "s),
2020
ex::just("world"s)
21-
) | ex::then([](auto s1, auto s2) { return s1 + s2; })
21+
) | ex::then([](auto const& s1, auto const& s2) { return s1 + s2; })
2222
).value_or(std::tuple(""s)
2323
);
2424
// clang-format on

examples/intro-2-hello-async.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ int main() {
3030
| ex::then([] { std::cout << ",\n"; return std::string(", "); }),
3131
timer.resume_after(2s)
3232
| ex::then([] { std::cout << "w\n"; return std::string("world"); })
33-
) | ex::then([](auto s1, auto s2, auto s3) { return s1 + s2 + s3; })
33+
) | ex::then([](auto const& s1, auto const& s2, auto const& s3) { return s1 + s2 + s3; })
3434
)
3535
).value_or(std::tuple(std::string("")));
3636
// clang-format on

examples/intro-5-consumer.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
#include <iostream>
88
#include <string>
99
#include <tuple>
10+
#include <cinttypes>
1011

1112
namespace ex = ::beman::execution;
1213
using namespace std::string_literals;
1314

14-
enum class success { one };
15-
enum class failure { fail_one };
15+
enum class success : std::uint8_t { one };
16+
enum class failure : std::uint8_t { fail_one };
1617

1718
struct expected_to_channel_t {
1819
template <typename Receiver>

0 commit comments

Comments
 (0)