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
.util
.Arrays
;
16 import java
.util
.List
;
17 import java
.util
.regex
.Pattern
;
19 import org
.eclipse
.core
.runtime
.IStatus
;
20 import org
.eclipse
.jdt
.annotation
.NonNull
;
21 import org
.eclipse
.jdt
.annotation
.Nullable
;
22 import org
.eclipse
.tracecompass
.ctf
.core
.CTFException
;
23 import org
.eclipse
.tracecompass
.ctf
.core
.event
.io
.BitBuffer
;
24 import org
.eclipse
.tracecompass
.ctf
.core
.event
.scope
.IDefinitionScope
;
25 import org
.eclipse
.tracecompass
.ctf
.core
.event
.scope
.ILexicalScope
;
26 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.Activator
;
29 * A CTF structure declaration.
31 * A structure is similar to a C structure, it is a compound data type that
32 * contains other datatypes in fields.
34 * <strong>Note that this implementation is not synchronized.</strong> If
35 * multiple threads access an <tt>StructDeclaration</tt> instance concurrently,
36 * and at least one of the threads modifies the list structurally, by calling
37 * {@link #addField(String, IDeclaration)} it <i>must</i> be synchronized
38 * externally. This is typically not the case though as it would mean modifying
39 * the TSDL/Metadata while reading events.
43 * @author Matthew Khouzam
44 * @author Simon Marchi
46 public class StructDeclaration
extends Declaration
{
48 // ------------------------------------------------------------------------
50 // ------------------------------------------------------------------------
53 private @NonNull String
[] fFieldNames
;
54 /** Field declarations */
55 private @NonNull IDeclaration
[] fFields
;
57 /** maximum bit alignment */
58 private long fMaxAlign
;
60 // ------------------------------------------------------------------------
62 // ------------------------------------------------------------------------
65 * The struct declaration, add fields later
68 * the minimum alignment of the struct. (if a struct is 8bit
69 * aligned and has a 32 bit aligned field, the struct becomes 32
72 public StructDeclaration(long align
) {
73 fMaxAlign
= Math
.max(align
, 1);
74 fFieldNames
= new @NonNull String
[0];
75 fFields
= new @NonNull IDeclaration
[0];
78 // ------------------------------------------------------------------------
79 // Getters/Setters/Predicates
80 // ------------------------------------------------------------------------
83 * Get current alignment
85 * @return the alignment of the struct and all its fields
87 public long getMaxAlign() {
92 * Query if the struct has a given field
95 * the name of the field, scopeless please
96 * @return does the field exist?
98 public boolean hasField(String name
) {
99 return Arrays
.asList(fFieldNames
).contains(name
);
103 * Get the field declaration corresponding to a field name.
107 * @return The declaration of the field, or null if there is no such field.
110 public IDeclaration
getField(String fieldName
) {
111 final int indexOf
= Arrays
.asList(fFieldNames
).indexOf(fieldName
);
115 return fFields
[indexOf
];
119 * Gets the field list.
121 * @return the field list.
123 public @NonNull Iterable
<@NonNull String
> getFieldsList() {
124 return Arrays
.asList(fFieldNames
);
128 public long getAlignment() {
129 return this.fMaxAlign
;
133 public int getMaximumSize() {
135 for (IDeclaration field
: fFields
) {
136 maxSize
+= field
.getMaximumSize();
138 return (int) Math
.min(maxSize
, Integer
.MAX_VALUE
);
141 // ------------------------------------------------------------------------
143 // ------------------------------------------------------------------------
146 public StructDefinition
createDefinition(IDefinitionScope definitionScope
,
147 String fieldName
, BitBuffer input
) throws CTFException
{
149 final Definition
[] myFields
= new Definition
[fFields
.length
];
150 StructDefinition structDefinition
= null;
151 if (definitionScope
== null) {
152 InternalDef localDefinitionScope
= new InternalDef(null, null);
153 structDefinition
= new StructDefinition(this, localDefinitionScope
, fieldName
, myFields
);
154 localDefinitionScope
.setDefinition(structDefinition
);
156 structDefinition
= new StructDefinition(this, definitionScope
, fieldName
, myFields
);
158 fillStruct(input
, myFields
, structDefinition
);
159 return structDefinition
;
163 * Create a definition from this declaration. This is a faster constructor
164 * as it has a lexical scope and this does not need to look it up.
166 * @param definitionScope
167 * the definition scope, the parent where the definition will be
170 * the scope of the definition
172 * a bitbuffer to read from
173 * @return a reference to the definition
174 * @throws CTFException
178 public StructDefinition
createDefinition(IDefinitionScope definitionScope
,
179 ILexicalScope fieldScope
, @NonNull BitBuffer input
) throws CTFException
{
181 final Definition
[] myFields
= new Definition
[fFields
.length
];
183 StructDefinition structDefinition
= new StructDefinition(this, definitionScope
,
184 fieldScope
, fieldScope
.getName(), Arrays
.asList(fFieldNames
), myFields
);
185 fillStruct(input
, myFields
, structDefinition
);
186 return structDefinition
;
190 * Add a field to the struct, will not add a field that is already declared
193 * the name of the field, scopeless
195 * the declaration of the field
197 public void addField(@NonNull String name
, @NonNull IDeclaration declaration
) {
198 if (hasField(name
)) {
199 Activator
.log(IStatus
.WARNING
, "Struct already contains a field named " + name
); //$NON-NLS-1$
203 final int length
= fFieldNames
.length
;
204 @NonNull String
[] names
= Arrays
.copyOf(fFieldNames
, length
+ 1);
205 @NonNull IDeclaration
[] fields
= Arrays
.copyOf(fFields
, length
+ 1);
207 names
[length
] = name
;
208 fields
[length
] = declaration
;
211 fMaxAlign
= Math
.max(fMaxAlign
, declaration
.getAlignment());
214 private void fillStruct(@NonNull BitBuffer input
, final IDefinition
[] myFields
, StructDefinition structDefinition
) throws CTFException
{
215 final @NonNull String
[] fieldNames
= fFieldNames
;
216 final @NonNull IDeclaration
[] fields
= fFields
;
217 for (int i
= 0; i
< fields
.length
; i
++) {
218 /* We should not have inserted null keys... */
219 myFields
[i
] = fields
[i
].createDefinition(structDefinition
, fieldNames
[i
], input
);
224 * Special constructor for fields
226 * @param eventHeaderDef
227 * the event header, used for scopes
228 * @param definitionScope
229 * the definition scope, in this case, the trace
233 * the input {@link BitBuffer}
234 * @return the fields definition
235 * @throws CTFException
236 * something went wrong
239 public StructDefinition
createFieldDefinition(ICompositeDefinition eventHeaderDef
, IDefinitionScope definitionScope
, ILexicalScope fields
, @NonNull BitBuffer input
) throws CTFException
{
241 final Definition
[] myFields
= new Definition
[fFields
.length
];
242 IDefinitionScope merged
= definitionScope
;
243 if (eventHeaderDef
!= null) {
244 merged
= new InternalDef(definitionScope
, eventHeaderDef
);
246 StructDefinition structDefinition
= new StructDefinition(this, merged
,
247 fields
, fields
.getName(), Arrays
.asList(fFieldNames
), myFields
);
248 if (merged
instanceof InternalDef
) {
249 InternalDef internalDef
= (InternalDef
) merged
;
250 internalDef
.setDefinition(structDefinition
);
252 fillStruct(input
, myFields
, structDefinition
);
253 return structDefinition
;
256 private static final Pattern EVENT_HEADER
= Pattern
.compile(ILexicalScope
.EVENT_HEADER
.getPath().replaceAll("\\.", "\\\\.") + "\\."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
258 static class InternalDef
implements IDefinitionScope
{
260 private final ICompositeDefinition fEventHeaderDef
;
261 private final IDefinitionScope fTraceDef
;
262 private StructDefinition fDefinition
;
264 public InternalDef(IDefinitionScope definitionScope
, ICompositeDefinition eventHeaderDef
) {
265 fTraceDef
= definitionScope
;
266 fEventHeaderDef
= eventHeaderDef
;
270 public ILexicalScope
getScopePath() {
271 return ILexicalScope
.EVENT
;
275 public IDefinition
lookupDefinition(String lookupPath
) {
276 IDefinition lookupDefinition
= null;
277 if (fTraceDef
!= null) {
278 lookupDefinition
= fTraceDef
.lookupDefinition(lookupPath
);
280 if (lookupDefinition
== null && fEventHeaderDef
!= null) {
281 String
[] paths
= EVENT_HEADER
.split(lookupPath
);
282 if (paths
.length
> 1) {
283 String
[] childLookup
= paths
[1].split("\\."); //$NON-NLS-1$
284 return getRecursiveDef(fEventHeaderDef
.getDefinition(childLookup
[0]), childLookup
, 1);
286 if (fDefinition
!= null) {
287 return fDefinition
.lookupDefinition(lookupPath
);
290 return lookupDefinition
;
293 public IDefinition
lookupDefinitionBreakLoop(String lookupPath
) {
294 IDefinition lookupDefinition
= null;
295 if (fTraceDef
!= null) {
296 lookupDefinition
= fTraceDef
.lookupDefinition(lookupPath
);
298 if (lookupDefinition
== null) {
299 if (fEventHeaderDef
!= null) {
300 String
[] paths
= EVENT_HEADER
.split(lookupPath
);
301 if (paths
.length
> 1) {
302 String
[] childLookup
= paths
[1].split("\\."); //$NON-NLS-1$
303 return getRecursiveDef(fEventHeaderDef
.getDefinition(childLookup
[0]), childLookup
, 1);
307 return lookupDefinition
;
310 private IDefinition
getRecursiveDef(Definition definition
, String
[] childLookup
, int i
) {
311 if (i
== childLookup
.length
) {
314 if (definition
instanceof ICompositeDefinition
) {
315 ICompositeDefinition compositeDefinition
= (ICompositeDefinition
) definition
;
316 return getRecursiveDef(compositeDefinition
.getDefinition(childLookup
[i
]), childLookup
, i
+ 1);
321 public void setDefinition(StructDefinition definition
) {
322 fDefinition
= definition
;
328 public String
toString() {
329 /* Only used for debugging */
330 StringBuilder sb
= new StringBuilder();
331 sb
.append("[declaration] struct["); //$NON-NLS-1$
332 for (int i
= 0; i
< fFields
.length
; i
++) {
333 sb
.append(fFieldNames
[i
]).append(':').append(fFields
[i
]);
336 return sb
.toString();
340 public int hashCode() {
341 final int prime
= 31;
343 for (int i
= 0; i
< fFields
.length
; i
++) {
344 result
= prime
* result
+ fFieldNames
[i
].hashCode();
345 result
= prime
* result
+ fFields
[i
].hashCode();
347 result
= (prime
* result
) + (int) (fMaxAlign ^
(fMaxAlign
>>> 32));
352 public boolean equals(Object obj
) {
359 if (!(obj
instanceof StructDeclaration
)) {
362 StructDeclaration other
= (StructDeclaration
) obj
;
363 if (fFields
.length
!= other
.fFields
.length
) {
367 List
<String
> localFieldNames
= Arrays
.asList(fFieldNames
);
368 List
<IDeclaration
> localDecs
= Arrays
.asList(fFields
);
369 List
<String
> otherFieldNames
= Arrays
.asList(other
.fFieldNames
);
370 List
<IDeclaration
> otherDecs
= Arrays
.asList(other
.fFields
);
372 // check fields in order
373 for (int i
= 0; i
< fFields
.length
; i
++) {
374 if ((!localFieldNames
.get(i
).equals(otherFieldNames
.get(i
))) ||
375 (!otherDecs
.get(i
).equals(localDecs
.get(i
)))) {
380 if (fMaxAlign
!= other
.fMaxAlign
) {
387 public boolean isBinaryEquivalent(IDeclaration obj
) {
394 if (!(obj
instanceof StructDeclaration
)) {
397 StructDeclaration other
= (StructDeclaration
) obj
;
398 if (fFields
.length
!= other
.fFields
.length
) {
401 List
<IDeclaration
> localDecs
= Arrays
.asList(fFields
);
402 List
<IDeclaration
> otherDecs
= Arrays
.asList(other
.fFields
);
403 for (int i
= 0; i
< fFields
.length
; i
++) {
404 if (!otherDecs
.get(i
).isBinaryEquivalent(localDecs
.get(i
))) {
409 if (fMaxAlign
!= other
.fMaxAlign
) {