continuable/doc/tutorial-creating-continuables.dox
Denis Blank 20e8c7d3e3 Reflow the license text
* For some reason some spaces were removed,
  the license text and content stays the same.
2019-01-04 13:39:46 +01:00

143 lines
5.6 KiB
Plaintext

/*
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
namespace cti {
/** \page tutorial-creating-continuables Creating continuables
\brief Explains how to create a \ref continuable_base.
\tableofcontents
A \ref continuable is an arbitrary instantiation of a \ref continuable_base,
it represents the main class of the library and makes it possible to build up
an asynchronous call hierarchy. When dealing with continuables we usually don't
know its exact type for avoiding expensive type erasure.
The \ref continuable_base is convertible to a \ref continuable which represents
a specified type of the \ref continuable_base on the cost of a type erasure.
\section tutorial-creating-continuables-ready From a value or exception
The library provides \ref make_ready_continuable which may be used to create a
\ref continuable_base from an arbitrary amount of values:
\code{.cpp}
auto one = cti::make_ready_continuable(0);
cti::continuable<int, float, char> three =
cti::make_ready_continuable(0, 1.f, '2');
\endcode
\note In most situations you will never use \ref make_ready_continuable
because the library is capable of working with plain values
directly and thus this burdens unnecessary overhead.
Additionally a \ref continuable_base which resolves with an exception may be
created through \ref make_exceptional_continuable.
\code{.cpp}
cti::continuable<int> c = cti::make_exceptional_continuable(std::exception{});
\endcode
\section tutorial-creating-continuables-promises From a promise taking callable
The main function for creating a \ref continuable_base is \ref make_continuable
which must be invoked with the types of arguments it resolves to.
It accepts a callable object which accepts an arbitrary object
(the \ref promise_base). The \ref promise_base is created by the library and
then passed to the given callback. This is in contrast to the usage of the
standard `std::promise` which is created by the user.
The \ref promise_base exposes methods to resolve it through result values or
through an exception. Below we implement pseudo `http_request` function
which resolves the request asynchronously trough a `std::string`.
\code{.cpp}
auto http_request(std::string url) {
return cti::make_continuable<std::string>(
[url = std::move(url)](auto&& promise) {
// Resolve the promise upon completion of the task.
promise.set_value("<html> ... </html>");
// Or promise.set_exception(...);
});
}
\endcode
An alternative would be a \ref continuable_base with a result of zero arguments:
\code{.cpp}
auto wait_for(std::chrono::milliseconds duration) {
return cti::make_continuable<void>([](auto&& promise) {
// ^^^^
// Resolve the promise later when the duration is over
promise.set_value();
});
\endcode
A \ref continuable_base may resolve with an arbitrary count of result values:
\code{.cpp}
auto resolve_sth() {
return cti::make_continuable<int, int, float, char>(
[](auto&& promise) {
promise.set_value(0, 1, 2.f, '3');
});
\endcode
\warning A \ref promise_base is only usable once and thus invalidated
after it was resolved!
A \ref promise_base always exposes a call operator for resolving it as
like when using \ref promise_base::set_value or
\ref promise_base::set_exception. See \ref promise_base for details.
\note In order to make proper use of a \ref promise_base you should
move it around, store it for later use and resolve it when
the asynchronous task was finished or rejected.
\section tutorial-creating-continuables-invocation The continuable invocation model
An asynchronous call hierarchy that is stored inside the \ref continuable_base
is executed when its result is requested (lazy evaluation) in contrast to
other commonly used implementations such as `std::future` which execute the
asynchronous call hierarchy instantly on creation (eager evaluation).
The lazy evaluation strategy used by continuables has many benefits over
eager evaluation that is used by other common implementations:
- prevention of side effects
- evasion of race conditions
- ensured deterministic behaviour.
The asynchronous call hierarchy is started when the \ref continuable_base is
destructed or the \ref continuable_base::done method is called.
It is possible to disable the automatic start through calling
\ref continuable_base::freeze on the corresponding \ref continuable_base.
\attention A \ref continuable_base is not designed to be stored permanently,
make sure you call \ref continuable_base::freeze before storing it
and start the continuation chain later through calling
\ref continuable_base::done.
*/
}