Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/Quuxplusone/coro

Single-header library facilities for C++2a Coroutines
https://github.com/Quuxplusone/coro

Last synced: 28 days ago
JSON representation

Single-header library facilities for C++2a Coroutines

Awesome Lists containing this project

README

        

# coro
This is a collection of single-header library facilities for C++2a Coroutines.

## coro/include/

### co_future.h

Provides `co_future`, which is like `std::future` but models `Awaitable`.

### co_optional.h

Provides `co_optional`, which is like `std::optional` but is awaitable.
This is based on [code originally by Toby Allsopp](https://github.com/toby-allsopp/coroutine_monad/#using-coroutines-for-monadic-composition).
Notice that `co_optional` is awaitable only in coroutine contexts where the
return type is itself `co_optional` — not, say, `task` or `generator` —
and therefore `co_optional` does _not_ model the P1288R0 `Awaitable` concept.

### concepts.h

Provides definitions for the concepts and type-traits from Lewis Baker's P1288R0,
based on his own reference implementation.

- `concept Awaitable`
- `concept AwaitableOf`
- `concept Awaiter`
- `concept AwaiterOf`
- `awaiter_type_t`
- `await_result_t`
- `get_awaiter(Awaitable t)`

### gor_generator.h

Gor Nishanov's `generator`. The difference between this one and "mcnellis_generator.h"
is that this one stores the value of `coro_.done()` in a bool member variable. That change
makes it more friendly to the compiler's optimizer. This is the only generator that works
as intended with "disappearing_coroutine.cpp".

This generator is move-only.

### mcnellis_generator.h

James McNellis's `int_generator` example from "Introduction to C++ Coroutines" (CppCon 2016),
templatized into `generator`. I had to fill in some boilerplate he didn't show, such
as iterator comparison, `return_void`/`unhandled_exception`, and several constructors.
Any mistakes are likely mine, not his.

This generator is neither moveable nor copyable.

### shared_generator.h, unique_generator.h

`unique_generator` is basically equivalent to `cppcoro::generator`.
It expresses unique ownership of a coroutine handle, which means it is move-only.
This is the most natural way to implement a generator object, but it does have the
downside that it is not a range-v3 `viewable_range`.

`shared_generator` is basically equivalent to range-v3's `ranges::experimental::generator`.
It expresses _reference-counted_ ownership of a coroutine handle, so that it is copyable.
It is a full `viewable_range` and interoperates correctly with range-v3.

These generators' `end()` methods return a sentinel type instead of `iterator`,
which means that these generators do not interoperate with the C++17 STL algorithms.

### resumable_thing.h

James McNellis's `resumable_thing` example from "Introduction to C++ Coroutines" (CppCon 2016).

### sync_wait.h

Lewis Baker's implementation of P1171 `sync_wait(Awaitable t)`.
Suppose you're in `main()`, and you have a `task` that you've received from a coroutine.
You can't `co_await` it, because as soon as you use the `co_await` keyword you
turn into a coroutine yourself. If (and only if?) the coroutine is being executed in another thread,
then you can pass the task off to `sync_wait`.

TODO: this needs some example code!

### task.h, gor_task.h

`task` is basically equivalent to `cppcoro::task`.
It models `Awaitable` (as defined in "concepts.h").

"gor_task.h" provides another implementation of `task`, as shown in Gor Nishanov's
"C++ Coroutines: Under the Covers" (CppCon 2016).

TODO: this needs some example code!

## examples/

### co_optional.cpp

Simple examples of using `co_optional` monadic operations with `co_await` and `co_return`.

### co_optional_tests.cpp

Toby Allsopp's monadic `optional` comes with a test suite.
This is that test suite.

### disappearing_coroutine.cpp

Gor Nishanov's example of passing a generator to `std::accumulate`, from
his talk "C++ Coroutines: Under the Covers" (CppCon 2016). Clang can optimize
this down to a single `printf`; but only if you use "gor_generator.h". If you use
one of the generators that doesn't cache `coro_.done()` in a data member, Clang will
not be able to optimize it.

### generate_ints.cpp

A very simple example of `unique_generator` with `co_yield`.

### generator_as_viewable_range.cpp

Similar to `generate_ints.cpp`, this example demonstrates mixing Coroutines with Ranges.
It uses `shared_generator` (which models `ranges::viewable_range`)
and pipes the generator object through `rv::take(10)`.

### mcnellis_generator.cpp

James McNellis's `int_generator` example from "Introduction to C++ Coroutines" (CppCon 2016).

### mcnellis_resumable_thing.cpp

James McNellis's first `resumable_thing` example from "Introduction to C++ Coroutines" (CppCon 2016).

### mcnellis_resumable_thing_dangling.cpp

James McNellis's second `resumable_thing` example from "Introduction to C++ Coroutines" (CppCon 2016),
showing the interleaved execution of two `named_counter` coroutines.

We show both McNellis's working `named_counter`, which captures a `std::string` by value,
_and_ a `broken_named_counter` that captures a `std::string_view` and thus suffers from a
subtle dangling-reference bug whose effects are visible in the output.

### p1288r0_concepts.cpp

Lewis Baker's reference implementation of P1288R0 comes with a test suite.
This is that test suite.

### pythagorean_triples_generator.cpp

[Eric's Famous Pythagorean Triples](http://ericniebler.com/2018/12/05/standard-ranges/),
but using a `shared_generator` that `co_yield`s tuples.
This is almost identical to `generator_as_viewable_range.cpp`; it's just
a slightly more interesting application.