implement basic operations over class Time
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Mon, 29 Jan 2018 13:02:18 +0000 (14:02 +0100)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Wed, 27 Mar 2019 09:31:38 +0000 (10:31 +0100)
This adds members and overloads for

    * addition, subtraction / difference, multiplication by
      time_t,
    * comparison, less-than / greater-than, equality,
    * trivial formatting (needed in boost unittest)

operations involving *class Time* objects.

src/timefunc.cpp
src/timefunc.hxx
test/test_timefunc.cpp

index cab9469..30df7a6 100644 (file)
@@ -779,7 +779,7 @@ namespace clock {
 
         static inline clockid_t
         clockid_of_flags (const enum type::id      id,
-                          const enum type::variant var)
+                          const enum type::variant var) NOEXCEPT
         {
             clockid_t cid = CLOCK_MONOTONIC_COARSE;
 
@@ -834,11 +834,10 @@ namespace clock {
 
         static const struct timespec zero_time = { 0, 0 };
 
-#       define NANO (1000L * 1000 * 1000)
-
     } /* [namespace] */
 
-    Time::Time (const enum type::id id, const enum type::variant var)
+    Time::Time (const enum type::id id,
+                const enum type::variant var) NOEXCEPT
         : value   (zero_time)
         , id      (id)
         , variant (var)
@@ -846,19 +845,41 @@ namespace clock {
     { }
 
     int64_t
-    Time::as_nanosec (void)
-    { return int64_t (this->value.tv_sec) * NANO + this->value.tv_nsec; }
+    Time::as_nanosec (void) const NOEXCEPT
+    {
+        return int64_t (this->value.tv_sec) * TIME_CONST_FACTOR_NANO
+             + this->value.tv_nsec;
+    }
 
     long
-    Time::as_nanosec_L (void) /* likely to overflow */
+    Time::as_nanosec_L (void) const NOEXCEPT /* likely to overflow */
     { return static_cast<long>(this->as_nanosec ()); }
 
+    Time &
+    Time::operator= (Time t2) NOEXCEPT
+    {
+        this->swap (t2);
+
+        return *this;
+    }
+
+    Time &
+    Time::operator= (struct timespec ts) NOEXCEPT
+    {
+        std::swap (this->value, ts);
+        this->id      = clock::type::mono;
+        this->variant = clock::type::dflt;
+        this->err     = 0;
+
+        return *this;
+    }
+
     void
-    Time::unset (void)
+    Time::unset (void) NOEXCEPT
     { this->value = zero_time; }
 
     bool
-    Time::set (void)
+    Time::set (void) NOEXCEPT
     {
         struct timespec now;
 
@@ -877,10 +898,43 @@ namespace clock {
         return true;
     }
 
+    Time &
+    Time::add (const time_t sec, const long nsec) NOEXCEPT
+    {
+        this->value.tv_sec  += sec;
+        this->value.tv_nsec += nsec;
+
+        this->carry_nsec ();
+
+        return *this;
+    }
+
+    Time &
+    Time::subtract (const time_t sec, const long nsec) NOEXCEPT
+    {
+        this->value.tv_sec  -= sec;
+        this->value.tv_nsec -= nsec;
+
+        this->carry_nsec ();
+
+        return *this;
+    }
+
+    Time &
+    Time::scale (const time_t factor) NOEXCEPT
+    {
+        this->value.tv_sec  *= factor;
+        this->value.tv_nsec *= factor;
+
+        this->carry_nsec ();
+
+        return *this;
+    }
+
     boost::optional<Time>
-    now (const enum type::id id, const enum type::variant var)
+    now (const enum type::id id, const enum type::variant var) NOEXCEPT
     {
-        Time ret (id);
+        Time ret (id, var);
 
         if (!ret.set ()) {
             return boost::none;
@@ -889,6 +943,32 @@ namespace clock {
         return ret;
     }
 
+    Time
+    zero (const enum type::id id, const enum type::variant var) NOEXCEPT
+    { return Time (id, var); }
+
+    int
+    compare (const Time &t1, const Time &t2) NOEXCEPT
+    {
+        if (t1.value.tv_sec < t2.value.tv_sec) {
+            return -1;
+        }
+
+        if (t1.value.tv_sec > t2.value.tv_sec) {
+            return 1;
+        }
+
+        if (t1.value.tv_nsec < t2.value.tv_nsec) {
+            return -1;
+        }
+
+        if (t1.value.tv_nsec > t2.value.tv_nsec) {
+            return 1;
+        }
+
+        return 0;
+    }
+
 } /* [namespace clock] */
 
 } /* [namespace I2n] */
index eec351b..09e4e5c 100644 (file)
@@ -26,14 +26,27 @@ on this file might be covered by the GNU General Public License.
 #ifndef __TIMEFUNC_HXX
 #define __TIMEFUNC_HXX
 
+#include <climits>
 #include <errno.h>
-#include <string>
 #include <list>
+#include <string>
 
 #include <boost/optional.hpp>
 
 #include <week.hpp>
 
+#include "stringfunc.hxx"
+
+#if __cplusplus >= 201103
+# define CONSTEXPR constexpr
+# define NOEXCEPT  noexcept
+#else
+# define CONSTEXPR
+# define NOEXCEPT
+#endif
+
+#define TIME_CONST_FACTOR_NANO (1000L * 1000 * 1000)
+
 double prec_time(void);
 
 time_t date_to_seconds(const std::string &date);
@@ -220,6 +233,19 @@ namespace I2n {
 
 namespace clock {
 
+    namespace {
+
+        /* helper for ctor initializer list; we still lack aggregate initializers */
+        struct timespec
+        timespec_of_parts (const time_t sec, const long nsec)
+        {
+            struct timespec ret = { sec, nsec};
+
+            return ret;
+        }
+
+    } /* [namespace] */
+
     namespace type {
         /*
          * represent the clock id options from clock_gettime(2) as
@@ -251,58 +277,274 @@ namespace clock {
     class Time {
 
         private:
-            struct timespec           value;
+            struct timespec     value;
 
         public:
-            const enum type::id       id;
-            const enum type::variant  variant;
-            int                       err;
+            enum type::id       id;
+            enum type::variant  variant;
+            int                 err;
+
+        private:
+            /*
+             * Handle decimal part (nanosecond) overflow; this is performed
+             * after arithmetic operations and whenever we there is the
+             * possibility of unsanitized input for example in constructors
+             * from other types and suchlike.
+             *
+             * POSIX defines the ns part as *long*. Technically, that means
+             * that on machines where *sizeof long* equals *sizeof int*, it can
+             * represent only up to arund 2.1 seconds. In this range, the loop
+             * version is most likely faster than division. However, since in
+             * practice *long* is 8 bytes just about anywhere, we have to
+             * handle greater dividends first.
+             */
+            inline void
+            carry_nsec (void)
+            {
+#           if LONG_BIT > 32
+                if (   this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO
+                    || this->value.tv_nsec >  3L * TIME_CONST_FACTOR_NANO)
+                {
+                    const long sec = this->value.tv_nsec / TIME_CONST_FACTOR_NANO;
+                    this->value.tv_nsec -= sec * TIME_CONST_FACTOR_NANO;
+                    this->value.tv_sec  += sec;
+                }
+#           endif /* [LONG_BIT > 32] */
+                while (this->value.tv_nsec >= TIME_CONST_FACTOR_NANO) {
+                    this->value.tv_sec  += 1;
+                    this->value.tv_nsec -= TIME_CONST_FACTOR_NANO;
+                }
+
+                while (this->value.tv_nsec < 0) {
+                    this->value.tv_sec  -= 1;
+                    this->value.tv_nsec += TIME_CONST_FACTOR_NANO;
+                }
+            }
 
         /* ctors *************************************************************/
         public:
 
             Time (const enum type::id      id  = type::mono,
-                  const enum type::variant var = type::dflt);
-
-        /* value access ******************************************************/
+                  const enum type::variant var = type::dflt) NOEXCEPT;
+
+            inline Time (const Time &t) NOEXCEPT
+                : value   (t.value)
+                , id      (t.id)
+                , variant (t.variant)
+                , err     (t.err)
+            { }
+
+            inline Time (const time_t sec,
+                         const long               nsec = 0,
+                         const enum type::id      id   = type::mono,
+                         const enum type::variant var  = type::dflt,
+                         const int                err  = 0) NOEXCEPT
+                : value   (timespec_of_parts (sec, nsec))
+                , id      (id)
+                , variant (var)
+                , err     (err)
+            { this->carry_nsec (); }
+
+        /* value read access *************************************************/
         public:
 
-            inline const struct timespec &get_time (void)
+            inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
             { return this->value; }
 
-            inline const time_t &get_sec (void)
-            { return this->value.tv_sec; };
+            inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
+            { return this->value.tv_sec; }
 
-            inline const long &get_nsec (void)
+            inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT
             { return this->value.tv_nsec; }
 
-            int64_t as_nanosec (void);
+            int64_t as_nanosec (void) const NOEXCEPT;
 
-            long as_nanosec_L (void);
+            long as_nanosec_L (void) const NOEXCEPT;
 
-        /* setting time ******************************************************/
+        /* value write access ************************************************/
         public:
 
             inline void
-            set (const struct timespec &ts)
-            { this->value = ts; };
+            swap (Time &t) NOEXCEPT
+            {
+                std::swap (this->value  , t.value  );
+                std::swap (this->id     , t.id     );
+                std::swap (this->variant, t.variant);
+                std::swap (this->err    , t.err    );
+            }
+
+            Time &operator= (Time t) NOEXCEPT;
+
+            Time &operator= (struct timespec ts) NOEXCEPT;
 
             inline void
-            set (const time_t sec, const long nsec)
+            set (const struct timespec &ts) NOEXCEPT
+            {
+                this->value = ts;
+                this->carry_nsec ();
+            }
+
+            inline void
+            set (const time_t sec,
+                 const long   nsec,
+                 const enum type::id      id  = type::mono,
+                 const enum type::variant var = type::dflt) NOEXCEPT
             {
                 this->value.tv_sec  = sec;
                 this->value.tv_nsec = nsec;
-            };
+                this->id      = id;
+                this->variant = var;
+
+                this->carry_nsec ();
+            }
 
-            bool set (void);
+            bool set (void) NOEXCEPT;
+
+            void unset (void) NOEXCEPT;
+
+        /* arithmetic ********************************************************/
+        public:
 
-            void unset (void);
+            Time &add (const time_t sec, const long nsec) NOEXCEPT;
+
+            Time &subtract (const time_t sec, const long nsec) NOEXCEPT;
+
+            inline Time &add (const Time &t2) NOEXCEPT
+            { return this->add (t2.value.tv_sec, t2.value.tv_nsec); }
+
+            inline Time &add (const time_t t2) NOEXCEPT
+            { return this->add (t2, 0L); };
+
+            inline Time &subtract (const Time &t2) NOEXCEPT
+            { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); }
+
+            inline Time &subtract (const time_t t2) NOEXCEPT
+            { return this->subtract (t2, 0L); };
+
+            Time &scale (const time_t factor) NOEXCEPT;
+
+            friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
+
+            inline Time
+            difference (const Time &t) NOEXCEPT
+            { return (*this < t) ? t - *this : *this - t; }
+
+        /* overloads *********************************************************/
+        public:
+
+            inline Time
+            operator+ (const Time &t2) const NOEXCEPT
+            { return Time (*this).add (t2); }
+
+            inline Time
+            operator+ (const time_t t2) const NOEXCEPT
+            { return Time (*this).add (t2); }
+
+            inline Time &
+            operator+= (const Time &t2) NOEXCEPT
+            { return this->add (t2); }
+
+            inline Time &
+            operator+= (const time_t t2) NOEXCEPT
+            { return this->add (t2); }
+
+            inline Time
+            operator- (const Time &t2) const NOEXCEPT
+            { return Time (*this).subtract (t2); }
+
+            inline Time
+            operator- (const time_t t2) const NOEXCEPT
+            { return Time (*this).subtract (t2); }
+
+            inline Time &
+            operator-= (const Time &t2) NOEXCEPT
+            { return this->subtract (t2); }
+
+            inline Time &
+            operator-= (const time_t t2) NOEXCEPT
+            { return this->subtract (t2); }
+
+            inline Time
+            operator* (const time_t factor) const NOEXCEPT
+            { return Time (*this).scale (factor); }
+
+            inline Time &
+            operator*= (const time_t factor) NOEXCEPT
+            { return this->scale (factor); }
+
+            friend CONSTEXPR bool
+            operator== (const Time &t1, const Time &t2) NOEXCEPT;
+
+            friend CONSTEXPR bool
+            operator< (const Time &t1, const Time &t2) NOEXCEPT;
+
+            friend CONSTEXPR bool
+            operator> (const Time &t1, const Time &t2) NOEXCEPT;
+
+            friend std::ostream &
+            operator<< (std::ostream &os, const Time &t);
 
     }; /* [class Time] */
 
+    inline Time 
+    operator+ (const time_t t1, const Time &t2) NOEXCEPT
+    { return Time (t1) + t2; }
+
+    inline Time 
+    operator- (const time_t t1, const Time &t2) NOEXCEPT
+    { return Time (t1) - t2; }
+
+    int compare (const Time &t1, const Time &t2) NOEXCEPT;
+
+    /*
+     * comparison for equality also considers the clock type;
+     */
+    inline CONSTEXPR bool
+    operator== (const Time &t1, const Time &t2) NOEXCEPT
+    {
+        return t1.id == t2.id && t1.variant == t2.variant
+            && t1.value.tv_sec  == t2.value.tv_sec
+            && t1.value.tv_nsec == t2.value.tv_nsec
+            ;
+    }
+
+    /* these ignore the *id* and *variant* fields */
+    inline CONSTEXPR bool
+    operator< (const Time &t1, const Time &t2) NOEXCEPT
+    {
+        return t1.value.tv_sec < t2.value.tv_sec
+            || (   t1.value.tv_sec  == t2.value.tv_sec
+                && t1.value.tv_nsec <  t2.value.tv_nsec)
+            ;
+    }
+
+    /* these ignore the *id* and *variant* fields */
+    inline CONSTEXPR bool
+    operator> (const Time &t1, const Time &t2) NOEXCEPT
+    {
+        return t1.value.tv_sec > t2.value.tv_sec
+            || (   t1.value.tv_sec  == t2.value.tv_sec
+                && t1.value.tv_nsec >  t2.value.tv_nsec)
+            ;
+    }
+
+    inline std::ostream &
+    operator<< (std::ostream &os, const Time &t)
+    {
+        os << I2n::to_string (t.value.tv_sec)  << "ms, "
+           << I2n::to_string (t.value.tv_nsec) << "ns"
+           ;
+
+        return os;
+    }
+
     boost::optional<Time>
     now (const enum type::id      id  = type::mono,
-         const enum type::variant var = type::dflt);
+         const enum type::variant var = type::dflt) NOEXCEPT;
+    Time
+    zero (const enum type::id      id  = type::mono,
+          const enum type::variant var = type::dflt) NOEXCEPT;
 
 } /* [namespace clock] */
 
