// Written by Curtis Olson, started December 1998.
//
-// Copyright (C) 1998 Curtis L. Olson - curt@flightgear.org
+// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#define _TIMESTAMP_HXX
-#ifndef __cplusplus
+#ifndef __cplusplus
# error This library requires C++
-#endif
-
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef HAVE_WINDOWS_H
-# include <windows.h>
#endif
+#include <iosfwd>
+#include <iomanip>
+#include <sstream>
#include <simgear/compiler.h>
-
-#ifdef SG_HAVE_STD_INCLUDES
-# include <ctime>
-#else
-# include <time.h>
-#endif
-
-#ifdef HAVE_SYS_TIMEB_H
-# include <sys/timeb.h> // for ftime() and struct timeb
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h> // for gettimeofday()
-#endif
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h> // for get/setitimer, gettimeofday, struct timeval
-#endif
-
-// -dw- want to use metrowerks time.h
-#ifdef macintosh
-# include <time.h>
-# include <timer.h>
-#endif
-
-#ifdef WIN32
-# include <windows.h>
-# if defined( __CYGWIN__ ) || defined( __CYGWIN32__ )
-# define NEAR /* */
-# define FAR /* */
-# endif
-# include <mmsystem.h>
-#endif
-
-// MSVC++ 6.0 kuldge - Need forward declaration of friends.
-class SGTimeStamp;
-SGTimeStamp operator + (const SGTimeStamp& t, const long& m);
-long operator - (const SGTimeStamp& a, const SGTimeStamp& b);
+#include <simgear/math/SGCMath.hxx>
/**
* The SGTimeStamp class allows you to mark and compare time stamps
- * with microsecond accuracy (if your system has support for this
- * level of accuracy.)
+ * with nanosecond accuracy (if your system has support for this
+ * level of accuracy).
*
* The SGTimeStamp is useful for tracking the elapsed time of various
* events in your program. You can also use it to keep constistant
* motion across varying frame rates.
+ *
+ * Note SGTimestamp does not deliver the time of day. The content of this
+ * stamps might be, dependent on the implementation, a time to an arbitrary
+ * base time.
*/
class SGTimeStamp {
+public:
+ typedef long sec_type;
+ typedef int nsec_type;
+
+ /** Default constructor, initialize time to zero. */
+ SGTimeStamp() :
+ _nsec(0),
+ _sec(0)
+ { }
+
+ /** Hmm, might reenable them at some time, but since it is not clear
+ what the input unit of the int is, omit them for now.
+ Use the static constructor functions where it is clear from the method
+ name how the arguments are meant.
+ */
+// SGTimeStamp(sec_type sec)
+// { setTime(sec, 0); }
+// SGTimeStamp(int sec)
+// { setTime(sec, 0); }
+// SGTimeStamp(const double& sec)
+// { setTime(sec); }
+
+ /** Update stored time to current time (seconds and nanoseconds) */
+ void stamp();
-private:
+ /** Set the time from a double value */
+ void setTime(const double& seconds)
+ {
+ sec_type wholeSecs = sec_type(floor(seconds));
+ nsec_type reminder;
+ reminder = nsec_type(floor((seconds - wholeSecs)*(1000*1000*1000)));
+ setTime(wholeSecs, reminder);
+ }
+ /** Set the time from a seconds/nanoseconds pair */
+ void setTime(sec_type sec, nsec_type nsec)
+ {
+ if (0 <= nsec) {
+ _sec = sec + nsec / (1000*1000*1000);
+ _nsec = nsec % (1000*1000*1000);
+ } else {
+ _sec = sec - 1 + nsec / (1000*1000*1000);
+ _nsec = (1000*1000*1000) + nsec % (1000*1000*1000);
+ }
+ }
+
+
+ /** @return the saved seconds of this time stamp */
+ long get_seconds() const { return _sec; }
- long seconds;
- long usec;
+ /** @return the saved microseconds of this time stamp */
+ int get_usec() const { return _nsec/1000; }
-public:
+ /** @return the saved seconds of this time stamp */
+ const sec_type& getSeconds() const
+ { return _sec; }
+ /** @return the saved nanoseconds of this time stamp */
+ const nsec_type& getNanoSeconds() const
+ { return _nsec; }
+
+ /** @return the value of the timestamp in nanoseconds,
+ * use doubles to avoid overflow.
+ * If you need real nanosecond accuracy for time differences, build up a
+ * SGTimeStamp reference time and compare SGTimeStamps directly.
+ */
+ double toNSecs() const
+ { return _nsec + double(_sec)*1000*1000*1000; }
- /** Default constructor */
- SGTimeStamp();
+ /** @return the value of the timestamp in microseconds,
+ * use doubles to avoid overflow.
+ * If you need real nanosecond accuracy for time differences, build up a
+ * SGTimeStamp reference time and compare SGTimeStamps directly.
+ */
+ double toUSecs() const
+ { return 1e-3*_nsec + double(_sec)*1000*1000; }
- /**
- * This creates an instance of the SGTimeStamp object. When
- * calling the constructor you may provide initial seconds an
- * microseconds values.
- * @param s initial seconds value
- * @param m initial microseconds value
+ /** @return the value of the timestamp in milliseconds,
+ * use doubles to avoid overflow.
+ * If you need real nanosecond accuracy for time differences, build up a
+ * SGTimeStamp reference time and compare SGTimeStamps directly.
*/
- SGTimeStamp( const long s, const long m );
- ~SGTimeStamp();
+ double toMSecs() const
+ { return 1e-6*_nsec + double(_sec)*1000; }
- /** Update stored time to current time (seconds and microseconds) */
- void stamp();
+ /** @return the value of the timestamp in seconds,
+ * use doubles to avoid overflow.
+ * If you need real nanosecond accuracy for time differences, build up a
+ * SGTimeStamp reference time and compare SGTimeStamps directly.
+ */
+ double toSecs() const
+ { return 1e-9*_nsec + _sec; }
- /** Compare two time stamps for equality */
- SGTimeStamp& operator = ( const SGTimeStamp& t );
+ /** Inplace addition.
+ */
+ SGTimeStamp& operator+=(const SGTimeStamp& c)
+ {
+ _sec += c._sec;
+ _nsec += c._nsec;
+ if ((1000*1000*1000) <= _nsec) {
+ _nsec -= (1000*1000*1000);
+ _sec += 1;
+ }
+ return *this;
+ }
+
+ /** Inplace subtraction.
+ */
+ SGTimeStamp& operator-=(const SGTimeStamp& c)
+ {
+ _sec -= c._sec;
+ _nsec -= c._nsec;
+ if (_nsec < 0) {
+ _nsec += (1000*1000*1000);
+ _sec -= 1;
+ }
+ return *this;
+ }
/**
- * Increment the saved time by the specified number of microseconds
- * @param t time stamp
- * @param m microseconds increment
- * @return new time stamp
+ * Create SGTimeStamps from input with given units
*/
- friend SGTimeStamp operator + (const SGTimeStamp& t, const long& m);
+ static SGTimeStamp fromSecMSec(sec_type sec, nsec_type msec)
+ { return SGTimeStamp(sec, 1000*1000*msec); }
+ static SGTimeStamp fromSecUSec(sec_type sec, nsec_type usec)
+ { return SGTimeStamp(sec, 1000*usec); }
+ static SGTimeStamp fromSecNSec(sec_type sec, nsec_type nsec)
+ { return SGTimeStamp(sec, nsec); }
+
+ static SGTimeStamp fromSec(int sec)
+ { SGTimeStamp ts; ts.setTime(sec); return ts; }
+ static SGTimeStamp fromSec(const double& sec)
+ { SGTimeStamp ts; ts.setTime(sec); return ts; }
+ static SGTimeStamp fromUSec(nsec_type usec)
+ { return SGTimeStamp(0, 1000*usec); }
+ static SGTimeStamp fromNSec(nsec_type nsec)
+ { return SGTimeStamp(0, nsec); }
/**
- * Subtract two time stamps returning the difference in microseconds.
- * @param a timestamp 1
- * @param b timestame 2
- * @return difference in microseconds
+ * Return a timestamp with the current time.
*/
- friend long operator - (const SGTimeStamp& a, const SGTimeStamp& b);
+ static SGTimeStamp now()
+ { SGTimeStamp ts; ts.stamp(); return ts; }
- /** @return the saved seconds of this time stamp */
- inline long get_seconds() const { return seconds; }
+private:
+ SGTimeStamp(sec_type sec, nsec_type nsec)
+ { setTime(sec, nsec); }
- /** @return the saved microseconds of this time stamp */
- inline long get_usec() const { return usec; }
+ nsec_type _nsec;
+ sec_type _sec;
};
-inline SGTimeStamp::SGTimeStamp() {
-}
-
-inline SGTimeStamp::SGTimeStamp( const long s, const long u ) {
- seconds = s;
- usec = u;
+inline bool
+operator==(const SGTimeStamp& c1, const SGTimeStamp& c2)
+{
+ if (c1.getNanoSeconds() != c2.getNanoSeconds())
+ return false;
+ return c1.getSeconds() == c2.getSeconds();
}
-inline SGTimeStamp::~SGTimeStamp() {
-}
+inline bool
+operator!=(const SGTimeStamp& c1, const SGTimeStamp& c2)
+{ return !operator==(c1, c2); }
-inline SGTimeStamp& SGTimeStamp::operator = (const SGTimeStamp& t)
+inline bool
+operator<(const SGTimeStamp& c1, const SGTimeStamp& c2)
{
- seconds = t.seconds;
- usec = t.usec;
- return *this;
+ if (c1.getSeconds() < c2.getSeconds())
+ return true;
+ if (c1.getSeconds() > c2.getSeconds())
+ return false;
+ return c1.getNanoSeconds() < c2.getNanoSeconds();
}
-inline void SGTimeStamp::stamp() {
-#if defined( WIN32 )
- unsigned int t;
- t = timeGetTime();
- seconds = 0;
- usec = t * 1000;
-#elif defined( HAVE_GETTIMEOFDAY )
- struct timeval current;
- struct timezone tz;
- // sg_timestamp currtime;
- gettimeofday(¤t, &tz);
- seconds = current.tv_sec;
- usec = current.tv_usec;
-#elif defined( HAVE_GETLOCALTIME )
- SYSTEMTIME current;
- GetLocalTime(¤t);
- seconds = current.wSecond;
- usec = current.wMilliseconds * 1000;
-#elif defined( HAVE_FTIME )
- struct timeb current;
- ftime(¤t);
- seconds = current.time;
- usec = current.millitm * 1000;
-// -dw- uses time manager
-#elif defined( macintosh )
- UnsignedWide ms;
- Microseconds(&ms);
-
- seconds = ms.lo / 1000000;
- usec = ms.lo - ( seconds * 1000000 );
-#else
-# error Port me
-#endif
-}
+inline bool
+operator>(const SGTimeStamp& c1, const SGTimeStamp& c2)
+{ return c2 < c1; }
-// increment the time stamp by the number of microseconds (usec)
-inline SGTimeStamp operator + (const SGTimeStamp& t, const long& m) {
-#ifdef WIN32
- return SGTimeStamp( 0, t.usec + m );
-#else
- return SGTimeStamp( t.seconds + ( t.usec + m ) / 1000000,
- ( t.usec + m ) % 1000000 );
-#endif
-}
+inline bool
+operator>=(const SGTimeStamp& c1, const SGTimeStamp& c2)
+{ return !(c1 < c2); }
+
+inline bool
+operator<=(const SGTimeStamp& c1, const SGTimeStamp& c2)
+{ return !(c1 > c2); }
+
+inline SGTimeStamp
+operator+(const SGTimeStamp& c1)
+{ return c1; }
+
+inline SGTimeStamp
+operator-(const SGTimeStamp& c1)
+{ return SGTimeStamp::fromSec(0) -= c1; }
-// difference between time stamps in microseconds (usec)
-inline long operator - (const SGTimeStamp& a, const SGTimeStamp& b)
+inline SGTimeStamp
+operator+(const SGTimeStamp& c1, const SGTimeStamp& c2)
+{ return SGTimeStamp(c1) += c2; }
+
+inline SGTimeStamp
+operator-(const SGTimeStamp& c1, const SGTimeStamp& c2)
+{ return SGTimeStamp(c1) -= c2; }
+
+template<typename char_type, typename traits_type>
+inline
+std::basic_ostream<char_type, traits_type>&
+operator<<(std::basic_ostream<char_type, traits_type>& os, const SGTimeStamp& c)
{
-#if defined( WIN32 )
- return a.usec - b.usec;
-#else
- return 1000000 * (a.seconds - b.seconds) + (a.usec - b.usec);
-#endif
-}
+ std::basic_stringstream<char_type, traits_type> stream;
+
+ SGTimeStamp pos = c;
+ if (c.getSeconds() < 0) {
+ stream << stream.widen('-');
+ pos = - c;
+ }
+ stream << pos.getSeconds() << stream.widen('.');
+ stream << std::setw(9) << std::setfill('0') << pos.getNanoSeconds();
+ return os << stream.str();
+}
#endif // _TIMESTAMP_HXX