ctf: Replace StructDeclaration map with an array
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / ctf / core / event / types / StructDeclaration.java
CommitLineData
866e5b51 1/*******************************************************************************
60ae41e1 2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
866e5b51
FC
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
f357bcd4 13package org.eclipse.tracecompass.ctf.core.event.types;
866e5b51 14
ba95ec1f 15import java.util.Arrays;
e00e6663 16import java.util.List;
94c255ef 17import java.util.regex.Pattern;
866e5b51 18
ba95ec1f 19import org.eclipse.core.runtime.IStatus;
a4fa4e36 20import org.eclipse.jdt.annotation.NonNull;
2db699c2 21import org.eclipse.jdt.annotation.Nullable;
680f9173 22import org.eclipse.tracecompass.ctf.core.CTFException;
f357bcd4
AM
23import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
24import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;
fbe6fa6f 25import org.eclipse.tracecompass.ctf.core.event.scope.ILexicalScope;
ba95ec1f 26import org.eclipse.tracecompass.internal.ctf.core.Activator;
a4fa4e36 27
866e5b51 28/**
d37aaa7f 29 * A CTF structure declaration.
77fdc5df 30 *
d37aaa7f 31 * A structure is similar to a C structure, it is a compound data type that
ba95ec1f
MK
32 * contains other datatypes in fields.
33 * <p>
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.
40 * <p>
d37aaa7f
FC
41 *
42 * @version 1.0
43 * @author Matthew Khouzam
44 * @author Simon Marchi
866e5b51 45 */
a4fa4e36 46public class StructDeclaration extends Declaration {
866e5b51
FC
47
48 // ------------------------------------------------------------------------
49 // Attributes
50 // ------------------------------------------------------------------------
51
ba95ec1f
MK
52 /** Field names */
53 private @NonNull String[] fFieldNames;
54 /** Field declarations */
55 private @NonNull IDeclaration[] fFields;
a4fa4e36
MK
56
57 /** maximum bit alignment */
58 private long fMaxAlign;
866e5b51
FC
59
60 // ------------------------------------------------------------------------
61 // Constructors
62 // ------------------------------------------------------------------------
63
9ac2eb62
MK
64 /**
65 * The struct declaration, add fields later
66 *
67 * @param align
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
70 * bit aligned.
71 */
2b7f6f09 72 public StructDeclaration(long align) {
a4fa4e36 73 fMaxAlign = Math.max(align, 1);
ba95ec1f
MK
74 fFieldNames = new @NonNull String[0];
75 fFields = new @NonNull IDeclaration[0];
a4fa4e36
MK
76 }
77
866e5b51
FC
78 // ------------------------------------------------------------------------
79 // Getters/Setters/Predicates
80 // ------------------------------------------------------------------------
81
9ac2eb62
MK
82 /**
83 * Get current alignment
a4fa4e36 84 *
9ac2eb62
MK
85 * @return the alignment of the struct and all its fields
86 */
2b7f6f09 87 public long getMaxAlign() {
a4fa4e36 88 return fMaxAlign;
866e5b51
FC
89 }
90
9ac2eb62
MK
91 /**
92 * Query if the struct has a given field
a4fa4e36
MK
93 *
94 * @param name
95 * the name of the field, scopeless please
9ac2eb62
MK
96 * @return does the field exist?
97 */
866e5b51 98 public boolean hasField(String name) {
ba95ec1f 99 return Arrays.asList(fFieldNames).contains(name);
866e5b51
FC
100 }
101
2db699c2
AM
102 /**
103 * Get the field declaration corresponding to a field name.
104 *
105 * @param fieldName
106 * The field name
107 * @return The declaration of the field, or null if there is no such field.
2db699c2
AM
108 */
109 @Nullable
110 public IDeclaration getField(String fieldName) {
ba95ec1f
MK
111 final int indexOf = Arrays.asList(fFieldNames).indexOf(fieldName);
112 if (indexOf == -1) {
113 return null;
114 }
115 return fFields[indexOf];
2db699c2
AM
116 }
117
9ac2eb62 118 /**
ba95ec1f 119 * Gets the field list.
a4fa4e36 120 *
9ac2eb62
MK
121 * @return the field list.
122 */
367e2932 123 public @NonNull Iterable<@NonNull String> getFieldsList() {
ba95ec1f 124 return Arrays.asList(fFieldNames);
866e5b51
FC
125 }
126
fd74e6c1
MK
127 @Override
128 public long getAlignment() {
a4fa4e36
MK
129 return this.fMaxAlign;
130 }
131
a4fa4e36
MK
132 @Override
133 public int getMaximumSize() {
ba95ec1f
MK
134 long maxSize = 0;
135 for (IDeclaration field : fFields) {
2db699c2 136 maxSize += field.getMaximumSize();
a4fa4e36 137 }
ba95ec1f 138 return (int) Math.min(maxSize, Integer.MAX_VALUE);
fd74e6c1 139 }
9ac2eb62 140
866e5b51
FC
141 // ------------------------------------------------------------------------
142 // Operations
143 // ------------------------------------------------------------------------
144
145 @Override
146 public StructDefinition createDefinition(IDefinitionScope definitionScope,
680f9173 147 String fieldName, BitBuffer input) throws CTFException {
a4fa4e36 148 alignRead(input);
ba95ec1f 149 final Definition[] myFields = new Definition[fFields.length];
94c255ef
MK
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);
155 } else {
156 structDefinition = new StructDefinition(this, definitionScope, fieldName, myFields);
157 }
cc575f45 158 fillStruct(input, myFields, structDefinition);
a4fa4e36 159 return structDefinition;
866e5b51
FC
160 }
161
70f60307 162 /**
6c7592e1
MK
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.
70f60307
MK
165 *
166 * @param definitionScope
6c7592e1
MK
167 * the definition scope, the parent where the definition will be
168 * placed
70f60307 169 * @param fieldScope
6c7592e1 170 * the scope of the definition
70f60307 171 * @param input
6c7592e1
MK
172 * a bitbuffer to read from
173 * @return a reference to the definition
680f9173 174 * @throws CTFException
6c7592e1 175 * error in reading
fbe6fa6f 176 * @since 1.0
70f60307
MK
177 */
178 public StructDefinition createDefinition(IDefinitionScope definitionScope,
680f9173 179 ILexicalScope fieldScope, @NonNull BitBuffer input) throws CTFException {
70f60307 180 alignRead(input);
ba95ec1f 181 final Definition[] myFields = new Definition[fFields.length];
5db5a3a4 182
94c255ef 183 StructDefinition structDefinition = new StructDefinition(this, definitionScope,
ba95ec1f 184 fieldScope, fieldScope.getName(), Arrays.asList(fFieldNames), myFields);
cc575f45 185 fillStruct(input, myFields, structDefinition);
70f60307
MK
186 return structDefinition;
187 }
188
9ac2eb62 189 /**
ba95ec1f 190 * Add a field to the struct, will not add a field that is already declared
a4fa4e36
MK
191 *
192 * @param name
193 * the name of the field, scopeless
194 * @param declaration
195 * the declaration of the field
9ac2eb62 196 */
56b62d1a 197 public void addField(@NonNull String name, @NonNull IDeclaration declaration) {
ba95ec1f
MK
198 if (hasField(name)) {
199 Activator.log(IStatus.WARNING, "Struct already contains a field named " + name); //$NON-NLS-1$
200 return;
201 }
202 /* extend by one */
203 final int length = fFieldNames.length;
204 @NonNull String[] names = Arrays.copyOf(fFieldNames, length + 1);
205 @NonNull IDeclaration[] fields = Arrays.copyOf(fFields, length + 1);
206 /* set the value */
207 names[length] = name;
208 fields[length] = declaration;
209 fFieldNames = names;
210 fFields = fields;
a4fa4e36 211 fMaxAlign = Math.max(fMaxAlign, declaration.getAlignment());
866e5b51
FC
212 }
213
ba95ec1f
MK
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++) {
5db5a3a4 218 /* We should not have inserted null keys... */
ba95ec1f 219 myFields[i] = fields[i].createDefinition(structDefinition, fieldNames[i], input);
cc575f45
MK
220 }
221 }
222
94c255ef
MK
223 /**
224 * Special constructor for fields
225 *
226 * @param eventHeaderDef
227 * the event header, used for scopes
228 * @param definitionScope
229 * the definition scope, in this case, the trace
230 * @param fields
231 * event fields
232 * @param input
233 * the input {@link BitBuffer}
234 * @return the fields definition
235 * @throws CTFException
236 * something went wrong
0336f981 237 * @since 1.1
94c255ef
MK
238 */
239 public StructDefinition createFieldDefinition(ICompositeDefinition eventHeaderDef, IDefinitionScope definitionScope, ILexicalScope fields, @NonNull BitBuffer input) throws CTFException {
240 alignRead(input);
ba95ec1f 241 final Definition[] myFields = new Definition[fFields.length];
94c255ef
MK
242 IDefinitionScope merged = definitionScope;
243 if (eventHeaderDef != null) {
244 merged = new InternalDef(definitionScope, eventHeaderDef);
245 }
246 StructDefinition structDefinition = new StructDefinition(this, merged,
ba95ec1f 247 fields, fields.getName(), Arrays.asList(fFieldNames), myFields);
94c255ef
MK
248 if (merged instanceof InternalDef) {
249 InternalDef internalDef = (InternalDef) merged;
250 internalDef.setDefinition(structDefinition);
251 }
252 fillStruct(input, myFields, structDefinition);
253 return structDefinition;
254 }
255
256 private static final Pattern EVENT_HEADER = Pattern.compile(ILexicalScope.EVENT_HEADER.getPath().replaceAll("\\.", "\\\\.") + "\\."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
257
5b341dc8 258 static class InternalDef implements IDefinitionScope {
94c255ef
MK
259
260 private final ICompositeDefinition fEventHeaderDef;
261 private final IDefinitionScope fTraceDef;
262 private StructDefinition fDefinition;
263
264 public InternalDef(IDefinitionScope definitionScope, ICompositeDefinition eventHeaderDef) {
265 fTraceDef = definitionScope;
266 fEventHeaderDef = eventHeaderDef;
267 }
268
269 @Override
270 public ILexicalScope getScopePath() {
271 return ILexicalScope.EVENT;
272 }
273
274 @Override
275 public IDefinition lookupDefinition(String lookupPath) {
276 IDefinition lookupDefinition = null;
277 if (fTraceDef != null) {
278 lookupDefinition = fTraceDef.lookupDefinition(lookupPath);
279 }
1dec66b2
MK
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);
285 }
286 if (fDefinition != null) {
287 return fDefinition.lookupDefinition(lookupPath);
94c255ef
MK
288 }
289 }
290 return lookupDefinition;
291 }
292
5b341dc8
MK
293 public IDefinition lookupDefinitionBreakLoop(String lookupPath) {
294 IDefinition lookupDefinition = null;
295 if (fTraceDef != null) {
296 lookupDefinition = fTraceDef.lookupDefinition(lookupPath);
297 }
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);
304 }
305 }
306 }
307 return lookupDefinition;
308 }
309
94c255ef
MK
310 private IDefinition getRecursiveDef(Definition definition, String[] childLookup, int i) {
311 if (i == childLookup.length) {
312 return definition;
313 }
314 if (definition instanceof ICompositeDefinition) {
315 ICompositeDefinition compositeDefinition = (ICompositeDefinition) definition;
316 return getRecursiveDef(compositeDefinition.getDefinition(childLookup[i]), childLookup, i + 1);
317 }
318 return null;
319 }
320
321 public void setDefinition(StructDefinition definition) {
322 fDefinition = definition;
323 }
324
325 }
326
866e5b51
FC
327 @Override
328 public String toString() {
329 /* Only used for debugging */
66aa25f0
MK
330 StringBuilder sb = new StringBuilder();
331 sb.append("[declaration] struct["); //$NON-NLS-1$
ba95ec1f
MK
332 for (int i = 0; i < fFields.length; i++) {
333 sb.append(fFieldNames[i]).append(':').append(fFields[i]);
66aa25f0
MK
334 }
335 sb.append(']');
336 return sb.toString();
866e5b51
FC
337 }
338
4dd0eaed
MK
339 @Override
340 public int hashCode() {
341 final int prime = 31;
342 int result = 1;
ba95ec1f
MK
343 for (int i = 0; i < fFields.length; i++) {
344 result = prime * result + fFieldNames[i].hashCode();
345 result = prime * result + fFields[i].hashCode();
e00e6663 346 }
a4fa4e36 347 result = (prime * result) + (int) (fMaxAlign ^ (fMaxAlign >>> 32));
4dd0eaed
MK
348 return result;
349 }
350
4dd0eaed
MK
351 @Override
352 public boolean equals(Object obj) {
353 if (this == obj) {
354 return true;
355 }
356 if (obj == null) {
357 return false;
358 }
359 if (!(obj instanceof StructDeclaration)) {
360 return false;
361 }
362 StructDeclaration other = (StructDeclaration) obj;
ba95ec1f 363 if (fFields.length != other.fFields.length) {
4dd0eaed
MK
364 return false;
365 }
e00e6663 366
ba95ec1f
MK
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);
e00e6663 371
94c255ef 372 // check fields in order
ba95ec1f 373 for (int i = 0; i < fFields.length; i++) {
e00e6663
MK
374 if ((!localFieldNames.get(i).equals(otherFieldNames.get(i))) ||
375 (!otherDecs.get(i).equals(localDecs.get(i)))) {
376 return false;
377 }
378 }
379
a4fa4e36 380 if (fMaxAlign != other.fMaxAlign) {
4dd0eaed
MK
381 return false;
382 }
383 return true;
384 }
385
66aa25f0
MK
386 @Override
387 public boolean isBinaryEquivalent(IDeclaration obj) {
388 if (this == obj) {
389 return true;
390 }
391 if (obj == null) {
392 return false;
393 }
394 if (!(obj instanceof StructDeclaration)) {
395 return false;
396 }
397 StructDeclaration other = (StructDeclaration) obj;
ba95ec1f 398 if (fFields.length != other.fFields.length) {
66aa25f0
MK
399 return false;
400 }
ba95ec1f
MK
401 List<IDeclaration> localDecs = Arrays.asList(fFields);
402 List<IDeclaration> otherDecs = Arrays.asList(other.fFields);
403 for (int i = 0; i < fFields.length; i++) {
66aa25f0
MK
404 if (!otherDecs.get(i).isBinaryEquivalent(localDecs.get(i))) {
405 return false;
406 }
407 }
408
409 if (fMaxAlign != other.fMaxAlign) {
410 return false;
411 }
412 return true;
413 }
414
866e5b51 415}
This page took 0.090543 seconds and 5 git commands to generate.