Connecting continuables
Explains how to connect various continuable_
Contents
Connections and strategies
Connections make it possible to describe the dependencies between an arbitrary count of continuable_
For each connection strategy continuable_
Using aggregated strategies
Aggregated strategies will call the result handler with the compound result of all connected continuable_
The compound result is deduced as following. Every continuable_
Continuation type | In tuple like | In container (std::vector ) |
---|---|---|
continuable_ | <none> | <none> |
continuable_ | Arg | Arg |
continuable_ | Args... | std::tuple<Args...> |
Using the all connection
The all strategy invokes all connected continuable at once, it tries to resolve the connected continuable_
(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. });
Using the sequential connection
The sequential strategy invokes all connected continuable one after each other, it tries to resolve the next connected continuable_
(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. });
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 continuable_
(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. });
Mixing different strategies
Mixing different strategies through operators and free functions is natively supported as shown below:
(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. });
Nested continuables and plain types
For every operator that was shown above, there exists a free function that provides at least the same functionality:
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"));
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.).
std::tuple<std::vector<cti::continuable<int>>> outstanding; // ... cti::when_all(std::make_tuple(std::move(outstanding), http_request("github.com"))) .then([](std::tuple<std::tuple<std::vector<int>>, std::string> result) { // ... });
Values which are given to such a free function are preserved and later passed to the result handler:
cti::when_seq(0, 1, cti::make_ready_continuable(2, 3), 4, 5) .then([](int r0, int r1, int r2, int r3, int r4) { // ... });
When combining both capabilities it's even possible do something like this:
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<int> r34, std::tuple<std::tuple<int>> r5) { // ... });
Populating a container from arbitrary continuables
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:
// 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(std::move(v)) .then([](std::vector<int> resolved) { // ... });