tmf: Fix the actual end time of state system modules
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / timestamp / TmfTimestamp.java
CommitLineData
8c8bf09f 1/*******************************************************************************
065cc19b 2 * Copyright (c) 2009, 2014 Ericsson, École Polytechnique de Montréal
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:
065cc19b 10 * Francois Chouinard - Initial API and implementation, refactoring and updates
d5efe032 11 * Thomas Gatterweh - Updated scaling / synchronization
065cc19b
AM
12 * Geneviève Bastien - Added copy constructor with new value
13 * Alexandre Montplaisir - Removed concept of precision
8c8bf09f
ASL
14 *******************************************************************************/
15
2bdf0193 16package org.eclipse.tracecompass.tmf.core.timestamp;
8c8bf09f 17
032ecd45
MAL
18import java.nio.ByteBuffer;
19
cbf0057c 20import org.eclipse.jdt.annotation.NonNull;
dd21f749
MK
21import org.eclipse.tracecompass.internal.tmf.core.timestamp.TmfNanoTimestamp;
22import org.eclipse.tracecompass.internal.tmf.core.timestamp.TmfSecondTimestamp;
cbf0057c 23
8c8bf09f 24/**
9e925522 25 * A generic timestamp implementation. The timestamp is represented by the tuple
b2c971ec 26 * { value, scale, precision }.
f8177ba2 27 *
b9e37ffd 28 * @author Francois Chouinard
8c8bf09f 29 */
b2c971ec 30public abstract class TmfTimestamp implements ITmfTimestamp {
c61fcbab
MK
31
32 /**
33 * Default implementation of the tmf timestamp. We want this to be hidden.
34 *
35 * @author Matthew Khouzam
36 *
37 */
38 private static final class Impl extends TmfTimestamp {
39
40 // ------------------------------------------------------------------------
41 // Attributes
42 // ------------------------------------------------------------------------
43
44 /**
45 * The timestamp raw value (mantissa)
46 */
47 private final long fValue;
48
49 /**
50 * The timestamp scale (magnitude)
51 */
52 private final int fScale;
53
54 // ------------------------------------------------------------------------
55 // Constructors
56 // ------------------------------------------------------------------------
57
58 /**
59 * Full constructor
60 *
61 * @param value
62 * the timestamp value
63 * @param scale
64 * the timestamp scale
65 */
66 public Impl(final long value, final int scale) {
67 fValue = value;
68 fScale = scale;
69 }
70
71 @Override
72 public long getValue() {
73 return fValue;
74 }
75
76 @Override
77 public int getScale() {
78 return fScale;
79 }
80 }
81
d7dbf09a 82 /**
b2c971ec
MK
83 * Create a timestamp.
84 *
85 * @param value
86 * the value in nanoseconds
87 * @return the timestamp
88 * @since 2.0
d7dbf09a 89 */
b2c971ec
MK
90 public static @NonNull ITmfTimestamp fromNanos(long value) {
91 return new TmfNanoTimestamp(value);
92 }
d7dbf09a
FC
93
94 /**
b2c971ec
MK
95 * Create a timestamp.
96 *
97 * @param value
98 * the value in microseconds
99 * @return the timestamp
100 * @since 2.0
d7dbf09a 101 */
b2c971ec
MK
102 public static @NonNull ITmfTimestamp fromMicros(long value) {
103 return create(value, ITmfTimestamp.MICROSECOND_SCALE);
104 }
8c8bf09f
ASL
105
106 /**
b2c971ec
MK
107 * Create a timestamp.
108 *
109 * @param value
110 * the value in milliseconds
111 * @return the timestamp
112 * @since 2.0
8c8bf09f 113 */
b2c971ec
MK
114 public static @NonNull ITmfTimestamp fromMillis(long value) {
115 return create(value, ITmfTimestamp.MILLISECOND_SCALE);
8c8bf09f
ASL
116 }
117
1f506a43 118 /**
b2c971ec 119 * Create a timestamp.
5179fc01 120 *
065cc19b 121 * @param value
b2c971ec
MK
122 * the value in seconds
123 * @return the timestamp
124 * @since 2.0
1f506a43 125 */
b2c971ec
MK
126 public static @NonNull ITmfTimestamp fromSeconds(long value) {
127 return new TmfSecondTimestamp(value);
8c8bf09f
ASL
128 }
129
130 /**
b2c971ec 131 * Create a timestamp.
f8177ba2 132 *
b2c971ec
MK
133 * @param bufferIn
134 * the byte buffer to read the timestamp from.
135 * @return the timestamp
136 * @since 2.0
8c8bf09f 137 */
b2c971ec
MK
138 public static @NonNull ITmfTimestamp create(ByteBuffer bufferIn) {
139 return create(bufferIn.getLong(), bufferIn.getInt());
8c8bf09f
ASL
140 }
141
142 /**
b2c971ec 143 * Create a timestamp.
f8177ba2 144 *
b2c971ec
MK
145 * @param value
146 * the value in time, the unit is specified by the scale
147 * @param scale
148 * the scale of the timestamp with respect to seconds, so a
149 * nanosecond would be -9 (10e-9) and a megasecond would be 6
150 * (10e6)
151 * @return the timestamp
152 * @since 2.0
8c8bf09f 153 */
b2c971ec
MK
154 public static @NonNull ITmfTimestamp create(long value, int scale) {
155 if (scale == ITmfTimestamp.NANOSECOND_SCALE) {
156 return fromNanos(value);
b9e37ffd 157 }
b2c971ec
MK
158 if (scale == ITmfTimestamp.SECOND_SCALE) {
159 return fromSeconds(value);
160 }
c61fcbab
MK
161 if (value == 0) {
162 return ZERO;
163 }
b2c971ec 164 return createOther(value, scale);
8c8bf09f 165 }
e73a4ba5
GB
166
167 /**
b2c971ec 168 * Write the time stamp to the ByteBuffer so that it can be saved to disk.
e73a4ba5 169 *
b2c971ec
MK
170 * @param bufferOut
171 * the buffer to write to
172 * @param ts
173 * the timestamp to write
174 * @since 2.0
e73a4ba5 175 */
b2c971ec
MK
176 public static void serialize(ByteBuffer bufferOut, ITmfTimestamp ts) {
177 bufferOut.putLong(ts.getValue());
178 bufferOut.putInt(ts.getScale());
179 }
180
181 private static @NonNull ITmfTimestamp createOther(long value, int scale) {
c61fcbab 182 return new Impl(value, scale);
e73a4ba5 183 }
8c8bf09f 184
5179fc01 185 // ------------------------------------------------------------------------
b2c971ec 186 // Constants
5179fc01 187 // ------------------------------------------------------------------------
8c8bf09f 188
032ecd45 189 /**
c61fcbab
MK
190 * Zero - a zero time constant. The value is zero, so this allows some
191 * interesting simplifications.
032ecd45 192 */
c61fcbab
MK
193 public static final @NonNull ITmfTimestamp ZERO = new TmfTimestamp() {
194 @Override
195 public long getValue() {
196 return 0;
197 }
198
199 @Override
200 public int getScale() {
201 return 0;
202 }
203
204 @Override
205 public @NonNull ITmfTimestamp normalize(long offset, int scale) {
206 if (offset == 0) {
207 return this;
208 }
209 return create(offset, scale);
210 }
211
212 @Override
213 public int compareTo(ITmfTimestamp ts) {
214 return Long.compare(0, ts.getValue());
215 }
216 };
032ecd45 217
b2c971ec 218 /**
c61fcbab 219 * The beginning of time will be lesser than any other timestamp
b2c971ec 220 */
c61fcbab
MK
221 public static final @NonNull ITmfTimestamp BIG_BANG = new TmfTimestamp() {
222 @Override
223 public long getValue() {
224 return Long.MIN_VALUE;
225 }
226
227 @Override
228 public int getScale() {
229 return Integer.MAX_VALUE;
230 }
231
232 @Override
233 public int compareTo(ITmfTimestamp other) {
234 if (equals(other) == true) {
235 return 0;
236 }
237 return -1;
238 }
239
240 @Override
241 public ITmfTimestamp normalize(long offset, int scale) {
242 return this;
243 }
244
245 @Override
246 public boolean equals(Object other) {
247 return this == other;
248 }
249 };
8c8bf09f 250
b2c971ec 251 /**
c61fcbab 252 * The end of time will be greater than any other timestamp
b2c971ec 253 */
c61fcbab
MK
254 public static final @NonNull ITmfTimestamp BIG_CRUNCH = new TmfTimestamp() {
255 @Override
256 public long getValue() {
257 return Long.MAX_VALUE;
258 }
259
260 @Override
261 public int getScale() {
262 return Integer.MAX_VALUE;
263 }
264
265 @Override
266 public int compareTo(ITmfTimestamp other) {
267 if (equals(other) == true) {
268 return 0;
269 }
270 return 1;
271 }
272
273 @Override
274 public ITmfTimestamp normalize(long offset, int scale) {
275 return this;
276 }
277
278 @Override
279 public boolean equals(Object other) {
280 return this == other;
281 }
282 };
b2c971ec
MK
283
284 // ------------------------------------------------------------------------
285 // ITmfTimestamp
286 // ------------------------------------------------------------------------
8c8bf09f 287
b2c971ec
MK
288 /**
289 * Scaling factors to help scale
290 *
291 * @since 2.0
292 */
293 protected static final long SCALING_FACTORS[] = new long[] {
9e925522
MK
294 1L,
295 10L,
296 100L,
297 1000L,
298 10000L,
299 100000L,
300 1000000L,
301 10000000L,
302 100000000L,
303 1000000000L,
304 10000000000L,
305 100000000000L,
306 1000000000000L,
307 10000000000000L,
308 100000000000000L,
309 1000000000000000L,
310 10000000000000000L,
311 100000000000000000L,
312 1000000000000000000L,
5179fc01 313 };
4ab33d2b 314
d7dbf09a 315 @Override
0316808c 316 public ITmfTimestamp normalize(final long offset, final int scale) {
8c8bf09f 317
9e925522 318 long value = getValue();
8c8bf09f 319
5179fc01 320 // Handle the trivial case
9e925522 321 if (getScale() == scale && offset == 0) {
4593bd5b 322 return this;
b9e37ffd 323 }
f8177ba2 324
9e925522 325 if (value == 0) {
b2c971ec 326 return create(offset, scale);
9e925522
MK
327 }
328
5179fc01 329 // First, scale the timestamp
9e925522
MK
330 if (getScale() != scale) {
331 final int scaleDiff = Math.abs(getScale() - scale);
b2c971ec 332 if (scaleDiff >= SCALING_FACTORS.length) {
9e925522
MK
333 if (getScale() < scale) {
334 value = 0;
335 } else {
336 value = value > 0 ? Long.MAX_VALUE : Long.MIN_VALUE;
337 }
8c8bf09f 338 } else {
b2c971ec 339 final long scalingFactor = SCALING_FACTORS[scaleDiff];
9e925522
MK
340 if (getScale() < scale) {
341 value /= scalingFactor;
342 } else {
343 value = saturatedMult(scalingFactor, value);
344 }
8c8bf09f
ASL
345 }
346 }
347
9e925522 348 value = saturatedAdd(value, offset);
023761c4 349
b2c971ec 350 return create(value, scale);
8c8bf09f
ASL
351 }
352
d7dbf09a 353 @Override
065cc19b 354 public ITmfTimestamp getDelta(final ITmfTimestamp ts) {
b2c971ec
MK
355 final int scale = getScale();
356 final ITmfTimestamp nts = ts.normalize(0, scale);
357 final long value = getValue() - nts.getValue();
358 return new TmfTimestampDelta(value, scale);
065cc19b
AM
359 }
360
361 @Override
362 public boolean intersects(TmfTimeRange range) {
363 if (this.compareTo(range.getStartTime()) >= 0 &&
364 this.compareTo(range.getEndTime()) <= 0) {
365 return true;
366 }
367 return false;
368 }
369
370 // ------------------------------------------------------------------------
371 // Comparable
372 // ------------------------------------------------------------------------
023761c4 373
065cc19b
AM
374 @Override
375 public int compareTo(final ITmfTimestamp ts) {
b2c971ec
MK
376 long value = getValue();
377 int scale = getScale();
9e925522
MK
378 // Check the corner cases (we can't use equals() because it uses
379 // compareTo()...)
c61fcbab 380 if (BIG_BANG.equals(ts)) {
b9e37ffd
FC
381 return 1;
382 }
c61fcbab
MK
383
384 if (BIG_CRUNCH.equals(ts)) {
5179fc01 385 return -1;
b9e37ffd 386 }
c61fcbab
MK
387
388 if (this == ts || isIdentical(this, ts)) {
389 return 0;
b9e37ffd 390 }
5179fc01 391
c61fcbab
MK
392 if (scale == ts.getScale()) {
393 if (ts.getValue() == Long.MIN_VALUE) {
5179fc01 394 return 1;
b9e37ffd 395 }
c61fcbab
MK
396 final long delta = saturatedAdd(getValue(), -ts.getValue());
397 return Long.compare(delta, 0);
398 }
399 final ITmfTimestamp largerScale = (scale > ts.getScale()) ? this : ts;
400 final ITmfTimestamp smallerScale = (scale < ts.getScale()) ? this : ts;
401
402 final ITmfTimestamp nts = largerScale.normalize(0, smallerScale.getScale());
403 if (hasSaturated(largerScale, nts)) {
404 // We've saturated largerScale.
405 if (smallerScale.getScale() == scale) {
406 return Long.compare(0, nts.getValue());
407 }
408 return Long.compare(nts.getValue(), 0);
5179fc01 409 }
c61fcbab
MK
410 if (smallerScale.getScale() == scale) {
411 return Long.compare(value, nts.getValue());
412 }
413 return Long.compare(nts.getValue(), smallerScale.getValue());
414 }
415
416 private static boolean hasSaturated(final ITmfTimestamp ts, final ITmfTimestamp nts) {
417 return (nts.getValue() == 0 && ts.getValue() != 0) || !isIdentical(ts, nts) && ((nts.getValue() == Long.MAX_VALUE) || (nts.getValue() == Long.MIN_VALUE));
418 }
419
420 private static boolean isIdentical(final ITmfTimestamp ts, final ITmfTimestamp nts) {
421 return ts.getValue() == nts.getValue() && ts.getScale() == nts.getScale();
9e925522
MK
422 }
423
424 /**
425 * Saturated multiplication. It will not overflow but instead clamp the
426 * result to {@link Long#MAX_VALUE} and {@link Long#MIN_VALUE}.
427 *
428 * @param left
429 * The left long to multiply
430 * @param right
431 * The right long to multiply
432 * @return The saturated multiplication result. The mathematical, not Java
433 * version of Min(Max(MIN_VALUE, left*right), MAX_VALUE).
434 * @see <a href="http://en.wikipedia.org/wiki/Saturation_arithmetic">
435 * Saturation arithmetic</a>
436 */
437 private static long saturatedMult(long left, long right) {
438 long retVal = left * right;
439 if ((left != 0) && ((retVal / left) != right)) {
440 return (sameSign(left, right) ? Long.MAX_VALUE : Long.MIN_VALUE);
441 }
442 return retVal;
443 }
444
445 /**
446 * Saturated addition. It will not overflow but instead clamp the result to
447 * {@link Long#MAX_VALUE} and {@link Long#MIN_VALUE}.
448 *
449 * @param left
450 * The left long to add
451 * @param right
452 * The right long to add
453 * @return The saturated addition result. The mathematical, not Java version
454 * of Min(Max(MIN_VALUE, left+right), MAX_VALUE).
455 * @see <a href="http://en.wikipedia.org/wiki/Saturation_arithmetic">
456 * Saturation arithmetic</a>
457 * @since 2.0
458 */
459 protected static final long saturatedAdd(final long left, final long right) {
460 long retVal = left + right;
461 if (sameSign(left, right) && !sameSign(left, retVal)) {
462 if (retVal > 0) {
463 return Long.MIN_VALUE;
464 }
465 return Long.MAX_VALUE;
466 }
467 return retVal;
468 }
469
470 private static boolean sameSign(final long left, final long right) {
471 return (left ^ right) >= 0;
8c8bf09f
ASL
472 }
473
5179fc01 474 // ------------------------------------------------------------------------
cbd4ad82 475 // Object
5179fc01 476 // ------------------------------------------------------------------------
28b94d61 477
8c8bf09f 478 @Override
cbd4ad82 479 public int hashCode() {
5179fc01
FC
480 final int prime = 31;
481 int result = 1;
b2c971ec
MK
482 final long value = getValue();
483 result = prime * result + (int) (value ^ (value >>> 32));
484 result = prime * result + getScale();
cbd4ad82
FC
485 return result;
486 }
487
5179fc01 488 @Override
085d898f 489 public boolean equals(final Object other) {
b9e37ffd 490 if (this == other) {
5179fc01 491 return true;
b9e37ffd
FC
492 }
493 if (other == null) {
5179fc01 494 return false;
b9e37ffd 495 }
065cc19b 496 if (!(other instanceof ITmfTimestamp)) {
5179fc01 497 return false;
b9e37ffd 498 }
065cc19b
AM
499 /* We allow comparing with other types of *I*TmfTimestamp though */
500 final ITmfTimestamp ts = (ITmfTimestamp) other;
c61fcbab
MK
501 if (getScale() == ts.getScale()) {
502 return getValue() == ts.getValue();
503 }
065cc19b 504 return (compareTo(ts) == 0);
8c8bf09f
ASL
505 }
506
1f506a43
FC
507 @Override
508 public String toString() {
f8177ba2
FC
509 return toString(TmfTimestampFormat.getDefaulTimeFormat());
510 }
511
f8177ba2
FC
512 @Override
513 public String toString(final TmfTimestampFormat format) {
514 try {
16801c72 515 return format.format(toNanos());
9e925522 516 } catch (ArithmeticException e) {
f8177ba2
FC
517 return format.format(0);
518 }
ff4ed569 519 }
023761c4 520}
This page took 0.122065 seconds and 5 git commands to generate.