1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
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
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.ctf
.core
.event
.types
;
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
;
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
;
28 import com
.google
.common
.collect
.ImmutableMap
;
31 * A CTF enum declaration.
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.
37 * @author Matthew Khouzam
38 * @author Simon Marchi
40 public final class EnumDeclaration
extends Declaration
implements ISimpleDatatypeDeclaration
{
43 * A pair of longs class
47 public static class Pair
{
48 private final long fFirst
;
49 private final long fSecond
;
51 private Pair(long first
, long second
) {
57 * @return the first element
59 public long getFirst() {
64 * @return the second element
66 public long getSecond() {
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
75 private final EnumTable fTable
= new EnumTable();
76 private final IntegerDeclaration fContainerType
;
77 private final Set
<String
> fLabels
= new HashSet
<>();
79 // ------------------------------------------------------------------------
81 // ------------------------------------------------------------------------
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.
92 public EnumDeclaration(IntegerDeclaration containerType
) {
93 fContainerType
= containerType
;
96 // ------------------------------------------------------------------------
97 // Getters/Setters/Predicates
98 // ------------------------------------------------------------------------
102 * @return The container type
104 public IntegerDeclaration
getContainerType() {
105 return fContainerType
;
109 public long getAlignment() {
110 return this.getContainerType().getAlignment();
114 public int getMaximumSize() {
115 return fContainerType
.getMaximumSize();
122 public boolean isByteOrderSet() {
123 return fContainerType
.isByteOrderSet();
130 public ByteOrder
getByteOrder() {
131 return fContainerType
.getByteOrder();
134 // ------------------------------------------------------------------------
136 // ------------------------------------------------------------------------
139 public EnumDefinition
createDefinition(@Nullable IDefinitionScope definitionScope
, String fieldName
, BitBuffer input
) throws CTFException
{
141 IntegerDefinition value
= getContainerType().createDefinition(definitionScope
, fieldName
, input
);
142 return new EnumDefinition(this, definitionScope
, fieldName
, value
);
146 * Add a value. Do not overlap, this is <em><strong>not</strong></em> an
150 * lowest value that this int can be to have label as a return
153 * highest value that this int can be to have label as a return
156 * the name of the value.
157 * @return was the value be added? true == success
159 public boolean add(long low
, long high
, @Nullable String label
) {
161 return fTable
.add(low
, high
, label
);
165 * Add a value. Do not overlap, this is <em><strong>not</strong></em> an
166 * interval tree. This could be seen more as a collection of segments.
169 * the name of the value.
170 * @return was the value be added? true == success
173 public boolean add(@Nullable String label
) {
175 return fTable
.add(label
);
179 * Check if the label for a value (enum a{day=0,night=1} would return "day"
183 * the value to lookup
184 * @return the label of that value, can be null
186 public @Nullable String
query(long value
) {
187 return fTable
.query(value
);
191 * Get the lookup table
193 * @return the lookup table
196 public Map
<String
, Pair
> getEnumTable() {
197 ImmutableMap
.Builder
<String
, Pair
> builder
= new ImmutableMap
.Builder
<>();
198 for (LabelAndRange range
: fTable
.ranges
) {
199 builder
.put(range
.getLabel(), new Pair(range
.low
, range
.high
));
201 return builder
.build();
206 * Gets a set of labels of the enum
208 * @return A set of labels of the enum, can be empty but not null
210 public Set
<String
> getLabels() {
211 return Collections
.unmodifiableSet(fLabels
);
215 * Maps integer range -> string. A simple list for now, but feel free to
216 * optimize it. Babeltrace suggests an interval tree.
218 private class EnumTable
{
220 private final List
<LabelAndRange
> ranges
= new LinkedList
<>();
225 public synchronized boolean add(@Nullable String label
) {
226 LabelAndRange lastAdded
= ranges
.isEmpty() ?
new LabelAndRange(-1, -1, "") : ranges
.get(ranges
.size() - 1); //$NON-NLS-1$
227 return add(lastAdded
.low
+ 1, lastAdded
.high
+ 1, label
);
230 public synchronized boolean add(long low
, long high
, @Nullable String label
) {
231 LabelAndRange newRange
= new LabelAndRange(low
, high
, label
);
233 for (LabelAndRange r
: ranges
) {
234 if (r
.intersects(newRange
)) {
239 ranges
.add(newRange
);
245 * Return the first label that matches a value
249 * @return the label corresponding to that value
251 public synchronized @Nullable String
query(long value
) {
252 for (LabelAndRange r
: ranges
) {
253 if (r
.intersects(value
)) {
261 public synchronized int hashCode() {
262 final int prime
= 31;
264 for (LabelAndRange range
: ranges
) {
265 result
= prime
* result
+ range
.hashCode();
271 public synchronized boolean equals(@Nullable Object obj
) {
278 if (getClass() != obj
.getClass()) {
281 EnumTable other
= (EnumTable
) obj
;
282 if (ranges
.size() != other
.ranges
.size()) {
285 for (int i
= 0; i
< ranges
.size(); i
++) {
286 if (!ranges
.get(i
).equals(other
.ranges
.get(i
))) {
295 private static class LabelAndRange
{
297 private final long low
, high
;
298 private final @Nullable String fLabel
;
305 public @Nullable String
getLabel() {
309 public LabelAndRange(long low
, long high
, @Nullable String str
) {
315 public boolean intersects(long i
) {
316 return (i
>= this.low
) && (i
<= this.high
);
319 public boolean intersects(LabelAndRange other
) {
320 return this.intersects(other
.low
)
321 || this.intersects(other
.high
);
325 public int hashCode() {
326 final int prime
= 31;
328 final String label
= fLabel
;
329 result
= prime
* result
+ ((label
== null) ?
0 : label
.hashCode());
330 result
= prime
* result
+ (int) (high ^
(high
>>> 32));
331 result
= prime
* result
+ (int) (low ^
(low
>>> 32));
336 public boolean equals(@Nullable Object obj
) {
343 if (getClass() != obj
.getClass()) {
346 LabelAndRange other
= (LabelAndRange
) obj
;
347 final String label
= fLabel
;
349 if (other
.fLabel
!= null) {
352 } else if (!label
.equals(other
.fLabel
)) {
355 if (high
!= other
.high
) {
358 if (low
!= other
.low
) {
366 public String
toString() {
367 /* Only used for debugging */
368 StringBuilder sb
= new StringBuilder();
369 sb
.append("[declaration] enum["); //$NON-NLS-1$
370 for (String label
: fLabels
) {
371 sb
.append("label:").append(label
).append(' '); //$NON-NLS-1$
373 sb
.append("type:").append(fContainerType
.toString()); //$NON-NLS-1$
375 return sb
.toString();
379 public int hashCode() {
380 final int prime
= 31;
381 int result
= prime
+ fContainerType
.hashCode();
382 for (String label
: fLabels
) {
383 result
= prime
* result
+ label
.hashCode();
385 result
= prime
* result
+ fTable
.hashCode();
390 public boolean equals(@Nullable Object obj
) {
397 if (getClass() != obj
.getClass()) {
400 EnumDeclaration other
= (EnumDeclaration
) obj
;
401 if (!fContainerType
.equals(other
.fContainerType
)) {
404 if (fLabels
.size() != other
.fLabels
.size()) {
407 if (!fLabels
.containsAll(other
.fLabels
)) {
410 if (!fTable
.equals(other
.fTable
)) {
417 public boolean isBinaryEquivalent(@Nullable IDeclaration obj
) {
424 if (getClass() != obj
.getClass()) {
427 EnumDeclaration other
= (EnumDeclaration
) obj
;
428 if (!fContainerType
.isBinaryEquivalent(other
.fContainerType
)) {
431 if (fLabels
.size() != other
.fLabels
.size()) {
434 if (!fLabels
.containsAll(other
.fLabels
)) {
437 if (!fTable
.equals(other
.fTable
)) {