index c973a4f..6752042 100644 (file)
@@ -497,6 +497,430 @@ BOOST_AUTO_TEST_SUITE(Clock)
         BOOST_CHECK_EQUAL(t->err, 0);
     }
 
-BOOST_AUTO_TEST_SUITE_END()
+    BOOST_AUTO_TEST_CASE(initializer_zero)
+    {
+        I2n::clock::Time stundenull = I2n::clock::zero ();
+
+        BOOST_CHECK_EQUAL(stundenull.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(stundenull.get_nsec (), 0);
+        BOOST_CHECK_EQUAL(stundenull.err, 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_set_now)
+    {
+        I2n::clock::Time t;
+
+        BOOST_CHECK(t.set ());
+
+        BOOST_CHECK_NE(t.get_sec (), 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_set_value)
+    {
+        I2n::clock::Time t;
+
+        t.set (42, 42);
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 42);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 42);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_set_value_type)
+    {
+        I2n::clock::Time t;
+
+        t.set (42, 42, I2n::clock::type::real, I2n::clock::type::exact);
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 42);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 42);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_add_parts)
+    {
+        I2n::clock::Time t;
+
+        t.set (42, 42);
+        t.add (2187, 2187);
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 2229);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 2229);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_sub_parts)
+    {
+        I2n::clock::Time t;
+
+        t.set (2, 0L);
+        t.subtract (1, 1L);
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 999999999);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_sub_Time)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (42, 42L);
+        t2.set (42,  0L);
+
+        t1.subtract (t2);
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (),  0);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 42L);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_diff)
+    {
+        static const time_t five = 5 * 365 * 24 * 3600;
+
+        I2n::clock::Time t1 (42, 1337);
+        I2n::clock::Time t2 = t1 + five;;
+        I2n::clock::Time t3 = t1 - five;;
+
+        BOOST_CHECK_EQUAL(t2, I2n::clock::Time ((time_t)42 + five, 1337));
+        BOOST_CHECK_EQUAL(t3, I2n::clock::Time ((time_t)42 - five, 1337));
+        BOOST_CHECK_EQUAL(t1.difference (t3), t3.difference (t1));
+        BOOST_CHECK_EQUAL(t3.difference (t3), t3.difference (t3));
+    }
+
+    BOOST_AUTO_TEST_CASE(op_copyassign)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        BOOST_CHECK(t1.set ());
+
+        t2 = t1;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), t2.get_sec  ());
+        BOOST_CHECK_EQUAL(t1.get_nsec (), t2.get_nsec ());
+    }
+
+    BOOST_AUTO_TEST_CASE(op_equal)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        BOOST_CHECK(t1.set ());
+        t2 = t1;
+
+        BOOST_CHECK_EQUAL(t1, t2);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_add_Time)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+        I2n::clock::Time tsum;
+
+        t1.set (2187, 2187);
+        t2.set (1337, 1337);
+        tsum = t1 + t2;
+
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 3524);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_add_Time_carry)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+        I2n::clock::Time tsum;
+
+        t1.set (2187, 2187);
+        t2.set (1300, 37L * 1000 * 1000 * 1000 + 1337);
+
+        tsum = t1 + t2;
+
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 3524);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_add_time_t)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        time_t           t2 = 1337;
+        I2n::clock::Time tsum;
+
+        tsum = t1 + t2;
+
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_add_time_t_external)
+    {
+        time_t           t1 = 1337;
+        I2n::clock::Time t2 (2187, 2187);
+        I2n::clock::Time tsum;
+
+        tsum = t1 + t2;
+
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_incr_Time)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        I2n::clock::Time t2 (1337, 1337);
+
+        t1 += t2;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 3524);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_incr_time_t)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        time_t           t2 = 1337;
+
+        t1 += t2;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_subtract_Time)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+        I2n::clock::Time tdiff;
+
+        t1.set (2187, 2187);
+        t2.set (1337, 1337);
+        tdiff = t1 - t2;
+
+        BOOST_CHECK_EQUAL(tdiff.get_sec  (), 850);
+        BOOST_CHECK_EQUAL(tdiff.get_nsec (), 850);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_subtract_time_t)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        time_t           t2 = 1337;
+        I2n::clock::Time tdiff;
+
+        tdiff = t1 - t2;
+
+        BOOST_CHECK_EQUAL(tdiff.get_sec  (), 850);
+        BOOST_CHECK_EQUAL(tdiff.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_subtract_time_t_external)
+    {
+        time_t           t1 = 1337;
+        I2n::clock::Time t2 (2187, 2187);
+        I2n::clock::Time tdiff;
+
+        tdiff = t1 - t2;
+
+        BOOST_CHECK_EQUAL(tdiff.get_sec  (), -851);
+        BOOST_CHECK_EQUAL(tdiff.get_nsec (), 999997813);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_decr_Time)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        I2n::clock::Time t2 (1337, 1337);
+
+        t1 -= t2;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 850);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 850);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_decr_time_t)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        time_t           t2 = 1337;
+
+        t1 -= t2;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 850);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_mult_scale)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (1, 1);
+        t2 = t1 * 42;
+
+        BOOST_CHECK_EQUAL(t2.get_sec  (), 42);
+        BOOST_CHECK_EQUAL(t2.get_nsec (), 42);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_mult_mutate)
+    {
+        I2n::clock::Time t1 (  42, 42);
+        I2n::clock::Time t2 (1337,  0);
+
+        t1 *=   2;
+        t2 *= -10;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (),     84);
+        BOOST_CHECK_EQUAL(t1.get_nsec (),     84);
+        BOOST_CHECK_EQUAL(t2.get_sec  (), -13370);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_mult_scale_carry)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (1, 500 * 1000 * 1000);
+        t2 = t1 * 3;
+
+        BOOST_CHECK_EQUAL(t2.get_sec  (),  4);
+        BOOST_CHECK_EQUAL(t2.get_nsec (),  500 * 1000 * 1000);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_equals)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (50, 50);
+        t2.set (50, 50);
+
+        BOOST_CHECK_EQUAL(t1, t2);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_equal)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (42, 42);
+        t2.set (42, 42);
+
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_equal_type)
+    {
+        I2n::clock::Time t1 (42, 42, I2n::clock::type::real);
+        I2n::clock::Time t2 (42, 42, I2n::clock::type::cpu);
+        I2n::clock::Time t3 (42,  0, I2n::clock::type::real);
+        I2n::clock::Time t4 (42, 42, I2n::clock::type::real);
+
+        BOOST_CHECK_NE(t1, t2);
+        BOOST_CHECK_NE(t1, t3);
+        BOOST_CHECK_EQUAL(t1, t4);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_ne_sec)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (  42, 42);
+        t2.set (1337, 42);
+
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), -1);
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1),  1);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_ne_nsec)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (42,   42);
+        t2.set (42, 1337);
+
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), -1);
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1),  1);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_ne_both)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (42, 2187);
+        t2.set (23, 1337);
+
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2),  1);
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1), -1);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_ineq_sec)
+    {
+        I2n::clock::Time t1 (1337);
+        I2n::clock::Time t2 (2187);
+
+        BOOST_CHECK_LT(t1, t2);
+        BOOST_CHECK_GT(t2, t1);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_ineq_nsec)
+    {
+        I2n::clock::Time t1 (1337, 23);
+        I2n::clock::Time t2 (1337, 42);
+
+        BOOST_CHECK_LT(t1, t2);
+        BOOST_CHECK_GT(t2, t1);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_ineq_both)
+    {
+        I2n::clock::Time t1 (2187, 23);
+        I2n::clock::Time t2 (1337, 42);
+
+        BOOST_CHECK_LT(t2, t1);
+        BOOST_CHECK_GT(t1, t2);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_eq_time_t)
+    {
+        boost::optional<I2n::clock::Time> t1  = I2n::clock::now ();
+        const time_t                      t2  = time (NULL); /* race here */
+
+        *t1 -= (time_t)42;
+
+        BOOST_CHECK_NE(*t1,  t2);
+        BOOST_CHECK_LT(*t1,  t2);
+        BOOST_CHECK_GT( t2, *t1);
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_list)
+    {
+        std::list<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::zero ());
+        ts.push_back (I2n::clock::zero ());
+
+        BOOST_CHECK_EQUAL(ts.size (), 2);
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_vec)
+    {
+        std::vector<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::zero ());
+        ts.push_back (I2n::clock::zero ());
+
+        BOOST_CHECK_EQUAL(ts.size (), 2);
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_set)
+    {
+        std::set<I2n::clock::Time> ts;
+
+        ts.insert (I2n::clock::zero ());
+        ts.insert (I2n::clock::Time (42, 2187));
+        ts.insert (I2n::clock::zero ());
+
+        BOOST_CHECK_EQUAL(ts.size (), 2);
+    }
+
+BOOST_AUTO_TEST_SUITE_END() /* [Clock] */
 
 BOOST_AUTO_TEST_SUITE_END()