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
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ set(TARGETS_EXPORT_NAME ${CMAKE_PROJECT_NAME}Targets)

FetchContent_Declare(
execution
# SOURCE_DIR <path-to>/execution
# SOURCE_DIR ${CMAKE_SOURCE_DIR}/../execution
GIT_REPOSITORY https://github.com/bemanproject/execution
GIT_TAG 330be95
GIT_TAG a5843eb
)
FetchContent_MakeAvailable(execution)

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#-dk: note to self: PATH=/opt/llvm-19.1.6/bin:$PATH LDFLAGS=-fuse-ld=lld

.PHONY: config test default compile clean distclean doc html pdf format tidy
.PHONY: config test default compile clean distclean doc html pdf format clang-format tidy

BUILDDIR = build
PRESET = gcc-release
Expand All @@ -26,7 +26,7 @@ compile:
list:
cmake --workflow --list-presets

format:
clang-format format:
git clang-format main

$(BUILDDIR)/tidy/compile_commands.json:
Expand Down
601 changes: 517 additions & 84 deletions docs/P3796-task-issues.md

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

set(ALL_EXAMPLES
odd-return
bulk
dangling-references
rvalue-task
aggregate-return
tls-scheduler
customize
issue-symmetric-transfer
Expand Down
20 changes: 20 additions & 0 deletions examples/aggregate-return.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// examples/aggregate-return.cpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/execution/execution.hpp>
#include <beman/task/task.hpp>

namespace ex = beman::execution;

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

int main() {
struct aggregate {
int value = 0;
};

ex::sync_wait([]() -> ex::task<aggregate> { co_return aggregate{42}; }());
ex::sync_wait([]() -> ex::task<aggregate> { co_return aggregate{}; }());
ex::sync_wait([]() -> ex::task<aggregate> { co_return {42}; }());
ex::sync_wait([]() -> ex::task<aggregate> { co_return {}; }());
}
29 changes: 29 additions & 0 deletions examples/bulk.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// examples/bulk.cpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/execution/execution.hpp>
#include <beman/execution/task.hpp>
#include <execution>

namespace ex = beman::execution;
namespace beman::execution {
inline constexpr struct par_t {
} par{};
using parallel_scheduler = inline_scheduler;
} // namespace beman::execution

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

int main() {
struct env {
auto query(ex::get_scheduler_t) const noexcept { return ex::parallel_scheduler(); }
};
struct work {
auto operator()(std::size_t) { /*...*/ };
};

ex::sync_wait(ex::write_env(ex::bulk(ex::just(), 16u, work{}), env{}));

ex::sync_wait(
ex::write_env([]() -> ex::task<void, ex::empty_env> { co_await ex::bulk(ex::just(), 16u, work{}); }(), env{}));
}
6 changes: 3 additions & 3 deletions examples/c++now-with_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ struct context {
ex::task<int, context> error_return(int arg) noexcept {
try {
if (arg == 1)
co_yield ex::with_error(E{arg});
co_yield ex::with_error{E{arg}};
co_return arg * 17;
} catch (...) {
unreachable("no error should escape co_yield with_error(E{0})");
unreachable("no error should escape co_yield with_error{E{0}}");
std::terminate();
}
}
Expand All @@ -40,7 +40,7 @@ struct ctxt {

ex::task<int, ctxt> call(int v) {
if (v == 1)
co_yield ex::with_error(-1);
co_yield ex::with_error{-1};
co_return 2 * v;
}
} // namespace
Expand Down
34 changes: 34 additions & 0 deletions examples/dangling-references.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// examples/dangling-references.cpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/execution/execution.hpp>
#include <beman/task/task.hpp>
#include <utility>
#include <functional>
#include <string>

namespace ex = beman::execution;

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

namespace {
ex::task<int, ex::empty_env> do_work(std::string) { /* work */ co_return 0; };
ex::task<void, ex::empty_env> execute_all() {
co_await ex::when_all(do_work("arguments 1"), do_work("arguments 2"));
co_return;
}

struct error_env {
using error_types = ex::completion_signatures<ex::set_error_t(int)>;
};
} // namespace

int main() {
ex::sync_wait([]() -> ex::task<ex::with_error<int>, error_env> { co_return ex::with_error<int>{42}; }());

ex::sync_wait(execute_all());
ex::sync_wait([]() -> ex::task<void, ex::empty_env> {
auto t = [](const int /* this would be added: &*/ v) -> ex::task<int, ex::empty_env> { co_return v; }(42);
[[maybe_unused]] auto v = co_await std::move(t);
}());
}
2 changes: 1 addition & 1 deletion examples/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ ex::task<int, error_context> fun(int i) {
// successful return of a value
co_return 17;
case 4:
co_yield ex::with_error(std::make_error_code(std::errc::io_error));
co_yield ex::with_error{std::make_error_code(std::errc::io_error)};
break;
}

Expand Down
84 changes: 78 additions & 6 deletions examples/loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,93 @@
#include <string>
#include <beman/execution/execution.hpp>
#include <beman/task/task.hpp>
#include <iostream>

namespace ex = beman::execution;

namespace {
struct run_loop_env {
using scheduler_type = decltype(std::declval<ex::run_loop>().get_scheduler());
};

template <ex::scheduler Scheduler>
struct log_scheduler {
using scheduler_concept = ex::scheduler_t;

std::remove_cvref_t<Scheduler> scheduler;

log_scheduler(auto&& sched) : scheduler(std::forward<decltype(sched)>(sched)) {}

struct sender {
using sender_concept = ex::sender_t;
using completion_signatures = ex::completion_signatures<ex::set_value_t()>;
using up_sender = decltype(ex::schedule(std::declval<Scheduler>()));

up_sender _sender;

template <ex::receiver Receiver>
struct state {
using operation_state_concept = ex::operation_state_t;
using up_state_t = decltype(ex::connect(std::declval<up_sender>(), std::declval<Receiver>()));

up_state_t _state;

template <ex::sender S, ex::receiver R>
state(S&& sender, R&& receiver)
: _state(ex::connect(std::forward<S>(sender), std::forward<R>(receiver))) {}

auto start() & noexcept -> void {
std::cout << "start scheduler: " << &this->_state << "\n";
ex::start(this->_state);
}
};

struct env {
log_scheduler _sched;
auto query(const ex::get_completion_scheduler_t<ex::set_value_t>&) const noexcept -> log_scheduler {
return this->_sched;
}
};
auto get_env() const noexcept -> env {
return {ex::get_completion_scheduler<ex::set_value_t>(ex::get_env(this->_sender))};
}
template <ex::receiver Receiver>
auto connect(Receiver&& receiver) noexcept -> state<std::remove_cvref_t<Receiver>> {
return {this->_sender, std::forward<Receiver>(receiver)};
}
};

auto schedule() noexcept { return sender{ex::schedule(this->scheduler)}; }
auto operator==(const log_scheduler&) const noexcept -> bool = default;
};
template <ex::scheduler Scheduler>
log_scheduler(Scheduler&&) -> log_scheduler<std::remove_cvref_t<Scheduler>>;

static_assert(ex::scheduler<log_scheduler<ex::inline_scheduler>>);
static_assert(ex::scheduler<log_scheduler<ex::task_scheduler>>);
} // namespace

namespace {
[[maybe_unused]] ex::task<void> loop(auto count) {
for (int i{}; i < count; ++i)
co_await ex::just(i);
for (decltype(count) i{}; i < count; ++i)
// co_await ex::just(i);
co_await [](int x) -> ex::task<> {
std::cout << "before co_await: " << &x << ": " << x << "\n";
co_await (ex::just(x) | ex::then([](int v) { std::cout << &v << ": " << v << "\n"; }));
std::cout << "after co_await: " << &x << ": " << x << "\n";
}(i);
}
} // namespace

int main(int ac, char* av[]) {
auto count = 1 < ac && av[1] == std::string_view("run-it") ? 1000000 : 10000;
#if 1
auto count = 1 < ac && av[1] == std::string_view("run-it") ? 1000000 : 1000;
ex::sync_wait(loop(count));
#else
ex::sync_wait(ex::detail::write_env(loop(count), ex::detail::make_env(ex::get_scheduler, ex::inline_scheduler{})));
ex::sync_wait([](std::size_t count) -> ex::task<void, run_loop_env> {
co_await ex::write_env(
loop(count),
ex::detail::make_env(ex::get_scheduler, log_scheduler(co_await ex::read_env(ex::get_scheduler))));
}(count));
#if 0
ex::sync_wait(ex::detail::write_env(loop(count), ex::detail::make_env(ex::get_scheduler, ex::inline_scheduler{})));
#endif
}
20 changes: 20 additions & 0 deletions examples/odd-return.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// examples/odd-return.cpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/execution/execution.hpp>
#include <beman/execution/task.hpp>
#include <cassert>
#include <exception>
#include <variant>

namespace ex = beman::execution;

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

int main() {
auto mono = ex::sync_wait([]() -> ex::task<std::monostate> { co_return std::monostate{}; }());
assert(mono);

auto exp = ex::sync_wait([]() -> ex::task<std::exception_ptr> { co_return std::make_exception_ptr(17); }());
assert(exp);
}
38 changes: 38 additions & 0 deletions examples/rvalue-task.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// examples/rvalue-task.cpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/execution/execution.hpp>
#include <beman/task/task.hpp>

namespace ex = beman::execution;

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

namespace {
struct receiver {
using receiver_concept = ex::receiver_t;
void set_value() && noexcept { std::cout << "set_value called\n"; }
void set_error(std::exception_ptr) && noexcept { std::cout << "set_error called\n"; }
void set_stopped() && noexcept { std::cout << "set_stopped called\n"; }

struct env {
auto query(const ex::get_scheduler_t&) const noexcept -> ex::inline_scheduler {
return ex::inline_scheduler{};
}
};
env get_env() const noexcept { return {}; }
};

template <typename T>
void test(T&& task) {
if (requires { ex::connect(std::forward<T>(task), receiver{}); }) {
//[[maybe_unused]] auto op_state = ex::connect(std::forward<T>(task), std::move(receiver{}));
}
}
} // namespace

int main() {
auto task = []() -> ex::task<void, ex::empty_env> { co_return; }();
test(std::move(task));
// test(task);
}
2 changes: 1 addition & 1 deletion include/beman/task/detail/promise_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class promise_base {
* \brief Set the value result.
* \internal
*/
template <typename T>
template <typename T = Value>
void return_value(T&& value) {
this->get_state()->set_value(::std::forward<T>(value));
}
Expand Down
25 changes: 2 additions & 23 deletions include/beman/task/detail/task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,36 +67,15 @@ class task {
~task() = default;

template <typename Receiver>
auto connect(Receiver receiver) -> state<Receiver> {
auto connect(Receiver receiver) && -> state<Receiver> {
return state<Receiver>(std::forward<Receiver>(receiver), std::move(this->handle));
}
template <typename ParentPromise>
auto as_awaitable(ParentPromise&) -> ::beman::task::detail::awaiter<Value, Env, promise_type, ParentPromise> {
auto as_awaitable(ParentPromise&) && -> ::beman::task::detail::awaiter<Value, Env, promise_type, ParentPromise> {
assert(this->handle.get());
return ::beman::task::detail::awaiter<Value, Env, promise_type, ParentPromise>(::std::move(this->handle));
}

struct dom_sender {
using sender_concept = ::beman::execution::sender_t;
using completion_signatures = ::beman::execution::completion_signatures< ::beman::execution::set_value_t()>;
struct state {
using operation_state_concept = ::beman::execution::operation_state_t;
auto start() & noexcept {}
};

auto connect(auto&&) noexcept -> state { return state{}; }
};
struct domain {
template <typename DS>
auto transform_sender(DS&&, auto&&...) const noexcept {
return dom_sender{};
}
};
struct env {
auto query(const ::beman::execution::get_domain_t&) const noexcept -> domain { return domain{}; }
};
auto xget_env() const noexcept { return env{}; }

private:
::beman::task::detail::handle<promise_type> handle;

Expand Down
16 changes: 0 additions & 16 deletions include/beman/task/detail/with_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,6 @@ template <typename E>
struct with_error {
using type = ::std::remove_cvref_t<E>;
type error;

template <typename EE>
with_error(EE&& e) noexcept(noexcept(type(::std::forward<EE>(e)))) : error(::std::forward<EE>(e)) {}
// the members below are only need for co_await with_error{...}
static constexpr bool await_ready() noexcept { return false; }
template <typename Promise>
requires requires(Promise p, E e) {
p.result.template emplace<E>(std::move(e));
p.state->complete(p.result);
}
void await_suspend(std::coroutine_handle<Promise> handle) noexcept(
noexcept(handle.promise().result.template emplace<E>(std::move(this->error)))) {
handle.promise().result.template emplace<E>(std::move(this->error));
handle.promise().state->complete(handle.promise().result);
}
static constexpr void await_resume() noexcept {}
};
template <typename E>
with_error(E&&) -> with_error<E>;
Expand Down
Loading