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