Merge: Infer more attribute types
[nit.git] / lib / realtime.nit
index a400619..31040ba 100644 (file)
@@ -23,15 +23,25 @@ in "C header" `{
 
 in "C" `{
 
-#if defined(__MACH__) && !defined(CLOCK_REALTIME)
+#ifdef __APPLE__
+       #include <TargetConditionals.h>
+       #if defined(TARGET_OS_IPHONE) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
+               // Preserve compatibility with pre-iOS 10 devices where there is no clock_get_time.
+               #undef CLOCK_REALTIME
+       #endif
+#endif
+
+#if (defined(__MACH__) || defined(TARGET_OS_IPHONE)) && !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
 */
 #include <mach/clock.h>
 #include <mach/mach.h>
+#undef CLOCK_REALTIME
+#undef CLOCK_MONOTONIC
 #define CLOCK_REALTIME CALENDAR_CLOCK
 #define CLOCK_MONOTONIC SYSTEM_CLOCK
-void clock_gettime(clock_t clock_name, struct timespec *ts) {
+void nit_clock_gettime(clock_t clock_name, struct timespec *ts) {
        clock_serv_t cclock;
        mach_timespec_t mts;
        host_get_clock_service(mach_host_self(), clock_name, &cclock);
@@ -40,11 +50,13 @@ void clock_gettime(clock_t clock_name, struct timespec *ts) {
        ts->tv_sec = mts.tv_sec;
        ts->tv_nsec = mts.tv_nsec;
 }
+#else
+       #define nit_clock_gettime clock_gettime
 #endif
 `}
 
 # 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 ) `{
@@ -56,7 +68,7 @@ extern class Timespec `{struct timespec*`}
        # Init a new Timespec from now.
        new monotonic_now `{
                struct timespec* tv = malloc( sizeof(struct timespec) );
-               clock_gettime( CLOCK_MONOTONIC, tv );
+               nit_clock_gettime( CLOCK_MONOTONIC, tv );
                return tv;
        `}
 
@@ -70,7 +82,7 @@ extern class Timespec `{struct timespec*`}
 
        # Update `self` clock.
        fun update `{
-               clock_gettime(CLOCK_MONOTONIC, self);
+               nit_clock_gettime(CLOCK_MONOTONIC, self);
        `}
 
        # Subtract `other` from `self`
@@ -86,6 +98,18 @@ extern class Timespec `{struct timespec*`}
                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 `{
                return self->tv_sec;
@@ -143,15 +167,17 @@ class Clock
        # TODO use less mallocs
 
        # Time at creation
-       protected var time_at_beginning = new Timespec.monotonic_now
+       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) );
-#if defined(__MACH__) && !defined(CLOCK_REALTIME)
+#if (defined(__MACH__) || defined(TARGET_OS_IPHONE)) && !defined(CLOCK_REALTIME)
                clock_serv_t cclock;
                int nsecs;
                mach_msg_type_number_t count;
@@ -169,40 +195,40 @@ class Clock
        # Seconds since the creation of this instance
        fun total: Float
        do
-               var now = new Timespec.monotonic_now
-               var diff = now - time_at_beginning
-               var r = diff.to_f
-               diff.free
-               now.free
-               return r
+               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 nt = new Timespec.monotonic_now
-               var dt = nt - time_at_last_lapse
-               var r = dt.to_f
-               dt.free
-               time_at_last_lapse.free
-               time_at_last_lapse = nt
+               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
-               var nt = new Timespec.monotonic_now
-               var dt = nt - time_at_last_lapse
-               var r = dt.to_f
-               nt.free
-               dt.free
-               return r
+               var now = temp
+               now.update
+               now.minus(now, time_at_last_lapse)
+               return now.to_f
        end
 
        redef fun finalize_once
        do
                time_at_beginning.free
                time_at_last_lapse.free
+               temp.free
        end
 end