83fb2e2198dc0515334da7399e43cf2661de2683
[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<@NonNull 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 field declaration corresponding to a field name.
97 *
98 * @param fieldName
99 * The field name
100 * @return The declaration of the field, or null if there is no such field.
101 */
102 @Nullable
103 public IDeclaration getField(String fieldName) {
104 return fFieldMap.get(fieldName);
105 }
106
107 /**
108 * Gets the field list. Very important since the map of fields does not
109 * retain the order of the fields.
110 *
111 * @return the field list.
112 */
113 public @NonNull Iterable<@NonNull String> getFieldsList() {
114 return fFieldMap.keySet();
115 }
116
117 @Override
118 public long getAlignment() {
119 return this.fMaxAlign;
120 }
121
122 @Override
123 public int getMaximumSize() {
124 int maxSize = 0;
125 for (IDeclaration field : fFieldMap.values()) {
126 maxSize += field.getMaximumSize();
127 }
128 return Math.min(maxSize, Integer.MAX_VALUE);
129 }
130
131 // ------------------------------------------------------------------------
132 // Operations
133 // ------------------------------------------------------------------------
134
135 @Override
136 public StructDefinition createDefinition(IDefinitionScope definitionScope,
137 String fieldName, BitBuffer input) throws CTFException {
138 alignRead(input);
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);
145 } else {
146 structDefinition = new StructDefinition(this, definitionScope, fieldName, myFields);
147 }
148 fillStruct(input, myFields, structDefinition);
149 return structDefinition;
150 }
151
152 /**
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.
155 *
156 * @param definitionScope
157 * the definition scope, the parent where the definition will be
158 * placed
159 * @param fieldScope
160 * the scope of the definition
161 * @param input
162 * a bitbuffer to read from
163 * @return a reference to the definition
164 * @throws CTFException
165 * error in reading
166 * @since 1.0
167 */
168 public StructDefinition createDefinition(IDefinitionScope definitionScope,
169 ILexicalScope fieldScope, @NonNull BitBuffer input) throws CTFException {
170 alignRead(input);
171 final Definition[] myFields = new Definition[fFieldMap.size()];
172
173 StructDefinition structDefinition = new StructDefinition(this, definitionScope,
174 fieldScope, fieldScope.getName(), checkNotNull(fFieldMap.keySet()), myFields);
175 fillStruct(input, myFields, structDefinition);
176 return structDefinition;
177 }
178
179 /**
180 * Add a field to the struct
181 *
182 * @param name
183 * the name of the field, scopeless
184 * @param declaration
185 * the declaration of the field
186 */
187 public void addField(@NonNull String name, IDeclaration declaration) {
188 fFieldMap.put(name, declaration);
189 fMaxAlign = Math.max(fMaxAlign, declaration.getAlignment());
190 }
191
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);
199 }
200 }
201
202 /**
203 * Special constructor for fields
204 *
205 * @param eventHeaderDef
206 * the event header, used for scopes
207 * @param definitionScope
208 * the definition scope, in this case, the trace
209 * @param fields
210 * event fields
211 * @param input
212 * the input {@link BitBuffer}
213 * @return the fields definition
214 * @throws CTFException
215 * something went wrong
216 * @since 1.1
217 */
218 public StructDefinition createFieldDefinition(ICompositeDefinition eventHeaderDef, IDefinitionScope definitionScope, ILexicalScope fields, @NonNull BitBuffer input) throws CTFException {
219 alignRead(input);
220 final Definition[] myFields = new Definition[fFieldMap.size()];
221 IDefinitionScope merged = definitionScope;
222 if (eventHeaderDef != null) {
223 merged = new InternalDef(definitionScope, eventHeaderDef);
224 }
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);
230 }
231 fillStruct(input, myFields, structDefinition);
232 return structDefinition;
233 }
234
235 private static final Pattern EVENT_HEADER = Pattern.compile(ILexicalScope.EVENT_HEADER.getPath().replaceAll("\\.", "\\\\.") + "\\."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
236
237 static class InternalDef implements IDefinitionScope {
238
239 private final ICompositeDefinition fEventHeaderDef;
240 private final IDefinitionScope fTraceDef;
241 private StructDefinition fDefinition;
242
243 public InternalDef(IDefinitionScope definitionScope, ICompositeDefinition eventHeaderDef) {
244 fTraceDef = definitionScope;
245 fEventHeaderDef = eventHeaderDef;
246 }
247
248 @Override
249 public ILexicalScope getScopePath() {
250 return ILexicalScope.EVENT;
251 }
252
253 @Override
254 public IDefinition lookupDefinition(String lookupPath) {
255 IDefinition lookupDefinition = null;
256 if (fTraceDef != null) {
257 lookupDefinition = fTraceDef.lookupDefinition(lookupPath);
258 }
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);
264 }
265 if (fDefinition != null) {
266 return fDefinition.lookupDefinition(lookupPath);
267 }
268 }
269 return lookupDefinition;
270 }
271
272 public IDefinition lookupDefinitionBreakLoop(String lookupPath) {
273 IDefinition lookupDefinition = null;
274 if (fTraceDef != null) {
275 lookupDefinition = fTraceDef.lookupDefinition(lookupPath);
276 }
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);
283 }
284 }
285 }
286 return lookupDefinition;
287 }
288
289 private IDefinition getRecursiveDef(Definition definition, String[] childLookup, int i) {
290 if (i == childLookup.length) {
291 return definition;
292 }
293 if (definition instanceof ICompositeDefinition) {
294 ICompositeDefinition compositeDefinition = (ICompositeDefinition) definition;
295 return getRecursiveDef(compositeDefinition.getDefinition(childLookup[i]), childLookup, i + 1);
296 }
297 return null;
298 }
299
300 public void setDefinition(StructDefinition definition) {
301 fDefinition = definition;
302 }
303
304 }
305
306 @Override
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());
313 }
314 sb.append(']');
315 return sb.toString();
316 }
317
318 @Override
319 public int hashCode() {
320 final int prime = 31;
321 int result = 1;
322 for (Entry<String, IDeclaration> field : fFieldMap.entrySet()) {
323 result = prime * result + field.getKey().hashCode();
324 result = prime * result + field.getValue().hashCode();
325 }
326 result = (prime * result) + (int) (fMaxAlign ^ (fMaxAlign >>> 32));
327 return result;
328 }
329
330 @Override
331 public boolean equals(Object obj) {
332 if (this == obj) {
333 return true;
334 }
335 if (obj == null) {
336 return false;
337 }
338 if (!(obj instanceof StructDeclaration)) {
339 return false;
340 }
341 StructDeclaration other = (StructDeclaration) obj;
342 if (fFieldMap.size() != other.fFieldMap.size()) {
343 return false;
344 }
345
346 List<String> localFieldNames = new ArrayList<>();
347 localFieldNames.addAll(fFieldMap.keySet());
348
349 List<IDeclaration> localDecs = new ArrayList<>();
350 localDecs.addAll(fFieldMap.values());
351
352 List<String> otherFieldNames = new ArrayList<>();
353 otherFieldNames.addAll(other.fFieldMap.keySet());
354
355 List<IDeclaration> otherDecs = new ArrayList<>();
356 otherDecs.addAll(other.fFieldMap.values());
357
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)))) {
362 return false;
363 }
364 }
365
366 if (fMaxAlign != other.fMaxAlign) {
367 return false;
368 }
369 return true;
370 }
371
372 @Override
373 public boolean isBinaryEquivalent(IDeclaration obj) {
374 if (this == obj) {
375 return true;
376 }
377 if (obj == null) {
378 return false;
379 }
380 if (!(obj instanceof StructDeclaration)) {
381 return false;
382 }
383 StructDeclaration other = (StructDeclaration) obj;
384 if (fFieldMap.size() != other.fFieldMap.size()) {
385 return false;
386 }
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))) {
393 return false;
394 }
395 }
396
397 if (fMaxAlign != other.fMaxAlign) {
398 return false;
399 }
400 return true;
401 }
402
403 }
This page took 0.039427 seconds and 4 git commands to generate.