2010-10-15 Francois Chouinard <fchouinard@gmail.com> Fix for Bug327910
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / event / TmfTimestamp.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
11 * Thomas Gatterweh - Updated scaling / synchronization
12 *******************************************************************************/
13
14 package org.eclipse.linuxtools.tmf.event;
15
16 /**
17 * <b><u>TmfTimestamp</u></b>
18 * <p>
19 * The fundamental time reference in the TMF.
20 * <p>
21 * It provides a generic timestamp implementation in its most basic form:
22 * <ul>
23 * <li>timestamp = [value] * 10**[scale] +/- [precision]
24 * </ul>
25 * Where:
26 * <ul>
27 * <li>[value] is an unstructured integer value
28 * <li>[scale] is the magnitude of the value wrt some application-specific
29 * base unit (e.g. the second)
30 * <li>[precision] indicates the error on the value (useful for comparing
31 * timestamps in different scales). Default: 0.
32 * </ul>
33 * In short:
34 * <ul>
35 * </ul>
36 * To allow synchronization of timestamps from different reference clocks,
37 * there is a possibility to "adjust" the timestamp by changing its scale
38 * (traces of different time scale) and/or by adding an offset to its value
39 * (clock drift between traces).
40 * <p>
41 * Notice that the adjusted timestamp value could be negative e.g. for events
42 * that occurred before t0 wrt the reference clock.
43 */
44 public class TmfTimestamp implements Cloneable {
45
46 // ------------------------------------------------------------------------
47 // Attributes
48 // ------------------------------------------------------------------------
49
50 protected long fValue; // The timestamp raw value
51 protected byte fScale; // The time scale
52 protected long fPrecision; // The value precision (tolerance)
53
54 // ------------------------------------------------------------------------
55 // Constants
56 // ------------------------------------------------------------------------
57
58 // The beginning and end of time
59 public static final TmfTimestamp BigBang = new TmfTimestamp(Long.MIN_VALUE, Byte.MAX_VALUE, 0);
60 public static final TmfTimestamp BigCrunch = new TmfTimestamp(Long.MAX_VALUE, Byte.MAX_VALUE, 0);
61 public static final TmfTimestamp Zero = new TmfTimestamp(0, (byte) 0, 0);
62
63 // ------------------------------------------------------------------------
64 // Constructors
65 // ------------------------------------------------------------------------
66
67 /**
68 * Default constructor
69 */
70 public TmfTimestamp() {
71 this(0, (byte) 0, 0);
72 }
73
74 /**
75 * Simple constructor with value only
76 */
77 public TmfTimestamp(long value) {
78 this(value, (byte) 0, 0);
79 }
80
81 /**
82 * Simple constructor with value and scale
83 *
84 * @param value
85 * @param scale
86 */
87 public TmfTimestamp(long value, byte scale) {
88 this(value, scale, 0);
89 }
90
91 /**
92 * Constructor with value, scale and precision
93 *
94 * @param value
95 * @param scale
96 * @param precision
97 */
98 public TmfTimestamp(long value, byte scale, long precision) {
99 fValue = value;
100 fScale = scale;
101 fPrecision = Math.abs(precision);
102 }
103
104 /**
105 * Copy constructor
106 *
107 * @param other
108 */
109 public TmfTimestamp(TmfTimestamp other) {
110 if (other == null)
111 throw new IllegalArgumentException();
112 fValue = other.fValue;
113 fScale = other.fScale;
114 fPrecision = other.fPrecision;
115 }
116
117 // ------------------------------------------------------------------------
118 // Accessors
119 // ------------------------------------------------------------------------
120
121 /**
122 * @return the timestamp value
123 */
124 public long getValue() {
125 return fValue;
126 }
127
128 /**
129 * @return the timestamp scale
130 */
131 public byte getScale() {
132 return fScale;
133 }
134
135 /**
136 * @return the timestamp value precision
137 */
138 public long getPrecision() {
139 return fPrecision;
140 }
141
142 // ------------------------------------------------------------------------
143 // Operators
144 // ------------------------------------------------------------------------
145
146 /**
147 * Return a shifted and scaled timestamp.
148 *
149 * Limitation: The scaling is limited to MAX_SCALING orders of magnitude.
150 * The main reason is that the 64 bits value starts to lose any significance
151 * meaning beyond that scale difference and it's not even worth the trouble
152 * to switch to BigDecimal arithmetics.
153 *
154 * @param offset the shift value (in the same scale as newScale)
155 * @param newScale the new timestamp scale
156 * @return the synchronized timestamp in the new scale
157 * @throws ArithmeticException
158 */
159 public TmfTimestamp synchronize(long offset, byte newScale) throws ArithmeticException {
160
161 long newValue = fValue;
162 long newPrecision = fPrecision;
163
164 // Handle the easy case
165 if (fScale == newScale && offset == 0)
166 return this;
167
168 // Determine the scaling factor
169 if (fScale != newScale) {
170 int scaleDiff = Math.abs(fScale - newScale);
171 // Let's try to be realistic...
172 if (scaleDiff >= scalingFactors.length) {
173 throw new ArithmeticException("Scaling exception");
174 }
175 // Adjust the timestamp
176 long scalingFactor = scalingFactors[scaleDiff];
177 if (newScale < fScale) {
178 newValue *= scalingFactor;
179 newPrecision *= scalingFactor;
180 } else {
181 newValue /= scalingFactor;
182 newPrecision /= scalingFactor;
183 }
184 }
185
186 if (offset < 0) {
187 newValue = (newValue < Long.MIN_VALUE - offset) ? Long.MIN_VALUE : newValue + offset;
188 } else {
189 newValue = (newValue > Long.MAX_VALUE - offset) ? Long.MAX_VALUE : newValue + offset;
190 }
191
192 return new TmfTimestamp(newValue, newScale, newPrecision);
193 }
194
195 private static final long scalingFactors[] = new long[] {
196 1L,
197 10L,
198 100L,
199 1000L,
200 10000L,
201 100000L,
202 1000000L,
203 10000000L,
204 100000000L,
205 1000000000L,
206 10000000000L,
207 100000000000L,
208 1000000000000L,
209 10000000000000L,
210 100000000000000L,
211 1000000000000000L,
212 10000000000000000L,
213 100000000000000000L,
214 1000000000000000000L,
215 };
216
217 private static final long scalingLimits[] = new long[] {
218 Long.MAX_VALUE / 1L,
219 Long.MAX_VALUE / 10L,
220 Long.MAX_VALUE / 100L,
221 Long.MAX_VALUE / 1000L,
222 Long.MAX_VALUE / 10000L,
223 Long.MAX_VALUE / 100000L,
224 Long.MAX_VALUE / 1000000L,
225 Long.MAX_VALUE / 10000000L,
226 Long.MAX_VALUE / 100000000L,
227 Long.MAX_VALUE / 1000000000L,
228 Long.MAX_VALUE / 10000000000L,
229 Long.MAX_VALUE / 100000000000L,
230 Long.MAX_VALUE / 1000000000000L,
231 Long.MAX_VALUE / 10000000000000L,
232 Long.MAX_VALUE / 100000000000000L,
233 Long.MAX_VALUE / 1000000000000000L,
234 Long.MAX_VALUE / 10000000000000000L,
235 Long.MAX_VALUE / 100000000000000000L,
236 Long.MAX_VALUE / 1000000000000000000L,
237 };
238
239 public static long getScalingFactor(byte scale)
240 {
241 return scalingFactors[scale];
242 }
243
244 /**
245 * Compute the adjustment, in the reference scale, needed to synchronize
246 * this timestamp with a reference timestamp.
247 *
248 * @param reference the reference timestamp to synchronize with
249 * @param scale the scale of the adjustment
250 * @return the adjustment term in the reference time scale
251 * @throws ArithmeticException
252 */
253 public long getAdjustment(TmfTimestamp reference, byte scale) throws ArithmeticException {
254 TmfTimestamp ts1 = synchronize(0, scale);
255 TmfTimestamp ts2 = reference.synchronize(0, scale);
256 return ts2.fValue - ts1.fValue;
257 }
258
259 /**
260 * Compare with another timestamp
261 *
262 * @param other the other timestamp
263 * @param withinPrecision indicates if precision is to be take into consideration
264 * @return -1: this timestamp is lower (i.e. anterior)
265 * 0: timestamps are equal (within precision if requested)
266 * 1: this timestamp is higher (i.e. posterior)
267 */
268 public int compareTo(final TmfTimestamp other, boolean withinPrecision) {
269
270 // If values have the same time scale, perform the comparison
271 if (fScale == other.fScale) {
272 if (withinPrecision)
273 return compareWithinPrecision(this.fValue, this.fPrecision, other.fValue, other.fPrecision);
274 else
275 return compareNoPrecision(this.fValue, other.fValue);
276 }
277
278 // If values have different time scales, adjust to the finest one and
279 // then compare. If the scaling difference is too large, revert to
280 // some heuristics. Hopefully, nobody will try to compare galactic and
281 // quantic clock events...
282 int scaleDiff = Math.abs(fScale - other.fScale);
283 long factor, limit;
284 if (scaleDiff < scalingFactors.length) {
285 factor = scalingFactors[scaleDiff];
286 limit = scalingLimits[scaleDiff];
287 } else {
288 factor = 0;
289 limit = 0; // !!! 0 can always be scaled!!!
290 }
291
292 if (fScale < other.fScale) {
293 // this has finer scale, so other should be scaled
294 if (withinPrecision)
295 if (other.fValue > limit || other.fValue < -limit
296 || other.fPrecision > limit
297 || other.fPrecision < -limit)
298 return other.fValue > 0 ? -1 : +1; // other exceeds scaling limit
299 else
300 return compareWithinPrecision(this.fValue, this.fPrecision,
301 other.fValue * factor, other.fPrecision * factor);
302 else if (other.fValue > limit || other.fValue < -limit)
303 return other.fValue > 0 ? -1 : +1; // other exceeds scaling limit
304 else
305 return compareNoPrecision(this.fValue, other.fValue * factor);
306 } else {
307 // other has finer scale, so this should be scaled
308 if (withinPrecision)
309 if (this.fValue > limit || this.fValue < -limit
310 || this.fPrecision > limit || this.fPrecision < -limit)
311 return this.fValue > 0 ? +1 : -1; // we exceed scaling limit
312 else
313 return compareWithinPrecision(this.fValue * factor,
314 this.fPrecision * factor, other.fValue,
315 other.fPrecision);
316 else if (this.fValue > limit || this.fValue < -limit)
317 return this.fValue > 0 ? +1 : -1; // we exceed scaling limit
318 else
319 return compareNoPrecision(this.fValue * factor, other.fValue);
320 }
321 }
322
323 private static int compareNoPrecision(long thisValue, long otherValue) {
324 return (thisValue == otherValue) ? 0 : (thisValue < otherValue) ? -1 : 1;
325 }
326
327 private static int compareWithinPrecision(long thisValue, long thisPrecision, long otherValue, long otherPrecision) {
328 if ((thisValue + thisPrecision) < (otherValue - otherPrecision))
329 return -1;
330 if ((thisValue - thisPrecision) > (otherValue + otherPrecision))
331 return 1;
332 return 0;
333 }
334
335 // ------------------------------------------------------------------------
336 // Object
337 // ------------------------------------------------------------------------
338
339 @Override
340 public int hashCode() {
341 int result = 17;
342 result = 37 * result + (int) (fValue ^ (fValue >>> 32));
343 result = 37 * result + fScale;
344 result = 37 * result + (int) (fPrecision ^ (fPrecision >>> 32));
345 return result;
346 }
347
348 @Override
349 public boolean equals(Object other) {
350 if (!(other instanceof TmfTimestamp))
351 return false;
352 TmfTimestamp o = (TmfTimestamp) other;
353 return compareTo(o, false) == 0;
354 }
355
356 @Override
357 public String toString() {
358 return "[TmfTimestamp(" + fValue + "," + fScale + "," + fPrecision + ")]";
359 }
360
361 @Override
362 public TmfTimestamp clone() {
363 TmfTimestamp clone = null;
364 try {
365 clone = (TmfTimestamp) super.clone();
366 clone.fValue = fValue;
367 clone.fScale = fScale;
368 clone.fPrecision = fPrecision;
369 } catch (CloneNotSupportedException e) {
370 }
371 return clone;
372 }
373
374 }
This page took 0.049011 seconds and 5 git commands to generate.