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/module.hpp"
9#include "../macros.hpp"
10#include <vector>
11#include <algorithm>
12#include <chrono>
13#include <functional>
14
15hi_export_module(hikogui.dispatch.function_timer);
16
17namespace hi::inline v1 {
18
24template<typename Proto = void()>
26public:
27 using callback_proto = Proto;
31
32 using result_type = function_type::result_type;
33
34 constexpr function_timer() noexcept = default;
35
36 [[nodiscard]] constexpr bool empty() const noexcept
37 {
38 return _functions.empty();
39 }
40
48 delay_function(utc_nanoseconds time_point, forward_of<callback_proto> auto&& callback) noexcept
49 {
50 hilet it = std::lower_bound(_functions.begin(), _functions.end(), time_point, [](hilet& x, hilet& time_point) {
51 return x.time_point > time_point;
52 });
53
54 hilet next_to_call = it == _functions.end();
55
56 auto token = std::make_shared<function_type>(hi_forward(callback));
57 _functions.emplace(it, time_point, std::chrono::nanoseconds::max(), token);
58 return {std::move(token), next_to_call};
59 }
60
70 utc_nanoseconds time_point,
71 forward_of<callback_proto> auto&& callback) noexcept
72 {
73 auto it = std::lower_bound(_functions.begin(), _functions.end(), time_point, [](hilet& x, hilet& time_point) {
74 return x.time_point > time_point;
75 });
76
77 auto token = std::make_shared<function_type>(hi_forward(callback));
78 it = _functions.emplace(it, time_point, period, token);
79 return {std::move(token), it + 1 == _functions.end()};
80 }
81
89 repeat_function(std::chrono::nanoseconds period, forward_of<callback_proto> auto&& callback) noexcept
90 {
91 return repeat_function(period, std::chrono::utc_clock::now(), hi_forward(callback));
92 }
93
98 utc_nanoseconds current_deadline() const noexcept
99 {
100 if (_functions.empty()) {
101 return utc_nanoseconds::max();
102 } else {
103 return _functions.back().time_point;
104 }
105 }
106
112 void run_all(utc_nanoseconds current_time, auto const&...args) noexcept
113 {
114 while (current_deadline() <= current_time) {
115 run_one(current_time, args...);
116 }
117 }
118
119private:
120 struct timer_type {
121 utc_nanoseconds time_point;
123 weak_callback_token token;
124
125 timer_type() noexcept = default;
126 timer_type(timer_type const&) noexcept = default;
127 timer_type(timer_type&&) noexcept = default;
128 timer_type& operator=(timer_type const&) noexcept = default;
129 timer_type& operator=(timer_type&&) noexcept = default;
130
131 timer_type(utc_nanoseconds time_point, std::chrono::nanoseconds period, weak_callback_token token) noexcept :
132 time_point(time_point), period(period), token(std::move(token))
133 {
134 }
135
136 timer_type(utc_nanoseconds time_point, weak_callback_token token) noexcept :
137 timer_type(time_point, std::chrono::nanoseconds::max(), std::move(token))
138 {
139 }
140
141 timer_type(std::chrono::nanoseconds period, weak_callback_token token) noexcept :
142 timer_type(std::chrono::utc_clock::now(), period, std::move(token))
143 {
144 }
145
146 [[nodiscard]] constexpr bool repeats() const noexcept
147 {
148 return period != std::chrono::nanoseconds::max();
149 }
150 };
151
152 void remove_or_reinsert(utc_nanoseconds current_time) noexcept
153 {
154 hi_assert(not _functions.empty());
155
156 if (_functions.back().repeats() and not _functions.back().token.expired()) {
157 // When the function is repeating, calculate the new.
158 auto item = std::move(_functions.back());
159 _functions.pop_back();
160
161 // Delay the function to be called on the next period.
162 // However if the current_time already is passed the deadline, delay it even further.
163 item.time_point += item.period;
164 if (item.time_point > current_time) {
165 item.time_point = current_time + item.period;
166 }
167
168 // Reinsert the function in the sorted list of functions.
169 hilet it = std::lower_bound(_functions.begin(), _functions.end(), item.time_point, [](hilet& x, hilet& time_point) {
170 return x.time_point > time_point;
171 });
172
173 _functions.insert(it, std::move(item));
174
175 } else {
176 _functions.pop_back();
177 }
178 }
179
187 result_type run_one(utc_nanoseconds current_time, auto&&...args)
188 {
189 hi_assert(not _functions.empty());
190
191 if constexpr (std::is_same_v<result_type, void>) {
192 if (auto token = _functions.back().token.lock()) {
193 (*token)(hi_forward(args)...);
194 }
195 remove_or_reinsert(current_time);
196 return;
197 } else {
198 if (auto token = _functions.back().token.lock()) {
199 auto result = (*token)(hi_forward(args)...);
200 remove_or_reinsert(current_time);
201 return result;
202 } else {
203 return {};
204 }
205 }
206 }
207
210 std::vector<timer_type> _functions;
211};
212
213} // namespace hi::inline v1
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:16
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
A time that calls functions.
Definition function_timer.hpp:25
std::pair< callback_token, bool > repeat_function(std::chrono::nanoseconds period, utc_nanoseconds time_point, forward_of< callback_proto > auto &&callback) noexcept
Add a function to be called repeatedly.
Definition function_timer.hpp:68
utc_nanoseconds current_deadline() const noexcept
Get the deadline of the next function to call.
Definition function_timer.hpp:98
std::pair< callback_token, bool > repeat_function(std::chrono::nanoseconds period, forward_of< callback_proto > auto &&callback) noexcept
Add a function to be called repeatedly.
Definition function_timer.hpp:89
std::pair< callback_token, bool > delay_function(utc_nanoseconds time_point, forward_of< callback_proto > auto &&callback) noexcept
Add a function to be called at a certain time.
Definition function_timer.hpp:48
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:112
T lower_bound(T... args)
T move(T... args)