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
<@NonNull 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 field declaration corresponding to a field name.
100 * @return The declaration of the field, or null if there is no such field.
103 public IDeclaration
getField(String fieldName
) {
104 return fFieldMap
.get(fieldName
);
108 * Gets the field list. Very important since the map of fields does not
109 * retain the order of the fields.
111 * @return the field list.
113 public @NonNull Iterable
<@NonNull String
> getFieldsList() {
114 return fFieldMap
.keySet();
118 public long getAlignment() {
119 return this.fMaxAlign
;
123 public int getMaximumSize() {
125 for (IDeclaration field
: fFieldMap
.values()) {
126 maxSize
+= field
.getMaximumSize();
128 return Math
.min(maxSize
, Integer
.MAX_VALUE
);
131 // ------------------------------------------------------------------------
133 // ------------------------------------------------------------------------
136 public StructDefinition
createDefinition(IDefinitionScope definitionScope
,
137 String fieldName
, BitBuffer input
) throws CTFException
{
139 final Definition
[] myFields
= new Definition
[fFieldMap
.size()];
140 StructDefinition structDefinition
= null;
141 if (definitionScope
== null) {
142 InternalDef localDefinitionScope
= new InternalDef(null, null);
143 structDefinition
= new StructDefinition(this, localDefinitionScope
, fieldName
, myFields
);
144 localDefinitionScope
.setDefinition(structDefinition
);
146 structDefinition
= new StructDefinition(this, definitionScope
, fieldName
, myFields
);
148 fillStruct(input
, myFields
, structDefinition
);
149 return structDefinition
;
153 * Create a definition from this declaration. This is a faster constructor
154 * as it has a lexical scope and this does not need to look it up.
156 * @param definitionScope
157 * the definition scope, the parent where the definition will be
160 * the scope of the definition
162 * a bitbuffer to read from
163 * @return a reference to the definition
164 * @throws CTFException
168 public StructDefinition
createDefinition(IDefinitionScope definitionScope
,
169 ILexicalScope fieldScope
, @NonNull BitBuffer input
) throws CTFException
{
171 final Definition
[] myFields
= new Definition
[fFieldMap
.size()];
173 StructDefinition structDefinition
= new StructDefinition(this, definitionScope
,
174 fieldScope
, fieldScope
.getName(), checkNotNull(fFieldMap
.keySet()), myFields
);
175 fillStruct(input
, myFields
, structDefinition
);
176 return structDefinition
;
180 * Add a field to the struct
183 * the name of the field, scopeless
185 * the declaration of the field
187 public void addField(@NonNull String name
, @NonNull IDeclaration declaration
) {
188 fFieldMap
.put(name
, declaration
);
189 fMaxAlign
= Math
.max(fMaxAlign
, declaration
.getAlignment());
192 private void fillStruct(@NonNull BitBuffer input
, final Definition
[] myFields
, StructDefinition structDefinition
) throws CTFException
{
193 Iterator
<Map
.Entry
<String
, IDeclaration
>> iter
= fFieldMap
.entrySet().iterator();
194 for (int i
= 0; i
< fFieldMap
.size(); i
++) {
195 Map
.Entry
<String
, IDeclaration
> entry
= iter
.next();
196 /* We should not have inserted null keys... */
197 String key
= checkNotNull(entry
.getKey());
198 myFields
[i
] = entry
.getValue().createDefinition(structDefinition
, key
, input
);
203 * Special constructor for fields
205 * @param eventHeaderDef
206 * the event header, used for scopes
207 * @param definitionScope
208 * the definition scope, in this case, the trace
212 * the input {@link BitBuffer}
213 * @return the fields definition
214 * @throws CTFException
215 * something went wrong
218 public StructDefinition
createFieldDefinition(ICompositeDefinition eventHeaderDef
, IDefinitionScope definitionScope
, ILexicalScope fields
, @NonNull BitBuffer input
) throws CTFException
{
220 final Definition
[] myFields
= new Definition
[fFieldMap
.size()];
221 IDefinitionScope merged
= definitionScope
;
222 if (eventHeaderDef
!= null) {
223 merged
= new InternalDef(definitionScope
, eventHeaderDef
);
225 StructDefinition structDefinition
= new StructDefinition(this, merged
,
226 fields
, fields
.getName(), checkNotNull(fFieldMap
.keySet()), myFields
);
227 if (merged
instanceof InternalDef
) {
228 InternalDef internalDef
= (InternalDef
) merged
;
229 internalDef
.setDefinition(structDefinition
);
231 fillStruct(input
, myFields
, structDefinition
);
232 return structDefinition
;
235 private static final Pattern EVENT_HEADER
= Pattern
.compile(ILexicalScope
.EVENT_HEADER
.getPath().replaceAll("\\.", "\\\\.") + "\\."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
237 static class InternalDef
implements IDefinitionScope
{
239 private final ICompositeDefinition fEventHeaderDef
;
240 private final IDefinitionScope fTraceDef
;
241 private StructDefinition fDefinition
;
243 public InternalDef(IDefinitionScope definitionScope
, ICompositeDefinition eventHeaderDef
) {
244 fTraceDef
= definitionScope
;
245 fEventHeaderDef
= eventHeaderDef
;
249 public ILexicalScope
getScopePath() {
250 return ILexicalScope
.EVENT
;
254 public IDefinition
lookupDefinition(String lookupPath
) {
255 IDefinition lookupDefinition
= null;
256 if (fTraceDef
!= null) {
257 lookupDefinition
= fTraceDef
.lookupDefinition(lookupPath
);
259 if (lookupDefinition
== null && fEventHeaderDef
!= null) {
260 String
[] paths
= EVENT_HEADER
.split(lookupPath
);
261 if (paths
.length
> 1) {
262 String
[] childLookup
= paths
[1].split("\\."); //$NON-NLS-1$
263 return getRecursiveDef(fEventHeaderDef
.getDefinition(childLookup
[0]), childLookup
, 1);
265 if (fDefinition
!= null) {
266 return fDefinition
.lookupDefinition(lookupPath
);
269 return lookupDefinition
;
272 public IDefinition
lookupDefinitionBreakLoop(String lookupPath
) {
273 IDefinition lookupDefinition
= null;
274 if (fTraceDef
!= null) {
275 lookupDefinition
= fTraceDef
.lookupDefinition(lookupPath
);
277 if (lookupDefinition
== null) {
278 if (fEventHeaderDef
!= null) {
279 String
[] paths
= EVENT_HEADER
.split(lookupPath
);
280 if (paths
.length
> 1) {
281 String
[] childLookup
= paths
[1].split("\\."); //$NON-NLS-1$
282 return getRecursiveDef(fEventHeaderDef
.getDefinition(childLookup
[0]), childLookup
, 1);
286 return lookupDefinition
;
289 private IDefinition
getRecursiveDef(Definition definition
, String
[] childLookup
, int i
) {
290 if (i
== childLookup
.length
) {
293 if (definition
instanceof ICompositeDefinition
) {
294 ICompositeDefinition compositeDefinition
= (ICompositeDefinition
) definition
;
295 return getRecursiveDef(compositeDefinition
.getDefinition(childLookup
[i
]), childLookup
, i
+ 1);
300 public void setDefinition(StructDefinition definition
) {
301 fDefinition
= definition
;
307 public String
toString() {
308 /* Only used for debugging */
309 StringBuilder sb
= new StringBuilder();
310 sb
.append("[declaration] struct["); //$NON-NLS-1$
311 for (Entry
<String
, IDeclaration
> field
: fFieldMap
.entrySet()) {
312 sb
.append(field
.getKey()).append(':').append(field
.getValue());
315 return sb
.toString();
319 public int hashCode() {
320 final int prime
= 31;
322 for (Entry
<String
, IDeclaration
> field
: fFieldMap
.entrySet()) {
323 result
= prime
* result
+ field
.getKey().hashCode();
324 result
= prime
* result
+ field
.getValue().hashCode();
326 result
= (prime
* result
) + (int) (fMaxAlign ^
(fMaxAlign
>>> 32));
331 public boolean equals(Object obj
) {
338 if (!(obj
instanceof StructDeclaration
)) {
341 StructDeclaration other
= (StructDeclaration
) obj
;
342 if (fFieldMap
.size() != other
.fFieldMap
.size()) {
346 List
<String
> localFieldNames
= new ArrayList
<>();
347 localFieldNames
.addAll(fFieldMap
.keySet());
349 List
<IDeclaration
> localDecs
= new ArrayList
<>();
350 localDecs
.addAll(fFieldMap
.values());
352 List
<String
> otherFieldNames
= new ArrayList
<>();
353 otherFieldNames
.addAll(other
.fFieldMap
.keySet());
355 List
<IDeclaration
> otherDecs
= new ArrayList
<>();
356 otherDecs
.addAll(other
.fFieldMap
.values());
358 // check fields in order
359 for (int i
= 0; i
< fFieldMap
.size(); i
++) {
360 if ((!localFieldNames
.get(i
).equals(otherFieldNames
.get(i
))) ||
361 (!otherDecs
.get(i
).equals(localDecs
.get(i
)))) {
366 if (fMaxAlign
!= other
.fMaxAlign
) {
373 public boolean isBinaryEquivalent(IDeclaration obj
) {
380 if (!(obj
instanceof StructDeclaration
)) {
383 StructDeclaration other
= (StructDeclaration
) obj
;
384 if (fFieldMap
.size() != other
.fFieldMap
.size()) {
387 List
<IDeclaration
> localDecs
= new ArrayList
<>();
388 localDecs
.addAll(fFieldMap
.values());
389 List
<IDeclaration
> otherDecs
= new ArrayList
<>();
390 otherDecs
.addAll(other
.fFieldMap
.values());
391 for (int i
= 0; i
< fFieldMap
.size(); i
++) {
392 if (!otherDecs
.get(i
).isBinaryEquivalent(localDecs
.get(i
))) {
397 if (fMaxAlign
!= other
.fMaxAlign
) {