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