HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
function_timer.hpp
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../utility/utility.hpp"
8#include "../time/time.hpp"
9#include "../concurrency/concurrency.hpp"
10#include "../macros.hpp"
11#include <vector>
12#include <algorithm>
13#include <chrono>
14#include <functional>
15
16hi_export_module(hikogui.dispatch.function_timer);
17
18hi_export namespace hi::inline v1 {
19
23public:
24 constexpr function_timer() noexcept = default;
25
26 [[nodiscard]] constexpr bool empty() const noexcept
27 {
28 return _functions.empty();
29 }
30
37 template<forward_of<void()> Func>
38 [[nodiscard]] std::pair<callback<void()>, bool> delay_function(utc_nanoseconds time_point, Func &&func) noexcept
39 {
40 auto const it = std::lower_bound(_functions.begin(), _functions.end(), time_point, [](auto const& x, auto const& time_point) {
41 return x.time_point > time_point;
42 });
43
44 auto const next_to_call = it == _functions.end();
45
46 auto token = callback<void()>{std::forward<Func>(func)};
47 _functions.emplace(it, time_point, std::chrono::nanoseconds::max(), token);
48 return {std::move(token), next_to_call};
49 }
50
58 template<forward_of<void()> Func>
59 [[nodiscard]] std::pair<callback<void()>, bool> repeat_function(
61 utc_nanoseconds time_point,
62 Func &&func) noexcept
63 {
64 auto it = std::lower_bound(_functions.begin(), _functions.end(), time_point, [](auto const& x, auto const& time_point) {
65 return x.time_point > time_point;
66 });
67
68 auto token = callback<void()>{std::forward<Func>(func)};
69 it = _functions.emplace(it, time_point, period, token);
70 return {std::move(token), it + 1 == _functions.end()};
71 }
72
79 template<forward_of<void()> Func>
80 [[nodiscard]] std::pair<callback<void()>, bool> repeat_function(std::chrono::nanoseconds period, Func &&func) noexcept
81 {
82 return repeat_function(period, std::chrono::utc_clock::now(), std::forward<Func>(func));
83 }
84
89 [[nodiscard]] utc_nanoseconds current_deadline() const noexcept
90 {
91 if (_functions.empty()) {
92 return utc_nanoseconds::max();
93 } else {
94 return _functions.back().time_point;
95 }
96 }
97
103 void run_all(utc_nanoseconds current_time, auto const&...args) noexcept
104 {
105 while (current_deadline() <= current_time) {
106 run_one(current_time, args...);
107 }
108 }
109
110private:
111 struct timer_type {
112 utc_nanoseconds time_point;
114 weak_callback<void()> callback;
115
116 timer_type() noexcept = default;
117 timer_type(timer_type const&) noexcept = default;
118 timer_type(timer_type&&) noexcept = default;
119 timer_type& operator=(timer_type const&) noexcept = default;
120 timer_type& operator=(timer_type&&) noexcept = default;
121
122 timer_type(utc_nanoseconds time_point, std::chrono::nanoseconds period, weak_callback<void()> callback) noexcept :
123 time_point(time_point), period(period), callback(std::move(callback))
124 {
125 }
126
127 timer_type(utc_nanoseconds time_point, weak_callback<void()> callback) noexcept :
128 timer_type(time_point, std::chrono::nanoseconds::max(), std::move(callback))
129 {
130 }
131
132 timer_type(std::chrono::nanoseconds period, weak_callback<void()> callback) noexcept :
133 timer_type(std::chrono::utc_clock::now(), period, std::move(callback))
134 {
135 }
136
137 [[nodiscard]] constexpr bool repeats() const noexcept
138 {
139 return period != std::chrono::nanoseconds::max();
140 }
141 };
142
143 void remove_or_reinsert(utc_nanoseconds current_time) noexcept
144 {
145 hi_assert(not _functions.empty());
146
147 if (_functions.back().repeats() and not _functions.back().callback.expired()) {
148 // When the function is repeating, calculate the new.
149 auto item = std::move(_functions.back());
150 _functions.pop_back();
151
152 // Delay the function to be called on the next period.
153 // However if the current_time already is passed the deadline, delay it even further.
154 item.time_point += item.period;
155 if (item.time_point > current_time) {
156 item.time_point = current_time + item.period;
157 }
158
159 // Reinsert the function in the sorted list of functions.
160 auto const it = std::lower_bound(_functions.begin(), _functions.end(), item.time_point, [](auto const& x, auto const& time_point) {
161 return x.time_point > time_point;
162 });
163
164 _functions.insert(it, std::move(item));
165
166 } else {
167 _functions.pop_back();
168 }
169 }
170
176 void run_one(utc_nanoseconds current_time)
177 {
178 hi_assert(not _functions.empty());
179
180 auto &callback = _functions.back().callback;
181 if (auto cb = callback.lock()) {
182 cb();
183 }
184 remove_or_reinsert(current_time);
185 }
186
189 std::vector<timer_type> _functions;
190};
191
192} // namespace hi::inline v1
STL namespace.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
A timer that calls functions.
Definition function_timer.hpp:22
utc_nanoseconds current_deadline() const noexcept
Get the deadline of the next function to call.
Definition function_timer.hpp:89
void run_all(utc_nanoseconds current_time, auto const &...args) noexcept
Run all the function that should have run by the current_time.
Definition function_timer.hpp:103
std::pair< callback< void()>, bool > delay_function(utc_nanoseconds time_point, Func &&func) noexcept
Add a function to be called at a certain time.
Definition function_timer.hpp:38
std::pair< callback< void()>, bool > repeat_function(std::chrono::nanoseconds period, Func &&func) noexcept
Add a function to be called repeatedly.
Definition function_timer.hpp:80
std::pair< callback< void()>, bool > repeat_function(std::chrono::nanoseconds period, utc_nanoseconds time_point, Func &&func) noexcept
Add a function to be called repeatedly.
Definition function_timer.hpp:59
T lower_bound(T... args)
T move(T... args)