Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
4384b0b311 | |||
8d9a56dc8e | |||
748fd0a586 | |||
e76623bef0 | |||
ceb3967178 | |||
8d7796998f | |||
d37f85f728 | |||
a1606fd3b6 | |||
5608eab8eb | |||
d546ca9db8 | |||
ce2c22676b | |||
9965f1e1c7 | |||
aca2724e0c |
@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
project(Asynco)
|
project(Asynco)
|
||||||
|
|
||||||
# Postavi verziju projekta
|
# Postavi verziju projekta
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
# Pronađi Boost biblioteku (ako nije uobičajeni direktorijum, postavi put)
|
# Pronađi Boost biblioteku (ako nije uobičajeni direktorijum, postavi put)
|
||||||
@ -14,7 +14,8 @@ include_directories(lib)
|
|||||||
|
|
||||||
# Dodaj biblioteku
|
# Dodaj biblioteku
|
||||||
add_library(asynco STATIC
|
add_library(asynco STATIC
|
||||||
src/engine.cpp
|
src/asynco.cpp
|
||||||
|
src/asynco_default.cpp
|
||||||
src/timers.cpp
|
src/timers.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,6 +25,9 @@ target_link_libraries(asynco Boost::system)
|
|||||||
# Dodaj testove
|
# Dodaj testove
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|
||||||
|
add_compile_options(-w)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Instaliraj biblioteku
|
# Instaliraj biblioteku
|
||||||
# install(TARGETS asynco DESTINATION lib)
|
# install(TARGETS asynco DESTINATION lib)
|
||||||
|
313
README.md
313
README.md
@ -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, tick, off) (like EventEmitter from JS: on, emit, etc)
|
- 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 asynco, 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" // async_ (), await_()
|
|
||||||
#include "asynco/lib/triggers.hpp" // trigger (event emitter)
|
|
||||||
#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 triggers;
|
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
@ -77,30 +107,10 @@ int t = time1.expired();
|
|||||||
// is it stopped
|
// is it stopped
|
||||||
bool stoped = time1.stoped();
|
bool stoped = time1.stoped();
|
||||||
|
|
||||||
// If you don't want to save in a variable, but you want to start a timer, use these functions
|
|
||||||
// And you can also save them, they are only of the shared pointer type
|
|
||||||
|
|
||||||
auto d = Delayed( [](){
|
|
||||||
cout << "Delayed" << endl;
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
auto p = Periodic( [](){
|
|
||||||
cout << "Periodic" << endl;
|
|
||||||
}, 700);
|
|
||||||
|
|
||||||
Periodic( [&] (){
|
|
||||||
cout << "Delayed expire " << d->expired() << endl;
|
|
||||||
cout << "Periodic ticks " << p->ticks() << endl;
|
|
||||||
cout << "Delayed stoped " << d->stoped() << endl;
|
|
||||||
cout << "Periodic stoped " << p->stoped() << endl;
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
Delayed( [&](){
|
|
||||||
p->stop();
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
```
|
```
|
||||||
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++
|
||||||
/**
|
/**
|
||||||
@ -108,7 +118,7 @@ Make functions asynchronous
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async_ ( []() {
|
async_ ( []() {
|
||||||
sleep_for(2s); // only for simulating long duration function
|
sleep(2); // only for simulating long duration function
|
||||||
cout << "nonsync " << endl;
|
cout << "nonsync " << endl;
|
||||||
return 5;
|
return 5;
|
||||||
});
|
});
|
||||||
@ -139,15 +149,14 @@ clm classes;
|
|||||||
async_ ( [&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++
|
||||||
/**
|
|
||||||
* await_ after runned as async
|
|
||||||
*/
|
|
||||||
|
|
||||||
auto a = async_ ( []() {
|
auto a = async_ ( []() {
|
||||||
sleep_for(2s); // only for simulating long duration function
|
sleep(2); // only for simulating long duration function
|
||||||
cout << "nonsync " << endl;
|
cout << "nonsync " << endl;
|
||||||
return 5;
|
return 5;
|
||||||
});
|
});
|
||||||
@ -159,115 +168,36 @@ cout << await_(a) << endl;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
cout << await_(async_ ( [] () {
|
cout << await_(async_ ( [] () {
|
||||||
sleep_for(chrono::seconds(1)); // only for simulating long duration function
|
sleep(1); // only for simulating long duration function
|
||||||
cout << "await_ end" << endl;
|
cout << "await_ end" << endl;
|
||||||
return 4;
|
return 4;
|
||||||
})) << endl;
|
})) << endl;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Await all
|
|
||||||
**/
|
|
||||||
|
|
||||||
auto a = async_ ( []() {
|
|
||||||
cout << "A" << endl;
|
|
||||||
return 3;
|
|
||||||
});
|
|
||||||
|
|
||||||
auto b = async_ ( []() {
|
|
||||||
cout << "B" << endl;
|
|
||||||
throw runtime_error("Test exception");
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
|
|
||||||
auto c = async_ ( []() {
|
|
||||||
cout << "C" << endl;
|
|
||||||
return "Hello";
|
|
||||||
});
|
|
||||||
|
|
||||||
int a_;
|
|
||||||
string c_;
|
|
||||||
|
|
||||||
auto await_all = [&] () {
|
|
||||||
a_ = await_(a);
|
|
||||||
await_(b);
|
|
||||||
c_ = await_(c);
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await_all();
|
|
||||||
cout << "a_ " << a_ << " c_ " << c_ << endl;
|
|
||||||
} catch (const exception& exc) {
|
|
||||||
cout << exc.what() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// // same type
|
|
||||||
|
|
||||||
vector<future<void>> fut_vec;
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
fut_vec.push_back(
|
|
||||||
async_ ( [i]() {
|
|
||||||
cout << "Async_ " << i << endl;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto await_all = [&] () {
|
|
||||||
for (int i=0; i<fut_vec.size(); i++) {
|
|
||||||
await_ (fut_vec[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
trigger<int, int> ev2int;
|
Trigger<int, int> ev2int = trigger<int, int>();
|
||||||
trigger<int, string> evintString;
|
Trigger<int, string> evintString = trigger<int, string>();
|
||||||
trigger<> 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;
|
||||||
@ -312,14 +242,14 @@ evoid.tick("void"); // nothing is happening
|
|||||||
Extend own class whit events
|
Extend own class whit events
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
class myOwnClass : public trigger<int> {
|
class myOwnClass : public Trigger<int> {
|
||||||
public:
|
public:
|
||||||
myOwnClass() : trigger() {};
|
myOwnClass() : Trigger(asynco_default_runtime()) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
myOwnClass myclass;
|
myOwnClass myclass;
|
||||||
|
|
||||||
delayed t( [&] {
|
Delayed t( [&] {
|
||||||
myclass.tick("constructed", 1);
|
myclass.tick("constructed", 1);
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
@ -334,10 +264,12 @@ Implementing a class with multiple triggers of different types
|
|||||||
```c++
|
```c++
|
||||||
|
|
||||||
class ClassWithTriggers {
|
class ClassWithTriggers {
|
||||||
trigger<int> emitter1;
|
Trigger<int> emitter1;
|
||||||
trigger<string> emitter2;
|
Trigger<string> emitter2;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
ClassWithTriggers(): emitter1(asynco_default_runtime()), emitter2(asynco_default_runtime()) {}
|
||||||
|
|
||||||
template<typename... T>
|
template<typename... T>
|
||||||
void on(const string& key, function<void(T...)> callback) {
|
void on(const string& key, function<void(T...)> callback) {
|
||||||
if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, int>) {
|
if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, int>) {
|
||||||
@ -377,47 +309,60 @@ mt.tick("string", string("Hello world"));
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Coroutine
|
||||||
|
|
||||||
Asynchronous file IO
|
If `define.hpp` is included, you can initialize coroutines with `boost::asio::awaitable<T>`.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
string data_;
|
|
||||||
|
|
||||||
fs::read("test.txt", [&data_] (string data, exception* error) {
|
awaitable<int> c2(int a) {
|
||||||
if (error) {
|
co_return a * 2;
|
||||||
cout << "Error " << error->what() << endl;
|
|
||||||
} else {
|
|
||||||
cout << "Data " << endl << data << endl;
|
|
||||||
data_ = data;
|
|
||||||
cout << "Data_" << data_ << endl;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fs::write("test1.txt", "Hello world", [] (exception* error) {
|
|
||||||
if (error) {
|
|
||||||
cout << "Error " << error->what() << endl;
|
|
||||||
} else {
|
|
||||||
cout << "Write successfuly" << endl;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
auto future_data = fs::read("test.txt");
|
|
||||||
|
|
||||||
try {
|
|
||||||
string data = await_(future_data);
|
|
||||||
} catch (exception& err) {
|
|
||||||
cout << err.what() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto future_status = fs::write("test.txt", "Hello world");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await_(future_status);
|
|
||||||
} catch (exception& err) {
|
|
||||||
cout << err.what() << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
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
|
||||||
|
|
||||||
|
210
lib/asynco.hpp
210
lib/asynco.hpp
@ -1,61 +1,187 @@
|
|||||||
#ifndef _ASYNCO_
|
#ifndef _ASYNCO_
|
||||||
#define _ASYNCO_
|
#define _ASYNCO_
|
||||||
|
|
||||||
#include "engine.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 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the function asynchronously
|
* Asynco runtime
|
||||||
|
* Used for all asynchronous capabilities of this wrapper
|
||||||
|
* Initializes threads and boost::asio::io_context
|
||||||
*/
|
*/
|
||||||
template<class F, class... Args>
|
class Asynco {
|
||||||
auto async_(F&& f, Args&&... args) -> future<typename result_of<F(Args...)>::type> {
|
vector<thread> _runners;
|
||||||
using return_type = typename result_of<F(Args...)>::type;
|
unique_ptr<io_service::work> _work;
|
||||||
future<return_type> res = _asynco_engine.io_context.post(boost::asio::use_future(bind(forward<F>(f), forward<Args>(args)...)));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
void init_loops_in_threads(uint8_t threads);
|
||||||
* Block until the asynchronous call completes
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
T await_(future<T>& r) {
|
|
||||||
return r.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public:
|
||||||
* Block until the asynchronous call completes
|
io_context io_ctx;
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
T await_(future<T>&& r) {
|
|
||||||
return move(r).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block until the asynchronous call completes or time expired
|
* It starts the thread initialization and the Boost::Asio event loop in each of them
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
|
||||||
T await_(future<T>& r, uint64_t time) {
|
void run(uint8_t threads = thread::hardware_concurrency());
|
||||||
if (r.wait_for(chrono::milliseconds(time)) == std::future_status::timeout) {
|
|
||||||
throw runtime_error("Asynchronous execution timed out");
|
/**
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
return r.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
#if __cplusplus >= 202002L
|
||||||
* Block until the asynchronous call completes or time expired
|
/**
|
||||||
*/
|
* Run the coroutine in runtime
|
||||||
template<typename T>
|
*/
|
||||||
T await_(future<T>&& r, uint64_t time) {
|
template <typename T>
|
||||||
if (r.wait_for(chrono::milliseconds(time)) == std::future_status::timeout) {
|
future<T> async(boost::asio::awaitable<T> _coroutine) {
|
||||||
throw runtime_error("Asynchronous execution timed out");
|
promise<T> promise;
|
||||||
}
|
auto future = promise.get_future();
|
||||||
return move(r).get();
|
|
||||||
}
|
co_spawn(io_ctx, [_coroutine = move(_coroutine), promise = move(promise)]() mutable -> boost::asio::awaitable<void> {
|
||||||
|
try {
|
||||||
|
if constexpr (!is_void_v<T>) {
|
||||||
|
T result = co_await move(_coroutine);
|
||||||
|
promise.set_value(move(result));
|
||||||
|
} else {
|
||||||
|
co_await move(_coroutine);
|
||||||
|
promise.set_value(); // Za void ne postavljamo rezultat
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
promise.set_exception(current_exception()); // Postavljamo izuzetak
|
||||||
|
}
|
||||||
|
}, boost::asio::detached);
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 coruotine and wait
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
T await(boost::asio::awaitable<T> _coroutine) {
|
||||||
|
return await(
|
||||||
|
async(
|
||||||
|
move(_coroutine)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
155
lib/asynco_default.hpp
Normal file
155
lib/asynco_default.hpp
Normal 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
|
@ -1,19 +0,0 @@
|
|||||||
#ifndef _ASYNCO_DEFINE_
|
|
||||||
#define _ASYNCO_DEFINE_
|
|
||||||
|
|
||||||
namespace marcelb {
|
|
||||||
namespace asynco {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Alternative names of functions - mostly for the sake of more beautiful coloring of the code
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define async_ marcelb::asynco::async_
|
|
||||||
#define await_ marcelb::asynco::await_
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,71 +0,0 @@
|
|||||||
#ifndef _ASYNCO_ENGINE_
|
|
||||||
#define _ASYNCO_ENGINE_
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
|
|
||||||
namespace marcelb {
|
|
||||||
namespace asynco {
|
|
||||||
|
|
||||||
#define HW_CONCURRENCY_MINIMAL 4
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal anonymous class for initializing the ASIO context and thread pool
|
|
||||||
* !!! It is anonymous to protect against use in the initialization of other objects of the same type !!!
|
|
||||||
*/
|
|
||||||
class Engine {
|
|
||||||
public:
|
|
||||||
boost::asio::io_context io_context;
|
|
||||||
|
|
||||||
void run() {
|
|
||||||
for (auto& runner : runners) {
|
|
||||||
runner.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
unique_ptr<boost::asio::io_service::work> work { [&] () {
|
|
||||||
return new boost::asio::io_service::work(io_context);
|
|
||||||
} ()};
|
|
||||||
|
|
||||||
vector<thread> runners { [&] () {
|
|
||||||
vector<thread> _runs;
|
|
||||||
unsigned int num_of_runners;
|
|
||||||
#ifdef NUM_OF_RUNNERS
|
|
||||||
num_of_runners = NUM_OF_RUNNERS;
|
|
||||||
#else
|
|
||||||
num_of_runners = thread::hardware_concurrency();
|
|
||||||
if (num_of_runners < HW_CONCURRENCY_MINIMAL) {
|
|
||||||
num_of_runners = HW_CONCURRENCY_MINIMAL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int i=0; i<num_of_runners; i++) {
|
|
||||||
_runs.push_back(thread ( [this] () {
|
|
||||||
io_context.run();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _runs;
|
|
||||||
} ()};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
extern Engine _asynco_engine;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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) {
|
|
||||||
asynco::async_( [&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 asynco::async_( [&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) {
|
|
||||||
asynco::async_( [&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 asynco::async_( [&path, &content] () {
|
|
||||||
ofstream file (path);
|
|
||||||
if (file.is_open()) {
|
|
||||||
file << content;
|
|
||||||
file.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw runtime_error("Unable to open file");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
108
lib/timers.hpp
108
lib/timers.hpp
@ -2,9 +2,11 @@
|
|||||||
#define _ASYNCO_TIMERS_
|
#define _ASYNCO_TIMERS_
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include "asynco.hpp"
|
#include <boost/asio.hpp>
|
||||||
|
using namespace boost::asio;
|
||||||
|
|
||||||
namespace marcelb {
|
namespace marcelb {
|
||||||
namespace asynco {
|
namespace asynco {
|
||||||
@ -21,13 +23,19 @@ int64_t rtime_ms();
|
|||||||
|
|
||||||
int64_t rtime_us();
|
int64_t rtime_us();
|
||||||
|
|
||||||
|
enum TimerType {
|
||||||
|
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;
|
||||||
@ -35,14 +43,13 @@ 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();
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop timer
|
* Stop timer
|
||||||
@ -61,99 +68,22 @@ class timer {
|
|||||||
*/
|
*/
|
||||||
uint64_t ticks();
|
uint64_t ticks();
|
||||||
|
|
||||||
/**
|
|
||||||
* The logic status of the timer stop state
|
|
||||||
*/
|
|
||||||
bool stoped();
|
|
||||||
/**
|
|
||||||
* The destructor stops the timer
|
|
||||||
*/
|
|
||||||
~timer();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop periodic
|
|
||||||
* The stop flag is set and periodic remove it from the queue
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run callback now
|
|
||||||
* Forces the callback function to run independently of the periodic
|
|
||||||
*/
|
|
||||||
void now();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the number of times the periodic callback was runned
|
|
||||||
*/
|
|
||||||
uint64_t ticks();
|
|
||||||
/**
|
|
||||||
* The logic status of the periodic stop state
|
|
||||||
*/
|
|
||||||
bool stoped();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The destructor stops the periodic
|
|
||||||
*/
|
|
||||||
~periodic();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop delayed
|
|
||||||
* The stop flag is set and delayed remove it from the queue
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run callback now
|
|
||||||
* Forces the callback function to run independently of the delayed
|
|
||||||
*/
|
|
||||||
void now();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get is the delayed callback runned
|
* Get is the delayed callback runned
|
||||||
*/
|
*/
|
||||||
bool expired();
|
bool expired();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logic status of the delayed stop state
|
* The logic status of the timer stop state
|
||||||
*/
|
*/
|
||||||
bool stoped();
|
bool stoped();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The destructor stops the delayed
|
* The destructor stops the timer
|
||||||
*/
|
*/
|
||||||
~delayed();
|
~Timer();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
shared_ptr<periodic> Periodic(function<void()> callback, uint64_t time);
|
|
||||||
shared_ptr<delayed> Delayed(function<void()> callback, uint64_t time);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,22 +8,26 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include "engine.hpp"
|
#include "asynco.hpp"
|
||||||
namespace marcelb {
|
namespace marcelb {
|
||||||
namespace asynco {
|
namespace asynco {
|
||||||
namespace triggers {
|
|
||||||
|
class Asynco;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* trigger 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 trigger {
|
class Trigger {
|
||||||
private:
|
private:
|
||||||
|
Asynco& engine;
|
||||||
mutex m_eve;
|
mutex m_eve;
|
||||||
unordered_map<string, vector<function<void(T...)>>> triggers;
|
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
|
||||||
@ -33,6 +37,7 @@ class trigger {
|
|||||||
triggers[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
|
||||||
*/
|
*/
|
||||||
@ -42,30 +47,29 @@ class trigger {
|
|||||||
if (it_eve != triggers.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)...);
|
||||||
asynco::async_(callback);
|
engine.async(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an trigger 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);
|
||||||
triggers.erase(key);
|
triggers.erase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all trigger listener
|
* Remove all Trigger listener
|
||||||
*/
|
*/
|
||||||
void off() {
|
void off() {
|
||||||
lock_guard _off(m_eve);
|
lock_guard _off(m_eve);
|
||||||
triggers.clear();
|
triggers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get num of listeners by an trigger key
|
* Get num of listeners by an Trigger key
|
||||||
*/
|
*/
|
||||||
unsigned int listeners(const string& key) {
|
unsigned int listeners(const string& key) {
|
||||||
return triggers[key].size();
|
return triggers[key].size();
|
||||||
@ -85,7 +89,6 @@ class trigger {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
41
src/asynco.cpp
Normal file
41
src/asynco.cpp
Normal 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
36
src/asynco_default.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
@ -1,7 +0,0 @@
|
|||||||
#include "../lib/engine.hpp"
|
|
||||||
|
|
||||||
namespace marcelb::asynco {
|
|
||||||
|
|
||||||
Engine _asynco_engine;
|
|
||||||
|
|
||||||
};
|
|
116
src/timers.cpp
116
src/timers.cpp
@ -3,23 +3,23 @@
|
|||||||
namespace marcelb::asynco {
|
namespace marcelb::asynco {
|
||||||
|
|
||||||
int64_t rtime_ms() {
|
int64_t rtime_ms() {
|
||||||
return chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now()
|
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()
|
||||||
.time_since_epoch())
|
.time_since_epoch())
|
||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t rtime_us() {
|
int64_t rtime_us() {
|
||||||
return chrono::duration_cast<chrono::microseconds>(chrono::system_clock::now()
|
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now()
|
||||||
.time_since_epoch())
|
.time_since_epoch())
|
||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer::init() {
|
void Timer::init() {
|
||||||
st.async_wait( [this] (const boost::system::error_code&) {
|
st.async_wait( [this] (const boost::system::error_code&) {
|
||||||
if (!_stop) {
|
if (!_stop) {
|
||||||
callback();
|
callback();
|
||||||
if (repeate) {
|
if (type == TimerType::Periodic) {
|
||||||
st = boost::asio::steady_timer(_asynco_engine.io_context, boost::asio::chrono::milliseconds(time));
|
st = steady_timer(io_ctx, boost::asio::chrono::milliseconds(time));
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
_ticks++;
|
_ticks++;
|
||||||
@ -27,119 +27,39 @@ void timer::init() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
timer::timer (function<void()> _callback, uint64_t _time, bool _repeate) :
|
Timer::Timer (io_context& _io_ctx, function<void()> _callback, uint64_t _time, TimerType _type):
|
||||||
st(_asynco_engine.io_context, boost::asio::chrono::milliseconds(_time)),
|
io_ctx(_io_ctx),
|
||||||
|
st(io_ctx, boost::asio::chrono::milliseconds(_time)),
|
||||||
_stop(false),
|
_stop(false),
|
||||||
repeate(_repeate),
|
type(_type),
|
||||||
callback(_callback),
|
callback(_callback),
|
||||||
time(_time) {
|
time(_time) {
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer::stop() {
|
void Timer::stop() {
|
||||||
_stop = true;
|
_stop = true;
|
||||||
st.cancel();
|
st.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer::now() {
|
void Timer::now() {
|
||||||
st.cancel();
|
st.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t timer::ticks() {
|
uint64_t Timer::ticks() {
|
||||||
return _ticks;
|
return _ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool timer::stoped() {
|
bool Timer::expired() {
|
||||||
|
return bool(_ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Timer::stoped() {
|
||||||
return _stop;
|
return _stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
timer::~timer() {
|
Timer::~Timer() {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
periodic::periodic(function<void()> callback, uint64_t time) :
|
|
||||||
_timer(make_shared<timer> (callback, time, true)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void periodic::stop() {
|
|
||||||
_timer->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void periodic::now() {
|
|
||||||
_timer->now();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t periodic::ticks() {
|
|
||||||
return _timer->ticks();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool periodic::stoped() {
|
|
||||||
return _timer->stoped();
|
|
||||||
}
|
|
||||||
|
|
||||||
periodic::~periodic() {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
delayed::delayed(function<void()> callback, uint64_t time) :
|
|
||||||
_timer(make_shared<timer> (callback, time, false)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void delayed::stop() {
|
|
||||||
_timer->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void delayed::now() {
|
|
||||||
_timer->now();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool delayed::expired() {
|
|
||||||
return bool(_timer->ticks());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool delayed::stoped() {
|
|
||||||
return _timer->stoped();
|
|
||||||
}
|
|
||||||
|
|
||||||
delayed::~delayed() {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex p_io, d_io;
|
|
||||||
vector<shared_ptr<periodic>> periodic_calls_container;
|
|
||||||
vector<shared_ptr<delayed>> delayed_calls_container;
|
|
||||||
|
|
||||||
shared_ptr<periodic> Periodic(function<void()> callback, uint64_t time) {
|
|
||||||
shared_ptr<periodic> periodic_ptr(make_shared<periodic>(callback, time));
|
|
||||||
async_ ( [&, periodic_ptr](){
|
|
||||||
lock_guard<mutex> lock(p_io);
|
|
||||||
periodic_calls_container.push_back(periodic_ptr);
|
|
||||||
for (uint32_t i=0; i<periodic_calls_container.size(); i++) {
|
|
||||||
if (periodic_calls_container[i]->stoped()) {
|
|
||||||
periodic_calls_container.erase(periodic_calls_container.begin()+i);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return periodic_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr<delayed> Delayed(function<void()> callback, uint64_t time) {
|
|
||||||
shared_ptr<delayed> delayed_ptr(make_shared<delayed>(callback, time));
|
|
||||||
async_ ( [&, delayed_ptr](){
|
|
||||||
lock_guard<mutex> lock(p_io);
|
|
||||||
delayed_calls_container.push_back(delayed_ptr);
|
|
||||||
for (uint32_t i=0; i<delayed_calls_container.size(); i++) {
|
|
||||||
if (delayed_calls_container[i]->stoped() || delayed_calls_container[i]->expired()) {
|
|
||||||
delayed_calls_container.erase(delayed_calls_container.begin()+i);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return delayed_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,29 @@
|
|||||||
add_executable(asynco_test main.cpp)
|
add_executable(asynco_default main_default.cpp)
|
||||||
|
target_link_libraries(asynco_default asynco Boost::system)
|
||||||
|
|
||||||
# Linkaj test sa Asynco bibliotekom
|
add_executable(asynco_init main_init.cpp)
|
||||||
target_link_libraries(asynco_test asynco Boost::system)
|
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)
|
454
test/main.cpp
454
test/main.cpp
@ -1,454 +0,0 @@
|
|||||||
#define NUM_OF_RUNNERS 4
|
|
||||||
|
|
||||||
#include "asynco.hpp"
|
|
||||||
#include "trigger.hpp"
|
|
||||||
#include "filesystem.hpp"
|
|
||||||
#include "timers.hpp"
|
|
||||||
#include "define.hpp"
|
|
||||||
|
|
||||||
using namespace marcelb::asynco;
|
|
||||||
using namespace triggers;
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <thread>
|
|
||||||
#include <future>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
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 trigger<int> {
|
|
||||||
public:
|
|
||||||
myOwnClass() : trigger() {};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------- MULTIPLE TRIGGERS IN ONE CLASS ------------------
|
|
||||||
|
|
||||||
class ClassWithTriggers {
|
|
||||||
trigger<int> emitter1;
|
|
||||||
trigger<string> emitter2;
|
|
||||||
|
|
||||||
public:
|
|
||||||
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 () {
|
|
||||||
|
|
||||||
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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// auto d = Delayed( [](){
|
|
||||||
// cout << "Delayed" << endl;
|
|
||||||
// }, 2000);
|
|
||||||
|
|
||||||
// auto p = Periodic( [](){
|
|
||||||
// cout << "Periodic" << endl;
|
|
||||||
// }, 700);
|
|
||||||
|
|
||||||
// Periodic( [&] (){
|
|
||||||
// cout << "Delayed expire " << d->expired() << endl;
|
|
||||||
// cout << "Periodic ticks " << p->ticks() << endl;
|
|
||||||
// cout << "Delayed stoped " << d->stoped() << endl;
|
|
||||||
// cout << "Periodic stoped " << p->stoped() << endl;
|
|
||||||
// }, 1000);
|
|
||||||
|
|
||||||
// Delayed( [&](){
|
|
||||||
// p->stop();
|
|
||||||
// }, 10000);
|
|
||||||
|
|
||||||
// // // // ------------------------ MAKE FUNCTIONS ASYNCHRONOUS -------------------------
|
|
||||||
|
|
||||||
// // /**
|
|
||||||
// // * Run an function asyncronic
|
|
||||||
// // */
|
|
||||||
|
|
||||||
// async_ ( []() {
|
|
||||||
// sleep_for(2s); // only for simulate log duration function
|
|
||||||
// cout << "asynco 1" << endl;
|
|
||||||
// return 5;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Call not lambda function
|
|
||||||
// */
|
|
||||||
|
|
||||||
// async_ (notLambdaFunction);
|
|
||||||
|
|
||||||
|
|
||||||
// await_ (
|
|
||||||
// async_ (
|
|
||||||
// notLambdaFunction
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
|
|
||||||
|
|
||||||
// // async(launch::async, [] () {
|
|
||||||
// // cout << "Another thread in async style!" << endl;
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// // /**
|
|
||||||
// // * Call class method
|
|
||||||
// // */
|
|
||||||
|
|
||||||
// clm classes;
|
|
||||||
// async_ ( [&classes] () {
|
|
||||||
// classes.classMethode();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// sleep(5);
|
|
||||||
|
|
||||||
// // /**
|
|
||||||
// // * await_ after runned as async
|
|
||||||
// // */
|
|
||||||
|
|
||||||
// auto aa = async_ ( []() {
|
|
||||||
// sleep_for(2s); // only for simulate log duration function
|
|
||||||
// cout << "async_ 2" << endl;
|
|
||||||
// return 5;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// cout << await_(aa) << endl;
|
|
||||||
// cout << "print after async_ 2" << endl;
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * await_ async function call and use i cout
|
|
||||||
// */
|
|
||||||
|
|
||||||
// cout << await_(async_ ( [] () {
|
|
||||||
// sleep_for(chrono::seconds(1)); // only for simulate log duration function
|
|
||||||
// cout << "await_ 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
|
|
||||||
// */
|
|
||||||
|
|
||||||
|
|
||||||
// async_ ( [] {
|
|
||||||
// cout << "idemo ..." << endl;
|
|
||||||
// async_ ( [] {
|
|
||||||
// cout << "ugdnježdena async funkcija " << endl;
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
// // -------------------------- AWAIT ALL ----------------------------------
|
|
||||||
|
|
||||||
// auto a = async_ ( []() {
|
|
||||||
// cout << "A" << endl;
|
|
||||||
// return 3;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// auto b = async_ ( []() {
|
|
||||||
// cout << "B" << endl;
|
|
||||||
// throw runtime_error("Test exception");
|
|
||||||
// return;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// auto c = async_ ( []() {
|
|
||||||
// cout << "C" << endl;
|
|
||||||
// return "Hello";
|
|
||||||
// });
|
|
||||||
|
|
||||||
// int a_;
|
|
||||||
// string c_;
|
|
||||||
|
|
||||||
// auto await_all = [&] () {
|
|
||||||
// a_ = await_(a);
|
|
||||||
// await_(b);
|
|
||||||
// c_ = await_(c);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// await_all();
|
|
||||||
// cout << "a_ " << a_ << " c_ " << c_ << endl;
|
|
||||||
// } catch (const exception& exc) {
|
|
||||||
// cout << exc.what() << endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // // same type
|
|
||||||
|
|
||||||
// vector<future<void>> fut_vec;
|
|
||||||
// for (int i=0; i<5; i++) {
|
|
||||||
// fut_vec.push_back(
|
|
||||||
// async_ ( [i]() {
|
|
||||||
// cout << "Async_ " << i << endl;
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// auto await_all2 = [&] () {
|
|
||||||
// for (int i=0; i<fut_vec.size(); i++) {
|
|
||||||
// await_ (fut_vec[i]);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// await_all2();
|
|
||||||
|
|
||||||
// // --------------- EVENTS -------------------
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * initialization of typed events
|
|
||||||
// */
|
|
||||||
|
|
||||||
// trigger<int, int> ev2int;
|
|
||||||
// trigger<int, string> evintString;
|
|
||||||
// trigger<> 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.tick("void");
|
|
||||||
// sleep(1);
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Emit
|
|
||||||
// */
|
|
||||||
|
|
||||||
// ev2int.tick("sum", 5, 8);
|
|
||||||
|
|
||||||
|
|
||||||
// sleep(1);
|
|
||||||
// evintString.tick("substract", 3, to_string(2));
|
|
||||||
|
|
||||||
// sleep(1);
|
|
||||||
// evoid.off("void");
|
|
||||||
// evoid.tick("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.tick("constructed", 1);
|
|
||||||
// }, 200);
|
|
||||||
|
|
||||||
// myclass.on("constructed", [] (int i) {
|
|
||||||
// cout << "Constructed " << i << endl;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// *
|
|
||||||
// * Use class with multiple triggers
|
|
||||||
// *
|
|
||||||
// */
|
|
||||||
|
|
||||||
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"));
|
|
||||||
|
|
||||||
|
|
||||||
// auto status = fs::read("test1.txt");
|
|
||||||
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// auto data = await_(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;
|
|
||||||
}
|
|
||||||
|
|
84
test/main_async.cpp
Normal file
84
test/main_async.cpp
Normal 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;
|
||||||
|
}
|
82
test/main_async_default.cpp
Normal file
82
test/main_async_default.cpp
Normal 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
43
test/main_coroutine.cpp
Normal 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;
|
||||||
|
}
|
41
test/main_coroutine_default.cpp
Normal file
41
test/main_coroutine_default.cpp
Normal 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
14
test/main_default.cpp
Normal 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
16
test/main_init.cpp
Normal 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
41
test/main_timers.cpp
Normal 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;
|
||||||
|
}
|
40
test/main_timers_default.cpp
Normal file
40
test/main_timers_default.cpp
Normal 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
124
test/main_trigger.cpp
Normal 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;
|
||||||
|
}
|
118
test/main_trigger_default.cpp
Normal file
118
test/main_trigger_default.cpp
Normal 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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user