root / include / simtime.h @ ffa9279f
History  View  Annotate  Download (12.5 KB)
1 
//==========================================================================


2 
// SIMTIME.H  part of

3 
// OMNeT++/OMNEST

4 
// Discrete System Simulation in C++

5 
//

6 
//==========================================================================

7  
8 
/**

9 
Copyright (C) 19922008 Andras Varga

10 
Copyright (C) 20062008 OpenSim Ltd.

11 

12 
This file is distributed WITHOUT ANY WARRANTY. See the file

13 
`license' for details on this and other legal matters.

14 
**/

15  
16 
#ifndef __SIMTIME_H

17 
#define __SIMTIME_H

18  
19 
#include <string> 
20 
#include <iostream> 
21 
#include "simkerneldefs.h" 
22 
#include "platdep/intxtypes.h" 
23  
24 
NAMESPACE_BEGIN 
25  
26 
class cPar; 
27  
28 
// the most positive int64 value, represented as double

29 
#define INT64_MAX_DBL 9.22337203685e18 
30  
31  
32 
/**

33 
* int64based, fixedpoint simulation time. Precision is determined by a scale

34 
* exponent, which is global (shared by all SimTime instances), and falls in

35 
* the range 18..0. For example, a scale exponent of 6 means microsecond

36 
* precision.

37 
*

38 
* Conversions and arithmetic operations are provided specifically for double

39 
* and cPar, and via template functions for integer types. Performance note:

40 
* conversion from double uses the scale stored as double, and conversion from

41 
* integer types uses the scale stored as int64; the former eliminates an

42 
* int64todouble conversion, and the latter allows the compiler

43 
* to optimize expressions like <tt>if (time>0)</tt> to a trivial integer

44 
* operation, without floatingpoint or int64 multiplication.

45 
*

46 
* The underlying raw 64bit integer is also made accessible.

47 
*/

