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