]> Dogcows Code - chaz/yoink/blobdiff - src/moof/timer.hh
further implementing runloop support
[chaz/yoink] / src / moof / timer.hh
index f5c3583ccc0525c90adf616979fddfb82d8819ce..9f3e9846096d7e09600a053ea929c66e7af91d19 100644 (file)
 namespace moof {
 
 
+/**
+ * A timer source is an object that keeps track of increasing time in units
+ * of seconds.  A timer source does not necessarily have to increment at
+ * the same rate or in the same way as the real time.  The time source must
+ * begin at zero and always remain the same or increase each time the time
+ * is queried.
+ */
+class timer_source
+{
+public:
+
+       /**
+        * Deconstruct a timer source.
+        */
+       virtual ~timer_source() {}
+
+       /**
+        * Get the number seconds since the timer source was created or reset.
+        */
+       virtual scalar ticks() const = 0;
+
+       /**
+        * Reset the timer such that the current time will become zero.
+        */
+       virtual void reset() = 0;
+
+       /**
+        * Scale the time.  After calling this, the timer source should either
+        * increment faster or slower, depending on the scale factor.
+        */
+       virtual void scale(scalar factor) = 0;
+};
+
+
+class runloop;
+
+
 /**
  * A class to represent a timer for scheduled events.  The timer events
  * will be executed on or sometime after their schedculed time.  The
@@ -43,10 +80,10 @@ public:
         */
        enum mode
        {
-               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.
+               invalid         = 0,    /// Timer is not scheduled.
+               relative        = 1,    /// Timer is scheduled by a relative time.
+               absolute        = 2,    /// Timer is scheduled by an absolute time.
+               repeat          = 3             /// Timer is scheduled by a periodic time.
        };
 
        /**
@@ -63,7 +100,8 @@ public:
         */
        timer() :
                mode_(invalid),
-               absolute_(SCALAR(0.0)) {}
+               absolute_(SCALAR(0.0)),
+               runloop_(0) {}
 
        /**
         * Construct a scheduled timer.
@@ -80,19 +118,21 @@ public:
         * 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)
+       timer(const function& function,
+                 scalar seconds,
+                 mode mode = relative,
+                 timer_source& source = default_source()) :
+               runloop_(0)
        {
-               init(function, seconds, mode);
+               init(function, seconds, mode, source);
        }
 
+
        /**
         * Deconstruct a timer.  This will automagically invalidate the timer,
         * so it will not expire or fire an event.
         */
-       ~timer()
-       {
-               invalidate();
-       }
+       ~timer();
 
 
        /**
@@ -114,16 +154,10 @@ public:
         */
        void init(const function& function,
                          scalar seconds,
-                         mode mode = relative);
+                         enum mode mode = relative,
+                         timer_source& source = default_source());
 
        
-       /**
-        * 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;
-
        /**
         * Manually invalidated the timer, removing any schedule such that the
         * timer will not expired and no event will be fired.
@@ -131,25 +165,71 @@ public:
        void invalidate();
 
 
+       enum mode mode() const
+       {
+               return mode_;
+       }
+
+
        /**
         * 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();
+       void fire(scalar t);
+       void fire()
+       {
+               fire(source_->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)
+       {
+               if (is_expired(t)) fire(t);
+               return absolute_;
+       }
+       scalar fire_if_expired()
+       {
+               return fire_if_expired(source_->ticks());
+       }
 
 
+       /**
+        * Get the absolute time of the next expiration of this timer.
+        * \return Seconds.
+        */
+       scalar expiration() const
+       {
+               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() const;
+       scalar remaining(scalar t) const
+       {
+               return expiration() - t;
+       }
+       scalar remaining() const
+       {
+               return remaining(source_->ticks());
+       }
 
-       scalar next_expiration() const;
 
        /**
         * Get whether or not the timer is expired.  A timer on a repeating
@@ -157,20 +237,25 @@ public:
         * 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() const;
+       bool is_expired(scalar t) const
+       {
+               return remaining(t) < SCALAR(0.0);
+       }
+       bool is_expired() const
+       {
+               return is_expired(source_->ticks());
+       }
 
-       /**
-        * Get whether or not the timer is on a repeating schedule.
-        * \return True if the timer is repeating, false otherwise.
-        */
-       bool is_repeating() const;
 
+       static timer_source& default_source();
 
        /**
-        * Get the number of seconds since a fixed, arbitrary point in the
-        * past.
+        * Get the number of real seconds since the default timer was first
+        * created or last reset.
         * \return Seconds.
         */
        static scalar ticks();
@@ -178,57 +263,78 @@ public:
 
        /**
         * Put the thread to sleep for a certain period of time.  If absolute
-        * is true, then it will sleep until seconds after the fixed time in
-        * the past.  If absolute is false, it will sleep for seconds starting
-        * now.  Unlike system sleep functions, this one automatically resumes
-        * sleep if sleep was interrupted by a signal.  Therefore, calling this
-        * function is guaranteed to sleep for the requested amount of time
-        * (and maybe longer).
+        * is true, then it will sleep until the default timer reaches the
+        * specified number of seconds.  If the mode is relative, the thread
+        * will sleep for that many seconds.  Unlike system sleep functions,
+        * this one automatically resumes sleep if sleep was interrupted by a
+        * signal.  Therefore, calling this function is guaranteed to sleep for
+        * at least the requested amount of time.
         * \param seconds Number of seconds.
         * \param mode The timer mode.
         */
-       static void sleep(scalar seconds, mode mode = relative);
+       static void sleep(scalar seconds, enum mode mode = relative);
 
 
-       /**
-        * Get the absolute time when the next timer is scheduled to expire.
-        * \return Absolute time, in seconds.
-        */
-       static scalar next_event()
+private:
+
+       void added_to_runloop(runloop& runloop);
+       void detach_from_runloop();
+
+
+       function                function_;
+       enum mode               mode_;
+       scalar                  absolute_;
+       scalar                  interval_;
+       timer_source*   source_;
+       runloop*                runloop_;
+};
+
+
+
+
+class game_time : public timer_source
+{
+public:
+
+       game_time(scalar timestep) :
+               timestep_(timestep),
+               scale_(timestep)
        {
-               return next_event_;
+               reset();
        }
 
+       scalar ticks() const
+       {
+               return reference_ + scalar(ticks_) * scale_;
+       }
 
-       /**
-        * Fire any timers which are not yet invalidated but have an expiration
-        * time in the past.
-        */
-       static void fire_expired_timers()
+       void reset()
        {
-               fire_expired_timers(ticks());
+               reference_ = SCALAR(0.0);
+               ticks_ = 0;
        }
 
-       /**
-        * Fire any timers which are not yet invalidated but have an expiration
-        * time before a given absolute time.
-        */
-       static void fire_expired_timers(scalar t);
+       void scale(scalar factor)
+       {
+               reference_ = ticks();
+               ticks_ = 1;
+               scale_ = timestep_ * factor;
+       }
 
 
-private:
+       unsigned step(unsigned step = 1)
+       {
+               ticks_ += step;
+               return ticks_;
+       }
 
-       static unsigned new_identifier();
-       static scalar find_next_event();
 
-       function        function_;
-       mode            mode_;
-       scalar          absolute_;
-       scalar          interval_;
-       unsigned        id_;
+private:
 
-       static scalar                                                           next_event_;
-       static hash<unsigned,timer*,hash_function>      timers_;
+       scalar          reference_;
+       unsigned        ticks_;
+       scalar          timestep_;
+       scalar          scale_;
 };
 
 
This page took 0.027772 seconds and 4 git commands to generate.