Project

General

Profile

Statistics
| Branch: | Revision:

root / include / simtime.h @ aeae20a1

History | View | Annotate | Download (12.4 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
103
    /**
104
     * Constructor initializes to zero.
105
     */
106
    SimTime() {t=0;}
107
    SimTime(double d) {operator=(d);}
108
    SimTime(cPar& d) {operator=(d);}
109
    SimTime(const SimTime& x) {operator=(x);}
110
    // note: template ctor is not a good idea -- often causes surprises
111
    // template<typename T> SimTime(T d) {operator=(d);}
112
113
    /** @name Arithmetic operations */
114
    //@{
115
    const SimTime& operator=(double d) {check(d); t=toInt64(fscale*d); return *this;}
116
    const SimTime& operator=(const cPar& d);
117
    const SimTime& operator=(const SimTime& x) {t=x.t; return *this;}
118
    template<typename T> const SimTime& operator=(T d) {check(d); t=toInt64(dscale*d); return *this;}
119
120
    const SimTime& operator+=(const SimTime& x) {checkedAdd(x); return *this;}
121
    const SimTime& operator-=(const SimTime& x) {checkedSub(x); return *this;}
122
123
    const SimTime& operator*=(double d) {t=toInt64(t*d); return *this;}
124
    const SimTime& operator/=(double d) {t=toInt64(t/d); return *this;}
125
    const SimTime& operator*=(const cPar& p);
126
    const SimTime& operator/=(const cPar& p);
127
    template<typename T> const SimTime& operator*=(T d) {t*=d; return *this;}
128
    template<typename T> const SimTime& operator/=(T d) {t/=d; return *this;}
129
130
    bool operator==(const SimTime& x) const  {return t==x.t;}
131
    bool operator!=(const SimTime& x) const  {return t!=x.t;}
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
137
    SimTime operator-() const {SimTime x; x.t = -t; return x;}
138
139
    friend const SimTime operator+(const SimTime& x, const SimTime& y);
140
    friend const SimTime operator-(const SimTime& x, const SimTime& y);
141
142
    friend const SimTime operator*(const SimTime& x, double d);
143
    friend const SimTime operator*(double d, const SimTime& x);
144
    friend const SimTime operator/(const SimTime& x, double d);
145
    friend double operator/(double d, const SimTime& x);
146
    friend double operator/(const SimTime& x, const SimTime& y);
147
148
    friend const SimTime operator*(const SimTime& x, const cPar& p);
149
    friend const SimTime operator*(const cPar& p, const SimTime& x);
150
    friend const SimTime operator/(const SimTime& x, const cPar& p);
151
    //@}
152
153
    /**
154
     * Converts simulation time to double. Note that conversion to and from
155
     * double may lose precision. We do not provide implicit conversion to
156
     * double as it would conflict with other overloaded operators, and would
157
     * cause ambiguities during compilation.
158
     */
159
    double dbl() const  {return t*invfscale;}
160
161
    /**
162
     * Converts to string.
163
     */
164
    std::string str() const;
165
166
    /**
167
     * Converts to a string. Use this variant over str() where performance is
168
     * critical. The result is placed somewhere in the given buffer (pointer
169
     * is returned), but for performance reasons, not necessarily at the buffer's
170
     * beginning. Please read the documentation of ttoa() for the minimum
171
     * required buffer size.
172
     */
173
    char *str(char *buf) {char *endp; return SimTime::ttoa(buf, t, getScaleExp(), endp);}
174
175
    /**
176
     * Returns the underlying 64-bit integer.
177
     */
178
    int64 raw() const  {return t;}
179
180
    /**
181
     * Directly sets the underlying 64-bit integer.
182
     */
183
    const SimTime& setRaw(int64 l) {t = l; return *this;}
184
185
    /**
186
     * Returns the largest simulation time that can be represented using the
187
     * present scale exponent.
188
     */
189
    static const SimTime getMaxTime() {return SimTime().setRaw(INT64_MAX);}
190
191
    /**
192
     * Returns the time resolution as the number of units per second,
193
     * e.g. for microsecond resolution it returns 1000000.
194
     */
195
    static int64 getScale()  {return dscale;}
196
197
    /**
198
     * Returns the scale exponent, which is an integer in the range -18..0.
199
     * For example, for microsecond resolution it returns -6.
200
     */
201
    static int getScaleExp() {return scaleexp;}
202
203
    /**
204
     * Sets the scale exponent, and thus the resolution of time. Accepted
205
     * values are -18..0; for example, setScaleExp(-6) selects microsecond
206
     * resolution. Normally, the scale exponent is set from the configuration
207
     * file (omnetpp.ini) on simulation startup.
208
     *
209
     * The scale exponent can only be set ONCE, and cannot be changed
210
     * afterwards. Any attempt to change it after it got initialized
211
     * will result in a runtime error. Reason: the simtime exponent is
212
     * a global variable, and changing it would silently change the
213
     * value of existing SimTime variables.
214
     */
215
    static void setScaleExp(int e);
216
217
    /**
218
     * Converts the given string to simulation time. Throws an error if
219
     * there is an error during conversion. Accepted format is: \<number\>
220
     * or (\<number\>\<unit\>)+.
221
     */
222
    static const SimTime parse(const char *s);
223
224
    /**
225
     * Converts a prefix of the given string to simulation time, up to the
226
     * first character that cannot occur in simulation time strings:
227
     * not (digit or letter or "." or "+" or "-" or whitespace).
228
     * Throws an error if there is an error during conversion of the prefix.
229
     * If the prefix is empty (whitespace only), then 0 is returned, and
230
     * endp is set equal to s; otherwise,  endp is set to point to the
231
     * first character that was not converted.
232
     */
233
    static const SimTime parse(const char *s, const char *&endp);
234
235
    /**
236
     * Utility function to convert a 64-bit fixed point number into a string
237
     * buffer. scaleexp must be in the -18..0 range, and the buffer must be
238
     * at least 64 bytes long. A pointer to the result string will be
239
     * returned. A pointer to the terminating '\\0' will be returned in endp.
240
     *
241
     * ATTENTION: For performance reasons, the returned pointer will point
242
     * *somewhere* into the buffer, but NOT necessarily at the beginning.
243
     */
244
    static char *ttoa(char *buf, int64 t, int scaleexp, char *&endp);
245
};
246
247
/*
248
 for *= and /=, we might need the following code:
249
    // linux bug workaround; don't change next two lines
250
    volatile double tmp = uint64_to_double( m_value ) * d;
251
    m_value = static_cast<int64>( tmp );
252
    return *this;
253
*/
254
255
inline const SimTime operator+(const SimTime& x, const SimTime& y)
256
{
257
    return SimTime(x)+=y;
258
}
259
260
inline const SimTime operator-(const SimTime& x, const SimTime& y)
261
{
262
    return SimTime(x)-=y;
263
}
264
265
inline const SimTime operator*(const SimTime& x, double d)
266
{
267
    return SimTime(x)*=d;
268
}
269
270
inline const SimTime operator*(double d, const SimTime& x)
271
{
272
    return SimTime(x)*=d;
273
}
274
275
inline const SimTime operator/(const SimTime& x, double d)
276
{
277
    return SimTime(x)/=d;
278
}
279
280
inline double operator/(double d, const SimTime& x)
281
{
282
    return d / x.dbl();
283
}
284
285
inline double operator/(const SimTime& x, const SimTime& y)
286
{
287
    return (double)x.raw() / (double)y.raw();
288
}
289
290
inline std::ostream& operator<<(std::ostream& os, const SimTime& x)
291
{
292
    char buf[64]; char *endp;
293
    return os << SimTime::ttoa(buf, x.raw(), SimTime::getScaleExp(), endp);
294
}
295
296
NAMESPACE_END
297
298
// used locally; needed because sign of a%b is implementation dependent if a<0
299
inline int64 _i64mod(const int64& any_t, const int64& positive_u)
300
{
301
    int64 m = any_t % positive_u;
302
    return m>=0 ? m : m+positive_u;
303
}
304
305
/**
306
 * simtime_t version of floor(double) from math.h.
307
 */
