Edit the readme

This commit is contained in:
Denis Blank 2017-03-04 02:08:44 +01:00
parent 7ab7c726b6
commit ccd77dee29
4 changed files with 134 additions and 123 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2015-2017 Denis Blank
Copyright (c) 2015 - 2017 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

227
Readme.md
View File

@ -1,6 +1,8 @@
# continuable->then(make_things_simple());
![](https://raw.githubusercontent.com/Naios/continuable/master/doc/slideshow.gif)
[![Build Status](https://travis-ci.org/Naios/continuable.svg?branch=master)](https://travis-ci.org/Naios/continuable) [![Build status](https://ci.appveyor.com/api/projects/status/328ta3r5x92f3byv?svg=true)](https://ci.appveyor.com/project/Naios/continuable) ![](https://img.shields.io/badge/License-MIT-blue.svg) [![](https://img.shields.io/badge/Try-online-green.svg)](http://melpon.org/wandbox/permlink/gRWxSNHtARvRcmSY)
![](https://img.shields.io/badge/Release-v1.0.0-0091EA.svg) [![Build Status](https://travis-ci.org/Naios/continuable.svg?branch=master)](https://travis-ci.org/Naios/continuable) [![Build status](https://ci.appveyor.com/api/projects/status/328ta3r5x92f3byv?svg=true)](https://ci.appveyor.com/project/Naios/continuable) ![](https://img.shields.io/badge/License-MIT-00838F.svg) [![](https://img.shields.io/badge/Documentation-Doxygen-26A69A.svg)](https://naios.github.io/continuable/) [![](https://img.shields.io/badge/Try-online-4DB6AC.svg)](http://melpon.org/wandbox/permlink/xVM2szjDLEge3YLV)
------
> Async C++14 platform independent continuation chainer providing light and allocation aware futures
@ -9,9 +11,30 @@ This library provides full feature support of:
* async continuation chaining using **callbacks** (*then*).
* **no enforced type-erasure** which means we need **extremely fewer heap allocations** .
* support for **finite logical connections** between continuables through an **all, any or sequence** strategy.
* **syntactic sugar** for attaching callbacks to a continuation like partial invocation.
* **syntactic sugar** for attaching callbacks to a continuation like partial invocation or tuple unpacking.
> **Note:** This library only provides the facility for building asynchronous functions. Thus functions shown in the examples and the documentation like `http_request`, `mysql_query` or `read_file` aren't provided by this library.
## Table of contents
- [The library design](#the-library-design)
- [Installation](#installation)
- [How-to use](#how-to-use)
- [Building the unit-tests](#building-the-unit-tests)
- [Stability and version](#stability-and-version)
- [Quick reference](#quick-reference)
- [Creating Continuables](#creating-continuables)
- [Chaining Continuables](#chaining-continuables)
- [Providing helper functions](#providing-helper-functions)
- [Connecting Continuables {all, any or sequential}](#connecting-continuables-all-any-or-sequential)
- [Partial argument application](#partial-argument-application)
- [Dispatching callbacks through a specific executor](#dispatching-callbacks-through-a-specific-executor)
- [Type erasure](#type-erasure)
- [Future conversion](#future-conversion)
- [Compatibility](#compatibility)
- [Similar implementations and alternatives](#similar-implementations-and-alternatives)
- [License](#license)
## The library design
@ -29,7 +52,7 @@ The continuable library was designed in order to provide you as much as flexibil
## Installation
### Inclusion
### How-to use
As mentioned earlier the library is header-only. There is a cmake project provided for simple setup:
@ -46,7 +69,7 @@ add_subdirectory(continuable)
target_link_libraries(my_project continuable)
```
On POSIX you are required to link your application against a corresponding thread library, otherwise `std:: future's` won't work properly, this is done automatically by the provided cmake project.
On POSIX platforms you are required to link your application against a corresponding thread library, otherwise `std::future's` won't work properly, this is done automatically by the provided cmake project.
### Building the unit-tests
@ -58,14 +81,14 @@ git clone --recursive https://github.com/Naios/continuable.git
```
## Stability and version
Currently, the library is in the incubation state, it provides a stable functionality as the CI unit tests indicate.
The library follows the rules of [semantic versioning](http://semver.org/), the API is kept stable across minor versions.
The API isn't fixed right now and will be eventually changed into the future.
Also, the unit-test is observed with the Clang sanitizers (asan, ubsan and lsan - when compiling with Clang) or Valgrind (when compiling with GCC).
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).
## Quick reference
This chapter only overflies the functionality of the continuable library, the full documentation is located at https://naios.github.io/continuable/.
### Creating Continuables
Create a continuable from a callback taking function:
@ -115,6 +138,7 @@ mysql_query("SELECT `id`, `name` FROM `users`")
});
```
> **Note:** The continuation chain is invoked when the object is destructed or the `done()` method is called.
### Providing helper functions
@ -144,12 +168,14 @@ mysql_query("SELECT `id`, `name` FROM users")
});
```
### Connecting Continuables {all or any}
### Connecting Continuables {all, any or sequential}
Continuables provide the operators **&&** and **||** for logical connection:
* **&&** invokes the final callback with the compound result of all connected continuables.
* **||** invokes the final callback once with the first result available.
* **&&** 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.
```C++
auto http_request(std::string url) {
@ -170,6 +196,12 @@ auto http_request(std::string url) {
// 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) {
@ -180,9 +212,40 @@ auto http_request(std::string url) {
// There are helper functions for connecting continuables:
auto all = cti::all_of(http_request("github.com"), http_request("travis-ci.org"));
auto any = cti::any_of(http_request("github.com"), http_request("travis-ci.org"));
auto seq = cti::seq_of(http_request("github.com"), http_request("travis-ci.org"));
```
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).
> **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).
### Partial argument application
The callback is called only with the arguments it's accepting:
```c++
(http_request("github.com") && read_file("entries.csv"))
.then([] {
// ^^^^^^ The original signature was <std::string, Buffer>,
// however, the callback is only invoked with the amount of
// arguments it's accepting.
});
```
### Dispatching callbacks through a specific executor
Dispatching a callback through a specific executor is supported through through the second argument of `then()`:
```c++
auto executor = [](auto&& work) {
// Dispatch the work here, store it for later invocation or move it to another thread.
std::forward<decltype(work)>(work)();
};
read_file("entries.csv")
.then([](Buffer buffer) {
// ...
}, executor);
// ^^^^^^^^
```
### Type erasure
@ -211,13 +274,13 @@ However you may still define your own continuation wrapper with the backend of y
```c++
template <typename... Args>
using mycontinuation = cti::continuable_of_t<
cti::continuable_erasure_of_t<std::function, std::function, Args...>,
Args...>;
using my_continuation = typename cti::continuable_trait<
std::function, std::function, Args...
>::continuable;
// ...
mycontinuation<int> myc = cti::make_continuable([](auto&& callback) {
my_continuation<int> myc = cti::make_continuable([](auto&& callback) {
// ^^^^^
// Signatures may be omitted for continuables which are type erased
callback(0);
@ -228,7 +291,7 @@ We could also think about using `std::future` as backend but this is even worse
### Future conversion
The library is capable of converting (*futurizing*) every continuable into a fitting **std::future** through the `continuable<...>::futurize()` method.
The library is capable of converting (*futurizing*) every continuable into a fitting **std::future** through the `continuable<...>::futurize()` method.:
```c++
std::future<std::string> future = http_request("github.com")
@ -243,87 +306,7 @@ std::future<std::tuple<std::string, std::string>> future =
(http_request("travis-ci.org") && http_request("atom.io")).futurize();
```
Continuables returning nothing will evaluate to: `std::future<void>`.
Continuables returning only one value will evaluate the corresponding future: `std::future<type>`.
Continuables returning more then one value will evaluate to a future providing a tuple carrying the values : `std::future<std::tuple<...>>`.
### In Progress (ToDo-List)
Although the library has progressed very far there are still some candies missing:
- [x] **Partial application**:
We could allow callbacks to be invoked with fewer arguments than expected:
```C++
http_request("github.com")
.then([]() { // ERROR: Because we expect an object accepting a std::string
// ...
});
```
- [x] The **sequential operator** which invokes continuables sequentially and calls the callback with all results:
```c++
(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 done sequentially and the callback is called
// with the response of github, travis and atom as soon as atom has responded.
// The responses of github and travis are stored meanwhile.
});
auto seq = cti::seq_of(http_request("github.com"), http_request("travis-ci.org"));
```
This differs from the `all` connection in the way that the continuables are invoked sequentially instead of parallel.
- [ ] **Inplace resolution** (makes it possible to keep the nesting level flat):
```c++
http_request("github.com")
.then([](std::string response) {
// Do something with the response
int response_code = get_code(response);
return std::make_tuple(http_request("atom.io"), response_code);
// ^^^^^^^^^^^^^^^^^^^^^^^
})
.then([](std::string atom, int response_code) {
// - `std::string atom` was resolved from `http_request("atom.io")`
// - `response_code` was passed through the tuple directly
});
```
- [ ] Library support of **infinite logical connections**:
```c++
std::vector<cti::continuable<int, int>> some;
cti::all(std::move(some))
.then([](std::vector<int, int> result) {
// ...
});
```
This library mainly aims to support un-erased continuations, however, sometimes it's required to work with a compile-time unknown amount of continuables.
- [ ] Maybe **Un-erasured fail/rejection handlers** and (possible exception support):
```c++
http_request("github.com")
.rejected([](std::error_code) {
// Is called when the request fails
// Potential difficult to implement with less type erasure
});
```
> **Note:** See the [doxygen documentation](https://naios.github.io/continuable/) for detailed information about the return type of `futurize()`.
## Compatibility
@ -335,11 +318,9 @@ Tested & compatible with:
Every compiler with modern C++14 support should work.
The library only depends on the standard library when using the `continuable/continuable-base.hpp` header only which provides the full un-erasured support.
The library only depends on the standard library when using the `continuable/continuable-base.hpp` header, which provides the basic continuation logic.
On Posix: don't forget to **link a corresponding thread library** into your application otherwise `std::future's` won't work `(-pthread)`.
> **Note:** On Posix: don't forget to **link a corresponding thread library** into your application otherwise `std::future's` won't work `(-pthread)`.
## Similar implementations and alternatives
@ -351,16 +332,46 @@ There are some existing solutions with similar design thoughts already, which I
Is designed in a similar way, however, it orientates itself more on the corresponding JavaScript libraries which leaves some benefits behind we could reach with modern C++ meta-programming. Like previous approaches, the library uses type erasure excessively (and thus isn't memory allocation aware). What differentiates **q** from the continuable library is that it supports infinite logical connections and ships with built-in exception support as well as it's own executors (thread pools) - thus the library isn't header-only anymore (but the library is still proclaimed to work with other executors). My personal opinion is that a continuation library shouldn't include any other stuff then the continuation logic itself.
### [cpprestsdk](https://github.com/Microsoft/cpprestsdk)
#### [cpprestsdk](https://github.com/Microsoft/cpprestsdk)
Basically, the same arguments as explained in the q section apply to the cpprestsdk as well, it's major drawbacks is the overwhelming use of type-erasure. Probably you will benefit a lot from the library if you intend to use it's provided asynchronously *http*, *websocket* and *filesystem* functionalities. The *continuable* library was designed with different thoughts in mind - it basically provides the continuation logic without any support methods so you can embed it into your application without depending on a heavy framework. This makes it possible to apply continuation chaning to esoteric domains such as C++ AI scripts with fast or immediately response times. Who knows - maybe someone will provide *continuable* wrappers for open-source libraries like *asio*, libuv or *uWebSockets* in the future too.
### Others
If I forget to mention a library here let me know, so we can add the alternatives.
> **Note:** If I forget to mention a library here let me know, so we can add the alternatives.
## License
The continuable library is licensed under the MIT License
The continuable library is licensed under the MIT License:
```c++
/**
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
https://github.com/Naios/continuable
v0.8.0
Copyright(c) 2015 - 2017 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.
**/
```

View File

@ -31,13 +31,11 @@ struct ResultSet {};
struct Buffer {};
cti::continuable<ResultSet> mysql_query(std::string /*url*/) {
return cti::make_continuable<std::string>(
[](auto&& callback) { callback("<html>...</html>"); });
return cti::make_continuable([](auto&& callback) { callback(ResultSet{}); });
}
cti::continuable<Buffer> read_file(std::string /*url*/) {
return cti::make_continuable<std::string>(
[](auto&& callback) { callback("<html>...</html>"); });
return cti::make_continuable([](auto&& callback) { callback(Buffer{}); });
}
struct a {
@ -55,34 +53,38 @@ int main(int, char**) {
// ----------
(http_request("github.com") && http_request("atom.io"))
.then([] (std::string github, std::string atom) {
.then([] (std::string /*github*/, std::string /*atom*/) {
// ...
return mysql_query("select * from `users`");
})
.then([] (ResultSet result) {
.then([] (ResultSet /*result*/) {
// ...
}, executor->post());
// ----------
auto cq = http_request("github.com") && http_request("atom.io") ;
auto c1 = http_request("github.com") && http_request("atom.io") ;
auto cq = http_request("github.com") || http_request("atom.io") ;
auto c2 = http_request("github.com") || http_request("atom.io") ;
auto cq = http_request("github.com") >> http_request("atom.io") ;
auto c3 = http_request("github.com") >> http_request("atom.io") ;
(void)c1;
(void)c2;
(void)c3;
// ----------
read_file("entries.csv")
.then([] (Buffer buffer) {
.then([] (Buffer /*buffer*/) {
// ...
return std::make_tuple("hey", true, 0);
})
.then([] (std::string msg) {
.then([] (std::string /*msg*/) {
// ...
});

View File

@ -22,6 +22,4 @@
#include "continuable/continuable.hpp"
int main(int, char**) {
return 0;
}
int main(int, char**) { return 0; }