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 static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import java
.util
.ArrayList
;
18 import java
.util
.Iterator
;
19 import java
.util
.LinkedHashMap
;
20 import java
.util
.List
;
22 import java
.util
.Map
.Entry
;
23 import java
.util
.regex
.Pattern
;
25 import org
.eclipse
.jdt
.annotation
.NonNull
;
26 import org
.eclipse
.jdt
.annotation
.Nullable
;
27 import org
.eclipse
.tracecompass
.ctf
.core
.CTFException
;
28 import org
.eclipse
.tracecompass
.ctf
.core
.event
.io
.BitBuffer
;
29 import org
.eclipse
.tracecompass
.ctf
.core
.event
.scope
.IDefinitionScope
;
30 import org
.eclipse
.tracecompass
.ctf
.core
.event
.scope
.ILexicalScope
;
33 * A CTF structure declaration.
35 * A structure is similar to a C structure, it is a compound data type that
36 * contains other datatypes in fields. they are stored in an hashmap and indexed
37 * by names which are strings.
40 * @author Matthew Khouzam
41 * @author Simon Marchi
43 public class StructDeclaration
extends Declaration
{
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
49 /** linked list of field names. So fieldName->fieldValue */
50 private final @NonNull Map
<String
, IDeclaration
> fFieldMap
= new LinkedHashMap
<>();
52 /** maximum bit alignment */
53 private long fMaxAlign
;
55 // ------------------------------------------------------------------------
57 // ------------------------------------------------------------------------
60 * The struct declaration, add fields later
63 * the minimum alignment of the struct. (if a struct is 8bit
64 * aligned and has a 32 bit aligned field, the struct becomes 32
67 public StructDeclaration(long align
) {
68 fMaxAlign
= Math
.max(align
, 1);
71 // ------------------------------------------------------------------------
72 // Getters/Setters/Predicates
73 // ------------------------------------------------------------------------
76 * Get current alignment
78 * @return the alignment of the struct and all its fields
80 public long getMaxAlign() {
85 * Query if the struct has a given field
88 * the name of the field, scopeless please
89 * @return does the field exist?
91 public boolean hasField(String name
) {
92 return fFieldMap
.containsKey(name
);
96 * Get the fields of the struct as a map.
98 * @return a Map of the fields (key is the name)
100 public Map
<String
, IDeclaration
> getFields() {
105 * Get the field declaration corresponding to a field name.
109 * @return The declaration of the field, or null if there is no such field.
112 public IDeclaration
getField(String fieldName
) {
113 return fFieldMap
.get(fieldName
);
117 * Gets the field list. Very important since the map of fields does not
118 * retain the order of the fields.
120 * @return the field list.
122 public Iterable
<String
> getFieldsList() {
123 return fFieldMap
.keySet();
127 public long getAlignment() {
128 return this.fMaxAlign
;
132 public int getMaximumSize() {
134 for (IDeclaration field
: fFieldMap
.values()) {
135 maxSize
+= field
.getMaximumSize();
137 return Math
.min(maxSize
, Integer
.MAX_VALUE
);
140 // ------------------------------------------------------------------------
142 // ------------------------------------------------------------------------
145 public StructDefinition
createDefinition(IDefinitionScope definitionScope
,
146 String fieldName
, BitBuffer input
) throws CTFException
{
148 final Definition
[] myFields
= new Definition
[fFieldMap
.size()];
149 StructDefinition structDefinition
= null;
150 if (definitionScope
== null) {
151 InternalDef localDefinitionScope
= new InternalDef(null, null);
152 structDefinition
= new StructDefinition(this, localDefinitionScope
, fieldName
, myFields
);
153 localDefinitionScope
.setDefinition(structDefinition
);
155 structDefinition
= new StructDefinition(this, definitionScope
, fieldName
, myFields
);
157 fillStruct(input
, myFields
, structDefinition
);
158 return structDefinition
;
162 * Create a definition from this declaration. This is a faster constructor
163 * as it has a lexical scope and this does not need to look it up.
165 * @param definitionScope
166 * the definition scope, the parent where the definition will be
169 * the scope of the definition
171 * a bitbuffer to read from
172 * @return a reference to the definition
173 * @throws CTFException
177 public StructDefinition
createDefinition(IDefinitionScope definitionScope
,
178 ILexicalScope fieldScope
, @NonNull BitBuffer input
) throws CTFException
{
180 final Definition
[] myFields
= new Definition
[fFieldMap
.size()];
182 StructDefinition structDefinition
= new StructDefinition(this, definitionScope
,
183 fieldScope
, fieldScope
.getName(), checkNotNull(fFieldMap
.keySet()), myFields
);
184 fillStruct(input
, myFields
, structDefinition
);
185 return structDefinition
;
189 * Add a field to the struct
192 * the name of the field, scopeless
194 * the declaration of the field
196 public void addField(String name
, IDeclaration declaration
) {
197 fFieldMap
.put(name
, declaration
);
198 fMaxAlign
= Math
.max(fMaxAlign
, declaration
.getAlignment());
201 private void fillStruct(@NonNull BitBuffer input
, final Definition
[] myFields
, StructDefinition structDefinition
) throws CTFException
{
202 Iterator
<Map
.Entry
<String
, IDeclaration
>> iter
= fFieldMap
.entrySet().iterator();
203 for (int i
= 0; i
< fFieldMap
.size(); i
++) {
204 Map
.Entry
<String
, IDeclaration
> entry
= iter
.next();
205 /* We should not have inserted null keys... */
206 String key
= checkNotNull(entry
.getKey());
207 myFields
[i
] = entry
.getValue().createDefinition(structDefinition
, key
, input
);
212 * Special constructor for fields
214 * @param eventHeaderDef
215 * the event header, used for scopes
216 * @param definitionScope
217 * the definition scope, in this case, the trace
221 * the input {@link BitBuffer}
222 * @return the fields definition
223 * @throws CTFException
224 * something went wrong
227 public StructDefinition
createFieldDefinition(ICompositeDefinition eventHeaderDef
, IDefinitionScope definitionScope
, ILexicalScope fields
, @NonNull BitBuffer input
) throws CTFException
{
229 final Definition
[] myFields
= new Definition
[fFieldMap
.size()];
230 IDefinitionScope merged
= definitionScope
;
231 if (eventHeaderDef
!= null) {
232 merged
= new InternalDef(definitionScope
, eventHeaderDef
);
234 StructDefinition structDefinition
= new StructDefinition(this, merged
,
235 fields
, fields
.getName(), checkNotNull(fFieldMap
.keySet()), myFields
);
236 if (merged
instanceof InternalDef
) {
237 InternalDef internalDef
= (InternalDef
) merged
;
238 internalDef
.setDefinition(structDefinition
);
240 fillStruct(input
, myFields
, structDefinition
);
241 return structDefinition
;
244 private static final Pattern EVENT_HEADER
= Pattern
.compile(ILexicalScope
.EVENT_HEADER
.getPath().replaceAll("\\.", "\\\\.") + "\\."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
246 static class InternalDef
implements IDefinitionScope
{
248 private final ICompositeDefinition fEventHeaderDef
;
249 private final IDefinitionScope fTraceDef
;
250 private StructDefinition fDefinition
;
252 public InternalDef(IDefinitionScope definitionScope
, ICompositeDefinition eventHeaderDef
) {
253 fTraceDef
= definitionScope
;
254 fEventHeaderDef
= eventHeaderDef
;
258 public ILexicalScope
getScopePath() {
259 return ILexicalScope
.EVENT
;
263 public IDefinition
lookupDefinition(String lookupPath
) {
264 IDefinition lookupDefinition
= null;
265 if (fTraceDef
!= null) {
266 lookupDefinition
= fTraceDef
.lookupDefinition(lookupPath
);
268 if (lookupDefinition
== null) {
269 if (fEventHeaderDef
!= null) {
270 String
[] paths
= EVENT_HEADER
.split(lookupPath
);
271 if (paths
.length
> 1) {
272 String
[] childLookup
= paths
[1].split("\\."); //$NON-NLS-1$
273 return getRecursiveDef(fEventHeaderDef
.getDefinition(childLookup
[0]), childLookup
, 1);
275 if (fDefinition
!= null) {
276 return fDefinition
.lookupDefinition(lookupPath
);
280 return lookupDefinition
;
283 public IDefinition
lookupDefinitionBreakLoop(String lookupPath
) {
284 IDefinition lookupDefinition
= null;
285 if (fTraceDef
!= null) {
286 lookupDefinition
= fTraceDef
.lookupDefinition(lookupPath
);
288 if (lookupDefinition
== null) {
289 if (fEventHeaderDef
!= null) {
290 String
[] paths
= EVENT_HEADER
.split(lookupPath
);
291 if (paths
.length
> 1) {
292 String
[] childLookup
= paths
[1].split("\\."); //$NON-NLS-1$
293 return getRecursiveDef(fEventHeaderDef
.getDefinition(childLookup
[0]), childLookup
, 1);
297 return lookupDefinition
;
300 private IDefinition
getRecursiveDef(Definition definition
, String
[] childLookup
, int i
) {
301 if (i
== childLookup
.length
) {
304 if (definition
instanceof ICompositeDefinition
) {
305 ICompositeDefinition compositeDefinition
= (ICompositeDefinition
) definition
;
306 return getRecursiveDef(compositeDefinition
.getDefinition(childLookup
[i
]), childLookup
, i
+ 1);
311 public void setDefinition(StructDefinition definition
) {
312 fDefinition
= definition
;
318 public String
toString() {
319 /* Only used for debugging */
320 StringBuilder sb
= new StringBuilder();
321 sb
.append("[declaration] struct["); //$NON-NLS-1$
322 for (Entry
<String
, IDeclaration
> field
: fFieldMap
.entrySet()) {
323 sb
.append(field
.getKey()).append(':').append(field
.getValue());
326 return sb
.toString();
330 public int hashCode() {
331 final int prime
= 31;
333 for (Entry
<String
, IDeclaration
> field
: fFieldMap
.entrySet()) {
334 result
= prime
* result
+ field
.getKey().hashCode();
335 result
= prime
* result
+ field
.getValue().hashCode();
337 result
= (prime
* result
) + (int) (fMaxAlign ^
(fMaxAlign
>>> 32));
342 public boolean equals(Object obj
) {
349 if (!(obj
instanceof StructDeclaration
)) {
352 StructDeclaration other
= (StructDeclaration
) obj
;
353 if (fFieldMap
.size() != other
.fFieldMap
.size()) {
357 List
<String
> localFieldNames
= new ArrayList
<>();
358 localFieldNames
.addAll(fFieldMap
.keySet());
360 List
<IDeclaration
> localDecs
= new ArrayList
<>();
361 localDecs
.addAll(fFieldMap
.values());
363 List
<String
> otherFieldNames
= new ArrayList
<>();
364 otherFieldNames
.addAll(other
.fFieldMap
.keySet());
366 List
<IDeclaration
> otherDecs
= new ArrayList
<>();
367 otherDecs
.addAll(other
.fFieldMap
.values());
369 // check fields in order
370 for (int i
= 0; i
< fFieldMap
.size(); i
++) {
371 if ((!localFieldNames
.get(i
).equals(otherFieldNames
.get(i
))) ||
372 (!otherDecs
.get(i
).equals(localDecs
.get(i
)))) {
377 if (fMaxAlign
!= other
.fMaxAlign
) {
384 public boolean isBinaryEquivalent(IDeclaration obj
) {
391 if (!(obj
instanceof StructDeclaration
)) {
394 StructDeclaration other
= (StructDeclaration
) obj
;
395 if (fFieldMap
.size() != other
.fFieldMap
.size()) {
398 List
<IDeclaration
> localDecs
= new ArrayList
<>();
399 localDecs
.addAll(fFieldMap
.values());
400 List
<IDeclaration
> otherDecs
= new ArrayList
<>();
401 otherDecs
.addAll(other
.fFieldMap
.values());
402 for (int i
= 0; i
< fFieldMap
.size(); i
++) {
403 if (!otherDecs
.get(i
).isBinaryEquivalent(localDecs
.get(i
))) {
408 if (fMaxAlign
!= other
.fMaxAlign
) {