Merge: highlight with ansi color (for console)
[nit.git] / lib / realtime.nit
index 8cfa4da..33708b6 100644 (file)
@@ -23,7 +23,7 @@ in "C header" `{
 
 in "C" `{
 
-#ifdef __MACH__
+#if defined(__MACH__) && !defined(CLOCK_REALTIME)
 /* OS X does not have clock_gettime, mascarade it and use clock_get_time
  * cf http://stackoverflow.com/questions/11680461/monotonic-clock-on-osx
 */
@@ -44,7 +44,7 @@ void clock_gettime(clock_t clock_name, struct timespec *ts) {
 `}
 
 # Elapsed time representation.
-extern class Timespec `{struct timespec*`}
+private extern class Timespec `{struct timespec*`}
 
        # Init a new Timespec from `s` seconds and `ns` nanoseconds.
        new ( s, ns : Int ) `{
@@ -73,14 +73,30 @@ extern class Timespec `{struct timespec*`}
                clock_gettime(CLOCK_MONOTONIC, self);
        `}
 
-       # Substract a Timespec from `self`.
-       fun - ( o : Timespec ) : Timespec
-       do
-               var s = sec - o.sec
-               var ns = nanosec - o.nanosec
-               if ns > nanosec then s += 1
-               return new Timespec( s, ns )
-       end
+       # Subtract `other` from `self`
+       fun -(other: Timespec): Timespec `{
+               time_t s = self->tv_sec - other->tv_sec;
+               long ns = self->tv_nsec - other->tv_nsec;
+               if (ns < 0) {
+                       s -= 1;
+                       ns += 1000000000l;
+               }
+               struct timespec* tv = malloc(sizeof(struct timespec));
+               tv->tv_sec = s; tv->tv_nsec = ns;
+               return tv;
+       `}
+
+       # Set `self` to `a` - `b`
+       fun minus(a, b: Timespec) `{
+               time_t s = a->tv_sec - b->tv_sec;
+               long ns = a->tv_nsec - b->tv_nsec;
+               if (ns < 0) {
+                       s -= 1;
+                       ns += 1000000000l;
+               }
+               self->tv_sec = s;
+               self->tv_nsec = ns;
+       `}
 
        # Number of whole seconds of elapsed time.
        fun sec : Int `{
@@ -111,23 +127,45 @@ extern class Timespec `{struct timespec*`}
        # Number of seconds as a `Float`
        #
        # Incurs a loss of precision, but the result is pretty to print.
-       fun to_f: Float do return sec.to_f + nanosec.to_f / 1000000000.0
+       fun to_f: Float `{
+               return (double)self->tv_sec + 0.000000001 * self->tv_nsec;
+       `}
 
        redef fun to_s do return "{to_f}s"
 end
 
 # Keeps track of real time
+#
+# ~~~
+# var clock = new Clock
+#
+# # sleeping at least 1s
+# 1.0.sleep
+# assert clock.total >= 1.0
+# assert clock.lapse >= 1.0
+#
+# # sleeping at least 5ms
+# 0.005.sleep
+# assert clock.total >= 1.005
+# assert clock.lapse >= 0.005
+# ~~~
 class Clock
-       # Time at instanciation
-       protected var time_at_beginning = new Timespec.monotonic_now
+       super FinalizableOnce
+
+       # TODO use less mallocs
+
+       # Time at creation
+       private var time_at_beginning = new Timespec.monotonic_now
 
        # Time at last time a lapse method was called
-       protected var time_at_last_lapse = new Timespec.monotonic_now
+       private var time_at_last_lapse = new Timespec.monotonic_now
+
+       private var temp = new Timespec.monotonic_now
 
        # Smallest time frame reported by clock
-       fun resolution : Timespec `{
+       private fun resolution: Timespec `{
                struct timespec* tv = malloc( sizeof(struct timespec) );
-#ifdef __MACH__
+#if defined(__MACH__) && !defined(CLOCK_REALTIME)
                clock_serv_t cclock;
                int nsecs;
                mach_msg_type_number_t count;
@@ -142,18 +180,43 @@ class Clock
                return tv;
        `}
 
-       # Return timelapse since instanciation of this instance
-       fun total : Timespec
+       # Seconds since the creation of this instance
+       fun total: Float
+       do
+               var now = temp
+               now.update
+               now.minus(now, time_at_beginning)
+               return now.to_f
+       end
+
+       # Seconds since the last call to `lapse`
+       fun lapse: Float
+       do
+               var time_at_last_lapse = time_at_last_lapse
+               var now = temp
+               now.update
+               time_at_last_lapse.minus(now, time_at_last_lapse)
+               var r = time_at_last_lapse.to_f
+
+               self.temp = time_at_last_lapse
+               self.time_at_last_lapse = now
+
+               return r
+       end
+
+       # Seconds since the last call to `lapse`, without resetting the lapse counter
+       fun peek_lapse: Float
        do
-               return new Timespec.monotonic_now - time_at_beginning
+               var now = temp
+               now.update
+               now.minus(now, time_at_last_lapse)
+               return now.to_f
        end
 
-       # Return timelapse since last call to lapse
-       fun lapse : Timespec
+       redef fun finalize_once
        do
-               var nt = new Timespec.monotonic_now
-               var dt = nt - time_at_last_lapse
-               time_at_last_lapse = nt
-               return dt
+               time_at_beginning.free
+               time_at_last_lapse.free
+               temp.free
        end
 end