diff --git a/doc/configuration.dox b/doc/configuration.dox
index b57a79b..64e588d 100644
--- a/doc/configuration.dox
+++ b/doc/configuration.dox
@@ -33,7 +33,7 @@ in order to change the libraries behaviour:
| `CONTINUABLE_WITH_NO_EXCEPTIONS` | Exceptions are disabled and `std::error_condition` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. |
| `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` | Exceptions are disabled and the type defined by `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. |
| `CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS` | Allows unhandled exceptions in asynchronous call hierarchies. See \ref tutorial-chaining-continuables-fail for details. |
-| `CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE` | Enables support for experimental coroutines and `co_await` expressions. |
+| `CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE` | Enables support for experimental coroutines and `co_await` expressions. See \ref continuable_base::operator co_await() for details. |
*/
}
diff --git a/doc/index.dox b/doc/index.dox
index 9e0ebef..0a8a300 100644
--- a/doc/index.dox
+++ b/doc/index.dox
@@ -26,18 +26,23 @@ namespace cti {
\section mainpage-overview Overview
Continuable is a C++14 library that provides full support for:
- - lazy async continuation chaining based on **callbacks** (`then`) and
- expression templates, callbacks are wrapped nicely as promises.
+ - lazy async continuation chaining based on **callbacks**
+ (\link continuable_base::then then\endlink) and
+ expression templates, callbacks are wrapped nicely as \link promise_base promises\endlink.
- **no enforced type-erasure** which means we need less heap
allocations than comparable libraries, strictly following the "don't
pay for what you don't use" principle.
- - support for **connections** between continuables through an **all, any or
- sequential** strategy through expressive operator overloads **&&**,
- || and >>.
- - asynchronous **error handling** through exceptions, error coded or
- user defined types.
+ - support for **all, any and sequential connections** between continuables
+ through expressive operator overloads \link continuable_base::operator && &&\endlink,
+ \link continuable_base::operator || ||\endlink and
+ \link continuable_base::operator>> >>\endlink as well as free functions
+ \ref when_all, \ref when_any and \ref when_seq.
+ - asynchronous \link continuable_base::fail error handling\endlink through
+ \link promise_base_base::set_exception exceptions\endlink,
+ \link configuration error codes\endlink and
+ \link configuration user defined types\endlink.
- **syntactic sugar** for instance: **partial invocation**, **tuple unpacking**
- and **executors**.
+ and \link continuable_base::then executors\endlink.
- **encapsuled from any runtime**, larger framework or executor making
it possible to use continuable even in smaller or esoteric usage scenarios.
@@ -47,7 +52,7 @@ Continuable is a header-only library with zero compilation dependencies.
The \ref installation is explained in its own chapter.
The \ref tutorial is everything you need in order to get to know the libraries
-API. Beside of this there is a detailed in-source documentation provided.
+API. Beside of this, there is a detailed in-source documentation provided.
\section mainpage-contact Contributing and Questions
@@ -56,10 +61,13 @@ you are welcomed to ask for questions, contribute code or request new features.
Also I would like to hear your personal opinion about the library design or
your personal experience in using the library to improve it.
-\note
- If you like the library I would be glad if you star it on Github,
- because it helps other users to find this library.
+\attention If you like the library I would be glad if you star it on Github,
+ because it helps other users to find this library.
+\note If you are using the library in your open-source or commercial project
+ I would highly appreciate if you could give me a short notice so I can
+ add you to a list of projects and companies using this library.
+
\section mainpage-license License
Continuable is licensed under the MIT license:
diff --git a/doc/tutorial-connecting-continuables.dox b/doc/tutorial-connecting-continuables.dox
index cc96d8f..6483957 100644
--- a/doc/tutorial-connecting-continuables.dox
+++ b/doc/tutorial-connecting-continuables.dox
@@ -34,15 +34,31 @@ count of \ref continuable_base objects in order resolve a returned
For each connection strategy \ref continuable_base provides an operator for
for instance \ref continuable_base::operator && and a free function,
-\ref when_all for example. But work similar however
+\ref when_all for example. Both work similar however the free functions are
+capable of working with nested sequences as described in
+\ref tutorial-connecting-continuables-nested.
-Currently there are following strategies available:
+\note Connections between continuable_base objects are ensured to be
+ thread-safe and wait-free by library design
+ (when assuming that `std::call_once` is wait-free - which depends
+ on the toolchain).
\section tutorial-connecting-continuables-aggregated Using aggregated strategies
Aggregated strategies will call the result handler with the compound result of
all connected \ref continuable_base objects.
+The compound result is deduced as following. Every continuable_base maps its
+result to the result itself as shown below. When multiple continuable_base
+objects are connected on the same depth, the result is joined.
+See \ref tutorial-connecting-continuables-nested for details.
+
+| Continuation type | In tuple like | In container (`std::vector`) |
+| : ------------------------------- | : --------- | : ------------------------------ |
+| `continuable_base with <>` | `` | `` |
+| `continuable_base with ` | `Arg` | `Arg` |
+| `continuable_base with ` | `Args...` | `std::tuple` |
+
\subsection tutorial-connecting-continuables-aggregated-all Using the all connection
The *all* strategy invokes all connected continuable at once, it tries to resolve
@@ -53,6 +69,16 @@ through the *all* strategy by using \ref continuable_base::operator && or
workin with plain types and deeply nested \ref continuable_base objects as
described in \ref tutorial-connecting-continuables-nested .
+\code{.cpp}
+(http_request("github.com") && http_request("travis-ci.org") &&
+ http_request("atom.io"))
+ .then([](std::string github, std::string travis,
+ std::string atom) {
+ // The callback is called with the
+ // response of github, travis and atom.
+ });
+\endcode
+
\subsection tutorial-connecting-continuables-aggregated-seq Using the sequential connection
The *sequential* strategy invokes all connected continuable one after each other,
@@ -62,57 +88,125 @@ It is possible to connect multiple \ref continuable_base objects together
through the *sequential* strategy by using \ref continuable_base::operator>> or
\ref when_seq.
+\code{.cpp}
+(http_request("github.com") >> http_request("travis-ci.org") >>
+ http_request("atom.io"))
+ .then([](std::string github, std::string travis,
+ std::string atom) {
+ // The requests are invoked sequentially instead
+ // of requesting all at once.
+ });
+\endcode
+
\section tutorial-connecting-continuables-any Using the any connection
+The any connection strategy is completely different from the two introduces
+before: It calls the result handler with the first result or exception
+available. All \ref continuable_base objects are required to have the same
+types of arguments.
+
+\code{.cpp}
+(http_request("github.com") || http_request("travis-ci.org") ||
+ http_request("atom.io"))
+ .then([](std::string github_or_travis_or_atom) {
+ // The callback is called with the first response
+ // of either github, travis or atom.
+ });
+\endcode
+
+\section tutorial-connecting-continuables-mixed Mixing different strategies
+
+Mixing different strategies through operators and free functions
+is natively supported as shown below:
+
+\code{.cpp}
+(http_request("github.com") &&
+ (http_request("travis-ci.org") || http_request("atom.io")))
+ .then([](std::string github, std::string travis_or_atom) {
+ // The callback is called with the response of
+ // github for sure and the second parameter represents
+ // the response of travis or atom.
+ });
+\endcode
\section tutorial-connecting-continuables-nested Nested continuables and plain types
+For every operator that was shown above, there exists a free function
+that provides at least the same functionality:
-
-Continuables provide the operators **&&** and **||** for logical connection:
-
-* **&&** invokes the final callback with the compound result of all connected continuables, the continuables were invoked in parallel.
-* **||** invokes the final callback once with the first result which becomes available.
-* **>\>** invokes the final callback with the compound result of all connected continuables but the continuations were invokes sequentially.
-
-\endcodeC++
-auto http_request(std::string url) {
- return cti::make_continuable([](auto&& promise) {
- promise.set_value("...");
- });
-}
-
-// `all` of connections:
-(http_request("github.com") && http_request("travis-ci.org") && http_request("atom.io"))
- .then([](std::string github, std::string travis, std::string atom) {
- // The callback is called with the response of github, travis and atom.
- });
-
-// `any` of connections:
-(http_request("github.com") || http_request("travis-ci.org") || http_request("atom.io"))
- .then([](std::string github_or_travis_or_atom) {
- // The callback is called with the first response of either github, travis or atom.
- });
-
-// `sequence` of connections:
-(http_request("github.com") >> http_request("travis-ci.org") >> http_request("atom.io"))
- .then([](std::string github, std::string travis, std::string atom) {
- // The requests are invoked sequentially
- });
-
-// mixed logical connections:
-(http_request("github.com") && (http_request("travis-ci.org") || http_request("atom.io")))
- .then([](std::string github, std::string travis_or_atom) {
- // The callback is called with the response of github for sure
- // and the second parameter represents the response of travis or atom.
- });
-
-// There are helper functions for connecting continuables:
-auto all = cti::when_all(http_request("github.com"), http_request("travis-ci.org"));
-auto any = cti::when_any(http_request("github.com"), http_request("travis-ci.org"));
-auto seq = cti::when_seq(http_request("github.com"), http_request("travis-ci.org"));
+\code{.cpp}
+cti::when_all(http_request("github.com"), http_request("travis-ci.org"));
+cti::when_any(http_request("github.com"), http_request("travis-ci.org"));
+cti::when_seq(http_request("github.com"), http_request("travis-ci.org"));
+\endcode
+
+Additionally the free functions are capable of working with continuables deeply
+nested inside tuple like objects (`std::tuple`, `std::pair` and `std::array`)
+as well as homogeneous containers (`std::vector`, `std::list` etc.).
+
+\code{.cpp}
+std::tuple>> outstanding;
+// ...
+
+cti::when_all(std::make_tuple(std::move(outstanding),
+ http_request("github.com")))
+ .then([](std::tuple>,
+ std::string> result) {
+ // ...
+ });
+\endcode
+
+Values which are given to such a free function are preserved and
+later passed to the result handler:
+
+\code{.cpp}
+cti::when_seq(0, 1,
+ cti::make_ready_continuable(2, 3),
+ 4, 5)
+ .then([](int r0, int r1, int r2,
+ int r3, int r4) {
+ // ...
+ });
+\endcode
+
+When combining both capabilities it's even possible do something like this:
+
+\code{.cpp}
+cti::when_all(
+ cti::make_ready_continuable(0, 1),
+ 2, //< See this plain value
+ cti::populate(cti::make_ready_continuable(3), // Creates a runtime
+ cti::make_ready_continuable(4)), // sized container.
+ std::make_tuple(std::make_tuple(cti::make_ready_continuable(5))))
+ .then([](int r0, int r1, int r2, std::vector r34,
+ std::tuple> r5) {
+ // ...
+ });
+\endcode
+
+\section tutorial-connecting-continuables-populate Populating a container from arbitrary continuables
+
+\ref populate mainly helps to create a homogeneous container from
+a runtime known count of continuables which type isn't exactly known.
+All continuables which are passed to this function should be originating
+from the same source or a method called with the same types of arguments:
+
+\code{.cpp}
+// cti::populate just creates a std::vector from the two continuables.
+auto v = cti::populate(cti::make_ready_continuable(0),
+ cti::make_ready_continuable(1));
+
+for (int i = 2; i < 5; ++i) {
+ // It is possible to add more continuables
+ // to the container afterwards
+ container.emplace_back(cti::make_ready_continuable(i));
+}
+
+cti::when_all(v)
+ .then([](std::vector resolved) {
+ // ...
+ });
\endcode
-> **Note:** Logical connections are ensured to be **thread-safe** and **wait-free** by library design (when assuming that *std::call_once* is wait-free - which depends on the toolchain).
*/
}
diff --git a/doc/tutorial-creating-continuables.dox b/doc/tutorial-creating-continuables.dox
index 2a57765..d79ce96 100644
--- a/doc/tutorial-creating-continuables.dox
+++ b/doc/tutorial-creating-continuables.dox
@@ -101,7 +101,7 @@ auto resolve_sth() {
return cti::make_continuable(
[](auto&& promise) {
promise.set_value(0, 1, 2.f, '3');
- });
+ });
\endcode
\warning A \ref promise_base is only usable once and thus invalidated
diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp
index c0c4978..970e286 100644
--- a/include/continuable/continuable-base.hpp
+++ b/include/continuable/continuable-base.hpp
@@ -476,8 +476,8 @@ public:
/// });
/// ```
///
- /// \note The continuable_base objects are invoked parallel on the
- /// current thread, because the `all` strategy tries to resolve
+ /// \note The continuable_base objects are invoked all at onve,
+ /// because the `all` strategy tries to resolve
/// the continuations as fast as possible.
/// Sequential invocation is also supported through the
/// continuable_base::operator>> method.
@@ -516,9 +516,9 @@ public:
/// });
/// ```
///
- /// \note The continuable_base objects are invoked parallel on the
- /// current thread, however, the callback is only called once with
- /// the first result which becomes available.
+ /// \note The continuable_base objects are invoked all at once,
+ /// however, the callback is only called once with
+ /// the first result or exception which becomes available.
///
/// \since 1.0.0
template
@@ -545,9 +545,9 @@ public:
/// });
/// ```
///
- /// \note The continuable_base objects are invoked sequential on the
- /// current thread. Parallel invocation is also supported through the
- /// continuable_base::operator&& method.
+ /// \note The continuable_base objects are invoked sequential one after
+ /// the previous one was finished. Parallel invocation is also
+ /// supported through the continuable_base::operator && method.
///
/// \since 1.0.0
template
@@ -855,6 +855,13 @@ constexpr auto make_ready_continuable(FirstResult&& first_result,
/// Returns a continuable with the parameterized result which instantly
/// resolves the promise with the given error type.
///
+/// See an example below:
+/// ```cpp
+/// std::logic_error exception("Some issue!");
+/// auto ptr = std::make_exception_ptr(exception);
+/// auto ct = cti::make_exceptional_continuable(ptr);
+/// ```
+///
/// \tparam Signature The fake signature of the returned continuable.
///
/// \since 3.0.0
diff --git a/include/continuable/continuable-testing.hpp b/include/continuable/continuable-testing.hpp
index fee5ebb..861fce8 100644
--- a/include/continuable/continuable-testing.hpp
+++ b/include/continuable/continuable-testing.hpp
@@ -167,6 +167,6 @@
ASSERT_ASYNC_BINARY_EXCEPTION_VALIDATION( \
cti::detail::testing::asserting_eq_check(), __VA_ARGS__)
-//// \}
+/// \}
#endif // CONTINUABLE_TESTING_HPP_INCLUDED