1 /*******************************************************************************
2 * Copyright (c) 2009, 2013 Ericsson
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 *******************************************************************************/
16 package org
.eclipse
.linuxtools
.tmf
.core
.timestamp
;
19 * A generic timestamp implementation. The timestamp is represented by the
20 * tuple { value, scale, precision }. By default, timestamps are scaled in
23 * @author Francois Chouinard
27 public class TmfTimestamp
implements ITmfTimestamp
{
29 // ------------------------------------------------------------------------
31 // ------------------------------------------------------------------------
34 * The beginning of time
36 public static final ITmfTimestamp BIG_BANG
=
37 new TmfTimestamp(Long
.MIN_VALUE
, Integer
.MAX_VALUE
, 0);
42 public static final ITmfTimestamp BIG_CRUNCH
=
43 new TmfTimestamp(Long
.MAX_VALUE
, Integer
.MAX_VALUE
, 0);
46 * A more practical definition of "beginning of time"
48 public static final ITmfTimestamp PROJECT_IS_FUNDED
= BIG_BANG
;
51 * A more practical definition of "end of time"
53 public static final ITmfTimestamp PROJECT_IS_CANNED
= BIG_CRUNCH
;
58 public static final ITmfTimestamp ZERO
=
59 new TmfTimestamp(0, 0, 0);
61 // ------------------------------------------------------------------------
63 // ------------------------------------------------------------------------
66 * The timestamp raw value (mantissa)
68 private final long fValue
;
71 * The timestamp scale (magnitude)
73 private final int fScale
;
76 * The value precision (tolerance)
78 private final int fPrecision
;
80 // ------------------------------------------------------------------------
82 // ------------------------------------------------------------------------
87 public TmfTimestamp() {
88 this(0, ITmfTimestamp
.SECOND_SCALE
, 0);
92 * Simple constructor (scale = precision = 0)
94 * @param value the timestamp value
96 public TmfTimestamp(final long value
) {
97 this(value
, ITmfTimestamp
.SECOND_SCALE
, 0);
101 * Simple constructor (precision = 0)
103 * @param value the timestamp value
104 * @param scale the timestamp scale
106 public TmfTimestamp(final long value
, final int scale
) {
107 this(value
, scale
, 0);
113 * @param value the timestamp value
114 * @param scale the timestamp scale
115 * @param precision the timestamp precision
117 public TmfTimestamp(final long value
, final int scale
, final int precision
) {
120 fPrecision
= Math
.abs(precision
);
126 * @param timestamp the timestamp to copy
128 public TmfTimestamp(final ITmfTimestamp timestamp
) {
129 if (timestamp
== null) {
130 throw new IllegalArgumentException();
132 fValue
= timestamp
.getValue();
133 fScale
= timestamp
.getScale();
134 fPrecision
= timestamp
.getPrecision();
137 // ------------------------------------------------------------------------
139 // ------------------------------------------------------------------------
142 public long getValue() {
147 public int getScale() {
152 public int getPrecision() {
156 private static final long scalingFactors
[] = new long[] {
175 1000000000000000000L,
179 public ITmfTimestamp
normalize(final long offset
, final int scale
) {
182 int precision
= fPrecision
;
184 // Handle the trivial case
185 if (fScale
== scale
&& offset
== 0) {
189 // In case of big bang and big crunch just return this (no need to normalize)
190 if (this.equals(BIG_BANG
) || this.equals(BIG_CRUNCH
)) {
194 // First, scale the timestamp
195 if (fScale
!= scale
) {
196 final int scaleDiff
= Math
.abs(fScale
- scale
);
197 if (scaleDiff
>= scalingFactors
.length
) {
198 throw new ArithmeticException("Scaling exception"); //$NON-NLS-1$
201 final long scalingFactor
= scalingFactors
[scaleDiff
];
202 if (scale
< fScale
) {
203 value
*= scalingFactor
;
204 precision
*= scalingFactor
;
206 value
/= scalingFactor
;
207 precision
/= 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
, precision
);
222 public int compareTo(final ITmfTimestamp ts
, final boolean withinPrecision
) {
224 // Check the corner cases (we can't use equals() because it uses compareTo()...)
228 if (this == ts
|| (fValue
== ts
.getValue() && fScale
== ts
.getScale())) {
231 if ((fValue
== BIG_BANG
.getValue() && fScale
== BIG_BANG
.getScale()) || (ts
.getValue() == BIG_CRUNCH
.getValue() && ts
.getScale() == BIG_CRUNCH
.getScale())) {
234 if ((fValue
== BIG_CRUNCH
.getValue() && fScale
== BIG_CRUNCH
.getScale()) || (ts
.getValue() == BIG_BANG
.getValue() && ts
.getScale() == BIG_BANG
.getScale())) {
239 final ITmfTimestamp nts
= ts
.normalize(0, fScale
);
240 final long delta
= fValue
- nts
.getValue();
241 if ((delta
== 0) || (withinPrecision
&& (Math
.abs(delta
) <= (fPrecision
+ nts
.getPrecision())))) {
244 return (delta
> 0) ?
1 : -1;
246 catch (final ArithmeticException e
) {
247 // Scaling error. We can figure it out nonetheless.
249 // First, look at the sign of the mantissa
250 final long value
= ts
.getValue();
251 if (fValue
== 0 && value
== 0) {
254 if (fValue
< 0 && value
>= 0) {
257 if (fValue
>= 0 && value
< 0) {
261 // Otherwise, just compare the scales
262 final int scale
= ts
.getScale();
263 return (fScale
> scale
) ?
(fValue
>= 0) ?
1 : -1 : (fValue
>= 0) ?
-1 : 1;
268 public ITmfTimestamp
getDelta(final ITmfTimestamp ts
) {
269 final ITmfTimestamp nts
= ts
.normalize(0, fScale
);
270 final long value
= fValue
- nts
.getValue();
271 return new TmfTimestampDelta(value
, fScale
, fPrecision
+ nts
.getPrecision());
275 public boolean intersects(TmfTimeRange range
) {
276 if (this.compareTo(range
.getStartTime()) >= 0 &&
277 this.compareTo(range
.getEndTime()) <= 0) {
283 // ------------------------------------------------------------------------
285 // ------------------------------------------------------------------------
288 public int compareTo(final ITmfTimestamp ts
) {
289 return compareTo(ts
, false);
292 // ------------------------------------------------------------------------
294 // ------------------------------------------------------------------------
297 public int hashCode() {
298 final int prime
= 31;
300 result
= prime
* result
+ (int) (fValue ^
(fValue
>>> 32));
301 result
= prime
* result
+ fScale
;
302 result
= prime
* result
+ fPrecision
;
307 public boolean equals(final Object other
) {
314 if (!(other
instanceof TmfTimestamp
)) {
317 final TmfTimestamp ts
= (TmfTimestamp
) other
;
318 return compareTo(ts
, false) == 0;
322 public String
toString() {
323 return toString(TmfTimestampFormat
.getDefaulTimeFormat());
330 public String
toString(final TmfTimestampFormat format
) {
332 ITmfTimestamp ts
= normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
333 return format
.format(ts
.getValue());
335 catch (ArithmeticException e
) {
336 return format
.format(0);