Files
unison/src/simulator/time-base.h
Mathieu Lacage 23a588f336 documentation
2010-07-08 10:31:31 +02:00

337 lines
9.4 KiB
C++

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2005,2006 INRIA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef TIME_BASE_H
#define TIME_BASE_H
#include "high-precision.h"
namespace ns3 {
/**
* \ingroup time
* \brief keep track of global simulation resolution
*
* This class is the base class for all time-related classes. It controls
* the resolution of the underlying time value . The default resolution
* is nanoseconds. That is, TimeStep (1).GetNanoSeconds () will return
* 1. It is possible to either increase or decrease the resolution and the
* code tries really hard to make this easy.
*
* If your resolution is X (say, nanoseconds) and if you create Time objects
* with a lower resolution (say, picoseconds), don't expect that this
* code will return 1: PicoSeconds (1).GetPicoSeconds (). It will most
* likely return 0 because the Time object has only 64 bits of fractional
* precision which means that PicoSeconds (1) is stored as a 64-bit aproximation
* of 1/1000 in the Time object. If you later multiply it again by the exact
* value 1000, the result is unlikely to be 1 exactly. It will be close to
* 1 but not exactly 1.
*
* In general, it is thus a really bad idea to try to use time objects of a
* resolution higher than the global resolution controlled through
* TimeBase::SetResolution. If you do need to use picoseconds, it's thus best
* to switch the global resolution to picoseconds to avoid nasty surprises.
*
* Another important issue to keep in mind is that if you increase the
* global resolution, you also implicitely decrease the range of your simulation.
* i.e., the global simulation time is stored in a 64 bit integer whose interpretation
* will depend on the global resolution so, 2^64 picoseconds which is the maximum
* duration of your simulation if the global resolution is picoseconds
* is smaller than 2^64 nanoseconds which is the maximum duration of your simulation
* if the global resolution is nanoseconds.
*
* Finally, don't even think about ever changing the global resolution after
* creating Time objects: all Time objects created before the call to SetResolution
* will contain values which are not updated to the new resolution. In practice,
* the default value for the attributes of many models is indeed calculated
* before the main function of the main program enters. Because of this, if you
* use one of these models (and it's likely), it's going to be hard to change
* the global simulation resolution in a way which gives reasonable results. This
* issue has been filed as bug 954 in the ns-3 bugzilla installation.
*/
class TimeBase
{
public:
/**
* The unit to use to interpret a number representing time
*/
enum Unit
{
S = 0,
MS = 1,
US = 2,
NS = 3,
PS = 4,
FS = 5,
LAST = 6
};
/**
* \param resolution the new resolution to use
*
* Change the global resolution used to convert all
* user-provided time values in Time objects and Time objects
* in user-expected time units.
*/
static void SetResolution (enum Unit resolution);
/**
* \returns the current global resolution.
*/
static enum Unit GetResolution (void);
/**
* \param value to convert into a Time object
* \param timeUnit the unit of the value to convert
* \return a new Time object
*
* This method interprets the input value according to the input
* unit and constructs a matching Time object.
*
* \sa FromDouble, ToDouble, ToInteger
*/
inline static TimeBase FromInteger (uint64_t value, enum Unit timeUnit);
/**
* \param value to convert into a Time object
* \param timeUnit the unit of the value to convert
* \return a new Time object
*
* \sa FromInteger, ToInteger, ToDouble
*/
inline static TimeBase FromDouble (double value, enum Unit timeUnit);
/**
* \param time a Time object
* \param timeUnit the unit of the value to return
*
* Convert the input time into an integer value according to the requested
* time unit.
*/
inline static uint64_t ToInteger (const TimeBase &time, enum Unit timeUnit);
/**
* \param time a Time object
* \param timeUnit the unit of the value to return
*
* Convert the input time into a floating point value according to the requested
* time unit.
*/
inline static double ToDouble (const TimeBase &time, enum Unit timeUnit);
inline TimeBase ();
inline TimeBase (const TimeBase &o);
inline TimeBase operator = (const TimeBase &o);
inline TimeBase (const HighPrecision &data);
/**
* \return true if the time is zero, false otherwise.
*/
inline bool IsZero (void) const;
/**
* \return true if the time is negative or zero, false otherwise.
*/
inline bool IsNegative (void) const;
/**
* \return true if the time is positive or zero, false otherwise.
*/
inline bool IsPositive (void) const;
/**
* \return true if the time is strictly negative, false otherwise.
*/
inline bool IsStrictlyNegative (void) const;
/**
* \return true if the time is strictly positive, false otherwise.
*/
inline bool IsStrictlyPositive (void) const;
/**
* This is really an internal method exported for the needs of
* the implementation. Please, Do not try to use this method, ever.
*
* \return the ns3::HighPrecision object which holds the value
* stored in this instance of Time type.
*/
inline HighPrecision const &GetHighPrecision (void) const;
inline HighPrecision * PeekHighPrecision (void);
protected:
HighPrecision m_data;
private:
struct Information
{
bool toMul;
bool fromMul;
uint64_t factor;
HighPrecision timeTo;
HighPrecision timeFrom;
};
struct Resolution
{
struct Information info[LAST];
enum TimeBase::Unit unit;
};
inline static struct Resolution *PeekResolution (void);
inline static struct Information *PeekInformation (enum Unit timeUnit);
static struct Resolution GetNsResolution (void);
static void SetResolution (enum Unit unit, struct Resolution *resolution);
inline static TimeBase From (HighPrecision tmp, enum Unit timeUnit);
inline static HighPrecision To (const TimeBase &time, enum Unit timeUnit);
};
} // namespace ns3
namespace ns3 {
TimeBase::TimeBase ()
: m_data ()
{
}
TimeBase::TimeBase (const TimeBase &o)
: m_data (o.m_data)
{
}
TimeBase TimeBase::operator = (const TimeBase &o)
{
m_data = o.m_data;
return *this;
}
TimeBase::TimeBase (const HighPrecision &data)
: m_data (data)
{
}
HighPrecision const &
TimeBase::GetHighPrecision (void) const
{
return m_data;
}
HighPrecision *
TimeBase::PeekHighPrecision (void)
{
return &m_data;
}
bool
TimeBase::IsZero (void) const
{
return m_data.Compare (HighPrecision::Zero ()) == 0;
}
bool
TimeBase::IsNegative (void) const
{
return m_data.Compare (HighPrecision::Zero ()) <= 0;
}
bool
TimeBase::IsPositive (void) const
{
return m_data.Compare (HighPrecision::Zero ()) >= 0;
}
bool
TimeBase::IsStrictlyNegative (void) const
{
return m_data.Compare (HighPrecision::Zero ()) < 0;
}
bool
TimeBase::IsStrictlyPositive (void) const
{
return m_data.Compare (HighPrecision::Zero ()) > 0;
}
struct TimeBase::Resolution *
TimeBase::PeekResolution (void)
{
static struct TimeBase::Resolution resolution = GetNsResolution ();
return &resolution;
}
struct TimeBase::Information *
TimeBase::PeekInformation (enum Unit timeUnit)
{
return &(PeekResolution ()->info[timeUnit]);
}
TimeBase
TimeBase::From (HighPrecision tmp, enum Unit timeUnit)
{
struct Information *info = PeekInformation (timeUnit);
if (info->fromMul)
{
tmp.Mul (info->timeFrom);
}
else
{
tmp.MulByInvert (info->timeFrom);
}
return TimeBase (tmp);
}
HighPrecision
TimeBase::To (const TimeBase &time, enum Unit timeUnit)
{
struct Information *info = PeekInformation (timeUnit);
HighPrecision tmp = time.GetHighPrecision ();
if (info->toMul)
{
tmp.Mul (info->timeTo);
}
else
{
tmp.MulByInvert (info->timeTo);
}
return tmp;
}
TimeBase
TimeBase::FromInteger (uint64_t value, enum Unit timeUnit)
{
struct Information *info = PeekInformation (timeUnit);
if (info->fromMul)
{
value *= info->factor;
return TimeBase (HighPrecision (value, false));
}
return From (HighPrecision (value, false), timeUnit);
}
TimeBase
TimeBase::FromDouble (double value, enum Unit timeUnit)
{
return From (HighPrecision (value), timeUnit);
}
uint64_t
TimeBase::ToInteger (const TimeBase &time, enum Unit timeUnit)
{
struct Information *info = PeekInformation (timeUnit);
uint64_t v = time.m_data.GetInteger ();
if (info->toMul)
{
v *= info->factor;
}
else
{
v /= info->factor;
}
return v;
}
double
TimeBase::ToDouble (const TimeBase &time, enum Unit timeUnit)
{
return To (time, timeUnit).GetDouble ();
}
} // namespace ns3
#endif /* TIME_BASE_H */