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
1 /*******************************************************************************
2 * Copyright (c) 2009, 2014 Ericsson, École Polytechnique de Montréal
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, refactoring and updates
11 * Thomas Gatterweh - Updated scaling / synchronization
12 * Geneviève Bastien - Added copy constructor with new value
13 * Alexandre Montplaisir - Removed concept of precision
14 *******************************************************************************/
15
16 package org.eclipse.tracecompass.tmf.core.timestamp;
17
18 import java.nio.ByteBuffer;
19
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.tracecompass.internal.tmf.core.timestamp.TmfNanoTimestamp;
22 import org.eclipse.tracecompass.internal.tmf.core.timestamp.TmfSecondTimestamp;
23
24 /**
25 * A generic timestamp implementation. The timestamp is represented by the tuple
26 * { value, scale, precision }.
27 *
28 * @author Francois Chouinard
29 */
30 public abstract class TmfTimestamp implements ITmfTimestamp {
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
82 /**
83 * Create a timestamp.
84 *
85 * @param value
86 * the value in nanoseconds
87 * @return the timestamp
88 * @since 2.0
89 */
90 public static @NonNull ITmfTimestamp fromNanos(long value) {
91 return new TmfNanoTimestamp(value);
92 }
93
94 /**
95 * Create a timestamp.
96 *
97 * @param value
98 * the value in microseconds
99 * @return the timestamp
100 * @since 2.0
101 */
102 public static @NonNull ITmfTimestamp fromMicros(long value) {
103 return create(value, ITmfTimestamp.MICROSECOND_SCALE);
104 }
105
106 /**
107 * Create a timestamp.
108 *
109 * @param value
110 * the value in milliseconds
111 * @return the timestamp
112 * @since 2.0
113 */
114 public static @NonNull ITmfTimestamp fromMillis(long value) {
115 return create(value, ITmfTimestamp.MILLISECOND_SCALE);
116 }
117
118 /**
119 * Create a timestamp.
120 *
121 * @param value
122 * the value in seconds
123 * @return the timestamp
124 * @since 2.0
125 */
126 public static @NonNull ITmfTimestamp fromSeconds(long value) {
127 return new TmfSecondTimestamp(value);
128 }
129
130 /**
131 * Create a timestamp.
132 *
133 * @param bufferIn
134 * the byte buffer to read the timestamp from.
135 * @return the timestamp
136 * @since 2.0
137 */
138 public static @NonNull ITmfTimestamp create(ByteBuffer bufferIn) {
139 return create(bufferIn.getLong(), bufferIn.getInt());
140 }
141
142 /**
143 * Create a timestamp.
144 *
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
153 */
154 public static @NonNull ITmfTimestamp create(long value, int scale) {
155 if (scale == ITmfTimestamp.NANOSECOND_SCALE) {
156 return fromNanos(value);
157 }
158 if (scale == ITmfTimestamp.SECOND_SCALE) {
159 return fromSeconds(value);
160 }
161 if (value == 0) {
162 return ZERO;
163 }
164 return createOther(value, scale);
165 }
166
167 /**
168 * Write the time stamp to the ByteBuffer so that it can be saved to disk.
169 *
170 * @param bufferOut
171 * the buffer to write to
172 * @param ts
173 * the timestamp to write
174 * @since 2.0
175 */
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) {
182 return new Impl(value, scale);
183 }
184
185 // ------------------------------------------------------------------------
186 // Constants
187 // ------------------------------------------------------------------------
188
189 /**
190 * Zero - a zero time constant. The value is zero, so this allows some
191 * interesting simplifications.
192 */
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 };
217
218 /**
219 * The beginning of time will be lesser than any other timestamp
220 */
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 };
250
251 /**
252 * The end of time will be greater than any other timestamp
253 */
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 };
283
284 // ------------------------------------------------------------------------
285 // ITmfTimestamp
286 // ------------------------------------------------------------------------
287
288 /**
289 * Scaling factors to help scale
290 *
291 * @since 2.0
292 */
293 protected static final long SCALING_FACTORS[] = new long[] {
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,
313 };
314
315 @Override
316 public ITmfTimestamp normalize(final long offset, final int scale) {
317
318 long value = getValue();
319
320 // Handle the trivial case
321 if (getScale() == scale && offset == 0) {
322 return this;
323 }
324
325 if (value == 0) {
326 return create(offset, scale);
327 }
328
329 // First, scale the timestamp
330 if (getScale() != scale) {
331 final int scaleDiff = Math.abs(getScale() - scale);
332 if (scaleDiff >= SCALING_FACTORS.length) {
333 if (getScale() < scale) {
334 value = 0;
335 } else {
336 value = value > 0 ? Long.MAX_VALUE : Long.MIN_VALUE;
337 }
338 } else {
339 final long scalingFactor = SCALING_FACTORS[scaleDiff];
340 if (getScale() < scale) {
341 value /= scalingFactor;
342 } else {
343 value = saturatedMult(scalingFactor, value);
344 }
345 }
346 }
347
348 value = saturatedAdd(value, offset);
349
350 return create(value, scale);
351 }
352
353 @Override
354 public ITmfTimestamp getDelta(final ITmfTimestamp ts) {
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);
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 // ------------------------------------------------------------------------
373
374 @Override
375 public int compareTo(final ITmfTimestamp ts) {
376 long value = getValue();
377 int scale = getScale();
378 // Check the corner cases (we can't use equals() because it uses
379 // compareTo()...)
380 if (BIG_BANG.equals(ts)) {
381 return 1;
382 }
383
384 if (BIG_CRUNCH.equals(ts)) {
385 return -1;
386 }
387
388 if (this == ts || isIdentical(this, ts)) {
389 return 0;
390 }
391
392 if (scale == ts.getScale()) {
393 if (ts.getValue() == Long.MIN_VALUE) {
394 return 1;
395 }
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);
409 }
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();
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;
472 }
473
474 // ------------------------------------------------------------------------
475 // Object
476 // ------------------------------------------------------------------------
477
478 @Override
479 public int hashCode() {
480 final int prime = 31;
481 int result = 1;
482 final long value = getValue();
483 result = prime * result + (int) (value ^ (value >>> 32));
484 result = prime * result + getScale();
485 return result;
486 }
487
488 @Override
489 public boolean equals(final Object other) {
490 if (this == other) {
491 return true;
492 }
493 if (other == null) {
494 return false;
495 }
496 if (!(other instanceof ITmfTimestamp)) {
497 return false;
498 }
499 /* We allow comparing with other types of *I*TmfTimestamp though */
500 final ITmfTimestamp ts = (ITmfTimestamp) other;
501 if (getScale() == ts.getScale()) {
502 return getValue() == ts.getValue();
503 }
504 return (compareTo(ts) == 0);
505 }
506
507 @Override
508 public String toString() {
509 return toString(TmfTimestampFormat.getDefaulTimeFormat());
510 }
511
512 @Override
513 public String toString(final TmfTimestampFormat format) {
514 try {
515 return format.format(toNanos());
516 } catch (ArithmeticException e) {
517 return format.format(0);
518 }
519 }
520 }
This page took 0.042477 seconds and 5 git commands to generate.