48 
class SIM_API SimTime 
49 
{ 
50 
private:

51 
int64 t; 
52  
53 
static int scaleexp; // scale exponent in the range 18..0 
54 
static int64 dscale; // 10^scaleexp, that is 1 or 1000 or 1000000... 
55 
static double fscale; // 10^scaleexp, that is 1 or 1000 or 1000000... 
56 
static double invfscale; // 1/fscale; we store it because floatingpoint multiplication is faster than division 
57  
58 
protected:

59 
static void resetScale() {scaleexp = SCALEEXP_UNINITIALIZED;} // for unit tests only 
60  
61 
private:

62 
template<typename T> void check(T d) {if (scaleexp==SCALEEXP_UNINITIALIZED) initError(d);} 
63 
void initError(double d); 
64  
65 
bool haveSameSign(int64 a, int64 b) { return (a^b) >= 0; } 
66  
67 
int64 toInt64(double i64) {

68 
if (fabs(i64) > INT64_MAX_DBL)

69 
rangeError(i64); 
70 
return (int64)i64;

71 
} 
72  
73 
void checkedAdd(const SimTime& x) { 
74 
// if operands are the same sign but result has different sign ==> overflow

75 
bool sameSign = haveSameSign(t, x.t);

76 
t += x.t; 
77 
if (sameSign && !haveSameSign(t, x.t))

78 
overflowAdding(x); 
79 
} 
80  
81 
void checkedSub(const SimTime& x) { 
82 
// if operands are different signs and result has same sign as x ==> overflow

83 
bool differentSign = !haveSameSign(t, x.t);

84 
t = x.t; 
85 
if (differentSign && haveSameSign(t, x.t))

86 
overflowSubstracting(x); 
87 
} 
88  
89 
void rangeError(double i64); 
90 
void overflowAdding(const SimTime& x); 
91 
void overflowSubstracting(const SimTime& x); 
92  
93 
public:

94 
static const int SCALEEXP_S = 0; 
95 
static const int SCALEEXP_MS = 3; 
96 
static const int SCALEEXP_US = 6; 
97 
static const int SCALEEXP_NS = 9; 
98 
static const int SCALEEXP_PS = 12; 
99 
static const int SCALEEXP_FS = 15; 
100 
static const int SCALEEXP_UNINITIALIZED = 0xffff; 
101 
static const SimTime simTimeZero; 
102 
static const double simTimeSequentialExecution; 
103 
static const double simTimeUninitialized; 
104  
105 
/**

106 
* Constructor initializes to zero.

107 
*/

108 
SimTime() {t=0;}

109 
SimTime(double d) {operator=(d);}

110 
SimTime(cPar& d) {operator=(d);} 
111 
SimTime(const SimTime& x) {operator=(x);}

112 
// note: template ctor is not a good idea  often causes surprises

113 
// template<typename T> SimTime(T d) {operator=(d);}

114  
115 
/** @name Arithmetic operations */

116 
//@{

117 
const SimTime& operator=(double d) {check(d); t=toInt64(fscale*d); return *this;} 
118 
const SimTime& operator=(const cPar& d); 
119 
const SimTime& operator=(const SimTime& x) {t=x.t; return *this;} 
120 
template<typename T> const SimTime& operator=(T d) {check(d); t=toInt64(dscale*d); return *this;} 
121  
122 
const SimTime& operator+=(const SimTime& x) {checkedAdd(x); return *this;} 
123 
const SimTime& operator=(const SimTime& x) {checkedSub(x); return *this;} 
124  
125 
const SimTime& operator*=(double d) {t=toInt64(t*d); return *this;} 
126 
const SimTime& operator/=(double d) {t=toInt64(t/d); return *this;} 
127 
const SimTime& operator*=(const cPar& p); 
128 
const SimTime& operator/=(const cPar& p); 
129 
template<typename T> const SimTime& operator*=(T d) {t*=d; return *this;} 
130 
template<typename T> const SimTime& operator/=(T d) {t/=d; return *this;} 
131  
132 
bool operator==(const SimTime& x) const {return t==x.t;} 
133 
bool operator!=(const SimTime& x) const {return t!=x.t;} 
134 
bool operator< (const SimTime& x) const {return t<x.t;} 
135 
bool operator> (const SimTime& x) const {return t>x.t;} 
136 
bool operator<=(const SimTime& x) const {return t<=x.t;} 
137 
bool operator>=(const SimTime& x) const {return t>=x.t;} 
138  
139 
SimTime operator() const {SimTime x; x.t = t; return x;} 
140  
141 
friend const SimTime operator+(const SimTime& x, const SimTime& y); 
142 
friend const SimTime operator(const SimTime& x, const SimTime& y); 
143  
144 
friend const SimTime operator*(const SimTime& x, double d); 
145 
friend const SimTime operator*(double d, const SimTime& x); 
146 
friend const SimTime operator/(const SimTime& x, double d); 
147 
friend double operator/(double d, const SimTime& x); 
148 
friend double operator/(const SimTime& x, const SimTime& y); 
149  
150 
friend const SimTime operator*(const SimTime& x, const cPar& p); 
151 
friend const SimTime operator*(const cPar& p, const SimTime& x); 
152 
friend const SimTime operator/(const SimTime& x, const cPar& p); 
153 
//@}

154  
155 
/**

156 
* Converts simulation time to double. Note that conversion to and from

157 
* double may lose precision. We do not provide implicit conversion to

158 
* double as it would conflict with other overloaded operators, and would

159 
* cause ambiguities during compilation.

160 
*/

161 
double dbl() const {return t*invfscale;} 
162  
163 
/**

164 
* Converts to string.

165 
*/

166 
std::string str() const;

167  
168 
/**

169 
* Converts to a string. Use this variant over str() where performance is

170 
* critical. The result is placed somewhere in the given buffer (pointer

171 
* is returned), but for performance reasons, not necessarily at the buffer's

172 
* beginning. Please read the documentation of ttoa() for the minimum

173 
* required buffer size.

174 
*/

175 
char *str(char *buf) {char *endp; return SimTime::ttoa(buf, t, getScaleExp(), endp);} 
176  
177 
/**

178 
* Returns the underlying 64bit integer.

179 
*/

180 
int64 raw() const {return t;} 
181  
182 
/**

183 
* Directly sets the underlying 64bit integer.

184 
*/

185 
const SimTime& setRaw(int64 l) {t = l; return *this;} 
186  
187 
/**

188 
* Returns the largest simulation time that can be represented using the

189 
* present scale exponent.

190 
*/

191 
static const SimTime getMaxTime() {return SimTime().setRaw(INT64_MAX);} 
192  
193 
/**

194 
* Returns the time resolution as the number of units per second,

195 
* e.g. for microsecond resolution it returns 1000000.

196 
*/

197 
static int64 getScale() {return dscale;} 
198  
199 
/**

200 
* Returns the scale exponent, which is an integer in the range 18..0.

201 
* For example, for microsecond resolution it returns 6.

202 
*/

203 
static int getScaleExp() {return scaleexp;} 
204  
205 
/**

206 
* Sets the scale exponent, and thus the resolution of time. Accepted

207 
* values are 18..0; for example, setScaleExp(6) selects microsecond

208 
* resolution. Normally, the scale exponent is set from the configuration

209 
* file (omnetpp.ini) on simulation startup.

210 
*

211 
* The scale exponent can only be set ONCE, and cannot be changed

212 
* afterwards. Any attempt to change it after it got initialized

213 
* will result in a runtime error. Reason: the simtime exponent is

214 
* a global variable, and changing it would silently change the

215 
* value of existing SimTime variables.

216 
*/

217 
static void setScaleExp(int e); 
218  
219 
/**

220 
* Converts the given string to simulation time. Throws an error if

221 
* there is an error during conversion. Accepted format is: \<number\>

222 
* or (\<number\>\<unit\>)+.

223 
*/

224 
static const SimTime parse(const char *s); 
225  
226 
/**

227 
* Converts a prefix of the given string to simulation time, up to the

228 
* first character that cannot occur in simulation time strings:

229 
* not (digit or letter or "." or "+" or "" or whitespace).

230 
* Throws an error if there is an error during conversion of the prefix.

231 
* If the prefix is empty (whitespace only), then 0 is returned, and

232 
* endp is set equal to s; otherwise, endp is set to point to the

233 
* first character that was not converted.

234 
*/

235 
static const SimTime parse(const char *s, const char *&endp); 
236  
237 
/**

238 
* Utility function to convert a 64bit fixed point number into a string

239 
* buffer. scaleexp must be in the 18..0 range, and the buffer must be

240 
* at least 64 bytes long. A pointer to the result string will be

241 
* returned. A pointer to the terminating '\\0' will be returned in endp.

242 
*

243 
* ATTENTION: For performance reasons, the returned pointer will point

244 
* *somewhere* into the buffer, but NOT necessarily at the beginning.

245 
*/

246 
static char *ttoa(char *buf, int64 t, int scaleexp, char *&endp); 
247 
}; 
248  
249 
/*

250 
for *= and /=, we might need the following code:

251 
// linux bug workaround; don't change next two lines

252 
volatile double tmp = uint64_to_double( m_value ) * d;

253 
m_value = static_cast<int64>( tmp );

254 
return *this;

255 
*/