308
inline const OPP::SimTime floor(const OPP::SimTime& x)
309
{
310
    int64 u = OPP::SimTime::getScale();
311
    int64 t = x.raw();
312
    return OPP::SimTime().setRaw(t - _i64mod(t,u));
313
}
314
315
/**
316
 * Generalized version of floor(), accepting a unit and an offset:
317
 * floor(x,u,off) = floor((x-off)/u)*u + off.
318
 *
319
 * Examples: floor(2.1234, 0.1) = 2.1; floor(2.1234, 0.1, 0.007) = 2.107;
320
 * floor(2.1006, 0.1, 0.007) = 2.007.
321
 */
322
inline const OPP::SimTime floor(const OPP::SimTime& x, const OPP::SimTime& unit, const OPP::SimTime& offset = OPP::SimTime())
323
{
324
    int64 off = offset.raw();
325
    int64 u = unit.raw();
326
    int64 t = x.raw() - off;
327
    return OPP::SimTime().setRaw(t - _i64mod(t,u) + off);
328
}
329
330
/**
331
 * simtime_t version of ceil(double) from math.h.
332
 */
333
inline const OPP::SimTime ceil(const OPP::SimTime& x)
334
{
335
    int64 u = OPP::SimTime::getScale();
336
    int64 t = x.raw() + u-1;
337
    return OPP::SimTime().setRaw(t - _i64mod(t,u));
338
}
339
340
/**
341
 * Generalized version of ceil(), accepting a unit and an offset:
342
 * ceil(x,u,off) = ceil((x-off)/u)*u + off.
343
 */
344
inline const OPP::SimTime ceil(const OPP::SimTime& x, const OPP::SimTime& unit, const OPP::SimTime& offset = OPP::SimTime())
345
{
346
    int64 off = offset.raw();
347
    int64 u = unit.raw();
348
    int64 t = x.raw() - off + u-1;
349
    return OPP::SimTime().setRaw(t - _i64mod(t,u) + off);
350
}
351
352
/**
353
 * simtime_t version of fabs(double) from math.h.
354
 */
355
inline const OPP::SimTime fabs(const OPP::SimTime& x)
356
{
357
    return x.raw()<0 ? OPP::SimTime().setRaw(-x.raw()) : x;
358
}
359
360
/**
361
 * simtime_t version of fmod(double,double) from math.h.
362
 */
363
inline const OPP::SimTime fmod(const OPP::SimTime& x, const OPP::SimTime& y)
364
{
365
    return OPP::SimTime().setRaw(x.raw() % y.raw());
366
}
367
368
#endif
369