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