256  
257 
inline const SimTime operator+(const SimTime& x, const SimTime& y) 
258 
{ 
259 
return SimTime(x)+=y;

260 
} 
261  
262 
inline const SimTime operator(const SimTime& x, const SimTime& y) 
263 
{ 
264 
return SimTime(x)=y;

265 
} 
266  
267 
inline const SimTime operator*(const SimTime& x, double d) 
268 
{ 
269 
return SimTime(x)*=d;

270 
} 
271  
272 
inline const SimTime operator*(double d, const SimTime& x) 
273 
{ 
274 
return SimTime(x)*=d;

275 
} 
276  
277 
inline const SimTime operator/(const SimTime& x, double d) 
278 
{ 
279 
return SimTime(x)/=d;

280 
} 
281  
282 
inline double operator/(double d, const SimTime& x) 
283 
{ 
284 
return d / x.dbl();

285 
} 
286  
287 
inline double operator/(const SimTime& x, const SimTime& y) 
288 
{ 
289 
return (double)x.raw() / (double)y.raw(); 
290 
} 
291  
292 
inline std::ostream& operator<<(std::ostream& os, const SimTime& x) 
293 
{ 
294 
char buf[64]; char *endp; 
295 
return os << SimTime::ttoa(buf, x.raw(), SimTime::getScaleExp(), endp);

296 
} 
297  
298 
NAMESPACE_END 
299  
300 
// used locally; needed because sign of a%b is implementation dependent if a<0

