* Functions for measuring time in a friendly unit.
*/
-#include <map>
-
#include <boost/bind.hpp>
#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+#include <moof/hash.hh>
#include <moof/math.hh>
+#include <moof/runloop.hh>
namespace moof {
-class timer
+/**
+ * A class to represent a timer for scheduled events. The timer events
+ * will be executed on or sometime after their schedculed time. The
+ * runloop associated with the current running view will make an attempt to
+ * fire any expired timers as close to their scheduled times as possible.
+ */
+class timer : public boost::noncopyable
{
public:
+ /**
+ * A type for the state of a timer.
+ */
enum mode
{
- invalid = -1,
- normal = 0,
- absolute = 1,
- repeat = 2
+ invalid = -1, /// Timer is not scheduled.
+ relative = 0, /// Timer is scheduled by a relative time.
+ absolute = 1, /// Timer is scheduled by an absolute time.
+ repeat = 2 /// Timer is scheduled by a periodic time.
};
+ /**
+ * Function protocol for a timer event handler. A function matching
+ * this protocol will be called when the timer expires. The function
+ * takes two parameters: the timer object that just expired, and the
+ * absolute time.
+ */
typedef boost::function<void(timer&,scalar)> function;
+ /**
+ * Construct an invalid (uninitialized) timer.
+ */
timer() :
- mode_(invalid) {}
+ mode_(invalid),
+ absolute_(SCALAR(0.0)) {}
- timer(const function& function, scalar seconds, mode mode = normal)
+ /**
+ * Construct a scheduled timer.
+ * \param function The event handler.
+ * \param seconds The number of seconds; the meaning of this depends on
+ * the mode of the timer.
+ * \param mode The timer mode. If the mode is relative (default), the
+ * seconds parameter is the number of seconds from the current time to
+ * wait before expiring the timer. If the mode is absolute, the
+ * seconds parameter is the number of seconds from some arbitrary,
+ * fixed time in the past. If the mode is repeat, the seconds
+ * parameter is the number of seconds from now to wait before expiring
+ * the timer, at which time the timer will be rescheduled to expired
+ * again at that many seconds from the expiration time. A repeating
+ * timer can be invalidated manually using invalidate().
+ */
+ timer(const function& function,
+ scalar seconds,
+ mode mode = relative,
+ runloop* runloop = runloop::current())
{
- init(function, seconds, mode);
+ init(function, seconds, mode, runloop);
}
+ /**
+ * Deconstruct a timer. This will automagically invalidate the timer,
+ * so it will not expire or fire an event.
+ */
~timer()
{
invalidate();
}
- void init(const function& function, scalar seconds, mode mode = normal);
- bool is_valid() const;
+ /**
+ * Initialize a timer with a scheduled time. If the timer is already
+ * scheduled, its prior schedule will be invalidated and replaced by
+ * this new schedule.
+ * \param function The event handler.
+ * \param seconds The number of seconds; the meaning of this depends on
+ * the mode of the timer.
+ * \param mode The timer mode. If the mode is relative (default), the
+ * seconds parameter is the number of seconds from the current time to
+ * wait before expiring the timer. If the mode is absolute, the
+ * seconds parameter is the number of seconds from some arbitrary,
+ * fixed time in the past. If the mode is repeat, the seconds
+ * parameter is the number of seconds from now to wait before expiring
+ * the timer, at which time the timer will be rescheduled to expired
+ * again at that many seconds from the expiration time. A repeating
+ * timer can be invalidated manually using invalidate().
+ */
+ void init(const function& function,
+ scalar seconds,
+ mode mode = relative,
+ runloop* runloop = runloop::current());
+
+
+ /**
+ * Get whether or not the timer is valid. If a timer is valid, it is
+ * still scheduled to expired. You can get the time remaining from
+ * seconds_remaining().
+ */
+ bool is_valid() const
+ {
+ return mode_ != invalid;
+ }
+
+ /**
+ * Manually invalidated the timer, removing any schedule such that the
+ * timer will not expired and no event will be fired.
+ */
void invalidate();
- void fire();
- scalar seconds_remaining() const;
- bool is_expired() const;
- bool is_repeating() const;
+ /**
+ * Manually fire the timer event. Usually, the timer event will be
+ * fired when the timer expires, but this can be used to fire it
+ * prematurely. If the timer is scheduled, it will be invalidated. If
+ * the timer is already invalid (but is initialized with an event
+ * handler), the event will be fired and the timer will remain invalid.
+ * \param t The absolute time passed to the timer event function.
+ */
+ void fire(scalar t = ticks());
+
+
+ /**
+ * Fire the timer event if it is expired.
+ * \param t The absolute time used as a reference to determine if the
+ * timer is expired; defaults to the current time.
+ * \return The absolute time of the next expiration (if repeating), or
+ * 0.0 otherwise.
+ */
+ scalar fire_if_expired(scalar t = ticks())
+ {
+ if (is_expired()) fire();
+ return absolute_;
+ }
+
+
+ /**
+ * Get the number of seconds remaining before the timer is scheduled to
+ * expired. If the timer is invalid, the retured value will be
+ * negative.
+ * \param t The absolute time used as a reference to determine the
+ * amount of time left; defaults to the current time.
+ * \return Seconds.
+ */
+ scalar seconds_remaining(scalar t = ticks()) const
+ {
+ return next_expiration() - t;
+ }
+
+ /**
+ * Get the absolute time of the next expiration of this timer.
+ * \return Seconds.
+ */
+ scalar next_expiration() const
+ {
+ return absolute_;
+ }
+
+
+ /**
+ * Get whether or not the timer is expired. A timer on a repeating
+ * schedule will never be expired since it will always have a scheduled
+ * expiration time in the future. If the timer is expired but not
+ * invalid, the timer event has not yet fired; the timer will be
+ * invalidated when it does fire.
+ * \param t The absolute time used as a reference to determine if the
+ * timer is expired; defaults to the current time.
+ * \return True if the timer is expired, false otherwise.
+ */
+ bool is_expired(scalar t = ticks()) const
+ {
+ return seconds_remaining(t) < SCALAR(0.0);
+ }
+
+ /**
+ * Get whether or not the timer is on a repeating schedule.
+ * \return True if the timer is repeating, false otherwise.
+ */
+ bool is_repeating() const
+ {
+ return mode_ == repeat;
+ }
/**
* \param seconds Number of seconds.
* \param mode The timer mode.
*/
- static void sleep(scalar seconds, mode mode = normal);
-
-
- static scalar next_expiration()
- {
- return gNextFire;
- }
-
- static void fire_expired_timers();
- static void fire_expired_timers(scalar t);
+ static void sleep(scalar seconds, mode mode = relative);
private:
- static unsigned new_identifier();
- static scalar find_next_expiration();
-
function function_;
mode mode_;
scalar absolute_;
scalar interval_;
- unsigned id_;
-
- static scalar gNextFire;
- static std::map<unsigned,timer*> gTimers;
+ runloop* runloop_;
};