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