#ifndef _ASYNCO_ #define _ASYNCO_ #include #include #include #include #include #include #include using namespace std; #include #if __cplusplus >= 202002L #include #include #include #endif using namespace boost::asio; #include "timers.hpp" #include "trigger.hpp" namespace marcelb { namespace asynco { /** * Asynco runtime * Used for all asynchronous capabilities of this wrapper * Initializes threads and boost::asio::io_context */ class Asynco { vector _runners; unique_ptr _work; void init_loops_in_threads(uint8_t threads); 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 auto async(F&& f, Args&&... args) -> future> { using return_type = invoke_result_t; future res = io_ctx.post(boost::asio::use_future(bind(forward(f), forward(args)...))); return res; } #if __cplusplus >= 202002L /** * Run the coroutine in runtime */ template future async(boost::asio::awaitable _coroutine) { promise promise; auto future = promise.get_future(); co_spawn(io_ctx, [_coroutine = move(_coroutine), promise = move(promise)]() mutable -> boost::asio::awaitable { try { if constexpr (!is_void_v) { 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 T await(future& 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 T await(future&& 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 auto await(F&& f, Args&&... args) -> invoke_result_t { return await( async(f, args...) ); } #if __cplusplus >= 202002L /** * Run the coruotine and wait */ template T await(boost::asio::awaitable _coroutine) { return await( async( move(_coroutine) )); } #endif /** * Wait until the multiple asynchronous call completes * Use only on no-void calls */ template auto await(F&&... f) -> tuple::type...> { return make_tuple(await(f)...); } /** * Wait until the multiple asynchronous call completes * Use only on no-void calls */ template auto await(F&... f) -> tuple::type...> { return make_tuple(await(f)...); } /** * Initialize the delayed timer */ Timer delayed(function callback, uint64_t time); /** * Initialize the periodic timer */ Timer periodic(function callback, uint64_t time); /** * Initialize trigger (typed event) */ template Trigger trigger() { return Trigger(*this); } }; } } #endif