diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2013-04-17 13:22:58 -0700 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2013-04-27 14:09:22 -0700 |
commit | d18f5bdb682a1d9c6e3a191926bfd46d36e813c1 (patch) | |
tree | c987d53ea924b761e5445572a438e0c4bc825d48 /src/common | |
parent | da6b990ca1f553a017003f32a436304c66c62b9e (diff) | |
download | tmwa-d18f5bdb682a1d9c6e3a191926bfd46d36e813c1.tar.gz tmwa-d18f5bdb682a1d9c6e3a191926bfd46d36e813c1.tar.bz2 tmwa-d18f5bdb682a1d9c6e3a191926bfd46d36e813c1.tar.xz tmwa-d18f5bdb682a1d9c6e3a191926bfd46d36e813c1.zip |
Force timers to be managed
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/timer.cpp | 83 | ||||
-rw-r--r-- | src/common/timer.hpp | 25 | ||||
-rw-r--r-- | src/common/timer.t.hpp | 42 |
3 files changed, 106 insertions, 44 deletions
diff --git a/src/common/timer.cpp b/src/common/timer.cpp index 219efd9..7b115d9 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp @@ -15,12 +15,22 @@ struct TimerData { + /// This will be reset on call, to avoid problems. + Timer *owner; + /// When it will be triggered tick_t tick; /// What will be done timer_func func; /// Repeat rate - 0 for oneshot interval_t interval; + + TimerData(Timer *o, tick_t t, timer_func f, interval_t i) + : owner(o) + , tick(t) + , func(std::move(f)) + , interval(i) + {} }; struct TimerCompare @@ -52,6 +62,30 @@ tick_t milli_clock::now(void) noexcept } static +void do_nothing(TimerData *, tick_t) +{ +} + +void Timer::cancel() +{ + if (!td) + return; + + assert (this == td->owner); + td->owner = nullptr; + td->func = do_nothing; + td->interval = interval_t::zero(); + td = nullptr; +} + +void Timer::detach() +{ + assert (this == td->owner); + td->owner = nullptr; + td = nullptr; +} + +static void push_timer_heap(TimerData *td) { timer_heap.push(td); @@ -71,34 +105,39 @@ void pop_timer_heap(void) timer_heap.pop(); } -TimerData *add_timer(tick_t tick, timer_func func) -{ - return add_timer_interval(tick, std::move(func), interval_t::zero()); -} - -TimerData *add_timer_interval(tick_t tick, timer_func func, interval_t interval) +Timer::Timer(tick_t tick, timer_func func, interval_t interval) +: td(new TimerData(this, tick, std::move(func), interval)) { assert (interval >= interval_t::zero()); - TimerData *td = new TimerData(); - td->tick = tick; - td->func = std::move(func); - td->interval = interval; push_timer_heap(td); - return td; } -static -void do_nothing(TimerData *, tick_t) +Timer::Timer(Timer&& t) +: td(t.td) { + t.td = nullptr; + if (td) + { + assert (td->owner == &t); + td->owner = this; + } } -void delete_timer(TimerData *td) +Timer& Timer::operator = (Timer&& t) { - assert (td != nullptr); - - td->func = do_nothing; - td->interval = interval_t::zero(); + std::swap(td, t.td); + if (td) + { + assert (td->owner == &t); + td->owner = this; + } + if (t.td) + { + assert (t.td->owner == this); + t.td->owner = &t; + } + return *this; } interval_t do_timer(tick_t tick) @@ -118,7 +157,13 @@ interval_t do_timer(tick_t tick) } pop_timer_heap(); - // If we are too far past the requested tick, call with the current tick instead to fix reregistering problems + // Prevent destroying the object we're in. + // Note: this would be surprising in an interval timer, + // but all interval timers do an immediate explicit detach(). + if (td->owner) + td->owner->detach(); + // If we are too far past the requested tick, call with + // the current tick instead to fix reregistration problems if (td->tick + std::chrono::seconds(1) < tick) td->func(td, tick); else diff --git a/src/common/timer.hpp b/src/common/timer.hpp index 876d519..c581377 100644 --- a/src/common/timer.hpp +++ b/src/common/timer.hpp @@ -5,12 +5,6 @@ # include "sanity.hpp" -# include <chrono> -# include <functional> - -/// (to get additional arguments, use std::bind or a lambda). -typedef std::function<void (TimerData *, tick_t)> timer_func; - // updated automatically when using milli_clock::now() // which is done only by core.cpp extern tick_t gettick_cache; @@ -21,23 +15,8 @@ tick_t gettick(void) return gettick_cache; } -/// Schedule a one-shot timer at the given tick. -/// The timer will automatically be freed after it is called -/// (during a do_timer). -TimerData *add_timer(tick_t t, timer_func f); - -/// Schedule a recurring timer initially at the given tick. -/// The timer will automatically reregister itself, with the same -/// opaque handle, every interval after the tick. -/// It will never be freed unless you use delete_timer. -TimerData *add_timer_interval(tick_t, timer_func, interval_t); - -/// Cancel the given timer. -/// This doesn't actually remove it, it just resets the functor. -/// and waits for the the tick to arrive in do_timer. -void delete_timer(TimerData *); - -/// Do all timers scheduled before tick, and return the number of milliseconds until the next timer happens +/// Do all timers scheduled before tick, and return the number of +/// milliseconds until the next timer happens interval_t do_timer(tick_t tick); /// Stat a file, and return its modification time, truncated to seconds. diff --git a/src/common/timer.t.hpp b/src/common/timer.t.hpp index 67d7450..ee9b5d2 100644 --- a/src/common/timer.t.hpp +++ b/src/common/timer.t.hpp @@ -2,6 +2,9 @@ #define TIMER_T_HPP # include <chrono> +# include <functional> + +struct TimerData; /// An implementation of the C++ "clock" concept, exposing /// durations in milliseconds. @@ -21,8 +24,43 @@ public: typedef milli_clock::time_point tick_t; /// The difference between two points in time. typedef milli_clock::duration interval_t; +/// (to get additional arguments, use std::bind or a lambda). +typedef std::function<void (TimerData *, tick_t)> timer_func; -/// Opaque type representing an active timer. -struct TimerData; +class Timer +{ + friend struct TimerData; + TimerData *td; + + Timer(const Timer&) = delete; + Timer& operator = (const Timer&) = delete; +public: + /// Don't own anything yet. + Timer() : td(nullptr) {} + /// Schedule a timer for the given tick. + /// If you do not wish to keep track of it, call disconnect(). + /// Otherwise, you may cancel() or replace (operator =) it later. + /// + /// If the interval argument is given, the timer will reschedule + /// itself again forever. Otherwise, it will disconnect() itself + /// just BEFORE it is called. + Timer(tick_t tick, timer_func func, interval_t interval=interval_t::zero()); + + Timer(Timer&& t); + Timer& operator = (Timer&& t); + ~Timer() { cancel(); } + + /// Cancel the delivery of this timer's function, and make it falsy. + /// Implementation note: this doesn't actually remove it, just sets + /// the functor to do_nothing, and waits for the tick before removing. + void cancel(); + /// Make it falsy without cancelling the timer, + void detach(); + + /// Check if there is a timer connected. + explicit operator bool() { return td; } + /// Check if there is no connected timer. + bool operator !() { return !td; } +}; #endif // TIMER_T_HPP |