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
423 changes: 423 additions & 0 deletions docs/create-a-sender.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ endif()
set(TODO suspend_never) #-dk:TODO including that causes ASAN errors

set(EXAMPLES
tutorial-create-a-sender
allocator
doc_just
doc_just_error
Expand All @@ -35,6 +36,9 @@ set(EXAMPLES
stop_token
when_all_cancel
)
set(xEXAMPLES
tutorial-create-a-sender
)
Comment on lines +39 to +41

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pre-commit] reported by reviewdog 🐶

Suggested change
set(xEXAMPLES
tutorial-create-a-sender
)
set(xEXAMPLES tutorial-create-a-sender)


if(BEMAN_USE_MODULES)
#-dk:TODO gcc doesn't like the modules: list(APPEND EXAMPLES modules modules_and_header)
Expand Down
198 changes: 198 additions & 0 deletions examples/tutorial-create-a-sender.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// examples/tutorial/create-a-sender.cpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <iostream>
#include <optional>
#include <stack>
#ifdef BEMAN_HAS_MODULES
import beman.execution;
import beman.execution.detail;
#else
#include <beman/execution/execution.hpp>
#endif

namespace ex = beman::execution;

namespace {
template <typename T>
class asynchronous_stack {
struct node {
node* next{};
virtual void complete(T) = 0;
};
std::stack<T> stack;
node* awaiting{};

template <ex::receiver Rcvr>
struct state : node {
using operation_state_concept = ex::operation_state_tag;
struct stop_fun {
state& st;
void operator()() noexcept {
std::cout << "stop callback start\n";
state& s = this->st;
this->st.callback.reset();
for (auto it{&this->st.self.awaiting}; it; it = &(*it)->next) {
if (*it == &this->st) {
*it = this->st.next;
break;
}
}
std::cout << "stop callback completing\n";
ex::set_stopped(std::move(s.rcvr));
std::cout << "stop callback done\n";
}
};
using stop_token_t = ex::stop_token_of_t<decltype(ex::get_env(std::declval<Rcvr&>()))>;
using callback_t = ex::stop_callback_for_t<stop_token_t, stop_fun>;
std::remove_cvref_t<Rcvr> rcvr;
asynchronous_stack& self;
std::optional<callback_t> callback;
state(Rcvr&& r, asynchronous_stack& s) : rcvr(std::forward<Rcvr>(r)), self(s) {}
void start() & noexcept {
if (not this->self.stack.empty()) {
T value(std::move(this->self.stack.top()));
this->self.stack.pop();
ex::set_value(std::move(rcvr), std::move(value));
} else {
this->next = std::exchange(this->self.awaiting, this);
this->callback.emplace(ex::get_stop_token(ex::get_env(this->rcvr)), stop_fun{*this});
}
}
void complete(T value) override {
this->callback.reset();
ex::set_value(std::move(rcvr), std::move(value));
}
};

public:
struct pop_sender {
using sender_concept = ex::sender_tag;
template <typename...>
static consteval auto get_completion_signatures() {
return ex::completion_signatures<ex::set_value_t(T), ex::set_stopped_t()>{};
}

asynchronous_stack& self;
template <ex::receiver Rcvr>
auto connect(Rcvr&& rcvr) const {
static_assert(ex::operation_state<state<Rcvr>>);
return state<Rcvr>{std::forward<Rcvr>(rcvr), self};
}
};

void push(T value) {
if (this->awaiting) {
std::exchange(this->awaiting, this->awaiting->next)->complete(std::move(value));
} else {
this->stack.push(std::move(value));
}
}
pop_sender pop() { return pop_sender{*this}; }
};

static_assert(ex::sender<asynchronous_stack<int>::pop_sender>);
static_assert(ex::sender_in<asynchronous_stack<int>::pop_sender>);

struct stop_test {
using sender_concept = ex::sender_tag;
template <typename...>
static consteval auto get_completion_signatures() {
return ex::completion_signatures<ex::set_value_t()>();
}
template <typename Rcvr>
struct state {
using operation_state_concept = ex::operation_state_tag;

struct cb {
state* self;
auto operator()() const noexcept -> void {
std::cout << "cb\n";
ex::set_value(std::move(self->rcvr));
}
};
using callback = ex::stop_callback_for_t<ex::stop_token_of_t<ex::env_of_t<Rcvr>>, cb>;

std::remove_cvref_t<Rcvr> rcvr;
std::optional<callback> callb;
auto start() & noexcept -> void {
std::cout << "stop_test start\n";
this->callb.emplace(ex::get_stop_token(ex::get_env(this->rcvr)), cb{this});
}
};
template <typename Rcvr>
state<Rcvr> connect(Rcvr&& rcvr) const {
return {std::forward<Rcvr>(rcvr)};
}
};
} // namespace
// ----------------------------------------------------------------------------

