#include #include namespace psemek::util { auto event_loop::heap_compare() { return [](deferred_task const & t1, deferred_task const & t2){ return t1.time > t2.time; }; } void event_loop::post(task t) { task_queue_.push_back(std::move(t)); } void event_loop::post_at(clock::time_point time, task t) { if (time > clock::now()) { deferred_task_heap_.push_back(deferred_task{time, std::move(t)}); std::push_heap(deferred_task_heap_.begin(), deferred_task_heap_.end(), heap_compare()); } else task_queue_.push_back(std::move(t)); } void event_loop::stop() { task_queue_.clear(); deferred_task_heap_.clear(); } void event_loop::wait() { while (!task_queue_.empty() || !deferred_task_heap_.empty()) { flush_deferred(); if (task_queue_.empty()) { std::this_thread::sleep_until(deferred_task_heap_.front().time); } else { auto t = std::move(task_queue_.front()); task_queue_.pop_front(); t(); } } } void event_loop::wait_for(clock::duration period) { wait_until(clock::now() + period); } void event_loop::wait_until(clock::time_point time) { while ((!task_queue_.empty() || !deferred_task_heap_.empty()) && clock::now() < time) { flush_deferred(); auto t = std::move(task_queue_.front()); task_queue_.pop_front(); t(); } } std::size_t event_loop::task_count() const { return task_queue_.size() + deferred_task_heap_.size(); } void event_loop::flush_deferred() { auto const now = clock::now(); while (!deferred_task_heap_.empty() && deferred_task_heap_.front().time <= now) { task_queue_.push_back(std::move(deferred_task_heap_.front().func)); std::pop_heap(deferred_task_heap_.begin(), deferred_task_heap_.end(), heap_compare()); deferred_task_heap_.pop_back(); } } }