Changelog

A description of the changes made to continuable.

Versions

Following versions were released:

4.0.0

Various issues have been resolved:

Following methods and functions have been added:

Various improvements to continuable_base:

An asychronous initiation function comparable to std::async:

The asynchronous facilities make it possible now to start with a handler instead of a continuation:

async([] {
  // ...
}).then(...);
  • async Makes it possible to start with a handler instead of a continuation, comparable to std::async
  • async_on allows to specify an additional executor parameter

The result class and modifying the asynchronous control flow

Every continuation handler used in continuable_base::then, continuable_base::next and continuable_base::fail allows now to return a result which represents the asynchronous result.

This allows recovering from failures or throwing of exception types from handlers when exceptions are disabled.

Result handling and

  • result
  • rethrow Throws an exception or error code from a result or failure handler
  • cancel Throws a default constructed exception type or error code from a result or failure handler to signal cancellation.
  • stop Can be used to stop an asynchronous continuation chain, no handler which comes after stop was received won't be called.
  • make_result Creates a present result from the given values.

Special result types

  • empty_result A class which is convertible to any result and that definitely holds no value so the real result gets invalidated when this object is passed to it.
  • cancellation_result A class which is convertible to any result and that definitely holds a default constructed exception which signals the cancellation of the asynchronous control flow.
  • exceptional_result A class which is convertible to any result and that holds an exception which is then passed to the converted result object.

Optimize 'ready' continuables:

Continuables which are 'ready' and side effect free can now be unpacked synchronously. Mainly such continuables are created through make_ready_continuable, make_exceptional_continuable and make_cancelling_continuable.

  • continuable_base::is_ready Returns true when the continuable can provide its result immediately, and its lazy invocation would be side-effect free.
  • continuable_base::unpack Invalidates the continuable and returns its immediate invocation result.
  • make_cancelling_continuable Returns a continuable_base with the parameterized result which never resolves its promise and thus cancels the asynchronous continuation chain through throwing a default constructed exception_t.

Including various helper tags for the underlying changed continuation object structure:

asio asynchronous initiate token:

The use_continuable_t special tag can be used to make (boost) asio return a continuable_base.

#include <continuable/continuable.hpp>
#include <continuable/external/asio.hpp>
#include <asio.hpp>

// ...

asio::tcp::resolver resolver(...);
resolver.async_resolve("127.0.0.1", "daytime", cti::use_continuable)
  .then([](asio::udp::resolver::iterator iterator) {
    // ...
  });

Iterating over an asynchronous control flow:

The loop function was added which makes is possible to emulate an asynchronous loop, that is comparable to a co_await with for.

  • loop
  • loop_result Can be used to indicate a specific result inside an asynchronous loop.
  • loop_break Can be used to create a loop_result which causes the loop to be cancelled and resolved with the given arguments.
  • loop_continue Can be used to create a loop_result which causes the loop to be repeated.
  • range_loop Can be used to create an asynchronous loop over a specific range.
  • range_loop Can be used to create an asynchronous loop over a specific range.
  • plain_t Represents the type that is used to disable the special meaning of types which are returned by a asynchronous result handler. See cti::plain for details.
  • make_plain Can be used to disable the special meaning for a returned value in asynchronous handler functions.

Synchronous wait transforms:

The wait transforms allows to block the current thread until a continuable_base was resolved.

Various changes:

Many more unlisted changes including:

Additional various bugfixes have been made.

3.0.0

New helper functions

New helper functions were added to create ready continuables:

Improvements to connections

The implementation of connections were rewritten entirely. It is possible now to connect runtime sized containers as well as deeply nested sequences. See Connecting continuables for details.

Additionally connection overloads were added that accept two iterators in order to come closer to the interface of the standard library.

Also populate was added which makes it possible to populate a dynamic container from continuable_base objects.

Disabled copies for promises and continuables entirely

The promise_base and continuable_base is now non copyable. This change should make it easier to work with the move only semantic of continuables in order to make less mistakes.

Traversal API

A new traversal API for synchronous and asynchronous pack traversal was added which makes it easy to specify new connection types.

2.0.0

Error handling

Usually it is inconvenient to handle error codes and exceptions in an asynchronous context, as we all know std::future supports error handling through exceptions already. We now introduce this capability to the continuable library while allowing error codes to be used as well.

Consider the function cti::continuable<> get_bad_continuable() which always resolves through an error, then you may handle the error code or exception as following:

get_bad_continuable()
  .then([] {
    // ... never invoked
  })
  .then([] {
    // ... never invoked as well
  })
  .fail([] (std::exception_ptr e) {
    try {
      std::rethrow_exception(e);
    } catch(std::exception const& e) {
      // Handle the exception here
    }
  });

Abstracting callbacks as promises

Since a callback may be called through an error or result the cri::promise class was added in order ro provide a similar interface to std::promise:

auto http_request(std::string url) {
  return cti::make_continuable<std::string>(
    [url = std::move(url)](cti::promise<std::string> promise) {
      // Perform the actual request through a different library,
      // resolve the promise upon completion of the task.
      promise.set_value("<html> ... </html>");
      // ...or promise.set_exception(...);
    });
}

co_await support

Experimental coroutine (co_await and co_return) support was added, this is available on MSVC 2017 and Clang 5.0.

int i = co_await cti::make_continuable<int>([](auto&& promise) {
  promise.set_value(0);
});

Minor improvements

The library was improved in other ways:

  • constexpr and noexcept improvements
  • Compile-time improvements
  • Documentation improvements

Header split

Since the overall library size was increased the headers were split into smaller chunks.

1.0.0

  • Documentation and readme changes
  • Change the assertion type of some GTest macros from expected to assertion.

0.8.0 (unstable)

  • Fixes a major issue with handling the ownership for consumed continuables which led to unintended invocations.
  • Adds partial application support which makes it possible to chain callbacks which accept less arguments then the curret signature.

    http_request("github.com")
      .then([] {
        // ...
      });
  • Adds Support for sequential invocation:

    http_request("github.com") >> http_request("atom.io")
      .then([] (std::string github, std::string atom) {
        // ...
      });

0.7.0 (unstable)

  • Continuation syntactic sugar
  • Executor support
  • Connection support

Semantic versioning and stability

Continuable strictly follows the rules of semantic versioning, the API is kept stable across minor versions.

The CI driven unit-tests are observed through the Clang sanitizers (asan, ubsan and lsan - when compiling with Clang) or Valgrind (when compiling with GCC) in order to prevent regressions.