Commit | Line | Data |
---|---|---|
8c8bf09f | 1 | /******************************************************************************* |
e73a4ba5 | 2 | * Copyright (c) 2009, 2013 Ericsson, École Polytechnique de Montréal |
f8177ba2 | 3 | * |
8c8bf09f ASL |
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 | |
f8177ba2 | 8 | * |
8c8bf09f | 9 | * Contributors: |
1f506a43 | 10 | * Francois Chouinard - Initial API and implementation |
023761c4 | 11 | * Thomas Gatterweh - Updated scaling / synchronization |
5179fc01 | 12 | * Francois Chouinard - Refactoring to align with TMF Event Model 1.0 |
f8177ba2 | 13 | * Francois Chouinard - Implement augmented interface |
e73a4ba5 | 14 | * Geneviève Bastien - Added copy constructor with new value |
8c8bf09f ASL |
15 | *******************************************************************************/ |
16 | ||
3bd46eef | 17 | package org.eclipse.linuxtools.tmf.core.timestamp; |
8c8bf09f | 18 | |
8c8bf09f | 19 | /** |
b9e37ffd | 20 | * A generic timestamp implementation. The timestamp is represented by the |
d96e9054 FC |
21 | * tuple { value, scale, precision }. By default, timestamps are scaled in |
22 | * seconds. | |
f8177ba2 | 23 | * |
b9e37ffd | 24 | * @author Francois Chouinard |
3bd46eef AM |
25 | * @version 1.1 |
26 | * @since 2.0 | |
8c8bf09f | 27 | */ |
4593bd5b | 28 | public class TmfTimestamp implements ITmfTimestamp { |
8c8bf09f | 29 | |
5179fc01 | 30 | // ------------------------------------------------------------------------ |
8c8bf09f | 31 | // Constants |
5179fc01 | 32 | // ------------------------------------------------------------------------ |
8c8bf09f | 33 | |
d7dbf09a FC |
34 | /** |
35 | * The beginning of time | |
36 | */ | |
085d898f | 37 | public static final ITmfTimestamp BIG_BANG = |
d7dbf09a FC |
38 | new TmfTimestamp(Long.MIN_VALUE, Integer.MAX_VALUE, 0); |
39 | ||
40 | /** | |
41 | * The end of time | |
42 | */ | |
085d898f | 43 | public static final ITmfTimestamp BIG_CRUNCH = |
d7dbf09a | 44 | new TmfTimestamp(Long.MAX_VALUE, Integer.MAX_VALUE, 0); |
085d898f | 45 | |
f8177ba2 FC |
46 | /** |
47 | * A more practical definition of "beginning of time" | |
f8177ba2 FC |
48 | */ |
49 | public static final ITmfTimestamp PROJECT_IS_FUNDED = BIG_BANG; | |
50 | ||
51 | /** | |
52 | * A more practical definition of "end of time" | |
f8177ba2 | 53 | */ |
d96e9054 | 54 | public static final ITmfTimestamp PROJECT_IS_CANNED = BIG_CRUNCH; |
f8177ba2 | 55 | |
d7dbf09a FC |
56 | /** |
57 | * Zero | |
58 | */ | |
085d898f | 59 | public static final ITmfTimestamp ZERO = |
d7dbf09a | 60 | new TmfTimestamp(0, 0, 0); |
5179fc01 FC |
61 | |
62 | // ------------------------------------------------------------------------ | |
63 | // Attributes | |
64 | // ------------------------------------------------------------------------ | |
8c8bf09f | 65 | |
d7dbf09a | 66 | /** |
d96e9054 | 67 | * The timestamp raw value (mantissa) |
d7dbf09a | 68 | */ |
4593bd5b | 69 | private final long fValue; |
d7dbf09a FC |
70 | |
71 | /** | |
72 | * The timestamp scale (magnitude) | |
73 | */ | |
4593bd5b | 74 | private final int fScale; |
d7dbf09a FC |
75 | |
76 | /** | |
77 | * The value precision (tolerance) | |
78 | */ | |
4593bd5b | 79 | private final int fPrecision; |
5179fc01 FC |
80 | |
81 | // ------------------------------------------------------------------------ | |
8c8bf09f | 82 | // Constructors |
5179fc01 | 83 | // ------------------------------------------------------------------------ |
8c8bf09f ASL |
84 | |
85 | /** | |
28b94d61 | 86 | * Default constructor |
8c8bf09f ASL |
87 | */ |
88 | public TmfTimestamp() { | |
f8177ba2 | 89 | this(0, ITmfTimestamp.SECOND_SCALE, 0); |
8c8bf09f ASL |
90 | } |
91 | ||
1f506a43 | 92 | /** |
5179fc01 FC |
93 | * Simple constructor (scale = precision = 0) |
94 | * | |
95 | * @param value the timestamp value | |
1f506a43 | 96 | */ |
085d898f | 97 | public TmfTimestamp(final long value) { |
f8177ba2 | 98 | this(value, ITmfTimestamp.SECOND_SCALE, 0); |
1f506a43 FC |
99 | } |
100 | ||
8c8bf09f | 101 | /** |
5179fc01 | 102 | * Simple constructor (precision = 0) |
f8177ba2 | 103 | * |
5179fc01 FC |
104 | * @param value the timestamp value |
105 | * @param scale the timestamp scale | |
8c8bf09f | 106 | */ |
085d898f | 107 | public TmfTimestamp(final long value, final int scale) { |
8c8bf09f ASL |
108 | this(value, scale, 0); |
109 | } | |
110 | ||
111 | /** | |
5179fc01 | 112 | * Full constructor |
f8177ba2 | 113 | * |
5179fc01 FC |
114 | * @param value the timestamp value |
115 | * @param scale the timestamp scale | |
116 | * @param precision the timestamp precision | |
8c8bf09f | 117 | */ |
085d898f | 118 | public TmfTimestamp(final long value, final int scale, final int precision) { |
8c8bf09f ASL |
119 | fValue = value; |
120 | fScale = scale; | |
121 | fPrecision = Math.abs(precision); | |
122 | } | |
123 | ||
124 | /** | |
28b94d61 | 125 | * Copy constructor |
f8177ba2 | 126 | * |
5179fc01 | 127 | * @param timestamp the timestamp to copy |
8c8bf09f | 128 | */ |
085d898f | 129 | public TmfTimestamp(final ITmfTimestamp timestamp) { |
b9e37ffd | 130 | if (timestamp == null) { |
5179fc01 | 131 | throw new IllegalArgumentException(); |
b9e37ffd | 132 | } |
4df4581d | 133 | fValue = timestamp.getValue(); |
134 | fScale = timestamp.getScale(); | |
135 | fPrecision = timestamp.getPrecision(); | |
8c8bf09f | 136 | } |
e73a4ba5 GB |
137 | |
138 | /** | |
139 | * Copies a timestamp but with a new time value | |
140 | * | |
141 | * @param timestamp | |
142 | * The timestamp to copy | |
143 | * @param newvalue | |
144 | * The value the new timestamp will have | |
145 | * @since 3.0 | |
146 | */ | |
147 | public TmfTimestamp(ITmfTimestamp timestamp, long newvalue) { | |
148 | if (timestamp == null) { | |
149 | throw new IllegalArgumentException(); | |
150 | } | |
151 | fValue = newvalue; | |
152 | fScale = timestamp.getScale(); | |
153 | fPrecision = timestamp.getPrecision(); | |
154 | } | |
8c8bf09f | 155 | |
5179fc01 FC |
156 | // ------------------------------------------------------------------------ |
157 | // ITmfTimestamp | |
158 | // ------------------------------------------------------------------------ | |
8c8bf09f | 159 | |
d7dbf09a | 160 | @Override |
8c8bf09f ASL |
161 | public long getValue() { |
162 | return fValue; | |
163 | } | |
164 | ||
d7dbf09a | 165 | @Override |
5179fc01 | 166 | public int getScale() { |
8c8bf09f ASL |
167 | return fScale; |
168 | } | |
169 | ||
d7dbf09a | 170 | @Override |
5179fc01 | 171 | public int getPrecision() { |
8c8bf09f ASL |
172 | return fPrecision; |
173 | } | |
174 | ||
5179fc01 FC |
175 | private static final long scalingFactors[] = new long[] { |
176 | 1L, | |
177 | 10L, | |
178 | 100L, | |
179 | 1000L, | |
180 | 10000L, | |
181 | 100000L, | |
182 | 1000000L, | |
183 | 10000000L, | |
184 | 100000000L, | |
185 | 1000000000L, | |
186 | 10000000000L, | |
187 | 100000000000L, | |
188 | 1000000000000L, | |
189 | 10000000000000L, | |
190 | 100000000000000L, | |
191 | 1000000000000000L, | |
192 | 10000000000000000L, | |
193 | 100000000000000000L, | |
194 | 1000000000000000000L, | |
195 | }; | |
4ab33d2b | 196 | |
d7dbf09a | 197 | @Override |
0316808c | 198 | public ITmfTimestamp normalize(final long offset, final int scale) { |
8c8bf09f | 199 | |
5179fc01 FC |
200 | long value = fValue; |
201 | int precision = fPrecision; | |
8c8bf09f | 202 | |
5179fc01 | 203 | // Handle the trivial case |
b9e37ffd | 204 | if (fScale == scale && offset == 0) { |
4593bd5b | 205 | return this; |
b9e37ffd | 206 | } |
f8177ba2 FC |
207 | |
208 | // In case of big bang and big crunch just return this (no need to normalize) | |
e461c849 BH |
209 | if (this.equals(BIG_BANG) || this.equals(BIG_CRUNCH)) { |
210 | return this; | |
211 | } | |
5179fc01 FC |
212 | |
213 | // First, scale the timestamp | |
214 | if (fScale != scale) { | |
085d898f | 215 | final int scaleDiff = Math.abs(fScale - scale); |
b9e37ffd | 216 | if (scaleDiff >= scalingFactors.length) { |
3b38ea61 | 217 | throw new ArithmeticException("Scaling exception"); //$NON-NLS-1$ |
b9e37ffd | 218 | } |
5179fc01 | 219 | |
085d898f | 220 | final long scalingFactor = scalingFactors[scaleDiff]; |
5179fc01 FC |
221 | if (scale < fScale) { |
222 | value *= scalingFactor; | |
223 | precision *= scalingFactor; | |
8c8bf09f | 224 | } else { |
5179fc01 FC |
225 | value /= scalingFactor; |
226 | precision /= scalingFactor; | |
8c8bf09f ASL |
227 | } |
228 | } | |
229 | ||
5179fc01 | 230 | // Then, apply the offset |
b9e37ffd | 231 | if (offset < 0) { |
5179fc01 | 232 | value = (value < Long.MIN_VALUE - offset) ? Long.MIN_VALUE : value + offset; |
b9e37ffd | 233 | } else { |
5179fc01 | 234 | value = (value > Long.MAX_VALUE - offset) ? Long.MAX_VALUE : value + offset; |
b9e37ffd | 235 | } |
023761c4 | 236 | |
5179fc01 | 237 | return new TmfTimestamp(value, scale, precision); |
8c8bf09f ASL |
238 | } |
239 | ||
d7dbf09a | 240 | @Override |
085d898f | 241 | public int compareTo(final ITmfTimestamp ts, final boolean withinPrecision) { |
023761c4 | 242 | |
5179fc01 | 243 | // Check the corner cases (we can't use equals() because it uses compareTo()...) |
b9e37ffd FC |
244 | if (ts == null) { |
245 | return 1; | |
246 | } | |
247 | if (this == ts || (fValue == ts.getValue() && fScale == ts.getScale())) { | |
5179fc01 | 248 | return 0; |
b9e37ffd FC |
249 | } |
250 | if ((fValue == BIG_BANG.getValue() && fScale == BIG_BANG.getScale()) || (ts.getValue() == BIG_CRUNCH.getValue() && ts.getScale() == BIG_CRUNCH.getScale())) { | |
5179fc01 | 251 | return -1; |
b9e37ffd FC |
252 | } |
253 | if ((fValue == BIG_CRUNCH.getValue() && fScale == BIG_CRUNCH.getScale()) || (ts.getValue() == BIG_BANG.getValue() && ts.getScale() == BIG_BANG.getScale())) { | |
5179fc01 | 254 | return 1; |
b9e37ffd | 255 | } |
085d898f | 256 | |
5179fc01 | 257 | try { |
085d898f FC |
258 | final ITmfTimestamp nts = ts.normalize(0, fScale); |
259 | final long delta = fValue - nts.getValue(); | |
b9e37ffd | 260 | if ((delta == 0) || (withinPrecision && (Math.abs(delta) <= (fPrecision + nts.getPrecision())))) { |
5179fc01 | 261 | return 0; |
b9e37ffd | 262 | } |
5179fc01 FC |
263 | return (delta > 0) ? 1 : -1; |
264 | } | |
085d898f | 265 | catch (final ArithmeticException e) { |
5179fc01 FC |
266 | // Scaling error. We can figure it out nonetheless. |
267 | ||
268 | // First, look at the sign of the mantissa | |
085d898f | 269 | final long value = ts.getValue(); |
b9e37ffd | 270 | if (fValue == 0 && value == 0) { |
5179fc01 | 271 | return 0; |
b9e37ffd FC |
272 | } |
273 | if (fValue < 0 && value >= 0) { | |
5179fc01 | 274 | return -1; |
b9e37ffd FC |
275 | } |
276 | if (fValue >= 0 && value < 0) { | |
5179fc01 | 277 | return 1; |
b9e37ffd | 278 | } |
5179fc01 FC |
279 | |
280 | // Otherwise, just compare the scales | |
085d898f FC |
281 | final int scale = ts.getScale(); |
282 | return (fScale > scale) ? (fValue >= 0) ? 1 : -1 : (fValue >= 0) ? -1 : 1; | |
5179fc01 | 283 | } |
8c8bf09f ASL |
284 | } |
285 | ||
5179fc01 | 286 | @Override |
085d898f FC |
287 | public ITmfTimestamp getDelta(final ITmfTimestamp ts) { |
288 | final ITmfTimestamp nts = ts.normalize(0, fScale); | |
289 | final long value = fValue - nts.getValue(); | |
a9ee1687 | 290 | return new TmfTimestampDelta(value, fScale, fPrecision + nts.getPrecision()); |
73005152 BH |
291 | } |
292 | ||
1de55ea2 AM |
293 | @Override |
294 | public boolean intersects(TmfTimeRange range) { | |
295 | if (this.compareTo(range.getStartTime()) >= 0 && | |
296 | this.compareTo(range.getEndTime()) <= 0) { | |
297 | return true; | |
298 | } | |
299 | return false; | |
300 | } | |
301 | ||
5179fc01 FC |
302 | // ------------------------------------------------------------------------ |
303 | // Comparable | |
304 | // ------------------------------------------------------------------------ | |
023761c4 | 305 | |
5179fc01 | 306 | @Override |
085d898f | 307 | public int compareTo(final ITmfTimestamp ts) { |
4df4581d | 308 | return compareTo(ts, false); |
5179fc01 | 309 | } |
f3a4c7f4 | 310 | |
5179fc01 | 311 | // ------------------------------------------------------------------------ |
cbd4ad82 | 312 | // Object |
5179fc01 | 313 | // ------------------------------------------------------------------------ |
28b94d61 | 314 | |
8c8bf09f | 315 | @Override |
cbd4ad82 | 316 | public int hashCode() { |
5179fc01 FC |
317 | final int prime = 31; |
318 | int result = 1; | |
319 | result = prime * result + (int) (fValue ^ (fValue >>> 32)); | |
320 | result = prime * result + fScale; | |
321 | result = prime * result + fPrecision; | |
cbd4ad82 FC |
322 | return result; |
323 | } | |
324 | ||
5179fc01 | 325 | @Override |
085d898f | 326 | public boolean equals(final Object other) { |
b9e37ffd | 327 | if (this == other) { |
5179fc01 | 328 | return true; |
b9e37ffd FC |
329 | } |
330 | if (other == null) { | |
5179fc01 | 331 | return false; |
b9e37ffd FC |
332 | } |
333 | if (!(other instanceof TmfTimestamp)) { | |
5179fc01 | 334 | return false; |
b9e37ffd | 335 | } |
085d898f | 336 | final TmfTimestamp ts = (TmfTimestamp) other; |
5179fc01 | 337 | return compareTo(ts, false) == 0; |
8c8bf09f ASL |
338 | } |
339 | ||
1f506a43 FC |
340 | @Override |
341 | public String toString() { | |
f8177ba2 FC |
342 | return toString(TmfTimestampFormat.getDefaulTimeFormat()); |
343 | } | |
344 | ||
f8177ba2 FC |
345 | /** |
346 | * @since 2.0 | |
347 | */ | |
348 | @Override | |
349 | public String toString(final TmfTimestampFormat format) { | |
350 | try { | |
351 | ITmfTimestamp ts = normalize(0, ITmfTimestamp.NANOSECOND_SCALE); | |
352 | return format.format(ts.getValue()); | |
353 | } | |
354 | catch (ArithmeticException e) { | |
355 | return format.format(0); | |
356 | } | |
ff4ed569 FC |
357 | } |
358 | ||
023761c4 | 359 | } |