## root / include / simtime.h @ ffa9279f

History | View | Annotate | Download (12.5 KB)

1 | 01873262 | Georg Kunz | ```
//==========================================================================
``` |
---|---|---|---|

2 | ```
// SIMTIME.H - part of
``` |
||

3 | ```
// OMNeT++/OMNEST
``` |
||

4 | ```
// Discrete System Simulation in C++
``` |
||

5 | ```
//
``` |
||

6 | ```
//==========================================================================
``` |
||

7 | |||

8 | ```
/*--------------------------------------------------------------*
``` |
||

9 | ```
Copyright (C) 1992-2008 Andras Varga
``` |
||

10 | ```
Copyright (C) 2006-2008 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 | ```
* int64-based, fixed-point 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 | ```
* int64-to-double conversion, and the latter allows the compiler
``` |
||

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

44 | ```
* operation, without floating-point or int64 multiplication.
``` |
||

45 | ```
*
``` |
||

46 | ```
* The underlying raw 64-bit 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 floating-point 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 | 0e7ff5c8 | Simon Tenbusch | static const double simTimeSequentialExecution; |

103 | static const double simTimeUninitialized; |
||

104 | 01873262 | Georg Kunz | |

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 64-bit integer.
``` |
||

179 | ```
*/
``` |
||

180 | int64 raw() const {return t;} |
||

181 | |||

182 | ```
/**
``` |
||

183 | ```
* Directly sets the underlying 64-bit 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 64-bit 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((x-off)/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() + u-1;
``` |
||

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((x-off)/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 + u-1;
``` |
||

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 |