151 lines
5.7 KiB
C++
151 lines
5.7 KiB
C++
#ifndef TIME_STAMPED_EVENT_H
|
|
#define TIME_STAMPED_EVENT_H
|
|
|
|
/** \file
|
|
Class definition file.
|
|
|
|
\copyright
|
|
Copyright (C) 2002, 2003 Oliver Schoenborn
|
|
|
|
This software is provided 'as-is', without
|
|
any express or implied warranty. In no event
|
|
will the authors be held liable for any
|
|
damages arising from the use of this
|
|
software.
|
|
|
|
You can redistribute it and/or modify it
|
|
under the terms found in the LICENSE file that
|
|
is included in the library distribution.
|
|
\endcopyright
|
|
*/
|
|
|
|
/**
|
|
Example of time stamper. It requires only one typedef (DataType), and one
|
|
member function (getTimeStamp). The extra member function, used
|
|
for ordering two time stamps, is only necessary if your code
|
|
does a call to the ordering functions of TimeStampedEvent.
|
|
\note
|
|
- The member functions need not be static and/or inline; this is
|
|
determined by your implementation of time-stamper;
|
|
- The return type and arguments to leftOlder() would be "const DataType&"
|
|
instead of "DataType", if DataType were a class rather than a
|
|
fundamental type.
|
|
*/
|
|
template <typename IntType>
|
|
struct TimeStamper
|
|
{
|
|
/// The type of data holding the timestamp
|
|
typedef IntType DataType;
|
|
static IntType getTimeStamp();
|
|
/// Return true only if \a left is strictly older than \a right
|
|
inline static bool leftOlder(IntType left, IntType right) {return left < right;}
|
|
};
|
|
|
|
/**
|
|
Get the time stamp. This is where we define how to
|
|
implement time stamping. Here, we simply increment a
|
|
counter.
|
|
*/
|
|
template <typename IntType>
|
|
IntType
|
|
TimeStamper<IntType>::getTimeStamp()
|
|
{
|
|
static IntType stamp = 0;
|
|
return ++ stamp;
|
|
}
|
|
|
|
/**
|
|
Default time stamper just uses a counter of type
|
|
unsigned long int. It has the benefit of
|
|
- complete portability
|
|
- speed
|
|
- garantee of unique stamp for every event
|
|
|
|
Time stampers that rely on system clocks typically
|
|
suffer in all three areas: the call is relatively costly,
|
|
several events may end up with the same time stamp,
|
|
the system clock may provide different resolutions on
|
|
different systems, and may not be accessible with the
|
|
same system calls.
|
|
|
|
The only disadvantage is that the time stamp will cycle every 2^N
|
|
events, where N is the number of bits for the long int data type.
|
|
Consequences:
|
|
- 32-bit longs:
|
|
- over 4 billion events before rollover;
|
|
- one million time-stamped events/second implies a rollover
|
|
every hour;
|
|
- therefore a program generating 1 million \em time-stamped
|
|
events/sec (not all event types need be time-stamped in your
|
|
program) would have to run \em uninterrupted for more than
|
|
one hour in order to see the rollover;
|
|
- 64-bit longs:
|
|
- 20 billion billion events (2x10^19) before rollover;
|
|
- one billion time-stamped events/second implies a rollover
|
|
every 700 years;
|
|
- therefore a program generating 1 billion \em time-stamped
|
|
events/sec would have to run \em uninterrupted for more than
|
|
700 years in order to see the rollover.
|
|
|
|
If this limitation is not acceptable, you have two choices:
|
|
- Create your own integer-based time-stamper, via a new class or a
|
|
specialization of TimeStamper<IntType>, with an integer type that
|
|
garantees enough bits (e.g., certain libraries provide a class
|
|
where the number of bits is specified via a template parameter,
|
|
e.g. Int<128>, or perhaps the Standard will eventually supply
|
|
int64 and int128);
|
|
- Create your own generic time-stamper via a new class, and
|
|
define the appropriate members (DataType, getTimeStamp(), and
|
|
leftOlder()).
|
|
*/
|
|
typedef TimeStamper<unsigned long int> DefaultTimeStamper;
|
|
|
|
/**
|
|
A simple basic event class that provides a time stamp for creation
|
|
of the event. This class must be subclassed into a specific event
|
|
(it can only be instantiated via a derived class since the
|
|
constructor and destructor are protected), where data relevant to
|
|
the event is stored.
|
|
|
|
The time stamp is the number of seconds since the first TimeStampedEvent
|
|
was instantiated. This strategy ensures that the reference is always
|
|
well defined and independent of compiler etc, is a relatively small
|
|
number, and can be repeated.
|
|
|
|
\author Oliver Schoenborn
|
|
\since Sept 2002
|
|
*/
|
|
template <class Stamper = DefaultTimeStamper>
|
|
class TimeStampedEvent
|
|
{
|
|
public:
|
|
/** Get creation time of this event. This is given as
|
|
the number of seconds (or fraction thereof) since the
|
|
first instantiation of a TimeStampedEvent object.
|
|
\return seconds since first TimeStampedEvent object created
|
|
*/
|
|
const typename Stamper::DataType& getTimeStamp() const {return _timeStamp;}
|
|
|
|
/// Return true only if *this has a time stamp older than that of \a tse
|
|
bool isOlderThan(const TimeStampedEvent& tse) const
|
|
{
|
|
return Stamper::leftOlder(_timeStamp, tse._timeStamp);
|
|
}
|
|
|
|
/// Return true only if *this has a time stamp older than that of \a tse
|
|
bool operator<(const TimeStampedEvent& tse) const {return isOlderThan(tse);}
|
|
|
|
protected:
|
|
/// Create a TimeStampedEvent object.
|
|
TimeStampedEvent(): _timeStamp( Stamper::getTimeStamp() ) {}
|
|
/// Protected destructor will prevent user from calling delete
|
|
/// on a pointer to a TimeStampedEvent.
|
|
~TimeStampedEvent() {}
|
|
|
|
private: // data
|
|
/// Creation time of current instance of event
|
|
const typename Stamper::DataType _timeStamp;
|
|
};
|
|
|
|
#endif // TIME_STAMPED_EVENT_H
|