Compare commits

..

27 Commits
0.3 ... dev

Author SHA1 Message Date
4384b0b311 Fix on multiple await, is block thread/loop: replace get with await. Add some comments 2025-06-12 08:45:30 +02:00
8d9a56dc8e Test, debug and fix coroutine 2025-06-11 19:32:40 +02:00
748fd0a586 Write examples and tests, refaktor, tested 2025-06-11 09:56:32 +02:00
e76623bef0 Remove fs, delayed, periodic class, use one shared type Timer, clean design, enable to init multiple runtimes 2025-06-11 00:27:10 +02:00
ceb3967178 Merge branch 'coroutines' into dev 2025-06-10 21:25:27 +02:00
8d7796998f Fix block loop in await_ 2025-06-10 15:07:54 +02:00
d37f85f728 Limit Nonblocking loop await 2025-06-10 11:32:21 +02:00
a1606fd3b6 Await all on no-void return values 2025-03-31 12:22:38 +02:00
5608eab8eb Add await_ to run on runtime and await_ - short code 2025-03-29 08:57:30 +01:00
d546ca9db8 Rename in readme 2 2025-03-28 23:20:13 +01:00
ce2c22676b Rename in readme 2025-03-28 23:18:49 +01:00
9965f1e1c7 Rename definition for awaitable coruotines 2025-03-28 23:14:34 +01:00
aca2724e0c Support Boost.Asio coroutine, clean, rename 2025-03-28 23:00:01 +01:00
marcelb
1853318016 Switch to CMake 2025-01-20 22:37:58 +01:00
marcelb
eb8cdee237 Example of implement multi trigger in class 2024-11-24 20:26:13 +01:00
marcelb
5b0e363cd5 Merge branch 'multiple_init_problem' of https://git.bitelex.co/marcelb/asynco into multiple_init_problem 2024-10-24 18:40:45 +02:00
marcelb
78501b0c9b Edit gitignore 2024-10-24 18:40:21 +02:00
3fc313a9b5 Timed await 2024-10-17 13:07:08 +00:00
marcelb
9e773f55c9 Fix multiple engine init problem and enable anonim init timers 2024-09-27 20:16:23 +02:00
1ccac9dbf8 Separate timers in hpp and cpp files 2024-09-26 09:59:55 +00:00
4f674467d2 Alignet in readme 2024-09-26 07:27:41 +00:00
8b23bd6728 Merge branch 'nonsync_wait' of https://git.bitelex.co/marcelb/asynco into nonsync_wait 2024-09-26 07:25:26 +00:00
2876372552 Add example for await all 2024-09-26 07:23:33 +00:00
7bf7a7d090 Async_ await_ 2024-09-26 06:51:45 +00:00
marcelb
d8e0d0b49d Edit readme 2024-09-25 22:40:46 +02:00
0b94c1e86c Change function names, and add #define for color 2024-09-06 08:56:08 +00:00
e3eddf006b Rename event to trigger 2024-04-26 09:58:45 +00:00
26 changed files with 1366 additions and 914 deletions

5
.gitignore vendored
View File

