[Bug309042] Improved code coverage, JUnit + minor bug fixes
[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 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.event;
14
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 /*
162 * A java <code>long</code> has a maximum of 19 significant digits.
163 * (-9,223,372,036,854,775,808 .. +9,223,372,036,854,775,807)
164 *
165 * It is therefore useless to try to synchronize 2 timestamps whose
166 * difference in scale exceeds that value.
167 */
168 int MAX_SCALING = 19;
169
170 long newValue = fValue;
171 long newPrecision = fPrecision;
172
173 // Determine the scaling factor
174 if (fScale != newScale) {
175 int scaleDiff = Math.abs(fScale - newScale);
176 // Let's try to be realistic...
177 if (scaleDiff > MAX_SCALING) {
178 throw new ArithmeticException("Scaling exception");
179 }
180 // Not pretty...
181 long scalingFactor = 1;
182 for (int i = 0; i < scaleDiff; i++) {
183 scalingFactor *= 10;
184 }
185 if (newScale < fScale) {
186 newValue *= scalingFactor;
187 newPrecision *= scalingFactor;
188 } else {
189 newValue /= scalingFactor;
190 newPrecision /= scalingFactor;
191 }
192 }
193
194 return new TmfTimestamp(newValue + offset, newScale, newPrecision);
195 }
196
197 /**
198 * Compute the adjustment, in the reference scale, needed to synchronize
199 * this timestamp with a reference timestamp.
200 *
201 * @param reference the reference timestamp to synchronize with
202 * @param scale the scale of the adjustment
203 * @return the adjustment term in the reference time scale
204 * @throws ArithmeticException
205 */
206 public long getAdjustment(TmfTimestamp reference, byte scale) throws ArithmeticException {
207 TmfTimestamp ts1 = synchronize(0, scale);
208 TmfTimestamp ts2 = reference.synchronize(0, scale);
209 return ts2.fValue - ts1.fValue;
210 }
211
212 /**
213 * Compare with another timestamp
214 *
215 * @param other the other timestamp
216 * @param withinPrecision indicates if precision is to be take into consideration
217 * @return -1: this timestamp is lower (i.e. anterior)
218 * 0: timestamps are equal (within precision if requested)
219 * 1: this timestamp is higher (i.e. posterior)
220 */
221 public int compareTo(final TmfTimestamp other, boolean withinPrecision) {
222
223 // If values have the same time scale, perform the comparison
224 if (fScale == other.fScale) {
225 if (withinPrecision) {
226 if ((fValue + fPrecision) < (other.fValue - other.fPrecision))
227 return -1;
228 if ((fValue - fPrecision) > (other.fValue + other.fPrecision))
229 return 1;
230 return 0;
231 }
232 return (fValue == other.fValue) ? 0 : (fValue < other.fValue) ? -1 : 1;
233 }
234
235 // If values have different time scales, adjust to the finest one and
236 // then compare. If the scaling difference is too large, revert to
237 // some heuristics. Hopefully, nobody will try to compare galactic and
238 // quantic clock events...
239 byte newScale = (fScale < other.fScale) ? fScale : other.fScale;
240 try {
241 TmfTimestamp ts1 = this.synchronize(0, newScale);
242 TmfTimestamp ts2 = other.synchronize(0, newScale);
243 return ts1.compareTo(ts2, withinPrecision);
244 } catch (ArithmeticException e) {
245 if ((fValue == 0) || (other.fValue == 0)) {
246 return (fValue == other.fValue) ? 0
247 : (fValue < other.fValue) ? -1 : 1;
248 }
249 if ((fValue > 0) && (other.fValue > 0)) {
250 return (fScale < other.fScale) ? -1 : 1;
251 }
252 if ((fValue < 0) && (other.fValue < 0)) {
253 return (fScale > other.fScale) ? -1 : 1;
254 }
255 return (fValue < 0) ? -1 : 1;
256 }
257 }
258
259 // ------------------------------------------------------------------------
260 // Object
261 // ------------------------------------------------------------------------
262
263 @Override
264 public int hashCode() {
265 int result = 17;
266 result = 37 * result + (int) (fValue ^ (fValue >>> 32));
267 result = 37 * result + fScale;
268 result = 37 * result + (int) (fPrecision ^ (fPrecision >>> 32));
269 return result;
270 }
271
272 @Override
273 public boolean equals(Object other) {
274 if (!(other instanceof TmfTimestamp))
275 return false;
276 TmfTimestamp o = (TmfTimestamp) other;
277 return compareTo(o, false) == 0;
278 }
279
280 @Override
281 public String toString() {
282 return "[TmfTimestamp(" + fValue + "," + fScale + "," + fPrecision + ")]";
283 }
284
285 @Override
286 public TmfTimestamp clone() {
287 TmfTimestamp clone = null;
288 try {
289 clone = (TmfTimestamp) super.clone();
290 clone.fValue = fValue;
291 clone.fScale = fScale;
292 clone.fPrecision = fPrecision;
293 } catch (CloneNotSupportedException e) {
294 }
295 return clone;
296 }
297
298 }
This page took 0.048226 seconds and 6 git commands to generate.