0d49b608a74a11ae3e76b865db2e7553a2157e43
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / ctf / core / event / types / StructDeclaration.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
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
13 package org.eclipse.tracecompass.ctf.core.event.types;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17 import java.util.ArrayList;
18 import java.util.Iterator;
19 import java.util.LinkedHashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.regex.Pattern;
24
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;
31
32 /**
33 * A CTF structure declaration.
34 *
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.
38 *
39 * @version 1.0
40 * @author Matthew Khouzam
41 * @author Simon Marchi
42 */
43 public class StructDeclaration extends Declaration {
44
45 // ------------------------------------------------------------------------
46 // Attributes
47 // ------------------------------------------------------------------------
48
49 /** linked list of field names. So fieldName->fieldValue */
50 private final @NonNull Map<String, IDeclaration> fFieldMap = new LinkedHashMap<>();
51
52 /** maximum bit alignment */
53 private long fMaxAlign;
54
55 // ------------------------------------------------------------------------
56 // Constructors
57 // ------------------------------------------------------------------------
58
59 /**
60 * The struct declaration, add fields later
61 *
62 * @param align
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
65 * bit aligned.
66 */
67 public StructDeclaration(long align) {
68 fMaxAlign = Math.max(align, 1);
69 }
70
71 // ------------------------------------------------------------------------
72 // Getters/Setters/Predicates
73 // ------------------------------------------------------------------------
74
75 /**
76 * Get current alignment
77 *
78 * @return the alignment of the struct and all its fields
79 */
80 public long getMaxAlign() {
81 return fMaxAlign;
82 }
83
84 /**
85 * Query if the struct has a given field
86 *
87 * @param name
88 * the name of the field, scopeless please
89 * @return does the field exist?
90 */
91 public boolean hasField(String name) {
92 return fFieldMap.containsKey(name);
93 }
94
95 /**
96 * Get the fields of the struct as a map.
97 *
98 * @return a Map of the fields (key is the name)
99 */
100 public Map<String, IDeclaration> getFields() {
101 return fFieldMap;
102 }
103
104 /**
105 * Get the field declaration corresponding to a field name.
106 *
107 * @param fieldName
108 * The field name
109 * @return The declaration of the field, or null if there is no such field.
110 */
111 @Nullable
112 public IDeclaration getField(String fieldName) {
113 return fFieldMap.get(fieldName);
114 }
115
116 /**
117 * Gets the field list. Very important since the map of fields does not
118 * retain the order of the fields.
119 *
120 * @return the field list.
121 */
122 public Iterable<String> getFieldsList() {
123 return fFieldMap.keySet();
124 }
125
126 @Override
127 public long getAlignment() {
128 return this.fMaxAlign;
129 }
130
131 @Override
132 public int getMaximumSize() {
133 int maxSize = 0;
134 for (IDeclaration field : fFieldMap.values()) {
135 maxSize += field.getMaximumSize();
136 }
137 return Math.min(maxSize, Integer.MAX_VALUE);
138 }
139
140 // ------------------------------------------------------------------------
141 // Operations
142 // ------------------------------------------------------------------------
143
144 @Override
145 public StructDefinition createDefinition(IDefinitionScope definitionScope,
146 String fieldName, BitBuffer input) throws CTFException {
147 alignRead(input);
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);
154 } else {
155 structDefinition = new StructDefinition(this, definitionScope, fieldName, myFields);
156 }
157 fillStruct(input, myFields, structDefinition);
158 return structDefinition;
159 }
160
161 /**
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.
164 *
165 * @param definitionScope
166 * the definition scope, the parent where the definition will be
167 * placed
168 * @param fieldScope
169 * the scope of the definition
170 * @param input
171 * a bitbuffer to read from
172 * @return a reference to the definition
173 * @throws CTFException
174 * error in reading
175 * @since 1.0
176 */
177 public StructDefinition createDefinition(IDefinitionScope definitionScope,
178 ILexicalScope fieldScope, @NonNull BitBuffer input) throws CTFException {
179 alignRead(input);
180 final Definition[] myFields = new Definition[fFieldMap.size()];
181
182 StructDefinition structDefinition = new StructDefinition(this, definitionScope,
183 fieldScope, fieldScope.getName(), checkNotNull(fFieldMap.keySet()), myFields);
184 fillStruct(input, myFields, structDefinition);
185 return structDefinition;
186 }
187
188 /**
189 * Add a field to the struct
190 *
191 * @param name
192 * the name of the field, scopeless
193 * @param declaration
194 * the declaration of the field
195 */
196 public void addField(String name, IDeclaration declaration) {
197 fFieldMap.put(name, declaration);
198 fMaxAlign = Math.max(fMaxAlign, declaration.getAlignment());
199 }
200
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);
208 }
209 }
210
211 /**
212 * Special constructor for fields
213 *
214 * @param eventHeaderDef
215 * the event header, used for scopes
216 * @param definitionScope
217 * the definition scope, in this case, the trace
218 * @param fields
219 * event fields
220 * @param input
221 * the input {@link BitBuffer}
222 * @return the fields definition
223 * @throws CTFException
224 * something went wrong
225 * @since 2.0
226 */
227 public StructDefinition createFieldDefinition(ICompositeDefinition eventHeaderDef, IDefinitionScope definitionScope, ILexicalScope fields, @NonNull BitBuffer input) throws CTFException {
228 alignRead(input);
229 final Definition[] myFields = new Definition[fFieldMap.size()];
230 IDefinitionScope merged = definitionScope;
231 if (eventHeaderDef != null) {
232 merged = new InternalDef(definitionScope, eventHeaderDef);
233 }
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);
239 }
240 fillStruct(input, myFields, structDefinition);
241 return structDefinition;
242 }
243
244 private static final Pattern EVENT_HEADER = Pattern.compile(ILexicalScope.EVENT_HEADER.getPath().replaceAll("\\.", "\\\\.") + "\\."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
245
246 static class InternalDef implements IDefinitionScope {
247
248 private final ICompositeDefinition fEventHeaderDef;
249 private final IDefinitionScope fTraceDef;
250 private StructDefinition fDefinition;
251
252 public InternalDef(IDefinitionScope definitionScope, ICompositeDefinition eventHeaderDef) {
253 fTraceDef = definitionScope;
254 fEventHeaderDef = eventHeaderDef;
255 }
256
257 @Override
258 public ILexicalScope getScopePath() {
259 return ILexicalScope.EVENT;
260 }
261
262 @Override
263 public IDefinition lookupDefinition(String lookupPath) {
264 IDefinition lookupDefinition = null;
265 if (fTraceDef != null) {
266 lookupDefinition = fTraceDef.lookupDefinition(lookupPath);
267 }
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);
274 }
275 if (fDefinition != null) {
276 return fDefinition.lookupDefinition(lookupPath);
277 }
278 }
279 }
280 return lookupDefinition;
281 }
282
283 public IDefinition lookupDefinitionBreakLoop(String lookupPath) {
284 IDefinition lookupDefinition = null;
285 if (fTraceDef != null) {
286 lookupDefinition = fTraceDef.lookupDefinition(lookupPath);
287 }
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);
294 }
295 }
296 }
297 return lookupDefinition;
298 }
299
300 private IDefinition getRecursiveDef(Definition definition, String[] childLookup, int i) {
301 if (i == childLookup.length) {
302 return definition;
303 }
304 if (definition instanceof ICompositeDefinition) {
305 ICompositeDefinition compositeDefinition = (ICompositeDefinition) definition;
306 return getRecursiveDef(compositeDefinition.getDefinition(childLookup[i]), childLookup, i + 1);
307 }
308 return null;
309 }
310
311 public void setDefinition(StructDefinition definition) {
312 fDefinition = definition;
313 }
314
315 }
316
317 @Override
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());
324 }
325 sb.append(']');
326 return sb.toString();
327 }
328
329 @Override
330 public int hashCode() {
331 final int prime = 31;
332 int result = 1;
333 for (Entry<String, IDeclaration> field : fFieldMap.entrySet()) {
334 result = prime * result + field.getKey().hashCode();
335 result = prime * result + field.getValue().hashCode();
336 }
337 result = (prime * result) + (int) (fMaxAlign ^ (fMaxAlign >>> 32));
338 return result;
339 }
340
341 @Override
342 public boolean equals(Object obj) {
343 if (this == obj) {
344 return true;
345 }
346 if (obj == null) {
347 return false;
348 }
349 if (!(obj instanceof StructDeclaration)) {
350 return false;
351 }
352 StructDeclaration other = (StructDeclaration) obj;
353 if (fFieldMap.size() != other.fFieldMap.size()) {
354 return false;
355 }
356
357 List<String> localFieldNames = new ArrayList<>();
358 localFieldNames.addAll(fFieldMap.keySet());
359
360 List<IDeclaration> localDecs = new ArrayList<>();
361 localDecs.addAll(fFieldMap.values());
362
363 List<String> otherFieldNames = new ArrayList<>();
364 otherFieldNames.addAll(other.fFieldMap.keySet());
365
366 List<IDeclaration> otherDecs = new ArrayList<>();
367 otherDecs.addAll(other.fFieldMap.values());
368
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)))) {
373 return false;
374 }
375 }
376
377 if (fMaxAlign != other.fMaxAlign) {
378 return false;
379 }
380 return true;
381 }
382
383 @Override
384 public boolean isBinaryEquivalent(IDeclaration obj) {
385 if (this == obj) {
386 return true;
387 }
388 if (obj == null) {
389 return false;
390 }
391 if (!(obj instanceof StructDeclaration)) {
392 return false;
393 }
394 StructDeclaration other = (StructDeclaration) obj;
395 if (fFieldMap.size() != other.fFieldMap.size()) {
396 return false;
397 }
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))) {
404 return false;
405 }
406 }
407
408 if (fMaxAlign != other.fMaxAlign) {
409 return false;
410 }
411 return true;
412 }
413
414 }
This page took 0.055733 seconds and 4 git commands to generate.