1 /*******************************************************************************
2 * Copyright (c) 2009, 2014 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, 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 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.tmf
.core
.timestamp
;
18 import java
.nio
.ByteBuffer
;
20 import org
.eclipse
.jdt
.annotation
.NonNull
;
23 * A generic timestamp implementation. The timestamp is represented by the
24 * tuple { value, scale, precision }. By default, timestamps are scaled in
27 * @author Francois Chouinard
30 public class TmfTimestamp
implements ITmfTimestamp
{
32 // ------------------------------------------------------------------------
34 // ------------------------------------------------------------------------
37 * The beginning of time
39 public static final @NonNull ITmfTimestamp BIG_BANG
=
40 new TmfTimestamp(Long
.MIN_VALUE
, Integer
.MAX_VALUE
);
45 public static final @NonNull ITmfTimestamp BIG_CRUNCH
=
46 new TmfTimestamp(Long
.MAX_VALUE
, Integer
.MAX_VALUE
);
51 public static final @NonNull ITmfTimestamp ZERO
=
52 new TmfTimestamp(0, 0);
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
59 * The timestamp raw value (mantissa)
61 private final long fValue
;
64 * The timestamp scale (magnitude)
66 private final int fScale
;
68 // ------------------------------------------------------------------------
70 // ------------------------------------------------------------------------
75 public TmfTimestamp() {
76 this(0, ITmfTimestamp
.SECOND_SCALE
);
80 * Simple constructor (scale = 0)
85 public TmfTimestamp(final long value
) {
86 this(value
, ITmfTimestamp
.SECOND_SCALE
);
97 public TmfTimestamp(final long value
, final int scale
) {
106 * the timestamp to copy
108 public TmfTimestamp(final ITmfTimestamp timestamp
) {
109 if (timestamp
== null) {
110 throw new IllegalArgumentException();
112 fValue
= timestamp
.getValue();
113 fScale
= timestamp
.getScale();
117 * Copies a timestamp but with a new time value
120 * The timestamp to copy
122 * The value the new timestamp will have
125 public TmfTimestamp(ITmfTimestamp timestamp
, long newvalue
) {
126 if (timestamp
== null) {
127 throw new IllegalArgumentException();
130 fScale
= timestamp
.getScale();
133 // ------------------------------------------------------------------------
135 // ------------------------------------------------------------------------
138 * Construct the timestamp from the ByteBuffer.
141 * the buffer to read from
145 public TmfTimestamp(ByteBuffer bufferIn
) {
146 this(bufferIn
.getLong(), bufferIn
.getInt());
150 public long getValue() {
155 public int getScale() {
159 private static final long scalingFactors
[] = new long[] {
178 1000000000000000000L,
182 public ITmfTimestamp
normalize(final long offset
, final int scale
) {
186 // Handle the trivial case
187 if (fScale
== scale
&& offset
== 0) {
191 // In case of big bang and big crunch just return this (no need to normalize)
192 if (this.equals(BIG_BANG
) || this.equals(BIG_CRUNCH
)) {
196 // First, scale the timestamp
197 if (fScale
!= scale
) {
198 final int scaleDiff
= Math
.abs(fScale
- scale
);
199 if (scaleDiff
>= scalingFactors
.length
) {
200 throw new ArithmeticException("Scaling exception"); //$NON-NLS-1$
203 final long scalingFactor
= scalingFactors
[scaleDiff
];
204 if (scale
< fScale
) {
205 value
*= scalingFactor
;
207 value
/= scalingFactor
;
211 // Then, apply the offset
213 value
= (value
< Long
.MIN_VALUE
- offset
) ? Long
.MIN_VALUE
: value
+ offset
;
215 value
= (value
> Long
.MAX_VALUE
- offset
) ? Long
.MAX_VALUE
: value
+ offset
;
218 return new TmfTimestamp(value
, scale
);
222 public ITmfTimestamp
getDelta(final ITmfTimestamp ts
) {
223 final ITmfTimestamp nts
= ts
.normalize(0, fScale
);
224 final long value
= fValue
- nts
.getValue();
225 return new TmfTimestampDelta(value
, fScale
);
229 public boolean intersects(TmfTimeRange range
) {
230 if (this.compareTo(range
.getStartTime()) >= 0 &&
231 this.compareTo(range
.getEndTime()) <= 0) {
237 // ------------------------------------------------------------------------
239 // ------------------------------------------------------------------------
242 public int compareTo(final ITmfTimestamp ts
) {
243 // Check the corner cases (we can't use equals() because it uses compareTo()...)
247 if (this == ts
|| (fValue
== ts
.getValue() && fScale
== ts
.getScale())) {
250 if ((fValue
== BIG_BANG
.getValue() && fScale
== BIG_BANG
.getScale()) || (ts
.getValue() == BIG_CRUNCH
.getValue() && ts
.getScale() == BIG_CRUNCH
.getScale())) {
253 if ((fValue
== BIG_CRUNCH
.getValue() && fScale
== BIG_CRUNCH
.getScale()) || (ts
.getValue() == BIG_BANG
.getValue() && ts
.getScale() == BIG_BANG
.getScale())) {
258 final ITmfTimestamp nts
= ts
.normalize(0, fScale
);
259 final long delta
= fValue
- nts
.getValue();
260 return Long
.compare(delta
, 0);
262 catch (final ArithmeticException e
) {
263 // Scaling error. We can figure it out nonetheless.
265 // First, look at the sign of the mantissa
266 final long value
= ts
.getValue();
267 if (fValue
== 0 && value
== 0) {
270 if (fValue
< 0 && value
>= 0) {
273 if (fValue
>= 0 && value
< 0) {
277 // Otherwise, just compare the scales
278 final int scale
= ts
.getScale();
279 return (fScale
> scale
) ?
(fValue
>= 0) ?
1 : -1 : (fValue
>= 0) ?
-1 : 1;
283 // ------------------------------------------------------------------------
285 // ------------------------------------------------------------------------
288 public int hashCode() {
289 final int prime
= 31;
291 result
= prime
* result
+ (int) (fValue ^
(fValue
>>> 32));
292 result
= prime
* result
+ fScale
;
297 public boolean equals(final Object other
) {
304 if (!(other
instanceof ITmfTimestamp
)) {
307 /* We allow comparing with other types of *I*TmfTimestamp though */
308 final ITmfTimestamp ts
= (ITmfTimestamp
) other
;
309 return (compareTo(ts
) == 0);
313 public String
toString() {
314 return toString(TmfTimestampFormat
.getDefaulTimeFormat());
321 public String
toString(final TmfTimestampFormat format
) {
323 ITmfTimestamp ts
= normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
324 return format
.format(ts
.getValue());
326 catch (ArithmeticException e
) {
327 return format
.format(0);
332 * Write the time stamp to the ByteBuffer so that it can be saved to disk.
333 * @param bufferOut the buffer to write to
337 public void serialize(ByteBuffer bufferOut
) {
338 bufferOut
.putLong(fValue
);
339 bufferOut
.putInt(fScale
);