Statistics
| Branch: | Revision:

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