ctf: preserve byte order if explicitly set in a typedef
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / ctf / core / event / types / EnumDeclaration.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
3 *
4 * All rights reserved. This program and the accompanying materials are made
5 * 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: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.ctf.core.event.types;
14
15 import java.nio.ByteOrder;
16 import java.util.Collections;
17 import java.util.HashSet;
18 import java.util.LinkedList;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.eclipse.tracecompass.ctf.core.CTFException;
25 import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
26 import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;
27
28 import com.google.common.collect.ImmutableMap;
29
30 /**
31 * A CTF enum declaration.
32 *
33 * The definition of a enum point basic data type. It will take the data from a
34 * trace and store it (and make it fit) as an integer and a string.
35 *
36 * @version 1.0
37 * @author Matthew Khouzam
38 * @author Simon Marchi
39 */
40 public final class EnumDeclaration extends Declaration implements ISimpleDatatypeDeclaration {
41
42 /**
43 * A pair of longs class
44 *
45 * @since 1.1
46 */
47 public static class Pair {
48 private final long fFirst;
49 private final long fSecond;
50
51 private Pair(long first, long second) {
52 fFirst = first;
53 fSecond = second;
54 }
55
56 /**
57 * @return the first element
58 */
59 public long getFirst() {
60 return fFirst;
61 }
62
63 /**
64 * @return the second element
65 */
66 public long getSecond() {
67 return fSecond;
68 }
69 }
70
71 // ------------------------------------------------------------------------
72 // Attributes
73 // ------------------------------------------------------------------------
74
75 private final EnumTable fTable = new EnumTable();
76 private final IntegerDeclaration fContainerType;
77 private final Set<String> fLabels = new HashSet<>();
78
79 // ------------------------------------------------------------------------
80 // Constructors
81 // ------------------------------------------------------------------------
82
83 /**
84 * constructor
85 *
86 * @param containerType
87 * the enum is an int, this is the type that the data is
88 * contained in. If you have 1000 possible values, you need at
89 * least a 10 bit enum. If you store 2 values in a 128 bit int,
90 * you are wasting space.
91 */
92 public EnumDeclaration(IntegerDeclaration containerType) {
93 fContainerType = containerType;
94 }
95
96 // ------------------------------------------------------------------------
97 // Getters/Setters/Predicates
98 // ------------------------------------------------------------------------
99
100 /**
101 *
102 * @return The container type
103 */
104 public IntegerDeclaration getContainerType() {
105 return fContainerType;
106 }
107
108 @Override
109 public long getAlignment() {
110 return this.getContainerType().getAlignment();
111 }
112
113 @Override
114 public int getMaximumSize() {
115 return fContainerType.getMaximumSize();
116 }
117
118 /**
119 * @since 2.0
120 */
121 @Override
122 public boolean isByteOrderSet() {
123 return fContainerType.isByteOrderSet();
124 }
125
126 /**
127 * @since 2.0
128 */
129 @Override
130 public ByteOrder getByteOrder() {
131 return fContainerType.getByteOrder();
132 }
133
134 // ------------------------------------------------------------------------
135 // Operations
136 // ------------------------------------------------------------------------
137
138 @Override
139 public EnumDefinition createDefinition(@Nullable IDefinitionScope definitionScope, String fieldName, BitBuffer input) throws CTFException {
140 alignRead(input);
141 IntegerDefinition value = getContainerType().createDefinition(definitionScope, fieldName, input);
142 return new EnumDefinition(this, definitionScope, fieldName, value);
143 }
144
145 /**
146 * Add a value. Do not overlap, this is <em><strong>not</strong></em> an
147 * interval tree.
148 *
149 * @param low
150 * lowest value that this int can be to have label as a return
151 * string
152 * @param high
153 * highest value that this int can be to have label as a return
154 * string
155 * @param label
156 * the name of the value.
157 * @return was the value be added? true == success
158 */
159 public boolean add(long low, long high, @Nullable String label) {
160 fLabels.add(label);
161 return fTable.add(low, high, label);
162 }
163
164 /**
165 * Check if the label for a value (enum a{day=0,night=1} would return "day"
166 * for query(0)
167 *
168 * @param value
169 * the value to lookup
170 * @return the label of that value, can be null
171 */
172 public @Nullable String query(long value) {
173 return fTable.query(value);
174 }
175
176 /**
177 * Get the lookup table
178 *
179 * @return the lookup table
180 * @since 1.1
181 */
182 public Map<String, Pair> getEnumTable() {
183 ImmutableMap.Builder<String, Pair> builder = new ImmutableMap.Builder<>();
184 for (LabelAndRange range : fTable.ranges) {
185 builder.put(range.getLabel(), new Pair(range.low, range.high));
186 }
187 return builder.build();
188
189 }
190
191 /**
192 * Gets a set of labels of the enum
193 *
194 * @return A set of labels of the enum, can be empty but not null
195 */
196 public Set<String> getLabels() {
197 return Collections.unmodifiableSet(fLabels);
198 }
199
200 /*
201 * Maps integer range -> string. A simple list for now, but feel free to
202 * optimize it. Babeltrace suggests an interval tree.
203 */
204 private class EnumTable {
205
206 private final List<LabelAndRange> ranges = new LinkedList<>();
207
208 public EnumTable() {
209 }
210
211 public synchronized boolean add(long low, long high, @Nullable String label) {
212 LabelAndRange newRange = new LabelAndRange(low, high, label);
213
214 for (LabelAndRange r : ranges) {
215 if (r.intersects(newRange)) {
216 return false;
217 }
218 }
219
220 ranges.add(newRange);
221
222 return true;
223 }
224
225 /**
226 * Return the first label that matches a value
227 *
228 * @param value
229 * the value to query
230 * @return the label corresponding to that value
231 */
232 public synchronized @Nullable String query(long value) {
233 for (LabelAndRange r : ranges) {
234 if (r.intersects(value)) {
235 return r.getLabel();
236 }
237 }
238 return null;
239 }
240
241 @Override
242 public synchronized int hashCode() {
243 final int prime = 31;
244 int result = 1;
245 for (LabelAndRange range : ranges) {
246 result = prime * result + range.hashCode();
247 }
248 return result;
249 }
250
251 @Override
252 public synchronized boolean equals(@Nullable Object obj) {
253 if (this == obj) {
254 return true;
255 }
256 if (obj == null) {
257 return false;
258 }
259 if (getClass() != obj.getClass()) {
260 return false;
261 }
262 EnumTable other = (EnumTable) obj;
263 if (ranges.size() != other.ranges.size()) {
264 return false;
265 }
266 for (int i = 0; i < ranges.size(); i++) {
267 if (!ranges.get(i).equals(other.ranges.get(i))) {
268 return false;
269 }
270 }
271 return true;
272 }
273
274 }
275
276 private static class LabelAndRange {
277
278 private final long low, high;
279 private final @Nullable String fLabel;
280
281 /**
282 * Get the label
283 *
284 * @return the label
285 */
286 public @Nullable String getLabel() {
287 return fLabel;
288 }
289
290 public LabelAndRange(long low, long high, @Nullable String str) {
291 this.low = low;
292 this.high = high;
293 this.fLabel = str;
294 }
295
296 public boolean intersects(long i) {
297 return (i >= this.low) && (i <= this.high);
298 }
299
300 public boolean intersects(LabelAndRange other) {
301 return this.intersects(other.low)
302 || this.intersects(other.high);
303 }
304
305 @Override
306 public int hashCode() {
307 final int prime = 31;
308 int result = 1;
309 final String label = fLabel;
310 result = prime * result + ((label == null) ? 0 : label.hashCode());
311 result = prime * result + (int) (high ^ (high >>> 32));
312 result = prime * result + (int) (low ^ (low >>> 32));
313 return result;
314 }
315
316 @Override
317 public boolean equals(@Nullable Object obj) {
318 if (this == obj) {
319 return true;
320 }
321 if (obj == null) {
322 return false;
323 }
324 if (getClass() != obj.getClass()) {
325 return false;
326 }
327 LabelAndRange other = (LabelAndRange) obj;
328 final String label = fLabel;
329 if (label == null) {
330 if (other.fLabel != null) {
331 return false;
332 }
333 } else if (!label.equals(other.fLabel)) {
334 return false;
335 }
336 if (high != other.high) {
337 return false;
338 }
339 if (low != other.low) {
340 return false;
341 }
342 return true;
343 }
344 }
345
346 @Override
347 public String toString() {
348 /* Only used for debugging */
349 StringBuilder sb = new StringBuilder();
350 sb.append("[declaration] enum["); //$NON-NLS-1$
351 for (String label : fLabels) {
352 sb.append("label:").append(label).append(' '); //$NON-NLS-1$
353 }
354 sb.append("type:").append(fContainerType.toString()); //$NON-NLS-1$
355 sb.append(']');
356 String string = sb.toString();
357 return string;
358 }
359
360 @Override
361 public int hashCode() {
362 final int prime = 31;
363 int result = prime + fContainerType.hashCode();
364 for (String label : fLabels) {
365 result = prime * result + label.hashCode();
366 }
367 result = prime * result + fTable.hashCode();
368 return result;
369 }
370
371 @Override
372 public boolean equals(@Nullable Object obj) {
373 if (this == obj) {
374 return true;
375 }
376 if (obj == null) {
377 return false;
378 }
379 if (getClass() != obj.getClass()) {
380 return false;
381 }
382 EnumDeclaration other = (EnumDeclaration) obj;
383 if (!fContainerType.equals(other.fContainerType)) {
384 return false;
385 }
386 if (fLabels.size() != other.fLabels.size()) {
387 return false;
388 }
389 if (!fLabels.containsAll(other.fLabels)) {
390 return false;
391 }
392 if (!fTable.equals(other.fTable)) {
393 return false;
394 }
395 return true;
396 }
397
398 @Override
399 public boolean isBinaryEquivalent(@Nullable IDeclaration obj) {
400 if (this == obj) {
401 return true;
402 }
403 if (obj == null) {
404 return false;
405 }
406 if (getClass() != obj.getClass()) {
407 return false;
408 }
409 EnumDeclaration other = (EnumDeclaration) obj;
410 if (!fContainerType.isBinaryEquivalent(other.fContainerType)) {
411 return false;
412 }
413 if (fLabels.size() != other.fLabels.size()) {
414 return false;
415 }
416 if (!fLabels.containsAll(other.fLabels)) {
417 return false;
418 }
419 if (!fTable.equals(other.fTable)) {
420 return false;
421 }
422 return true;
423 }
424
425 }
This page took 0.092169 seconds and 5 git commands to generate.