@ -1,2 +1,3 @@
test/test build
test/*.txt .vscode
example

View File

@ -1,16 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c17",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

74
.vscode/settings.json vendored
View File

@ -1,74 +0,0 @@
{
"files.associations": {
"iostream": "cpp",
"functional": "cpp",
"thread": "cpp",
"chrono": "cpp",
"ostream": "cpp",
"condition_variable": "cpp",
"array": "cpp",
"atomic": "cpp",
"cwchar": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"mutex": "cpp",
"new": "cpp",
"ratio": "cpp",
"stdexcept": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"future": "cpp",
"*.ipp": "cpp",
"bitset": "cpp",
"algorithm": "cpp",
"string": "cpp",
"string_view": "cpp",
"fstream": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwctype": "cpp",
"any": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"cstdint": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"system_error": "cpp",
"iomanip": "cpp",
"istream": "cpp",
"limits": "cpp",
"numbers": "cpp",
"semaphore": "cpp",
"sstream": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"variant": "cpp"
}
}

28
.vscode/tasks.json vendored
View File

@ -1,28 +0,0 @@
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: gcc build active file",
"command": "/usr/bin/g++",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}

35
CMakeLists.txt Normal file
View File

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.10)
project(Asynco)
# Postavi verziju projekta
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Pronađi Boost biblioteku (ako nije uobičajeni direktorijum, postavi put)
find_package(Boost REQUIRED COMPONENTS system)
# Dodaj direktorijume sa zaglavljima
include_directories(lib)
# Dodaj biblioteku
add_library(asynco STATIC
src/asynco.cpp
src/asynco_default.cpp
src/timers.cpp
)
# Linkaj Asynco biblioteku sa Boost-om
target_link_libraries(asynco Boost::system)
# Dodaj testove
add_subdirectory(test)
add_compile_options(-w)
# Instaliraj biblioteku
# install(TARGETS asynco DESTINATION lib)
# install(FILES lib/asynco.hpp lib/define.hpp lib/engine.hpp lib/filesystem.hpp lib/timers.hpp lib/trigger.hpp DESTINATION include/asynco)
#

300
README.md
View File

@ -1,59 +1,89 @@
# Asynco # Asynco
A C++ library for event-driven asynchronous multi-threaded programming. A C++ library for event-driven asynchronous multi-threaded programming that serves as a runtime for asynchronous operations. It acts as a wrapper around the Boost.Asio library, providing a cleaner way to write asynchronous, concurrent, and parallel code utilizing a set of threads and an event loops. It offers features for event-driven programming, timers, and coroutine support.
## Motivation ## Motivation
The original concept was to create an interface capable of asynchronously calling any function. It has since evolved into a library that incorporates a thread pool, each with its own event loop, event-driven programming, and functions inherently designed for asynchronous operation (including periodic and delayed functions). The initial goal was to create an interface that makes it easy and clean to asynchronously invoke any function in C++ without resorting to complex calls. Initially, the library was built around a custom implementation of a scheduling loop for queuing functions. However, this part was later replaced with Boost.Asio, mainly for its timer functionality. As the library evolved, it expanded to include a thread pool, each with its own event loop, and adopted event-driven programming. This enhancement also introduced functions specifically designed for asynchronous operations, including periodic and delayed execution.
The asynchronous filesystem is provided solely to guide users on how to wrap any time- or IO-intensive function for asynchronous execution. The asynchronous filesystem was included solely to demonstrate how users can wrap any time- or I/O-intensive functions for asynchronous execution.
## Features ## Features
- Object oriented - Object oriented
- Small and easy to integrate - Small and easy to integrate
- Header only
- Asynchronous programming - Asynchronous programming
- Multithread - Multithread
- Asynchronous timer functions: periodic, delayed (like setInterval and setTimeout from JS) - Asynchronous timer functions: Periodic, Delayed (like setInterval and setTimeout from JS)
- Typed events (on, emit, off) - Typed events (on, tick, off) (like EventEmitter from JS: on, emit, etc)
- Event loops - Event loops
- Multiple parallel execution loops - Multiple parallel execution loops
- Asynchronous file IO
- Based on ASIO (Boost Asio) - Based on ASIO (Boost Asio)
- On C++20 support Boost.Asio coroutines
## Installation ## Installation
Just download the latest release and unzip it into your project. Just download the latest release and unzip it into your project.
```c++ ```c++
#define NUM_OF_RUNNERS 8 // To change the number of threads used by atask, without this it runs according to the number of cores // for default global runtime
#include "asynco/lib/asynco_default.hpp"
#include "asynco/lib/asynco.hpp" // atask(), wait()
#include "asynco/lib/event.hpp" // event
#include "asynco/lib/timers.hpp" // periodic, delayed (like setInterval and setTimeout from JS)
#include "asynco/lib/filesystem.hpp" // for async read and write files
using namespace marcelb; using namespace marcelb;
using namespace asynco; using namespace asynco;
using namespace events;
// At the end of the main function, always set int main() {
_asynco_engine.run(); asynco_default_run();
return 0;
// code
asynco_default_join()
return 0;
}
// own instace of runtime
#include "asynco/lib/asynco.hpp"
using namespace marcelb;
using namespace asynco;
int main() {
Asynco asynco;
asynco.run(2);
// code
asynco.join();
return 0;
}
``` ```
## Usage ## Usage
Time asynchronous functions In the following sections, we will explore timers, function execution via the runtime, asynchronous invocation, and waiting for results. We will cover essential use cases involving triggers, and coroutines.
### Timers
We have one timer classes, int two mode Periodic (which runs a callback function periodically), and Delayed (delayed runs a callback function only once).
```c++ ```c++
// start periodic // start periodic
periodic inter1 ([]() { Timer inter1 = periodic ([]() {
cout << "Interval 1" << endl; cout << "Interval 1" << endl;
}, 1000); }, 1000);
// or usint own instance runtime
/**
* Asynco asynco;
* asynco.run(2);
* Timer inter1 = asynco.periodic ([]() {
* cout << "Interval 1" << endl;
* }, 1000);
*/
// stop periodic // stop periodic
inter1.stop(); inter1.stop();
@ -64,7 +94,7 @@ int t = inter1.ticks();
bool stoped = inter1.stoped(); bool stoped = inter1.stoped();
// start delayed // start delayed
delayed time1 ( [] () { Timer time1 = delayed( [] () {
cout << "Timeout 1 " << endl; cout << "Timeout 1 " << endl;
}, 10000); }, 10000);
@ -78,16 +108,18 @@ int t = time1.expired();
bool stoped = time1.stoped(); bool stoped = time1.stoped();
``` ```
Make functions asynchronous ### Make functions asynchronous
Running functions at runtime, asynchronous execution, uses the `async_` call and its return type is `std::future<T>`
```c++ ```c++
/** /**
* Run an lambda function asynchronously * Run an lambda function asynchronously
*/ */
atask( []() { async_ ( []() {
sleep_for(2s); // only for simulating long duration function sleep(2); // only for simulating long duration function
cout << "atask" << endl; cout << "nonsync " << endl;
return 5; return 5;
}); });
@ -100,7 +132,7 @@ void notLambdaFunction() {
cout << "Call to not lambda function" << endl; cout << "Call to not lambda function" << endl;
} }
atask (notLambdaFunction); async_ (notLambdaFunction);
/** /**
* Run class method * Run class method
@ -114,84 +146,58 @@ class clm {
}; };
clm classes; clm classes;
atask( [&classes] () { async_ ( [&classes] () {
classes.classMethode(); classes.classMethode();
}); });
```
To wait for the result (blocking the flow) use `await_` (This does not block the event loop in principle. If the result is not ready for a short time, it starts another job in place while it waits.)
```c++
/** auto a = async_ ( []() {
* Wait after runned as async sleep(2); // only for simulating long duration function
*/ cout << "nonsync " << endl;
auto a = atask( []() {
sleep_for(2s); // only for simulating long duration function
cout << "atask" << endl;
return 5; return 5;
}); });
cout << wait(a) << endl; cout << await_(a) << endl;
/** /**
* Wait async function call and use i cout * await_ async function call and use i cout
*/ */
cout << wait(atask( [] () { cout << await_(async_ ( [] () {
sleep_for(chrono::seconds(1)); // only for simulating long duration function sleep(1); // only for simulating long duration function
cout << "wait end" << endl; cout << "await_ end" << endl;
return 4; return 4;
})) << endl; })) << endl;
/**
* Sleep with delayed sleep implement
*/
void sleep_to (int _time) {
promise<void> _promise;
delayed t( [&]() {
_promise.set_value();
}, _time);
return _promise.get_future().get();
}
sleep_to(3000);
/**
* Catch promise reject
*/
void promise_reject (int _time) {
promise<void> _promise;
delayed t( [&]() {
try {
// simulate except
throw runtime_error("Error simulation");
_promise.set_value();
} catch (...) {
_promise.set_exception(current_exception());
}
}, _time);
return _promise.get_future().get();
}
try {
promise_reject(3000);
} catch (runtime_error err) {
cout<< err.what() << endl;
}
``` ```
Events
If you want to run asynchronously but need the result immediately, you can use a shorter notation
```c++
await_ ([]() {
cout << "Hello" << endl;
});
```
Here too you can use your own runtime instance, only the methods are `.async()` and `.await()`
### Triggers
The library implements Triggers, which are basically typed Events.
```c++ ```c++
/** /**
* initialization of typed events * initialization of typed events
*/ */
event<int, int> ev2int; Trigger<int, int> ev2int = trigger<int, int>();
event<int, string> evintString; Trigger<int, string> evintString = trigger<int, string>();
event<> evoid; Trigger<> evoid = trigger<>();
ev2int.on("sum", [](int a, int b) { ev2int.on("sum", [](int a, int b) {
cout << "Sum " << a+b << endl; cout << "Sum " << a+b << endl;
@ -219,32 +225,32 @@ sleep(1);
* Emit * Emit
*/ */
ev2int.emit("sum", 5, 8); ev2int.tick("sum", 5, 8);
sleep(1); sleep(1);
evintString.emit("substract", 3, to_string(2)); evintString.tick("substract", 3, to_string(2));
sleep(1); sleep(1);
evoid.emit("void"); evoid.tick("void");
// Turn off the event listener // Turn off the event listener
evoid.off("void"); evoid.off("void");
evoid.emit("void"); // nothing is happening evoid.tick("void"); // nothing is happening
``` ```
Extend own class whit events Extend own class whit events
```c++ ```c++
class myOwnClass : public event<int> { class myOwnClass : public Trigger<int> {
public: public:
myOwnClass() : event() {}; myOwnClass() : Trigger(asynco_default_runtime()) {};
}; };
myOwnClass myclass; myOwnClass myclass;
delayed t( [&] { Delayed t( [&] {
myclass.emit("constructed", 1); myclass.tick("constructed", 1);
}, 200); }, 200);
myclass.on("constructed", [] (int i) { myclass.on("constructed", [] (int i) {
@ -253,46 +259,110 @@ myclass.on("constructed", [] (int i) {
``` ```
Asynchronous file IO Implementing a class with multiple triggers of different types
```c++ ```c++
string data_;
fs::read("test.txt", [&data_] (string data, exception* error) { class ClassWithTriggers {
if (error) { Trigger<int> emitter1;
cout << "Error " << error->what() << endl; Trigger<string> emitter2;
} else {
cout << "Data " << endl << data << endl; public:
data_ = data; ClassWithTriggers(): emitter1(asynco_default_runtime()), emitter2(asynco_default_runtime()) {}
cout << "Data_" << data_ << endl;
template<typename... T>
void on(const string& key, function<void(T...)> callback) {
if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, int>) {
emitter1.on(key, callback);
}
else if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, string>) {
emitter2.on(key, callback);
}
} }
});
fs::write("test1.txt", "Hello world", [] (exception* error) { template <typename... Args>
if (error) { void tick(const string& key, Args&&... args) {
cout << "Error " << error->what() << endl; if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, int>) {
} else { emitter1.tick(key, forward<Args>(args)...);
cout << "Write successfuly" << endl; }
else if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, string>) {
emitter2.tick(key, forward<Args>(args)...);
}
else {
static_assert(sizeof...(Args) == 0, "Unsupported number or types of arguments");
}
} }
}); };
auto future_data = fs::read("test.txt"); ClassWithTriggers mt;
try { mt.on<int>("int", function<void(int)>([&](int i) {
string data = wait(future_data); cout << "Emit int " << i << endl;
} catch (exception& err) { }));
cout << err.what() << endl;
}
auto future_status = fs::write("test.txt", "Hello world"); mt.on<string>("string", function<void(string)>([&](string s) {
cout << "Emit string " << s << endl;
}));
try { mt.tick("int", 5);
wait(future_status); mt.tick("string", string("Hello world"));
} catch (exception& err) {
cout << err.what() << endl; ```
## Coroutine
If `define.hpp` is included, you can initialize coroutines with `boost::asio::awaitable<T>`.
```c++
awaitable<int> c2(int a) {
co_return a * 2;
} }
``` ```
To run the coroutine at runtime, simply call:
```c++
async_(c2(4));
```
Or using a lambda expression:
```c++
async_([]() -> awaitable<void> {
std::cout << "Hello" << std::endl;
co_await c2(4);
co_return;
}());
```
To retrieve results from coroutines, you can do so as you would from classical functions by calling `await_`:
```c++
int r = await_(
async_(
c2(10)
));
```
If you need the result immediately, you can use a shorter notation
```c++
auto a = await_ ( c2(3));
cout << a << endl;
await_ ([]() -> awaitable<void> {
cout << "Hello" << endl;
co_return;
}());
```
If you need a result, you can also retrieve it with `await_`.
Here too you can use your own runtime instance, only the methods are `.async()` and `.await()`
## License ## License

View File

@ -1,85 +1,187 @@
#ifndef _ASYNCO_ #ifndef _ASYNCO_
#define _ASYNCO_ #define _ASYNCO_
#include <boost/asio.hpp> #include <vector>
#include <memory>
#include <type_traits>
#include <thread>
#include <future>
#include <functional>
#include <iostream> #include <iostream>
using namespace std; using namespace std;
#include <boost/asio.hpp>
#if __cplusplus >= 202002L
#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/use_awaitable.hpp>
#endif
using namespace boost::asio;
#include "timers.hpp"
#include "trigger.hpp"
namespace marcelb { namespace marcelb {
namespace asynco { namespace asynco {
#define HW_CONCURRENCY_MINIMAL 4
/** /**
* Internal anonymous class for initializing the ASIO context and thread pool * Asynco runtime
* !!! It is anonymous to protect against use in the initialization of other objects of the same type !!! * Used for all asynchronous capabilities of this wrapper
* Initializes threads and boost::asio::io_context
*/ */
class { class Asynco {
public: vector<thread> _runners;
boost::asio::io_context io_context; unique_ptr<io_service::work> _work;
void run() { void init_loops_in_threads(uint8_t threads);
for (auto& runner : runners) {
runner.join(); public:
} io_context io_ctx;
/**
* It starts the thread initialization and the Boost::Asio event loop in each of them
*/
void run(uint8_t threads = thread::hardware_concurrency());
/**
* Starts Boost::Asio event loop in the current thread
*/
void run_on_this();
/**
* Waits until all threads have finished working
*/
void join();
/**
* Run the function asynchronously in runtime
*/
template<class F, class... Args>
auto async(F&& f, Args&&... args) -> future<invoke_result_t<F, Args...>> {
using return_type = invoke_result_t<F, Args...>;
future<return_type> res = io_ctx.post(boost::asio::use_future(bind(forward<F>(f), forward<Args>(args)...)));
return res;
} }
private: #if __cplusplus >= 202002L
/**
* Run the coroutine in runtime
*/
template <typename T>
future<T> async(boost::asio::awaitable<T> _coroutine) {
promise<T> promise;
auto future = promise.get_future();
unique_ptr<boost::asio::io_service::work> work { [&] () { co_spawn(io_ctx, [_coroutine = move(_coroutine), promise = move(promise)]() mutable -> boost::asio::awaitable<void> {
return new boost::asio::io_service::work(io_context); try {
} ()}; if constexpr (!is_void_v<T>) {
T result = co_await move(_coroutine);
vector<thread> runners { [&] () { promise.set_value(move(result));
vector<thread> _runs; } else {
unsigned int num_of_runners; co_await move(_coroutine);
#ifdef NUM_OF_RUNNERS promise.set_value(); // Za void ne postavljamo rezultat
num_of_runners = NUM_OF_RUNNERS; }
#else } catch (...) {
num_of_runners = thread::hardware_concurrency(); promise.set_exception(current_exception()); // Postavljamo izuzetak
if (num_of_runners < HW_CONCURRENCY_MINIMAL) {
num_of_runners = HW_CONCURRENCY_MINIMAL;
} }
#endif }, boost::asio::detached);
for (int i=0; i<num_of_runners; i++) { return future;
_runs.push_back(thread ( [this] () { }
io_context.run(); #endif
}));
/**
* Wait until the asynchronous call completes
*/
template<typename T>
T await(future<T>& r, uint16_t time_us = 10) {
while (r.wait_for(std::chrono::microseconds(time_us)) != future_status::ready) {
io_ctx.poll_one();
} }
return r.get();
}
return _runs; /**
} ()}; * Wait until the asynchronous call completes
*/
template<typename T>
T await(future<T>&& r, uint16_t time_us = 10) {
while (r.wait_for(std::chrono::microseconds(time_us)) != future_status::ready) {
io_ctx.poll_one();
}
return move(r).get();
}
} _asynco_engine; /**
* Run the function asynchronously an wait until completes
*/
template<class F, class... Args>
auto await(F&& f, Args&&... args) -> invoke_result_t<F, Args...> {
return await(
async(f, args...)
);
}
/** #if __cplusplus >= 202002L
* Run the function asynchronously /**
*/ * Run the coruotine and wait
template<class F, class... Args> */
auto atask(F&& f, Args&&... args) -> future<typename result_of<F(Args...)>::type> { template <typename T>
using return_type = typename result_of<F(Args...)>::type; T await(boost::asio::awaitable<T> _coroutine) {
future<return_type> res = _asynco_engine.io_context.post(boost::asio::use_future(bind(forward<F>(f), forward<Args>(args)...))); return await(
return res; async(
} move(_coroutine)
));
}
#endif
/** /**
* Block until the asynchronous call completes * Wait until the multiple asynchronous call completes
*/ * Use only on no-void calls
template<typename T> */
T wait(future<T>& r) {
return r.get(); template<typename... F>
} auto await(F&&... f) -> tuple<typename decay<decltype(await(f))>::type...> {
return make_tuple(await(f)...);
}
/**
* Wait until the multiple asynchronous call completes
* Use only on no-void calls
*/
template<typename... F>
auto await(F&... f) -> tuple<typename decay<decltype(await(f))>::type...> {
return make_tuple(await(f)...);
}
/**
* Initialize the delayed timer
*/
Timer delayed(function<void()> callback, uint64_t time);
/**
* Initialize the periodic timer
*/
Timer periodic(function<void()> callback, uint64_t time);
/**
* Initialize trigger (typed event)
*/
template<typename... T>
Trigger<T...> trigger() {
return Trigger<T...>(*this);
}
};
/**
* Block until the asynchronous call completes
*/
template<typename T>
T wait(future<T>&& r) {
return move(r).get();
}
} }
} }

155
lib/asynco_default.hpp Normal file
View File

@ -0,0 +1,155 @@
#ifndef _ASYNCO_DEFAULT_
#define _ASYNCO_DEFAULT_
#include "asynco.hpp"
namespace marcelb {
namespace asynco {
/**
* Default runtime
*/
extern Asynco Asynco_Default_Runtime;
/**
* Run the function asynchronously in default runtime
*/
template<class F, class... Args>
auto async_(F&& f, Args&&... args) -> future<invoke_result_t<F, Args...>> {
return Asynco_Default_Runtime.async(bind(forward<F>(f), forward<Args>(args)...));
}
#if __cplusplus >= 202002L
/**
* Run the coroutine in default runtime
*/
template <typename T>
std::future<T> async_(boost::asio::awaitable<T> _coroutine) {
return Asynco_Default_Runtime.async(move(_coroutine));
}
#endif
/**
* Wait until the asynchronous call completes
*/
template<typename T>
T await_(future<T>& r, uint16_t time_us = 10) {
return Asynco_Default_Runtime.await(r, time_us);
}
/**
* Wait until the asynchronous call completes
*/
template<typename T>
T await_(future<T>&& r, uint16_t time_us = 10) {
return Asynco_Default_Runtime.await(r, time_us);
}
/**
* Run the function asynchronously an wait until completes
*/
template<class F, class... Args>
auto await_(F&& f, Args&&... args) -> invoke_result_t<F, Args...> {
return Asynco_Default_Runtime.await(bind(forward<F>(f), forward<Args>(args)...));
}
#if __cplusplus >= 202002L
/**
* Run the coruotine and wait
*/
template <typename T>
T await_(boost::asio::awaitable<T> _coroutine) {
return Asynco_Default_Runtime.await(move(_coroutine));
}
#endif
/**
* Wait until the multiple asynchronous call completes
* Use only on no-void calls
*/
template<typename... F>
auto await_(F&&... f) -> std::tuple<typename std::decay<decltype(Asynco_Default_Runtime.await(f))>::type...> {
return Asynco_Default_Runtime.await(move(f)...);
}
/**
* Wait until the multiple asynchronous call completes
* Use only on no-void calls
*/
template<typename... F>
auto await_(F&... f) -> std::tuple<typename std::decay<decltype(Asynco_Default_Runtime.await(f))>::type...> {
return Asynco_Default_Runtime.await(f...);;
}
/**
* Initialize the delayed timer
*/
Timer delayed(function<void()> callback, uint64_t time);
/**
* Initialize the periodic timer
*/
Timer periodic(function<void()> callback, uint64_t time);
/**
* Initialize trigger (typed event)
*/
template<typename... T>
Trigger<T...> trigger() {
return Trigger<T...>(Asynco_Default_Runtime);
}
/**
* Get reference of default runtime
*/
Asynco& asynco_default_runtime();
/**
* Run default runtime
*/
void asynco_default_run();
/**
* Run default runtime in this thread
*/
void asynco_default_run_on_this();
/**
* Waits until all threads have finished working
*/
void asynco_default_join();
/**
* Get reference of boost::asio::io_context
*/
io_context& asynco_default_io_context();
/**
* Run the function asynchronously in default runtime
*/
#define async_ marcelb::asynco::async_
/**
* Wait until the asynchronous call completes
*/
#define await_ marcelb::asynco::await_
}
}
#endif

View File

@ -1,115 +0,0 @@
#ifndef _ASYNCO_FS_
#define _ASYNCO_FS_
#include "asynco.hpp"
using namespace marcelb;
using namespace asynco;
#include <fstream>
using namespace std;
namespace marcelb {
namespace asynco {
namespace fs {
/**
* Asynchronous file reading with callback after read complete
*/
template<typename Callback>
void read(string path, Callback&& callback) {
atask( [&path, callback] () {
string content;
try {
string line;
ifstream file (path);
if (file.is_open()) {
line.clear();
while ( getline (file,line) ) {
content += line + "\n";
}
file.close();
}
else {
throw runtime_error("Unable to open file");
}
callback(content, nullptr);
} catch(exception& error) {
callback(content, &error);
}
});
}
/**
* Asynchronous file reading
*/
future<string> read(string path) {
return atask( [&path] () {
string content;
string line;
ifstream file (path);
if (file.is_open()) {
line.clear();
while ( getline (file,line) ) {
content += line + "\n";
}
file.close();
return content;
}
else {
throw runtime_error("Unable to open file");
}
});
}
/**
* Asynchronous file writing with callback after write complete
*/
template<typename Callback>
void write(string path, string content, Callback&& callback) {
atask( [&path, &content, callback] () {
try {
ofstream file (path);
if (file.is_open()) {
file << content;
file.close();
}
else {
throw runtime_error("Unable to open file");
}
callback(nullptr);
} catch(exception& error) {
callback(&error);
}
});
}
/**
* Asynchronous file writing with callback after write complete
*/
future<void> write(string path, string content) {
return atask( [&path, &content] () {
ofstream file (path);
if (file.is_open()) {
file << content;
file.close();
return;
}
else {
throw runtime_error("Unable to open file");
}
});
}
}
}
}
#endif

View File

@ -1,12 +1,12 @@
#ifndef _TIMERS_ #ifndef _ASYNCO_TIMERS_
#define _TIMERS_ #define _ASYNCO_TIMERS_
#include "asynco.hpp"
#include <chrono> #include <chrono>
#include <iostream>
using namespace std; using namespace std;
using namespace marcelb;
using namespace asynco; #include <boost/asio.hpp>
using namespace boost::asio;
namespace marcelb { namespace marcelb {
namespace asynco { namespace asynco {
@ -15,29 +15,27 @@ namespace asynco {
* Get the time in ms from the epoch * Get the time in ms from the epoch
*/ */
int64_t rtime_ms() { int64_t rtime_ms();
return chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now()
.time_since_epoch())
.count();
}
/** /**
* Get the time in us from the epoch * Get the time in us from the epoch
*/ */
int64_t rtime_us() { int64_t rtime_us();
return chrono::duration_cast<chrono::microseconds>(chrono::system_clock::now()
.time_since_epoch()) enum TimerType {
.count(); Delayed,
} Periodic
};
/** /**
* Core timer class for construct time async functions * Core timer class for construct time async functions
*/ */
class timer { class Timer {
boost::asio::steady_timer st; io_context& io_ctx;
steady_timer st;
bool _stop = false; bool _stop = false;
bool repeate; TimerType type;
function<void()> callback; function<void()> callback;
uint64_t time; uint64_t time;
uint64_t _ticks = 0; uint64_t _ticks = 0;
@ -45,178 +43,48 @@ class timer {
/** /**
* A method to assign a callback wrapper and a reinitialization algorithm * A method to assign a callback wrapper and a reinitialization algorithm
*/ */
void init() { void init();
st.async_wait( [this] (const boost::system::error_code&) {
if (!_stop) {
callback();
if (repeate) {
st = boost::asio::steady_timer(_asynco_engine.io_context, boost::asio::chrono::milliseconds(time));
init();
}
_ticks++;
}
});
}
public: public:
/** /**
* The constructor creates the steady_timer and accompanying variables and runs a method to initialize the timer * The constructor creates the steady_timer and accompanying variables and runs a method to initialize the timer
*/ */
timer (function<void()> _callback, uint64_t _time, bool _repeate) : Timer (io_context& io_ctx, function<void()> _callback, uint64_t _time, TimerType _type = TimerType::Delayed);
st(_asynco_engine.io_context, boost::asio::chrono::milliseconds(_time)),
_stop(false),
repeate(_repeate),
callback(_callback),
time(_time) {
init();
}
/** /**
* Stop timer * Stop timer
* The stop flag is set and timer remove it from the queue * The stop flag is set and timer remove it from the queue
*/ */
void stop() { void stop();
_stop = true;
st.cancel();
}
/** /**
* Run callback now * Run callback now
* Forces the callback function to run independently of the timer * Forces the callback function to run independently of the timer
*/ */
void now() { void now();
st.cancel();
}
/** /**
* Get the number of times the timer callback was runned * Get the number of times the timer callback was runned
*/ */
uint64_t ticks() { uint64_t ticks();
return _ticks;
}
/**
* The logic status of the timer stop state
*/
bool stoped() {
return _stop;
}
/**
* The destructor stops the timer
*/
~timer() {
stop();
}
};
/**
* Class periodic for periodic execution of the callback in time in ms
*/
class periodic {
shared_ptr<timer> _timer;
public:
/**
* Constructor initializes a shared pointer of type timer
*/
periodic(function<void()> callback, uint64_t time) :
_timer(make_shared<timer> (callback, time, true)) {
}
/**
* Stop periodic
* The stop flag is set and periodic remove it from the queue
*/
void stop() {
_timer->stop();
}
/**
* Run callback now
* Forces the callback function to run independently of the periodic
*/
void now() {
_timer->now();
}
/**
* Get the number of times the periodic callback was runned
*/
uint64_t ticks() {
return _timer->ticks();
}
/**
* The logic status of the periodic stop state
*/
bool stoped() {
return _timer->stoped();
}
/**
* The destructor stops the periodic
*/
~periodic() {
stop();
}
};
/**
* Class delayed for delayed callback execution in ms
*/
class delayed {
shared_ptr<timer> _timer;
public:
/**
* Constructor initializes a shared pointer of type timer
*/
delayed(function<void()> callback, uint64_t time) :
_timer(make_shared<timer> (callback, time, false)) {
}
/**
* Stop delayed
* The stop flag is set and delayed remove it from the queue
*/
void stop() {
_timer->stop();
}
/**
* Run callback now
* Forces the callback function to run independently of the delayed
*/
void now() {
_timer->now();
}
/** /**
* Get is the delayed callback runned * Get is the delayed callback runned
*/ */
bool expired() { bool expired();
return bool(_timer->ticks());
}
/** /**
* The logic status of the delayed stop state * The logic status of the timer stop state
*/ */
bool stoped() { bool stoped();
return _timer->stoped();
}
/** /**
* The destructor stops the delayed * The destructor stops the timer
*/ */
~delayed() { ~Timer();
stop();
}
}; };
} }
} }

View File

@ -1,5 +1,5 @@
#ifndef _EVENT_ #ifndef _ASYNCO_TRIGGER_
#define _EVENT_ #define _ASYNCO_TRIGGER_
#include <map> #include <map>
#include <vector> #include <vector>
@ -11,64 +11,68 @@ using namespace std;
#include "asynco.hpp" #include "asynco.hpp"
namespace marcelb { namespace marcelb {
namespace asynco { namespace asynco {
namespace events {
class Asynco;
/** /**
* Event class, for event-driven programming. * Trigger class, for event-driven programming.
* These events are typed according to the arguments of the callback function * These events are typed according to the arguments of the callback function
*/ */
template<typename... T> template<typename... T>
class event { class Trigger {
private: private:
Asynco& engine;
mutex m_eve; mutex m_eve;
unordered_map<string, vector<function<void(T...)>>> events; unordered_map<string, vector<function<void(T...)>>> triggers;
public: public:
Trigger(Asynco& _engine)
: engine(_engine) {}
/** /**
* Defines event by key, and callback function * Defines event by key, and callback function
*/ */
void on(const string& key, function<void(T...)> callback) { void on(const string& key, function<void(T...)> callback) {
lock_guard _off(m_eve); lock_guard _off(m_eve);
events[key].push_back(callback); triggers[key].push_back(callback);
} }
/** /**
* It emits an event and sends a callback function saved according to the key with the passed parameters * It emits an event and sends a callback function saved according to the key with the passed parameters
*/ */
template<typename... Args> template<typename... Args>
void emit(const string& key, Args... args) { void tick(const string& key, Args... args) {
auto it_eve = events.find(key); auto it_eve = triggers.find(key);
if (it_eve != events.end()) { if (it_eve != triggers.end()) {
for (uint i =0; i<it_eve->second.size(); i++) { for (uint i =0; i<it_eve->second.size(); i++) {
auto callback = bind(it_eve->second[i], forward<Args>(args)...); auto callback = bind(it_eve->second[i], forward<Args>(args)...);
atask(callback); engine.async(callback);
} }
} }
} }
/** /**
* Remove an event listener from an event * Remove an Trigger listener from an event
*/ */
void off(const string& key) { void off(const string& key) {
lock_guard _off(m_eve); lock_guard _off(m_eve);
events.erase(key); triggers.erase(key);
} }
/** /**
* Remove all event listener * Remove all Trigger listener
*/ */
void off() { void off() {
lock_guard _off(m_eve); lock_guard _off(m_eve);
events.clear(); triggers.clear();
} }
/** /**
* Get num of listeners by an event key * Get num of listeners by an Trigger key
*/ */
unsigned int listeners(const string& key) { unsigned int listeners(const string& key) {
return events[key].size(); return triggers[key].size();
} }
/** /**
@ -76,7 +80,7 @@ class event {
*/ */
unsigned int listeners() { unsigned int listeners() {
unsigned int listeners = 0; unsigned int listeners = 0;
for (auto& ev : events) { for (auto& ev : triggers) {
listeners += ev.second.size(); listeners += ev.second.size();
} }
return listeners; return listeners;
@ -85,7 +89,6 @@ class event {
}; };
}
} }
} }

41
src/asynco.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "../lib/asynco.hpp"
namespace marcelb::asynco {
void Asynco::init_loops_in_threads(uint8_t threads) {
for (int i=0; i<threads; i++) {
_runners.push_back(thread ( [this] () {
io_ctx.run();
}));
}
}
void Asynco::run(uint8_t threads) {
_work = make_unique<io_service::work>(io_ctx);
init_loops_in_threads(threads);
}
void Asynco::run_on_this() {
if (!_work) {
_work = make_unique<io_service::work>(io_ctx);
}
io_ctx.run();
}
void Asynco::join() {
for (auto& runner : _runners) {
runner.join();
}
}
Timer Asynco::delayed(function<void()> callback, uint64_t time) {
return Timer(io_ctx, callback, time, TimerType::Delayed);
}
Timer Asynco::periodic(function<void()> callback, uint64_t time) {
return Timer(io_ctx, callback, time, TimerType::Periodic);
}
};

36
src/asynco_default.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "../lib/asynco_default.hpp"
namespace marcelb::asynco {
Asynco Asynco_Default_Runtime;
Timer delayed(function<void()> callback, uint64_t time) {
return Timer(Asynco_Default_Runtime.io_ctx, callback, time, TimerType::Delayed);
}
Timer periodic(function<void()> callback, uint64_t time) {
return Timer(Asynco_Default_Runtime.io_ctx, callback, time, TimerType::Periodic);
}
Asynco& asynco_default_runtime() {
return Asynco_Default_Runtime;
}
void asynco_default_run() {
Asynco_Default_Runtime.run();
}
void asynco_default_run_on_this() {
Asynco_Default_Runtime.run_on_this();
}
void asynco_default_join() {
Asynco_Default_Runtime.join();
}
io_context& asynco_default_io_context() {
return Asynco_Default_Runtime.io_ctx;
}
};

65
src/timers.cpp Normal file
View File

@ -0,0 +1,65 @@
#include "../lib/timers.hpp"
namespace marcelb::asynco {
int64_t rtime_ms() {
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()
.time_since_epoch())
.count();
}
int64_t rtime_us() {
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now()
.time_since_epoch())
.count();
}
void Timer::init() {
st.async_wait( [this] (const boost::system::error_code&) {
if (!_stop) {
callback();
if (type == TimerType::Periodic) {
st = steady_timer(io_ctx, boost::asio::chrono::milliseconds(time));
init();
}
_ticks++;
}
});
}
Timer::Timer (io_context& _io_ctx, function<void()> _callback, uint64_t _time, TimerType _type):
io_ctx(_io_ctx),
st(io_ctx, boost::asio::chrono::milliseconds(_time)),
_stop(false),
type(_type),
callback(_callback),
time(_time) {
init();
}
void Timer::stop() {
_stop = true;
st.cancel();
}
void Timer::now() {
st.cancel();
}
uint64_t Timer::ticks() {
return _ticks;
}
bool Timer::expired() {
return bool(_ticks);
}
bool Timer::stoped() {
return _stop;
}
Timer::~Timer() {
stop();
}
};

29
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,29 @@
add_executable(asynco_default main_default.cpp)
target_link_libraries(asynco_default asynco Boost::system)
add_executable(asynco_init main_init.cpp)
target_link_libraries(asynco_init asynco Boost::system)
add_executable(asynco_async_default main_async_default.cpp)
target_link_libraries(asynco_async_default asynco Boost::system)
add_executable(asynco_async main_async.cpp)
target_link_libraries(asynco_async asynco Boost::system)
add_executable(asynco_timers_default main_timers_default.cpp)
target_link_libraries(asynco_timers_default asynco Boost::system)
add_executable(asynco_timers main_timers.cpp)
target_link_libraries(asynco_timers asynco Boost::system)
add_executable(asynco_trigger_default main_trigger_default.cpp)
target_link_libraries(asynco_trigger_default asynco Boost::system)
add_executable(asynco_trigger main_trigger.cpp)
target_link_libraries(asynco_trigger asynco Boost::system)
add_executable(asynco_coroutine_default main_coroutine_default.cpp)
target_link_libraries(asynco_coroutine_default asynco Boost::system)
add_executable(asynco_coroutine main_coroutine.cpp)
target_link_libraries(asynco_coroutine asynco Boost::system)

84
test/main_async.cpp Normal file
View File

@ -0,0 +1,84 @@
#include "../lib/asynco.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
Asynco asynco;
void notLambdaFunction() {
cout << "Call to not lambda function" << endl;
}
class clm {
public:
void classMethode() {
cout << "Call class method" << endl;
}
};
void sleep_to (int _time) {
promise<void> _promise;
Timer t = asynco.delayed( [&]() {
_promise.set_value();
}, _time);
return asynco.await(_promise.get_future());
}
int main() {
asynco.run(2);
/**
* Run an lambda function asynchronously
*/
asynco.async ( []() {
cout << "async " << endl;
});
/**
* Run not lambda function
*/
asynco.async (notLambdaFunction);
/**
* Run class method
*/
clm classes;
asynco.async ( [&classes] () {
classes.classMethode();
});
//------------------AWAIT----------------------
auto a = asynco.async ( []() {
sleep_to(1000); //only for simulating long duration function
return 5;
});
cout << asynco.await(a) << endl;
/**
* await async function call and use i cout
*/
cout << asynco.await(asynco.async ( [] () {
sleep_to(1000);
cout << "await_ end" << endl;
return 4;
})) << endl;
asynco.await ([]() { // run in runtime and await now
cout << "Hello" << endl;
});
asynco.join();
return 0;
}

View File

@ -0,0 +1,82 @@
#include "../lib/asynco_default.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
void notLambdaFunction() {
cout << "Call to not lambda function" << endl;
}
class clm {
public:
void classMethode() {
cout << "Call class method" << endl;
}
};
void sleep_to (int _time) {
promise<void> _promise;
Timer t = delayed( [&]() {
_promise.set_value();
}, _time);
return await_(_promise.get_future());
}
int main() {
asynco_default_run();
/**
* Run an lambda function asynchronously
*/
async_ ( []() {
cout << "async " << endl;
});
/**
* Run not lambda function
*/
async_ (notLambdaFunction);
/**
* Run class method
*/
clm classes;
async_ ( [&classes] () {
classes.classMethode();
});
//------------------AWAIT----------------------
auto a = async_ ( []() {
sleep_to(1000); //only for simulating long duration function
return 5;
});
cout << await_(a) << endl;
/**
* await async function call and use i cout
*/
cout << await_(async_ ( [] () {
sleep_to(1000);
cout << "await_ end" << endl;
return 4;
})) << endl;
await_ ([]() { // run in runtime and await now
cout << "Hello" << endl;
});
asynco_default_join();
return 0;
}

43
test/main_coroutine.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "../lib/asynco.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
awaitable<int> c2(int a) {
co_return a * 2;
}
int main() {
Asynco asynco; // or global
asynco.run(2);
asynco.async(c2(4));
asynco.async([]() -> awaitable<void> {
std::cout << "Hello" << std::endl;
co_await c2(4);
co_return;
}());
int r = asynco.await(
asynco.async(
c2(10)
));
auto a = asynco.await( c2(3));
cout << a << endl;
asynco.await([]() -> awaitable<void> {
cout << "Hello" << endl;
co_return;
}());
asynco.join();
return 0;
}

View File

@ -0,0 +1,41 @@
#include "../lib/asynco_default.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
awaitable<int> c2(int a) {
co_return a * 2;
}
int main() {
asynco_default_run();
async_(c2(4));
async_([]() -> awaitable<void> {
std::cout << "Hello" << std::endl;
co_await c2(4);
co_return;
}());
int r = await_(
async_(
c2(10)
));
auto a = await_ ( c2(3));
cout << a << endl;
await_ ([]() -> awaitable<void> {
cout << "Hello" << endl;
co_return;
}());
asynco_default_join();
return 0;
}

14
test/main_default.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "../lib/asynco_default.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
int main() {
asynco_default_run();
// code
asynco_default_join();
return 0;
}

16
test/main_init.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "../lib/asynco.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
int main() {
Asynco asynco;
asynco.run(2);
// code
asynco.join();
return 0;
}

41
test/main_timers.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "../lib/asynco.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
int main() {
Asynco asynco;
asynco.run(2);
Timer inter1 = asynco.periodic ([]() {
cout << "Interval 1" << endl;
}, 1000);
// stop periodic
inter1.stop();
// how many times it has expired
int ti = inter1.ticks();
// is it stopped
bool stoped_i = inter1.stoped();
// start delayed
Timer time1 = asynco.delayed ( [] () {
cout << "Timeout 1 " << endl;
}, 10000);
// stop delayed
time1.stop();
// is it expired
int tt = time1.expired();
// is it stopped
bool stoped_t = time1.stoped();
asynco.join();
return 0;
}

View File

@ -0,0 +1,40 @@
#include "../lib/asynco_default.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
int main() {
asynco_default_run();
Timer inter1 = periodic ([]() {
cout << "Interval 1" << endl;
}, 1000);
// stop periodic
// inter1.stop();
// how many times it has expired
int ti = inter1.ticks();
// is it stopped
bool stoped_i = inter1.stoped();
// start delayed
Timer time1 = delayed ( [] () {
cout << "Timeout 1 " << endl;
}, 10000);
// stop delayed
// time1.stop();
// is it expired
int tt = time1.expired();
// is it stopped
bool stoped_t = time1.stoped();
asynco_default_join();
return 0;
}

124
test/main_trigger.cpp Normal file
View File

@ -0,0 +1,124 @@
#include "../lib/asynco.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
Asynco asynco;
class ClassWithTriggers {
Trigger<int> emitter1;
Trigger<string> emitter2;
public:
ClassWithTriggers(): emitter1(asynco), emitter2(asynco) {}
template<typename... T>
void on(const string& key, function<void(T...)> callback) {
if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, int>) {
emitter1.on(key, callback);
}
else if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, string>) {
emitter2.on(key, callback);
}
}
template <typename... Args>
void tick(const string& key, Args&&... args) {
if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, int>) {
emitter1.tick(key, forward<Args>(args)...);
}
else if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, string>) {
emitter2.tick(key, forward<Args>(args)...);
}
else {
static_assert(sizeof...(Args) == 0, "Unsupported number or types of arguments");
}
}
};
int main() {
asynco.run(2);
/**
* initialization of typed events
*/
Trigger<int, int> ev2int = asynco.trigger<int, int>();
Trigger<int, string> evintString = asynco.trigger<int, string>();
Trigger<> evoid = asynco.trigger<>();
ev2int.on("sum", [](int a, int b) {
cout << "Sum " << a+b << endl;
});
evintString.on("substract", [](int a, string b) {
cout << "Substract " << a-stoi(b) << endl;
});
evoid.on("void", []() {
cout << "Void emited" << endl;
});
// multiple listeners
string emited2 = "2";
evoid.on("void", [&]() {
cout << "Void emited " << emited2 << endl;
});
sleep(1);
/**
* Emit
*/
ev2int.tick("sum", 5, 8);
sleep(1);
evintString.tick("substract", 3, to_string(2));
sleep(1);
evoid.tick("void");
// Turn off the event listener
evoid.off("void");
evoid.tick("void"); // nothing is happening
class myOwnClass : public Trigger<int> {
public:
myOwnClass() : Trigger(asynco) {};
};
myOwnClass myclass;
Timer t = asynco.delayed( [&] {
myclass.tick("constructed", 1);
}, 200);
myclass.on("constructed", [] (int i) {
cout << "Constructed " << i << endl;
});
ClassWithTriggers mt;
mt.on<int>("int", function<void(int)>([&](int i) {
cout << "Emit int " << i << endl;
}));
mt.on<string>("string", function<void(string)>([&](string s) {
cout << "Emit string " << s << endl;
}));
mt.tick("int", 5);
mt.tick("string", string("Hello world"));
asynco.join();
return 0;
}

View File

@ -0,0 +1,118 @@
#include "../lib/asynco_default.hpp"
using namespace marcelb::asynco;
#include <iostream>
using namespace std;
class ClassWithTriggers {
Trigger<int> emitter1;
Trigger<string> emitter2;
public:
ClassWithTriggers(): emitter1(asynco_default_runtime()), emitter2(asynco_default_runtime()) {}
template<typename... T>
void on(const string& key, function<void(T...)> callback) {
if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, int>) {
emitter1.on(key, callback);
}
else if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, string>) {
emitter2.on(key, callback);
}
}
template <typename... Args>
void tick(const string& key, Args&&... args) {
if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, int>) {
emitter1.tick(key, forward<Args>(args)...);
}
else if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, string>) {
emitter2.tick(key, forward<Args>(args)...);
}
else {
static_assert(sizeof...(Args) == 0, "Unsupported number or types of arguments");
}
}
};
int main() {
asynco_default_run();
/**
* initialization of typed events
*/
Trigger<int, int> ev2int = trigger<int, int>();
Trigger<int, string> evintString = trigger<int, string>();
Trigger<> evoid = trigger<>();
ev2int.on("sum", [](int a, int b) {
cout << "Sum " << a+b << endl;
});
evintString.on("substract", [](int a, string b) {
cout << "Substract " << a-stoi(b) << endl;
});
evoid.on("void", []() {
cout << "Void emited" << endl;
});
// multiple listeners
string emited2 = "2";
evoid.on("void", [&]() {
cout << "Void emited " << emited2 << endl;
});
sleep(1);
/**
* Emit
*/
ev2int.tick("sum", 5, 8);
sleep(1);
evintString.tick("substract", 3, to_string(2));
sleep(1);
evoid.tick("void");
// Turn off the event listener
evoid.off("void");
evoid.tick("void"); // nothing is happening
class myOwnClass : public Trigger<int> {
public:
myOwnClass() : Trigger(asynco_default_runtime()) {};
};
myOwnClass myclass;
Timer t = delayed( [&] {
myclass.tick("constructed", 1);
}, 200);
myclass.on("constructed", [] (int i) {
cout << "Constructed " << i << endl;
});
ClassWithTriggers mt;
mt.on<int>("int", function<void(int)>([&](int i) {
cout << "Emit int " << i << endl;
}));
mt.on<string>("string", function<void(string)>([&](string s) {
cout << "Emit string " << s << endl;
}));
mt.tick("int", 5);
mt.tick("string", string("Hello world"));
asynco_default_join();
return 0;
}

View File

@ -1,323 +0,0 @@
// // #define NUM_OF_RUNNERS 2
#include "../lib/asynco.hpp"
#include "../lib/event.hpp"
#include "../lib/filesystem.hpp"
#include "../lib/timers.hpp"
using namespace marcelb::asynco;
using namespace events;
#include <iostream>
#include <unistd.h>
#include <thread>
using namespace std;
using namespace this_thread;
void sleep_to (int _time) {
promise<void> _promise;
delayed t( [&]() {
_promise.set_value();
}, _time);
return _promise.get_future().get();
}
void promise_reject (int _time) {
promise<void> _promise;
delayed t( [&]() {
try {
// simulate except
throw runtime_error("Error simulation");
_promise.set_value();
} catch (...) {
_promise.set_exception(current_exception());
}
}, _time);
return _promise.get_future().get();
}
void notLambdaFunction() {
cout << "Call to not lambda function" << endl;
}
class clm {
public:
void classMethode() {
cout << "Call class method" << endl;
}
};
// ------------------ EXTEND OWN CLASS WITH EVENTS -------------------
class myOwnClass : public event<int> {
public:
myOwnClass() : event() {};
};
int main () {
auto start = rtime_ms();
// --------------- TIME ASYNCHRONOUS FUNCTIONS --------------
// /**
// * Init periodic and delayed; clear periodic and delayed
// */
// periodic inter1 ([&]() {
// cout << "periodic prvi " << rtime_ms() - start << endl;
// }, 1000);
// periodic inter2 ([&]() {
// cout << "periodic drugi " << rtime_ms() - start << endl;
// }, 2000);
// periodic inter3 ([&]() {
// cout << "periodic treći " << rtime_ms() - start << endl;
// }, 1000);
// periodic inter4 ([&]() {
// // cout << "periodic cetvrti " << rtime_ms() - start << endl;
// cout << "Ticks " << inter3.ticks() << endl;
// }, 500);
// periodic inter5 ([&]() {
// cout << "periodic peti " << rtime_ms() - start << endl;
// }, 2000);
// periodic inter6 ([&]() {
// cout << "periodic sesti " << rtime_ms() - start << endl;
// }, 3000);
// delayed time1 ( [&] () {
// cout << "Close periodic 1 i 2 " << rtime_ms() - start << endl;
// inter1.stop();
// cout << "inter1.stop " << endl;
// inter2.stop();
// cout << "inter2.stop " << endl;
// }, 8000);
// delayed time2 ([&] () {
// cout << "Close periodic 3 " << rtime_ms() - start << endl;
// inter3.stop();
// cout << "Stoped " << inter3.stoped() << endl;
// // time1.stop();
// }, 5000);
// if (time2.expired()) {
// cout << "isteko " << endl;
// } else {
// cout << "nije isteko " << endl;
// }
// // sleep(6);
// if (time2.expired()) {
// cout << "isteko " << endl;
// } else {
// cout << "nije isteko " << endl;
// }
// // // ------------------------ MAKE FUNCTIONS ASYNCHRONOUS -------------------------
// /**
// * Run an function asyncronic
// */
// atask( []() {
// sleep_for(2s); // only for simulate log duration function
// cout << "atask 1" << endl;
// return 5;
// });
// /**
// * Call not lambda function
// */
// atask (notLambdaFunction);
// wait (
// atask (
// notLambdaFunction
// )
// );
// /**
// * Call class method
// */
// clm classes;
// atask( [&classes] () {
// classes.classMethode();
// });
// sleep(5);
// /**
// * Wait after runned as async
// */
// auto a = atask( []() {
// sleep_for(2s); // only for simulate log duration function
// cout << "atask 2" << endl;
// return 5;
// });
// cout << wait(a) << endl;
// cout << "print after atask 2" << endl;
// /**
// * Wait async function call and use i cout
// */
// cout << wait(atask( [] () {
// sleep_for(chrono::seconds(1)); // only for simulate log duration function
// cout << "wait end" << endl;
// return 4;
// })) << endl;
// /**
// * Sleep with delayed sleep implement
// */
// sleep_to(3000);
// cout << "sleep_to " << rtime_ms() - start << endl;
// /**
// * Catch promise reject
// */
// try {
// promise_reject(3000);
// } catch (runtime_error err) {
// cout<< err.what() << endl;
// }
// cout << "promise_reject " << rtime_ms() - start << endl;
// /**
// * Nested asynchronous invocation
// */
// atask( [] {
// cout << "idemo ..." << endl;
// atask( [] {
// cout << "ugdnježdena async funkcija " << endl;
// });
// });
// // --------------- EVENTS -------------------
// /**
// * initialization of typed events
// */
// event<int, int> ev2int;
// event<int, string> evintString;
// event<> evoid;
// ev2int.on("sum", [](int a, int b) {
// cout << "Sum " << a+b << endl;
// });
// ev2int.on("sum", [](int a, int b) {
// cout << "Sum done" << endl;
// });
// evintString.on("substract", [](int a, string b) {
// cout << "Substract " << a-stoi(b) << endl;
// });
// evoid.on("void", []() {
// cout << "Void emited" << endl;
// });
// string emited2 = "2";
// evoid.on("void", [&]() {
// cout << "Void emited " << emited2 << endl;
// });
// evoid.emit("void");
// sleep(1);
// /**
// * Emit
// */
// ev2int.emit("sum", 5, 8);
// sleep(1);
// evintString.emit("substract", 3, to_string(2));
// sleep(1);
// evoid.off("void");
// evoid.emit("void");
// cout << "Ukupno 2 int " << ev2int.listeners() << endl;
// cout << "Ukupno evintString " << evintString.listeners() << endl;
// cout << "Ukupno evoid " << evoid.listeners() << endl;
// cout << "Ukupno 2 int " << ev2int.listeners("sum") << endl;
// /**
// * Own class
// */
// myOwnClass myclass;
// delayed t( [&] {
// myclass.emit("constructed", 1);
// }, 200);
// myclass.on("constructed", [] (int i) {
// cout << "Constructed " << i << endl;
// });
// auto status = fs::read("test1.txt");
// try {
// auto data = wait(status);
// cout << data;
// } catch (exception& err) {
// cout << err.what() << endl;
// }
// string data_;
// auto start_read = rtime_us();
// fs::read("test1.txt", [&data_, &start_read] (string data, exception* error) {
// if (error) {
// cout << "Error " << error->what() << endl;
// } else {
// // cout << "Data " << endl << data << endl;
// // data_ = data;
// // cout << "Data_" << data_ << endl;
// cout << "read " << rtime_us() - start_read << endl;
// }
// });
// // ----------------------------------------------------------------------------------------------------
cout << "Run" << endl;
_asynco_engine.run();
return 0;
}