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
29 public class TmfTimestamp
implements ITmfTimestamp
{
31 // ------------------------------------------------------------------------
33 // ------------------------------------------------------------------------
36 * The beginning of time
38 public static final @NonNull ITmfTimestamp BIG_BANG
=
39 new TmfTimestamp(Long
.MIN_VALUE
, Integer
.MAX_VALUE
);
44 public static final @NonNull ITmfTimestamp BIG_CRUNCH
=
45 new TmfTimestamp(Long
.MAX_VALUE
, Integer
.MAX_VALUE
);
50 public static final @NonNull ITmfTimestamp ZERO
=
51 new TmfTimestamp(0, 0);
53 // ------------------------------------------------------------------------
55 // ------------------------------------------------------------------------
58 * The timestamp raw value (mantissa)
60 private final long fValue
;
63 * The timestamp scale (magnitude)
65 private final int fScale
;
67 // ------------------------------------------------------------------------
69 // ------------------------------------------------------------------------
74 public TmfTimestamp() {
75 this(0, ITmfTimestamp
.SECOND_SCALE
);
79 * Simple constructor (scale = 0)
84 public TmfTimestamp(final long value
) {
85 this(value
, ITmfTimestamp
.SECOND_SCALE
);
96 public TmfTimestamp(final long value
, final int scale
) {
105 * the timestamp to copy
107 public TmfTimestamp(final ITmfTimestamp timestamp
) {
108 if (timestamp
== null) {
109 throw new IllegalArgumentException();
111 fValue
= timestamp
.getValue();
112 fScale
= timestamp
.getScale();
116 * Copies a timestamp but with a new time value
119 * The timestamp to copy
121 * The value the new timestamp will have
123 public TmfTimestamp(ITmfTimestamp timestamp
, long newvalue
) {
124 if (timestamp
== null) {
125 throw new IllegalArgumentException();
128 fScale
= timestamp
.getScale();
131 // ------------------------------------------------------------------------
133 // ------------------------------------------------------------------------
136 * Construct the timestamp from the ByteBuffer.
139 * the buffer to read from
141 public TmfTimestamp(ByteBuffer bufferIn
) {
142 this(bufferIn
.getLong(), bufferIn
.getInt());
146 public long getValue() {
151 public int getScale() {
155 private static final long scalingFactors
[] = new long[] {
174 1000000000000000000L,
178 public ITmfTimestamp
normalize(final long offset
, final int scale
) {
182 // Handle the trivial case
183 if (fScale
== scale
&& offset
== 0) {
187 // In case of big bang and big crunch just return this (no need to normalize)
188 if (this.equals(BIG_BANG
) || this.equals(BIG_CRUNCH
)) {
192 // First, scale the timestamp
193 if (fScale
!= scale
) {
194 final int scaleDiff
= Math
.abs(fScale
- scale
);
195 if (scaleDiff
>= scalingFactors
.length
) {
196 throw new ArithmeticException("Scaling exception"); //$NON-NLS-1$
199 final long scalingFactor
= scalingFactors
[scaleDiff
];
200 if (scale
< fScale
) {
201 value
*= scalingFactor
;
203 value
/= scalingFactor
;
207 // Then, apply the offset
209 value
= (value
< Long
.MIN_VALUE
- offset
) ? Long
.MIN_VALUE
: value
+ offset
;
211 value
= (value
> Long
.MAX_VALUE
- offset
) ? Long
.MAX_VALUE
: value
+ offset
;
214 return new TmfTimestamp(value
, scale
);
218 public ITmfTimestamp
getDelta(final ITmfTimestamp ts
) {
219 final ITmfTimestamp nts
= ts
.normalize(0, fScale
);
220 final long value
= fValue
- nts
.getValue();
221 return new TmfTimestampDelta(value
, fScale
);
225 public boolean intersects(TmfTimeRange range
) {
226 if (this.compareTo(range
.getStartTime()) >= 0 &&
227 this.compareTo(range
.getEndTime()) <= 0) {
233 // ------------------------------------------------------------------------
235 // ------------------------------------------------------------------------
238 public int compareTo(final ITmfTimestamp ts
) {
239 // Check the corner cases (we can't use equals() because it uses compareTo()...)
243 if (this == ts
|| (fValue
== ts
.getValue() && fScale
== ts
.getScale())) {
246 if ((fValue
== BIG_BANG
.getValue() && fScale
== BIG_BANG
.getScale()) || (ts
.getValue() == BIG_CRUNCH
.getValue() && ts
.getScale() == BIG_CRUNCH
.getScale())) {
249 if ((fValue
== BIG_CRUNCH
.getValue() && fScale
== BIG_CRUNCH
.getScale()) || (ts
.getValue() == BIG_BANG
.getValue() && ts
.getScale() == BIG_BANG
.getScale())) {
254 final ITmfTimestamp nts
= ts
.normalize(0, fScale
);
255 final long delta
= fValue
- nts
.getValue();
256 return Long
.compare(delta
, 0);
258 catch (final ArithmeticException e
) {
259 // Scaling error. We can figure it out nonetheless.
261 // First, look at the sign of the mantissa
262 final long value
= ts
.getValue();
263 if (fValue
== 0 && value
== 0) {
266 if (fValue
< 0 && value
>= 0) {
269 if (fValue
>= 0 && value
< 0) {
273 // Otherwise, just compare the scales
274 final int scale
= ts
.getScale();
275 return (fScale
> scale
) ?
(fValue
>= 0) ?
1 : -1 : (fValue
>= 0) ?
-1 : 1;
279 // ------------------------------------------------------------------------
281 // ------------------------------------------------------------------------
284 public int hashCode() {
285 final int prime
= 31;
287 result
= prime
* result
+ (int) (fValue ^
(fValue
>>> 32));
288 result
= prime
* result
+ fScale
;
293 public boolean equals(final Object other
) {
300 if (!(other
instanceof ITmfTimestamp
)) {
303 /* We allow comparing with other types of *I*TmfTimestamp though */
304 final ITmfTimestamp ts
= (ITmfTimestamp
) other
;
305 return (compareTo(ts
) == 0);
309 public String
toString() {
310 return toString(TmfTimestampFormat
.getDefaulTimeFormat());
314 public String
toString(final TmfTimestampFormat format
) {
316 ITmfTimestamp ts
= normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
317 return format
.format(ts
.getValue());
319 catch (ArithmeticException e
) {
320 return format
.format(0);
325 * Write the time stamp to the ByteBuffer so that it can be saved to disk.
326 * @param bufferOut the buffer to write to
328 public void serialize(ByteBuffer bufferOut
) {
329 bufferOut
.putLong(fValue
);
330 bufferOut
.putInt(fScale
);