Commit | Line | Data |
---|---|---|
8c8bf09f | 1 | /******************************************************************************* |
5179fc01 | 2 | * Copyright (c) 2009, 2010, 2012 Ericsson |
f8177ba2 | 3 | * |
8c8bf09f ASL |
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 | |
f8177ba2 | 8 | * |
8c8bf09f | 9 | * Contributors: |
1f506a43 | 10 | * Francois Chouinard - Initial API and implementation |
023761c4 | 11 | * Thomas Gatterweh - Updated scaling / synchronization |
5179fc01 | 12 | * Francois Chouinard - Refactoring to align with TMF Event Model 1.0 |
f8177ba2 | 13 | * Francois Chouinard - Implement augmented interface |
8c8bf09f ASL |
14 | *******************************************************************************/ |
15 | ||
6c13869b | 16 | package org.eclipse.linuxtools.tmf.core.event; |
8c8bf09f | 17 | |
8c8bf09f | 18 | /** |
b9e37ffd | 19 | * A generic timestamp implementation. The timestamp is represented by the |
f8177ba2 FC |
20 | * tuple { value, scale, precision }. By default, timestamps are in the |
21 | * nanosecond scale. | |
22 | * | |
23 | * @version 1.1 | |
b9e37ffd | 24 | * @author Francois Chouinard |
8c8bf09f | 25 | */ |
b9e37ffd | 26 | public class TmfTimestamp implements ITmfTimestamp, Cloneable { |
8c8bf09f | 27 | |
5179fc01 | 28 | // ------------------------------------------------------------------------ |
8c8bf09f | 29 | // Constants |
5179fc01 | 30 | // ------------------------------------------------------------------------ |
8c8bf09f | 31 | |
d7dbf09a FC |
32 | /** |
33 | * The beginning of time | |
34 | */ | |
085d898f | 35 | public static final ITmfTimestamp BIG_BANG = |
d7dbf09a FC |
36 | new TmfTimestamp(Long.MIN_VALUE, Integer.MAX_VALUE, 0); |
37 | ||
38 | /** | |
39 | * The end of time | |
40 | */ | |
085d898f | 41 | public static final ITmfTimestamp BIG_CRUNCH = |
d7dbf09a | 42 | new TmfTimestamp(Long.MAX_VALUE, Integer.MAX_VALUE, 0); |
085d898f | 43 | |
f8177ba2 FC |
44 | /** |
45 | * A more practical definition of "beginning of time" | |
46 | * @since 2.0 | |
47 | */ | |
48 | public static final ITmfTimestamp PROJECT_IS_FUNDED = BIG_BANG; | |
49 | ||
50 | /** | |
51 | * A more practical definition of "end of time" | |
52 | * @since 2.0 | |
53 | */ | |
54 | public static final ITmfTimestamp PROJECT_IS_CANCELLED = BIG_CRUNCH; | |
55 | ||
d7dbf09a FC |
56 | /** |
57 | * Zero | |
58 | */ | |
085d898f | 59 | public static final ITmfTimestamp ZERO = |
d7dbf09a | 60 | new TmfTimestamp(0, 0, 0); |
5179fc01 FC |
61 | |
62 | // ------------------------------------------------------------------------ | |
63 | // Attributes | |
64 | // ------------------------------------------------------------------------ | |
8c8bf09f | 65 | |
d7dbf09a | 66 | /** |
f8177ba2 | 67 | * The timestamp raw value (mantissa) in nanoseconds |
d7dbf09a | 68 | */ |
b9e37ffd | 69 | private long fValue; |
d7dbf09a FC |
70 | |
71 | /** | |
72 | * The timestamp scale (magnitude) | |
73 | */ | |
b9e37ffd | 74 | private int fScale; |
d7dbf09a FC |
75 | |
76 | /** | |
77 | * The value precision (tolerance) | |
78 | */ | |
b9e37ffd | 79 | private int fPrecision; |
5179fc01 FC |
80 | |
81 | // ------------------------------------------------------------------------ | |
8c8bf09f | 82 | // Constructors |
5179fc01 | 83 | // ------------------------------------------------------------------------ |
8c8bf09f ASL |
84 | |
85 | /** | |
28b94d61 | 86 | * Default constructor |
8c8bf09f ASL |
87 | */ |
88 | public TmfTimestamp() { | |
f8177ba2 | 89 | this(0, ITmfTimestamp.SECOND_SCALE, 0); |
8c8bf09f ASL |
90 | } |
91 | ||
1f506a43 | 92 | /** |
5179fc01 FC |
93 | * Simple constructor (scale = precision = 0) |
94 | * | |
95 | * @param value the timestamp value | |
1f506a43 | 96 | */ |
085d898f | 97 | public TmfTimestamp(final long value) { |
f8177ba2 | 98 | this(value, ITmfTimestamp.SECOND_SCALE, 0); |
1f506a43 FC |
99 | } |
100 | ||
8c8bf09f | 101 | /** |
5179fc01 | 102 | * Simple constructor (precision = 0) |
f8177ba2 | 103 | * |
5179fc01 FC |
104 | * @param value the timestamp value |
105 | * @param scale the timestamp scale | |
8c8bf09f | 106 | */ |
085d898f | 107 | public TmfTimestamp(final long value, final int scale) { |
8c8bf09f ASL |
108 | this(value, scale, 0); |
109 | } | |
110 | ||
111 | /** | |
5179fc01 | 112 | * Full constructor |
f8177ba2 | 113 | * |
5179fc01 FC |
114 | * @param value the timestamp value |
115 | * @param scale the timestamp scale | |
116 | * @param precision the timestamp precision | |
8c8bf09f | 117 | */ |
085d898f | 118 | public TmfTimestamp(final long value, final int scale, final int precision) { |
8c8bf09f ASL |
119 | fValue = value; |
120 | fScale = scale; | |
121 | fPrecision = Math.abs(precision); | |
122 | } | |
123 | ||
124 | /** | |
28b94d61 | 125 | * Copy constructor |
f8177ba2 | 126 | * |
5179fc01 | 127 | * @param timestamp the timestamp to copy |
8c8bf09f | 128 | */ |
085d898f | 129 | public TmfTimestamp(final ITmfTimestamp timestamp) { |
b9e37ffd | 130 | if (timestamp == null) { |
5179fc01 | 131 | throw new IllegalArgumentException(); |
b9e37ffd | 132 | } |
4df4581d | 133 | fValue = timestamp.getValue(); |
134 | fScale = timestamp.getScale(); | |
135 | fPrecision = timestamp.getPrecision(); | |
8c8bf09f ASL |
136 | } |
137 | ||
b9e37ffd FC |
138 | // ------------------------------------------------------------------------ |
139 | // Setters | |
140 | // ------------------------------------------------------------------------ | |
141 | ||
142 | protected void setValue(long value, int scale, int precision) { | |
143 | fValue = value; | |
144 | fScale = scale; | |
145 | fPrecision = precision; | |
146 | } | |
147 | ||
5179fc01 FC |
148 | // ------------------------------------------------------------------------ |
149 | // ITmfTimestamp | |
150 | // ------------------------------------------------------------------------ | |
8c8bf09f | 151 | |
d7dbf09a FC |
152 | /* (non-Javadoc) |
153 | * @see org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp#getValue() | |
154 | */ | |
155 | @Override | |
8c8bf09f ASL |
156 | public long getValue() { |
157 | return fValue; | |
158 | } | |
159 | ||
d7dbf09a FC |
160 | /* (non-Javadoc) |
161 | * @see org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp#getScale() | |
162 | */ | |
163 | @Override | |
5179fc01 | 164 | public int getScale() { |
8c8bf09f ASL |
165 | return fScale; |
166 | } | |
167 | ||
d7dbf09a FC |
168 | /* (non-Javadoc) |
169 | * @see org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp#getPrecision() | |
170 | */ | |
171 | @Override | |
5179fc01 | 172 | public int getPrecision() { |
8c8bf09f ASL |
173 | return fPrecision; |
174 | } | |
175 | ||
5179fc01 FC |
176 | private static final long scalingFactors[] = new long[] { |
177 | 1L, | |
178 | 10L, | |
179 | 100L, | |
180 | 1000L, | |
181 | 10000L, | |
182 | 100000L, | |
183 | 1000000L, | |
184 | 10000000L, | |
185 | 100000000L, | |
186 | 1000000000L, | |
187 | 10000000000L, | |
188 | 100000000000L, | |
189 | 1000000000000L, | |
190 | 10000000000000L, | |
191 | 100000000000000L, | |
192 | 1000000000000000L, | |
193 | 10000000000000000L, | |
194 | 100000000000000000L, | |
195 | 1000000000000000000L, | |
196 | }; | |
4ab33d2b | 197 | |
d7dbf09a FC |
198 | /* (non-Javadoc) |
199 | * @see org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp#normalize(long, int) | |
200 | */ | |
201 | @Override | |
0316808c | 202 | public ITmfTimestamp normalize(final long offset, final int scale) { |
8c8bf09f | 203 | |
5179fc01 FC |
204 | long value = fValue; |
205 | int precision = fPrecision; | |
8c8bf09f | 206 | |
5179fc01 | 207 | // Handle the trivial case |
b9e37ffd | 208 | if (fScale == scale && offset == 0) { |
5179fc01 | 209 | return new TmfTimestamp(this); |
b9e37ffd | 210 | } |
f8177ba2 FC |
211 | |
212 | // In case of big bang and big crunch just return this (no need to normalize) | |
e461c849 BH |
213 | if (this.equals(BIG_BANG) || this.equals(BIG_CRUNCH)) { |
214 | return this; | |
215 | } | |
5179fc01 FC |
216 | |
217 | // First, scale the timestamp | |
218 | if (fScale != scale) { | |
085d898f | 219 | final int scaleDiff = Math.abs(fScale - scale); |
b9e37ffd | 220 | if (scaleDiff >= scalingFactors.length) { |
3b38ea61 | 221 | throw new ArithmeticException("Scaling exception"); //$NON-NLS-1$ |
b9e37ffd | 222 | } |
5179fc01 | 223 | |
085d898f | 224 | final long scalingFactor = scalingFactors[scaleDiff]; |
5179fc01 FC |
225 | if (scale < fScale) { |
226 | value *= scalingFactor; | |
227 | precision *= scalingFactor; | |
8c8bf09f | 228 | } else { |
5179fc01 FC |
229 | value /= scalingFactor; |
230 | precision /= scalingFactor; | |
8c8bf09f ASL |
231 | } |
232 | } | |
233 | ||
5179fc01 | 234 | // Then, apply the offset |
b9e37ffd | 235 | if (offset < 0) { |
5179fc01 | 236 | value = (value < Long.MIN_VALUE - offset) ? Long.MIN_VALUE : value + offset; |
b9e37ffd | 237 | } else { |
5179fc01 | 238 | value = (value > Long.MAX_VALUE - offset) ? Long.MAX_VALUE : value + offset; |
b9e37ffd | 239 | } |
023761c4 | 240 | |
5179fc01 | 241 | return new TmfTimestamp(value, scale, precision); |
8c8bf09f ASL |
242 | } |
243 | ||
d7dbf09a FC |
244 | /* (non-Javadoc) |
245 | * @see org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp#compareTo(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp, boolean) | |
246 | */ | |
247 | @Override | |
085d898f | 248 | public int compareTo(final ITmfTimestamp ts, final boolean withinPrecision) { |
023761c4 | 249 | |
5179fc01 | 250 | // Check the corner cases (we can't use equals() because it uses compareTo()...) |
b9e37ffd FC |
251 | if (ts == null) { |
252 | return 1; | |
253 | } | |
254 | if (this == ts || (fValue == ts.getValue() && fScale == ts.getScale())) { | |
5179fc01 | 255 | return 0; |
b9e37ffd FC |
256 | } |
257 | if ((fValue == BIG_BANG.getValue() && fScale == BIG_BANG.getScale()) || (ts.getValue() == BIG_CRUNCH.getValue() && ts.getScale() == BIG_CRUNCH.getScale())) { | |
5179fc01 | 258 | return -1; |
b9e37ffd FC |
259 | } |
260 | if ((fValue == BIG_CRUNCH.getValue() && fScale == BIG_CRUNCH.getScale()) || (ts.getValue() == BIG_BANG.getValue() && ts.getScale() == BIG_BANG.getScale())) { | |
5179fc01 | 261 | return 1; |
b9e37ffd | 262 | } |
085d898f | 263 | |
5179fc01 | 264 | try { |
085d898f FC |
265 | final ITmfTimestamp nts = ts.normalize(0, fScale); |
266 | final long delta = fValue - nts.getValue(); | |
b9e37ffd | 267 | if ((delta == 0) || (withinPrecision && (Math.abs(delta) <= (fPrecision + nts.getPrecision())))) { |
5179fc01 | 268 | return 0; |
b9e37ffd | 269 | } |
5179fc01 FC |
270 | return (delta > 0) ? 1 : -1; |
271 | } | |
085d898f | 272 | catch (final ArithmeticException e) { |
5179fc01 FC |
273 | // Scaling error. We can figure it out nonetheless. |
274 | ||
275 | // First, look at the sign of the mantissa | |
085d898f | 276 | final long value = ts.getValue(); |
b9e37ffd | 277 | if (fValue == 0 && value == 0) { |
5179fc01 | 278 | return 0; |
b9e37ffd FC |
279 | } |
280 | if (fValue < 0 && value >= 0) { | |
5179fc01 | 281 | return -1; |
b9e37ffd FC |
282 | } |
283 | if (fValue >= 0 && value < 0) { | |
5179fc01 | 284 | return 1; |
b9e37ffd | 285 | } |
5179fc01 FC |
286 | |
287 | // Otherwise, just compare the scales | |
085d898f FC |
288 | final int scale = ts.getScale(); |
289 | return (fScale > scale) ? (fValue >= 0) ? 1 : -1 : (fValue >= 0) ? -1 : 1; | |
5179fc01 | 290 | } |
8c8bf09f ASL |
291 | } |
292 | ||
d7dbf09a FC |
293 | /* (non-Javadoc) |
294 | * @see org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp#getDelta(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp) | |
295 | */ | |
5179fc01 | 296 | @Override |
085d898f FC |
297 | public ITmfTimestamp getDelta(final ITmfTimestamp ts) { |
298 | final ITmfTimestamp nts = ts.normalize(0, fScale); | |
299 | final long value = fValue - nts.getValue(); | |
5179fc01 | 300 | return new TmfTimestamp(value, fScale, fPrecision + nts.getPrecision()); |
73005152 BH |
301 | } |
302 | ||
5179fc01 FC |
303 | // ------------------------------------------------------------------------ |
304 | // Cloneable | |
305 | // ------------------------------------------------------------------------ | |
306 | ||
d7dbf09a FC |
307 | /* (non-Javadoc) |
308 | * @see java.lang.Object#clone() | |
309 | */ | |
5179fc01 | 310 | @Override |
8c149234 | 311 | public TmfTimestamp clone() { |
5179fc01 FC |
312 | TmfTimestamp clone = null; |
313 | try { | |
314 | clone = (TmfTimestamp) super.clone(); | |
315 | clone.fValue = fValue; | |
316 | clone.fScale = fScale; | |
317 | clone.fPrecision = fPrecision; | |
085d898f | 318 | } catch (final CloneNotSupportedException e) { |
5179fc01 FC |
319 | } |
320 | return clone; | |
8c8bf09f ASL |
321 | } |
322 | ||
5179fc01 FC |
323 | // ------------------------------------------------------------------------ |
324 | // Comparable | |
325 | // ------------------------------------------------------------------------ | |
023761c4 | 326 | |
d7dbf09a FC |
327 | /* (non-Javadoc) |
328 | * @see org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp#compareTo(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp) | |
329 | */ | |
5179fc01 | 330 | @Override |
085d898f | 331 | public int compareTo(final ITmfTimestamp ts) { |
4df4581d | 332 | return compareTo(ts, false); |
5179fc01 | 333 | } |
f3a4c7f4 | 334 | |
5179fc01 | 335 | // ------------------------------------------------------------------------ |
cbd4ad82 | 336 | // Object |
5179fc01 | 337 | // ------------------------------------------------------------------------ |
28b94d61 | 338 | |
d7dbf09a FC |
339 | /* (non-Javadoc) |
340 | * @see java.lang.Object#hashCode() | |
341 | */ | |
8c8bf09f | 342 | @Override |
cbd4ad82 | 343 | public int hashCode() { |
5179fc01 FC |
344 | final int prime = 31; |
345 | int result = 1; | |
346 | result = prime * result + (int) (fValue ^ (fValue >>> 32)); | |
347 | result = prime * result + fScale; | |
348 | result = prime * result + fPrecision; | |
cbd4ad82 FC |
349 | return result; |
350 | } | |
351 | ||
d7dbf09a FC |
352 | /* (non-Javadoc) |
353 | * @see java.lang.Object#equals(java.lang.Object) | |
354 | */ | |
5179fc01 | 355 | @Override |
085d898f | 356 | public boolean equals(final Object other) { |
b9e37ffd | 357 | if (this == other) { |
5179fc01 | 358 | return true; |
b9e37ffd FC |
359 | } |
360 | if (other == null) { | |
5179fc01 | 361 | return false; |
b9e37ffd FC |
362 | } |
363 | if (!(other instanceof TmfTimestamp)) { | |
5179fc01 | 364 | return false; |
b9e37ffd | 365 | } |
085d898f | 366 | final TmfTimestamp ts = (TmfTimestamp) other; |
5179fc01 | 367 | return compareTo(ts, false) == 0; |
8c8bf09f ASL |
368 | } |
369 | ||
d7dbf09a FC |
370 | /* (non-Javadoc) |
371 | * @see java.lang.Object#toString() | |
372 | */ | |
1f506a43 FC |
373 | @Override |
374 | public String toString() { | |
f8177ba2 FC |
375 | return toString(TmfTimestampFormat.getDefaulTimeFormat()); |
376 | } | |
377 | ||
378 | /* (non-Javadoc) | |
379 | * @see org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp#toString(org.eclipse.linuxtools.tmf.core.event.TmfTimestampFormat) | |
380 | */ | |
381 | /** | |
382 | * @since 2.0 | |
383 | */ | |
384 | @Override | |
385 | public String toString(final TmfTimestampFormat format) { | |
386 | try { | |
387 | ITmfTimestamp ts = normalize(0, ITmfTimestamp.NANOSECOND_SCALE); | |
388 | return format.format(ts.getValue()); | |
389 | } | |
390 | catch (ArithmeticException e) { | |
391 | return format.format(0); | |
392 | } | |
ff4ed569 FC |
393 | } |
394 | ||
023761c4 | 395 | } |