int main() {
std::cout << std::unitbuf;
#if 1
asynchronous_stack<int> st;
ex::counting_scope scope;
[[maybe_unused]] auto sender = st.pop() | ex::then([](int v) { std::cout << "got value=" << v << "\n"; });

#if 1
for (int value{1}; value < 4; ++value) {
st.push(value);
}
std::cout << "pushed 1,2,3\n";

int count{8};
for (int value{1}; value < count; ++value) {
ex::spawn(st.pop() | ex::then([value](int v) noexcept {
std::cout << "got value=" << v << " for request " << value << "\n";
}) | ex::upon_stopped([value] noexcept { std::cout << "request " << value << " was stopped\n"; }),
scope.get_token());
}

std::cout << "requested " << (count - 1) << " values\n";

for (int value{4}; value < 7; ++value) {
st.push(value);
}
std::cout << "pushed 4,5,6\n";
#endif

std::cout << "requesting stop\n";
scope.request_stop();
std::cout << "requested stop\n";
ex::sync_wait(scope.join() | ex::then([] { std::cout << "joined\n"; }));
std::cout << "joined\n";
#else

std::optional<ex::inplace_stop_source> source1{};
source1.emplace();
std::optional<ex::inplace_stop_source> source2{};
source2.emplace();
struct receiver {
using receiver_concept = ex::receiver_tag;
std::optional<ex::inplace_stop_source>& source1;
std::optional<ex::inplace_stop_source>& source2;
auto query(ex::get_stop_token_t) const noexcept { return this->source2->get_token(); }
auto get_env() const noexcept {
std::cout << "get_env\n";
return *this;
}
auto set_value() noexcept {
std::cout << "receiver::set_value\n";
source1.reset();
std::cout << "receiver::set_value done\n";
}
auto set_stopped() noexcept { std::cout << "receiver::set_stopped\n"; }
};
#if 1
auto sws(ex::connect(ex::detail::stop_when(stop_test(), source1->get_token()), receiver{source1, source2}));
#else
auto sws(ex::connect(stop_test(), receiver{source1, source2}));
#endif
std::cout << "start\n";
ex::start(sws);
std::cout << "request stop\n";
source1->request_stop();
std::cout << "requested stop\n";
#endif
}
6 changes: 3 additions & 3 deletions include/beman/execution/detail/call_result_t.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/call_result_t.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_RESULT
#define INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_RESULT
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_RESULT_T
#define INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_RESULT_T

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
Expand All @@ -25,4 +25,4 @@ using call_result_t = decltype(::std::declval<Fun>()(std::declval<Args>()...));

// ----------------------------------------------------------------------------

#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_RESULT
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_RESULT_T
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/completion_signaturess_of_t.hpp -*-C++-*-
// include/beman/execution/detail/completion_signatures_of_t.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_SIGNATURES_OF
#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_SIGNATURES_OF
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_SIGNATURES_OF_T
#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_SIGNATURES_OF_T

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_MODULES
Expand Down Expand Up @@ -31,4 +31,4 @@ using completion_signatures_of_t = decltype(::beman::execution::get_completion_s

// ----------------------------------------------------------------------------

#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_SIGNATURES_OF
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_SIGNATURES_OF_T
6 changes: 3 additions & 3 deletions include/beman/execution/detail/connect_result_t.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/connect_result_t.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_CONNECT_RESULT
#define INCLUDED_BEMAN_EXECUTION_DETAIL_CONNECT_RESULT
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_CONNECT_RESULT_T
#define INCLUDED_BEMAN_EXECUTION_DETAIL_CONNECT_RESULT_T

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
Expand All @@ -29,4 +29,4 @@ using connect_result_t = decltype(::beman::execution::connect(::std::declval<Sen

// ----------------------------------------------------------------------------

#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CONNECT_RESULT
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CONNECT_RESULT_T
4 changes: 2 additions & 2 deletions include/beman/execution/detail/dependent_sender_error.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/dependent_sender_error.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_DEPENDENT_SENDER_ERROR
#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_DEPENDENT_SENDER_ERROR
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_DEPENDENT_SENDER_ERROR
#define INCLUDED_BEMAN_EXECUTION_DETAIL_DEPENDENT_SENDER_ERROR

// ----------------------------------------------------------------------------

Expand Down
6 changes: 3 additions & 3 deletions include/beman/execution/detail/env_of_t.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/env_of_t.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ENV_OF
#define INCLUDED_BEMAN_EXECUTION_DETAIL_ENV_OF
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ENV_OF_T
#define INCLUDED_BEMAN_EXECUTION_DETAIL_ENV_OF_T

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
Expand All @@ -29,4 +29,4 @@ using env_of_t = decltype(::beman::execution::get_env(::std::declval<T>()));

// ----------------------------------------------------------------------------

#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_ENV_OF
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_ENV_OF_T
6 changes: 3 additions & 3 deletions include/beman/execution/detail/error_types_of_t.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/error_types_of_t.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ERROR_TYPES_OF
#define INCLUDED_BEMAN_EXECUTION_DETAIL_ERROR_TYPES_OF
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ERROR_TYPES_OF_T
#define INCLUDED_BEMAN_EXECUTION_DETAIL_ERROR_TYPES_OF_T

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
Expand Down Expand Up @@ -46,4 +46,4 @@ using error_types_of_t =

// ----------------------------------------------------------------------------

#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_ERROR_TYPES_OF
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_ERROR_TYPES_OF_T
4 changes: 2 additions & 2 deletions include/beman/execution/detail/get_completion_domain.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/get_completion_domain.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_DOMAIN
#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_DOMAIN
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_DOMAIN
#define INCLUDED_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_DOMAIN

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
Expand Down
6 changes: 3 additions & 3 deletions include/beman/execution/detail/hide_sched.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/hide_sched.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED
#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_HIDE_SCHED
#define INCLUDED_BEMAN_EXECUTION_DETAIL_HIDE_SCHED

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
Expand Down Expand Up @@ -48,4 +48,4 @@ auto hide_sched(const Q& q) noexcept {

// ----------------------------------------------------------------------------

#endif // INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_HIDE_SCHED
4 changes: 2 additions & 2 deletions include/beman/execution/detail/indeterminate_domain.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// include/beman/execution/detail/indeterminate_domain.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN
#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN
#define INCLUDED_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN

#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
Expand Down
Loading
Loading