Commit | Line | Data |
---|---|---|
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 | 13 | package org.eclipse.tracecompass.ctf.core.event.types; |
866e5b51 | 14 | |
e00e6663 | 15 | import java.util.ArrayList; |
2db699c2 | 16 | import java.util.Iterator; |
a4fa4e36 | 17 | import java.util.LinkedHashMap; |
e00e6663 | 18 | import java.util.List; |
0594c61c | 19 | import java.util.Map; |
e00e6663 | 20 | import java.util.Map.Entry; |
866e5b51 | 21 | |
a4fa4e36 | 22 | import org.eclipse.jdt.annotation.NonNull; |
2db699c2 | 23 | import org.eclipse.jdt.annotation.Nullable; |
f357bcd4 AM |
24 | import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer; |
25 | import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope; | |
26 | import org.eclipse.tracecompass.ctf.core.event.scope.LexicalScope; | |
27 | import org.eclipse.tracecompass.ctf.core.trace.CTFReaderException; | |
a4fa4e36 | 28 | |
866e5b51 | 29 | /** |
d37aaa7f | 30 | * A CTF structure declaration. |
77fdc5df | 31 | * |
d37aaa7f FC |
32 | * A structure is similar to a C structure, it is a compound data type that |
33 | * contains other datatypes in fields. they are stored in an hashmap and indexed | |
34 | * by names which are strings. | |
35 | * | |
36 | * @version 1.0 | |
37 | * @author Matthew Khouzam | |
38 | * @author Simon Marchi | |
866e5b51 | 39 | */ |
a4fa4e36 | 40 | public class StructDeclaration extends Declaration { |
866e5b51 FC |
41 | |
42 | // ------------------------------------------------------------------------ | |
43 | // Attributes | |
44 | // ------------------------------------------------------------------------ | |
45 | ||
a4fa4e36 | 46 | /** linked list of field names. So fieldName->fieldValue */ |
2db699c2 | 47 | private final @NonNull Map<String, IDeclaration> fFieldMap = new LinkedHashMap<>(); |
a4fa4e36 MK |
48 | |
49 | /** maximum bit alignment */ | |
50 | private long fMaxAlign; | |
866e5b51 FC |
51 | |
52 | // ------------------------------------------------------------------------ | |
53 | // Constructors | |
54 | // ------------------------------------------------------------------------ | |
55 | ||
9ac2eb62 MK |
56 | /** |
57 | * The struct declaration, add fields later | |
58 | * | |
59 | * @param align | |
60 | * the minimum alignment of the struct. (if a struct is 8bit | |
61 | * aligned and has a 32 bit aligned field, the struct becomes 32 | |
62 | * bit aligned. | |
63 | */ | |
2b7f6f09 | 64 | public StructDeclaration(long align) { |
a4fa4e36 | 65 | fMaxAlign = Math.max(align, 1); |
a4fa4e36 MK |
66 | } |
67 | ||
68 | /** | |
69 | * Struct declaration constructor | |
70 | * | |
71 | * @param names | |
72 | * the names of all the fields | |
73 | * @param declarations | |
74 | * all the fields | |
75 | * @since 3.0 | |
76 | */ | |
a4fa4e36 MK |
77 | public StructDeclaration(String[] names, Declaration[] declarations) { |
78 | fMaxAlign = 1; | |
2db699c2 | 79 | |
a4fa4e36 MK |
80 | for (int i = 0; i < names.length; i++) { |
81 | addField(names[i], declarations[i]); | |
82 | } | |
866e5b51 FC |
83 | } |
84 | ||
85 | // ------------------------------------------------------------------------ | |
86 | // Getters/Setters/Predicates | |
87 | // ------------------------------------------------------------------------ | |
88 | ||
9ac2eb62 MK |
89 | /** |
90 | * Get current alignment | |
a4fa4e36 | 91 | * |
9ac2eb62 MK |
92 | * @return the alignment of the struct and all its fields |
93 | */ | |
2b7f6f09 | 94 | public long getMaxAlign() { |
a4fa4e36 | 95 | return fMaxAlign; |
866e5b51 FC |
96 | } |
97 | ||
9ac2eb62 MK |
98 | /** |
99 | * Query if the struct has a given field | |
a4fa4e36 MK |
100 | * |
101 | * @param name | |
102 | * the name of the field, scopeless please | |
9ac2eb62 MK |
103 | * @return does the field exist? |
104 | */ | |
866e5b51 | 105 | public boolean hasField(String name) { |
a4fa4e36 | 106 | return fFieldMap.containsKey(name); |
866e5b51 FC |
107 | } |
108 | ||
9ac2eb62 | 109 | /** |
2db699c2 | 110 | * Get the fields of the struct as a map. |
a4fa4e36 | 111 | * |
2db699c2 | 112 | * @return a Map of the fields (key is the name) |
0594c61c | 113 | * @since 2.0 |
9ac2eb62 | 114 | */ |
0594c61c | 115 | public Map<String, IDeclaration> getFields() { |
a4fa4e36 | 116 | return fFieldMap; |
866e5b51 FC |
117 | } |
118 | ||
2db699c2 AM |
119 | /** |
120 | * Get the field declaration corresponding to a field name. | |
121 | * | |
122 | * @param fieldName | |
123 | * The field name | |
124 | * @return The declaration of the field, or null if there is no such field. | |
125 | * @since 3.1 | |
126 | */ | |
127 | @Nullable | |
128 | public IDeclaration getField(String fieldName) { | |
129 | return fFieldMap.get(fieldName); | |
130 | } | |
131 | ||
9ac2eb62 | 132 | /** |
a4fa4e36 MK |
133 | * Gets the field list. Very important since the map of fields does not |
134 | * retain the order of the fields. | |
135 | * | |
9ac2eb62 | 136 | * @return the field list. |
a4fa4e36 | 137 | * @since 3.0 |
9ac2eb62 | 138 | */ |
a4fa4e36 MK |
139 | public Iterable<String> getFieldsList() { |
140 | return fFieldMap.keySet(); | |
866e5b51 FC |
141 | } |
142 | ||
fd74e6c1 MK |
143 | @Override |
144 | public long getAlignment() { | |
a4fa4e36 MK |
145 | return this.fMaxAlign; |
146 | } | |
147 | ||
148 | /** | |
149 | * @since 3.0 | |
150 | */ | |
151 | @Override | |
152 | public int getMaximumSize() { | |
153 | int maxSize = 0; | |
2db699c2 AM |
154 | for (IDeclaration field : fFieldMap.values()) { |
155 | maxSize += field.getMaximumSize(); | |
a4fa4e36 MK |
156 | } |
157 | return Math.min(maxSize, Integer.MAX_VALUE); | |
fd74e6c1 | 158 | } |
9ac2eb62 | 159 | |
866e5b51 FC |
160 | // ------------------------------------------------------------------------ |
161 | // Operations | |
162 | // ------------------------------------------------------------------------ | |
163 | ||
a4fa4e36 MK |
164 | /** |
165 | * @since 3.0 | |
166 | */ | |
866e5b51 FC |
167 | @Override |
168 | public StructDefinition createDefinition(IDefinitionScope definitionScope, | |
a4fa4e36 MK |
169 | String fieldName, BitBuffer input) throws CTFReaderException { |
170 | alignRead(input); | |
2db699c2 AM |
171 | final Definition[] myFields = new Definition[fFieldMap.size()]; |
172 | StructDefinition structDefinition = new StructDefinition(this, definitionScope, fieldName, fFieldMap.keySet(), myFields); | |
cc575f45 | 173 | fillStruct(input, myFields, structDefinition); |
a4fa4e36 | 174 | return structDefinition; |
866e5b51 FC |
175 | } |
176 | ||
70f60307 | 177 | /** |
6c7592e1 MK |
178 | * Create a definition from this declaration. This is a faster constructor |
179 | * as it has a lexical scope and this does not need to look it up. | |
70f60307 MK |
180 | * |
181 | * @param definitionScope | |
6c7592e1 MK |
182 | * the definition scope, the parent where the definition will be |
183 | * placed | |
70f60307 | 184 | * @param fieldScope |
6c7592e1 | 185 | * the scope of the definition |
70f60307 | 186 | * @param input |
6c7592e1 MK |
187 | * a bitbuffer to read from |
188 | * @return a reference to the definition | |
70f60307 | 189 | * @throws CTFReaderException |
6c7592e1 | 190 | * error in reading |
70f60307 MK |
191 | * @since 3.1 |
192 | */ | |
193 | public StructDefinition createDefinition(IDefinitionScope definitionScope, | |
194 | LexicalScope fieldScope, @NonNull BitBuffer input) throws CTFReaderException { | |
195 | alignRead(input); | |
196 | final Definition[] myFields = new Definition[fFieldMap.size()]; | |
bbe3a6a4 MK |
197 | /* |
198 | * Key set is NOT null | |
199 | */ | |
200 | @SuppressWarnings("null") | |
201 | StructDefinition structDefinition = new StructDefinition(this, definitionScope, fieldScope, fieldScope.getName(), fFieldMap.keySet(), myFields); | |
cc575f45 | 202 | fillStruct(input, myFields, structDefinition); |
70f60307 MK |
203 | return structDefinition; |
204 | } | |
205 | ||
9ac2eb62 MK |
206 | /** |
207 | * Add a field to the struct | |
a4fa4e36 MK |
208 | * |
209 | * @param name | |
210 | * the name of the field, scopeless | |
211 | * @param declaration | |
212 | * the declaration of the field | |
9ac2eb62 | 213 | */ |
866e5b51 | 214 | public void addField(String name, IDeclaration declaration) { |
a4fa4e36 MK |
215 | fFieldMap.put(name, declaration); |
216 | fMaxAlign = Math.max(fMaxAlign, declaration.getAlignment()); | |
866e5b51 FC |
217 | } |
218 | ||
cc575f45 MK |
219 | @SuppressWarnings("null") |
220 | private void fillStruct(@NonNull BitBuffer input, final Definition[] myFields, StructDefinition structDefinition) throws CTFReaderException { | |
221 | Iterator<Map.Entry<String, IDeclaration>> iter = fFieldMap.entrySet().iterator(); | |
222 | for (int i = 0; i < fFieldMap.size(); i++) { | |
223 | Map.Entry<String, IDeclaration> entry = iter.next(); | |
224 | myFields[i] = entry.getValue().createDefinition(structDefinition, entry.getKey(), input); | |
225 | } | |
226 | } | |
227 | ||
866e5b51 FC |
228 | @Override |
229 | public String toString() { | |
230 | /* Only used for debugging */ | |
66aa25f0 MK |
231 | StringBuilder sb = new StringBuilder(); |
232 | sb.append("[declaration] struct["); //$NON-NLS-1$ | |
233 | for (Entry<String, IDeclaration> field : fFieldMap.entrySet()) { | |
234 | sb.append(field.getKey()).append(':').append(field.getValue()); | |
235 | } | |
236 | sb.append(']'); | |
237 | return sb.toString(); | |
866e5b51 FC |
238 | } |
239 | ||
4dd0eaed MK |
240 | @Override |
241 | public int hashCode() { | |
242 | final int prime = 31; | |
243 | int result = 1; | |
e00e6663 MK |
244 | for (Entry<String, IDeclaration> field : fFieldMap.entrySet()) { |
245 | result = prime * result + field.getKey().hashCode(); | |
246 | result = prime * result + field.getValue().hashCode(); | |
247 | } | |
a4fa4e36 | 248 | result = (prime * result) + (int) (fMaxAlign ^ (fMaxAlign >>> 32)); |
4dd0eaed MK |
249 | return result; |
250 | } | |
251 | ||
4dd0eaed MK |
252 | @Override |
253 | public boolean equals(Object obj) { | |
254 | if (this == obj) { | |
255 | return true; | |
256 | } | |
257 | if (obj == null) { | |
258 | return false; | |
259 | } | |
260 | if (!(obj instanceof StructDeclaration)) { | |
261 | return false; | |
262 | } | |
263 | StructDeclaration other = (StructDeclaration) obj; | |
e00e6663 | 264 | if (fFieldMap.size() != other.fFieldMap.size()) { |
4dd0eaed MK |
265 | return false; |
266 | } | |
e00e6663 MK |
267 | |
268 | List<String> localFieldNames = new ArrayList<>(); | |
269 | localFieldNames.addAll(fFieldMap.keySet()); | |
270 | ||
271 | List<IDeclaration> localDecs = new ArrayList<>(); | |
272 | localDecs.addAll(fFieldMap.values()); | |
273 | ||
274 | List<String> otherFieldNames = new ArrayList<>(); | |
275 | otherFieldNames.addAll(other.fFieldMap.keySet()); | |
276 | ||
277 | List<IDeclaration> otherDecs = new ArrayList<>(); | |
278 | otherDecs.addAll(other.fFieldMap.values()); | |
279 | ||
280 | //check fields in order | |
281 | for (int i = 0; i < fFieldMap.size(); i++) { | |
282 | if ((!localFieldNames.get(i).equals(otherFieldNames.get(i))) || | |
283 | (!otherDecs.get(i).equals(localDecs.get(i)))) { | |
284 | return false; | |
285 | } | |
286 | } | |
287 | ||
a4fa4e36 | 288 | if (fMaxAlign != other.fMaxAlign) { |
4dd0eaed MK |
289 | return false; |
290 | } | |
291 | return true; | |
292 | } | |
293 | ||
66aa25f0 MK |
294 | @Override |
295 | public boolean isBinaryEquivalent(IDeclaration obj) { | |
296 | if (this == obj) { | |
297 | return true; | |
298 | } | |
299 | if (obj == null) { | |
300 | return false; | |
301 | } | |
302 | if (!(obj instanceof StructDeclaration)) { | |
303 | return false; | |
304 | } | |
305 | StructDeclaration other = (StructDeclaration) obj; | |
306 | if (fFieldMap.size() != other.fFieldMap.size()) { | |
307 | return false; | |
308 | } | |
309 | List<IDeclaration> localDecs = new ArrayList<>(); | |
310 | localDecs.addAll(fFieldMap.values()); | |
311 | List<IDeclaration> otherDecs = new ArrayList<>(); | |
312 | otherDecs.addAll(other.fFieldMap.values()); | |
313 | for (int i = 0; i < fFieldMap.size(); i++) { | |
314 | if (!otherDecs.get(i).isBinaryEquivalent(localDecs.get(i))) { | |
315 | return false; | |
316 | } | |
317 | } | |
318 | ||
319 | if (fMaxAlign != other.fMaxAlign) { | |
320 | return false; | |
321 | } | |
322 | return true; | |
323 | } | |
324 | ||
866e5b51 | 325 | } |