#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);
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
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] */