-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4237dbf
commit 0e7e697
Showing
4 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
[#context] | ||
== cobalt/experimental/context.hpp | ||
|
||
WARNING: This is (most likely) undefined behaviour, since the violates a precondition in the standard. A paper to address this can be found here (https://isocpp.org/files/papers/P3203R0.html). | ||
|
||
This header provides `experimental` support for using `boost.fiber` based stackful coroutines | ||
as if they were C++20 coroutines. That is, they can use `awaitables` by being able to be put into a `coroutine_handle`. | ||
Likewise the implementation uses a C++20 coroutine promise and runs is as if it was a C++20 coroutine. | ||
|
||
[source,cpp] | ||
---- | ||
// | ||
void delay(experimental::context<promise<void>> h, std::chrono::milliseconds ms) | ||
{ | ||
asio::steady_timer tim{co_await cobalt::this_coro::executor, ms}; | ||
h.await(tim.async_wait(cobalt::use_op)); // instead of co_await. | ||
} | ||
cobalt::main co_main(int argc, char *argv[]) | ||
{ | ||
cobalt::promise<void> dl = cobalt::experimental::make_context(&delay, 50); | ||
co_await dl; | ||
co_return 0; | ||
} | ||
---- | ||
|
||
=== Reference | ||
|
||
[source,cpp] | ||
---- | ||
// The internal coroutine context. | ||
/// Args are the function arguments after the handle. | ||
template<typename Return, typename ... Args> | ||
struct context | ||
{ | ||
// Get a handle to the promise | ||
promise_type & promise(); | ||
const promise_type & promise() const; | ||
// Convert it to any context if the underlying promise is the same | ||
template<typename Return_, typename ... Args_> | ||
constexpr operator context<Return_, Args_...>() const; | ||
// Await something. Uses await_transform automatically. | ||
template<typename Awaitable> | ||
auto await(Awaitable && aw); | ||
// Yield a value, if supported by the promise. | ||
template<typename Yield> | ||
auto yield(Yield && value); | ||
}; | ||
// Create a fiber with a custom stack allocator (see boost.fiber for details) and explicit result (e.g. `promise<void>`) | ||
template<typename Return, typename ... Args, std::invocable<context<Return, Args...>, Args...> Func, typename StackAlloc> | ||
auto make_context(Func && func, std::allocator_arg_t, StackAlloc && salloc, Args && ... args); | ||
// Create a fiber with the default allocator and explicit result (e.g. `promise<void>`) | ||
template<typename Return, typename ... Args, std::invocable<context<Return, Args...>, Args...> Func> | ||
auto make_context(Func && func, Args && ... args); | ||
// Create a fiber with a custom stack allocator and implicit result (deduced from the first argument to func). | ||
template<typename ... Args, typename Func, typename StackAlloc> | ||
auto make_context(Func && func, std::allocator_arg_t, StackAlloc && salloc, Args && ... args); | ||
// Create a fiber with the default stack allocator and implicit result (deduced from the first argument to func). | ||
template<typename ... Args, typename Func> | ||
auto make_context(Func && func, Args && ... args); | ||
---- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
[#continuation] | ||
== cobalt/experimental/continuation.hpp | ||
|
||
WARNING: This is clearly undefined behaviour, since it does an explicit specialization of `std::coroutine_handle`. A paper to address this can be found here (https://isocpp.org/files/papers/P3203R0.html). | ||
|
||
This header provides low level support for creating a `std::coroutine_handle` from within a `boost::context::continuation`. | ||
|
||
|
||
[source,cpp] | ||
---- | ||
template<cobalt::awaitable_type Aw> | ||
auto continuation_await(boost::context::continuation && f, Aw && aw) | ||
{ | ||
if (!aw.await_ready()) | ||
{ | ||
boost::cobalt::experimental::continuation_frame ff; // This must be on the continuation stack | ||
f = std::move(f).resume_with( | ||
[&](boost::context::continuation && f_) -> boost::context::continuation | ||
{ | ||
ff.continuation() = std::move(f_); | ||
std::coroutine_handle<boost::context::continuation> h(ff); | ||
static_assert(std::is_void_v<decltype(aw.await_suspend(h)>, | ||
"This example only supports awaitables return `void` from await_suspend"); | ||
aw.await_suspend(h); | ||
return {}; | ||
}); | ||
} | ||
return aw.await_resume(); | ||
} | ||
---- | ||
|
||
=== Reference | ||
|
||
[source,cpp] | ||
---- | ||
struct experimental::continuation_frame | ||
{ | ||
boost::context::continuation& continuation(); | ||
const boost::context::continuation& continuation() const; | ||
continuation_frame(boost::context::continuation && continuation_ = {}); | ||
}; | ||
template<> | ||
struct std::coroutine_handle<boost::context::continuation> | ||
{ | ||
constexpr operator coroutine_handle<>() const noexcept; | ||
constexpr explicit operator bool() const noexcept; | ||
constexpr bool done() const noexcept: | ||
void operator()() const noexcept; | ||
void resume() const noexcept; | ||
void destroy() const noexcept; | ||
boost::context::continuation& promise() const noexcept; | ||
constexpr void* address() const noexcept; | ||
// construct if from a frame | ||
coroutine_handle(boost::cobalt::experimental::continuation_frame & frame | ||
}; | ||
---- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
[#fiber] | ||
== cobalt/experimental/fiber.hpp | ||
|
||
WARNING: This is clearly undefined behaviour, since it does an explicit specialization of `std::coroutine_handle`. A paper to address this can be found here (https://isocpp.org/files/papers/P3203R0.html). | ||
|
||
This header provides low level support for creating a `std::coroutine_handle` from within a `boost::context::fiber`. | ||
|
||
|
||
[source,cpp] | ||
---- | ||
template<cobalt::awaitable_type Aw> | ||
auto fiber_await(boost::context::fiber && f, Aw && aw) | ||
{ | ||
if (!aw.await_ready()) | ||
{ | ||
boost::cobalt::experimental::fiber_frame ff; // This must be on the fiber stack | ||
f = std::move(f).resume_with( | ||
[&](boost::context::fiber && f_) -> boost::context::fiber | ||
{ | ||
ff.fiber() = std::move(f_); | ||
std::coroutine_handle<boost::context::fiber> h(ff); | ||
static_assert(std::is_void_v<decltype(aw.await_suspend(h)>, | ||
"This example only supports awaitables return `void` from await_suspend"); | ||
aw.await_suspend(h); | ||
return {}; | ||
}); | ||
} | ||
return aw.await_resume(); | ||
} | ||
---- | ||
|
||
=== Reference | ||
|
||
[source,cpp] | ||
---- | ||
struct experimental::fiber_frame | ||
{ | ||
boost::context::fiber& fiber(); | ||
const boost::context::fiber& fiber() const; | ||
fiber_frame(boost::context::fiber && fiber_ = {}); | ||
}; | ||
template<> | ||
struct std::coroutine_handle<boost::context::fiber> | ||
{ | ||
constexpr operator coroutine_handle<>() const noexcept; | ||
constexpr explicit operator bool() const noexcept; | ||
constexpr bool done() const noexcept: | ||
void operator()() const noexcept; | ||
void resume() const noexcept; | ||
void destroy() const noexcept; | ||
boost::context::fiber& promise() const noexcept; | ||
constexpr void* address() const noexcept; | ||
// construct if from a frame | ||
coroutine_handle(boost::cobalt::experimental::fiber_frame & frame | ||
}; | ||
---- |