1 /*******************************************************************************
2 * Copyright (c) 2009, 2013 Ericsson, École Polytechnique de Montréal
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
10 * Francois Chouinard - Initial API and implementation
11 * Thomas Gatterweh - Updated scaling / synchronization
12 * Francois Chouinard - Refactoring to align with TMF Event Model 1.0
13 * Francois Chouinard - Implement augmented interface
14 * Geneviève Bastien - Added copy constructor with new value
15 *******************************************************************************/
17 package org
.eclipse
.tracecompass
.tmf
.core
.timestamp
;
19 import java
.nio
.ByteBuffer
;
22 * A generic timestamp implementation. The timestamp is represented by the
23 * tuple { value, scale, precision }. By default, timestamps are scaled in
26 * @author Francois Chouinard
30 public class TmfTimestamp
implements ITmfTimestamp
{
32 // ------------------------------------------------------------------------
34 // ------------------------------------------------------------------------
37 * The beginning of time
39 public static final ITmfTimestamp BIG_BANG
=
40 new TmfTimestamp(Long
.MIN_VALUE
, Integer
.MAX_VALUE
, 0);
45 public static final ITmfTimestamp BIG_CRUNCH
=
46 new TmfTimestamp(Long
.MAX_VALUE
, Integer
.MAX_VALUE
, 0);
49 * A more practical definition of "beginning of time"
51 public static final ITmfTimestamp PROJECT_IS_FUNDED
= BIG_BANG
;
54 * A more practical definition of "end of time"
56 public static final ITmfTimestamp PROJECT_IS_CANNED
= BIG_CRUNCH
;
61 public static final ITmfTimestamp ZERO
=
62 new TmfTimestamp(0, 0, 0);
64 // ------------------------------------------------------------------------
66 // ------------------------------------------------------------------------
69 * The timestamp raw value (mantissa)
71 private final long fValue
;
74 * The timestamp scale (magnitude)
76 private final int fScale
;
79 * The value precision (tolerance)
81 private final int fPrecision
;
83 // ------------------------------------------------------------------------
85 // ------------------------------------------------------------------------
90 public TmfTimestamp() {
91 this(0, ITmfTimestamp
.SECOND_SCALE
, 0);
95 * Simple constructor (scale = precision = 0)
97 * @param value the timestamp value
99 public TmfTimestamp(final long value
) {
100 this(value
, ITmfTimestamp
.SECOND_SCALE
, 0);
104 * Simple constructor (precision = 0)
106 * @param value the timestamp value
107 * @param scale the timestamp scale
109 public TmfTimestamp(final long value
, final int scale
) {
110 this(value
, scale
, 0);
116 * @param value the timestamp value
117 * @param scale the timestamp scale
118 * @param precision the timestamp precision
120 public TmfTimestamp(final long value
, final int scale
, final int precision
) {
123 fPrecision
= Math
.abs(precision
);
129 * @param timestamp the timestamp to copy
131 public TmfTimestamp(final ITmfTimestamp timestamp
) {
132 if (timestamp
== null) {
133 throw new IllegalArgumentException();
135 fValue
= timestamp
.getValue();
136 fScale
= timestamp
.getScale();
137 fPrecision
= timestamp
.getPrecision();
141 * Copies a timestamp but with a new time value
144 * The timestamp to copy
146 * The value the new timestamp will have
149 public TmfTimestamp(ITmfTimestamp timestamp
, long newvalue
) {
150 if (timestamp
== null) {
151 throw new IllegalArgumentException();
154 fScale
= timestamp
.getScale();
155 fPrecision
= timestamp
.getPrecision();
158 // ------------------------------------------------------------------------
160 // ------------------------------------------------------------------------
163 * Construct the timestamp from the ByteBuffer.
166 * the buffer to read from
170 public TmfTimestamp(ByteBuffer bufferIn
) {
171 this(bufferIn
.getLong(), bufferIn
.getInt(), bufferIn
.getInt());
175 public long getValue() {
180 public int getScale() {
185 public int getPrecision() {
189 private static final long scalingFactors
[] = new long[] {
208 1000000000000000000L,
212 public ITmfTimestamp
normalize(final long offset
, final int scale
) {
215 int precision
= fPrecision
;
217 // Handle the trivial case
218 if (fScale
== scale
&& offset
== 0) {
222 // In case of big bang and big crunch just return this (no need to normalize)
223 if (this.equals(BIG_BANG
) || this.equals(BIG_CRUNCH
)) {
227 // First, scale the timestamp
228 if (fScale
!= scale
) {
229 final int scaleDiff
= Math
.abs(fScale
- scale
);
230 if (scaleDiff
>= scalingFactors
.length
) {
231 throw new ArithmeticException("Scaling exception"); //$NON-NLS-1$
234 final long scalingFactor
= scalingFactors
[scaleDiff
];
235 if (scale
< fScale
) {
236 value
*= scalingFactor
;
237 precision
*= scalingFactor
;
239 value
/= scalingFactor
;
240 precision
/= scalingFactor
;
244 // Then, apply the offset
246 value
= (value
< Long
.MIN_VALUE
- offset
) ? Long
.MIN_VALUE
: value
+ offset
;
248 value
= (value
> Long
.MAX_VALUE
- offset
) ? Long
.MAX_VALUE
: value
+ offset
;
251 return new TmfTimestamp(value
, scale
, precision
);
255 public int compareTo(final ITmfTimestamp ts
, final boolean withinPrecision
) {
257 // Check the corner cases (we can't use equals() because it uses compareTo()...)
261 if (this == ts
|| (fValue
== ts
.getValue() && fScale
== ts
.getScale())) {
264 if ((fValue
== BIG_BANG
.getValue() && fScale
== BIG_BANG
.getScale()) || (ts
.getValue() == BIG_CRUNCH
.getValue() && ts
.getScale() == BIG_CRUNCH
.getScale())) {
267 if ((fValue
== BIG_CRUNCH
.getValue() && fScale
== BIG_CRUNCH
.getScale()) || (ts
.getValue() == BIG_BANG
.getValue() && ts
.getScale() == BIG_BANG
.getScale())) {
272 final ITmfTimestamp nts
= ts
.normalize(0, fScale
);
273 final long delta
= fValue
- nts
.getValue();
274 if ((delta
== 0) || (withinPrecision
&& (Math
.abs(delta
) <= (fPrecision
+ nts
.getPrecision())))) {
277 return (delta
> 0) ?
1 : -1;
279 catch (final ArithmeticException e
) {
280 // Scaling error. We can figure it out nonetheless.
282 // First, look at the sign of the mantissa
283 final long value
= ts
.getValue();
284 if (fValue
== 0 && value
== 0) {
287 if (fValue
< 0 && value
>= 0) {
290 if (fValue
>= 0 && value
< 0) {
294 // Otherwise, just compare the scales
295 final int scale
= ts
.getScale();
296 return (fScale
> scale
) ?
(fValue
>= 0) ?
1 : -1 : (fValue
>= 0) ?
-1 : 1;
301 public ITmfTimestamp
getDelta(final ITmfTimestamp ts
) {
302 final ITmfTimestamp nts
= ts
.normalize(0, fScale
);
303 final long value
= fValue
- nts
.getValue();
304 return new TmfTimestampDelta(value
, fScale
, fPrecision
+ nts
.getPrecision());
308 public boolean intersects(TmfTimeRange range
) {
309 if (this.compareTo(range
.getStartTime()) >= 0 &&
310 this.compareTo(range
.getEndTime()) <= 0) {
316 // ------------------------------------------------------------------------
318 // ------------------------------------------------------------------------
321 public int compareTo(final ITmfTimestamp ts
) {
322 return compareTo(ts
, false);
325 // ------------------------------------------------------------------------
327 // ------------------------------------------------------------------------
330 public int hashCode() {
331 final int prime
= 31;
333 result
= prime
* result
+ (int) (fValue ^
(fValue
>>> 32));
334 result
= prime
* result
+ fScale
;
335 result
= prime
* result
+ fPrecision
;
340 public boolean equals(final Object other
) {
347 if (!(other
instanceof TmfTimestamp
)) {
350 final TmfTimestamp ts
= (TmfTimestamp
) other
;
351 return compareTo(ts
, false) == 0;
355 public String
toString() {
356 return toString(TmfTimestampFormat
.getDefaulTimeFormat());
363 public String
toString(final TmfTimestampFormat format
) {
365 ITmfTimestamp ts
= normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
366 return format
.format(ts
.getValue());
368 catch (ArithmeticException e
) {
369 return format
.format(0);
374 * Write the time stamp to the ByteBuffer so that it can be saved to disk.
375 * @param bufferOut the buffer to write to
379 public void serialize(ByteBuffer bufferOut
) {
380 bufferOut
.putLong(fValue
);
381 bufferOut
.putInt(fScale
);
382 bufferOut
.putInt(fPrecision
);