Re-structure LTTng sub-project as per the Linux Tools guidelines
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / 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.core.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, Comparable<TmfTimestamp> {
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"); //$NON-NLS-1$
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 * Compute the delta between two timestamps (adjusted to scale of current timestamp).
261 *
262 * @param reference the reference timestamp to synchronize with
263 * @return the delta timestamp
264 * @throws ArithmeticException
265 */
266 public TmfTimestamp getDelta(TmfTimestamp other) throws ArithmeticException {
267 TmfTimestamp newSecond = other;
268 if ((fScale != other.fScale) || (fPrecision != other.fPrecision)) {
269 newSecond = other.synchronize(0, fScale);
270 }
271 return new TmfTimestamp(fValue - newSecond.fValue,
272 fScale,
273 newSecond.fPrecision > fPrecision ? newSecond.fPrecision : fPrecision);
274 }
275
276 /**
277 * Compare with another timestamp
278 *
279 * @param other the other timestamp
280 * @param withinPrecision indicates if precision is to be take into consideration
281 * @return -1: this timestamp is lower (i.e. anterior)
282 * 0: timestamps are equal (within precision if requested)
283 * 1: this timestamp is higher (i.e. posterior)
284 */
285 public int compareTo(final TmfTimestamp other, boolean withinPrecision) {
286
287 // If values have the same time scale, perform the comparison
288 if (fScale == other.fScale) {
289 if (withinPrecision)
290 return compareWithinPrecision(this.fValue, this.fPrecision, other.fValue, other.fPrecision);
291 else
292 return compareNoPrecision(this.fValue, other.fValue);
293 }
294
295 // If values have different time scales, adjust to the finest one and
296 // then compare. If the scaling difference is too large, revert to
297 // some heuristics. Hopefully, nobody will try to compare galactic and
298 // quantic clock events...
299 int scaleDiff = Math.abs(fScale - other.fScale);
300 long factor, limit;
301 if (scaleDiff < scalingFactors.length) {
302 factor = scalingFactors[scaleDiff];
303 limit = scalingLimits[scaleDiff];
304 } else {
305 factor = 0;
306 limit = 0; // !!! 0 can always be scaled!!!
307 }
308
309 if (fScale < other.fScale) {
310 // this has finer scale, so other should be scaled
311 if (withinPrecision)
312 if (other.fValue > limit || other.fValue < -limit
313 || other.fPrecision > limit
314 || other.fPrecision < -limit)
315 return other.fValue > 0 ? -1 : +1; // other exceeds scaling limit
316 else
317 return compareWithinPrecision(this.fValue, this.fPrecision,
318 other.fValue * factor, other.fPrecision * factor);
319 else if (other.fValue > limit || other.fValue < -limit)
320 return other.fValue > 0 ? -1 : +1; // other exceeds scaling limit
321 else
322 return compareNoPrecision(this.fValue, other.fValue * factor);
323 } else {
324 // other has finer scale, so this should be scaled
325 if (withinPrecision)
326 if (this.fValue > limit || this.fValue < -limit
327 || this.fPrecision > limit || this.fPrecision < -limit)
328 return this.fValue > 0 ? +1 : -1; // we exceed scaling limit
329 else
330 return compareWithinPrecision(this.fValue * factor,
331 this.fPrecision * factor, other.fValue,
332 other.fPrecision);
333 else if (this.fValue > limit || this.fValue < -limit)
334 return this.fValue > 0 ? +1 : -1; // we exceed scaling limit
335 else
336 return compareNoPrecision(this.fValue * factor, other.fValue);
337 }
338 }
339
340 private static int compareNoPrecision(long thisValue, long otherValue) {
341 return (thisValue == otherValue) ? 0 : (thisValue < otherValue) ? -1 : 1;
342 }
343
344 private static int compareWithinPrecision(long thisValue, long thisPrecision, long otherValue, long otherPrecision) {
345 if ((thisValue + thisPrecision) < (otherValue - otherPrecision))
346 return -1;
347 if ((thisValue - thisPrecision) > (otherValue + otherPrecision))
348 return 1;
349 return 0;
350 }
351
352 // ------------------------------------------------------------------------
353 // Object
354 // ------------------------------------------------------------------------
355
356 @Override
357 public int hashCode() {
358 int result = 17;
359 result = 37 * result + (int) (fValue ^ (fValue >>> 32));
360 result = 37 * result + fScale;
361 result = 37 * result + (int) (fPrecision ^ (fPrecision >>> 32));
362 return result;
363 }
364
365 @Override
366 public boolean equals(Object other) {
367 if (!(other instanceof TmfTimestamp))
368 return false;
369 TmfTimestamp o = (TmfTimestamp) other;
370 return compareTo(o, false) == 0;
371 }
372
373 @Override
374 @SuppressWarnings("nls")
375 public String toString() {
376 return "[TmfTimestamp(" + fValue + "," + fScale + "," + fPrecision + ")]";
377 }
378
379 @Override
380 public TmfTimestamp clone() {
381 TmfTimestamp clone = null;
382 try {
383 clone = (TmfTimestamp) super.clone();
384 clone.fValue = fValue;
385 clone.fScale = fScale;
386 clone.fPrecision = fPrecision;
387 } catch (CloneNotSupportedException e) {
388 }
389 return clone;
390 }
391
392 @Override
393 public int compareTo(TmfTimestamp o) {
394 return compareTo(o, false);
395 }
396
397 }
This page took 0.073149 seconds and 5 git commands to generate.