301 
inline int64 _i64mod(const int64& any_t, const int64& positive_u) 
302 
{ 
303 
int64 m = any_t % positive_u; 
304 
return m>=0 ? m : m+positive_u; 
305 
} 
306  
307 
/**

308 
* simtime_t version of floor(double) from math.h.

309 
*/

310 
inline const OPP::SimTime floor(const OPP::SimTime& x) 
311 
{ 
312 
int64 u = OPP::SimTime::getScale(); 
313 
int64 t = x.raw(); 
314 
return OPP::SimTime().setRaw(t  _i64mod(t,u));

315 
} 
316  
317 
/**

318 
* Generalized version of floor(), accepting a unit and an offset:

319 
* floor(x,u,off) = floor((xoff)/u)*u + off.

320 
*

321 
* Examples: floor(2.1234, 0.1) = 2.1; floor(2.1234, 0.1, 0.007) = 2.107;

322 
* floor(2.1006, 0.1, 0.007) = 2.007.

323 
*/

324 
inline const OPP::SimTime floor(const OPP::SimTime& x, const OPP::SimTime& unit, const OPP::SimTime& offset = OPP::SimTime()) 
325 
{ 
326 
int64 off = offset.raw(); 
327 
int64 u = unit.raw(); 
328 
int64 t = x.raw()  off; 
329 
return OPP::SimTime().setRaw(t  _i64mod(t,u) + off);

330 
} 
331  
332 
/**

333 
* simtime_t version of ceil(double) from math.h.

334 
*/

335 
inline const OPP::SimTime ceil(const OPP::SimTime& x) 
336 
{ 
337 
int64 u = OPP::SimTime::getScale(); 
338 
int64 t = x.raw() + u1;

339 
return OPP::SimTime().setRaw(t  _i64mod(t,u));

340 
} 
341  
342 
/**

343 
* Generalized version of ceil(), accepting a unit and an offset:

344 
* ceil(x,u,off) = ceil((xoff)/u)*u + off.

345 
*/

346 
inline const OPP::SimTime ceil(const OPP::SimTime& x, const OPP::SimTime& unit, const OPP::SimTime& offset = OPP::SimTime()) 
347 
{ 
348 
int64 off = offset.raw(); 
349 
int64 u = unit.raw(); 
350 
int64 t = x.raw()  off + u1;

351 
return OPP::SimTime().setRaw(t  _i64mod(t,u) + off);

352 
} 
353  
354 
/**

355 
* simtime_t version of fabs(double) from math.h.

356 
*/

357 
inline const OPP::SimTime fabs(const OPP::SimTime& x) 
358 
{ 
359 
return x.raw()<0 ? OPP::SimTime().setRaw(x.raw()) : x; 
360 
} 
361  
362 
/**

363 
* simtime_t version of fmod(double,double) from math.h.

364 
*/

365 
inline const OPP::SimTime fmod(const OPP::SimTime& x, const OPP::SimTime& y) 
366 
{ 
367 
return OPP::SimTime().setRaw(x.raw() % y.raw());

368 
} 
369  
370 
#endif

371  
372 