Timer in C++

This commit is contained in:
Olivier Goffart 2020-12-10 13:08:58 +01:00
parent 7f04301bca
commit a949570c57
3 changed files with 99 additions and 0 deletions

View file

@ -18,6 +18,7 @@ LICENSE END */
#include <memory>
#include <algorithm>
#include <iostream> // FIXME: remove: iostream always bring it lots of code so we should not have it in this header
#include <chrono>
namespace sixtyfps::cbindgen_private {
// Workaround https://github.com/eqrion/cbindgen/issues/43
@ -248,6 +249,41 @@ public:
}
};
/// A Timer that can call a callback at repeated interval
///
/// Use the static single_shot function to make a single shot timer
struct Timer {
/// Construct a timer which will repeat the callback every `duration` milliseconds until
/// the destructor of the timer is called.
template<typename F>
Timer(std::chrono::milliseconds duration, F callback)
: id(cbindgen_private::sixtyfps_timer_start(
duration.count(),
[](void *data) { (*reinterpret_cast<F*>(data))(); },
new F(std::move(callback)),
[](void *data) { delete reinterpret_cast<F*>(data); }))
{}
Timer(const Timer&) = delete;
Timer &operator=(const Timer&) = delete;
~Timer() {
cbindgen_private::sixtyfps_timer_stop(id);
}
/// Call the callback after the given duration.
template<typename F>
static void single_shot(std::chrono::milliseconds duration, F callback) {
cbindgen_private::sixtyfps_timer_singleshot(
duration.count(),
[](void *data) { (*reinterpret_cast<F*>(data))(); },
new F(std::move(callback)),
[](void *data) { delete reinterpret_cast<F*>(data); });
}
private:
int64_t id;
};
// layouts:
using cbindgen_private::box_layout_info;
using cbindgen_private::BoxLayoutCellData;

View file

@ -85,4 +85,5 @@ pub fn use_modules() -> usize {
+ string::ffi::sixtyfps_shared_string_bytes as usize
+ eventloop::ffi::sixtyfps_component_window_drop as usize
+ component::ffi::sixtyfps_component_init_items as usize
+ timers::ffi::sixtyfps_timer_start as usize
}

View file

@ -302,3 +302,65 @@ fn lower_bound<T>(vec: &Vec<T>, mut less_than: impl FnMut(&T) -> bool) -> usize
left
}
pub(crate) mod ffi {
use super::*;
#[allow(non_camel_case_types)]
type c_void = ();
struct WrapFn {
callback: extern "C" fn(*mut c_void),
user_data: *mut c_void,
drop_user_data: Option<extern "C" fn(*mut c_void)>,
}
impl Drop for WrapFn {
fn drop(&mut self) {
if let Some(x) = self.drop_user_data {
x(self.user_data)
}
}
}
/// Start a timer with the given duration in millisecond.
/// Returns the timer id.
/// The timer MUST be stopped with sixtyfps_timer_stop
#[no_mangle]
pub extern "C" fn sixtyfps_timer_start(
duration: u64,
callback: extern "C" fn(*mut c_void),
user_data: *mut c_void,
drop_user_data: Option<extern "C" fn(*mut c_void)>,
) -> i64 {
let wrap = WrapFn { callback, user_data, drop_user_data };
let timer = Timer::default();
timer.start(TimerMode::Repeated, core::time::Duration::from_millis(duration), move || {
(wrap.callback)(wrap.user_data)
});
timer.id.get().map(|x| x as i64).unwrap_or(-1)
}
/// Execute a callback with a delay in milisecond
#[no_mangle]
pub extern "C" fn sixtyfps_timer_singleshot(
delay: u64,
callback: extern "C" fn(*mut c_void),
user_data: *mut c_void,
drop_user_data: Option<extern "C" fn(*mut c_void)>,
) {
let wrap = WrapFn { callback, user_data, drop_user_data };
Timer::single_shot(core::time::Duration::from_millis(delay), move || {
(wrap.callback)(wrap.user_data)
});
}
/// Stop a timer and free its raw data
#[no_mangle]
pub extern "C" fn sixtyfps_timer_stop(id: i64) {
if id == -1 {
return;
}
let timer = Timer { id: Cell::new(Some(id as _)) };
timer.stop()
}
}