| /******************************************************************************* |
| * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others |
| * |
| * All rights reserved. This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: Matthew Khouzam - Initial API and implementation |
| * Contributors: Simon Marchi - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.ctf.core.event.types; |
| |
| import java.util.Collections; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.tracecompass.common.core.math.SaturatedArithmetic; |
| import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope; |
| import org.eclipse.tracecompass.ctf.core.event.scope.ILexicalScope; |
| import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration.InternalDef; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableMap.Builder; |
| |
| /** |
| * A CTF structure definition (similar to a C structure). |
| * |
| * A structure is similar to a C structure, it is a compound data type that |
| * contains other datatypes in fields. they are stored in an hashmap and indexed |
| * by names which are strings. |
| * |
| * TODO: move me to internal |
| * |
| * @version 1.0 |
| * @author Matthew Khouzam |
| * @author Simon Marchi |
| */ |
| public final class StructDefinition extends ScopedDefinition implements ICompositeDefinition { |
| |
| // ------------------------------------------------------------------------ |
| // Attributes |
| // ------------------------------------------------------------------------ |
| |
| private final @NonNull List<@NonNull String> fFieldNames; |
| private final Definition[] fDefinitions; |
| private Map<String, Definition> fDefinitionsMap = null; |
| |
| // ------------------------------------------------------------------------ |
| // Constructors |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Constructor |
| * |
| * @param declaration |
| * the parent declaration |
| * @param definitionScope |
| * the parent scope |
| * @param structFieldName |
| * the field name |
| * @param definitions |
| * the definitions |
| * @since 1.0 |
| */ |
| public StructDefinition(@NonNull StructDeclaration declaration, |
| IDefinitionScope definitionScope, |
| @NonNull String structFieldName, |
| Definition[] definitions) { |
| super(declaration, definitionScope, structFieldName); |
| fFieldNames = ImmutableList.copyOf(declaration.getFieldsList()); |
| fDefinitions = definitions; |
| if (fFieldNames.isEmpty()) { |
| fDefinitionsMap = Collections.emptyMap(); |
| } |
| } |
| |
| /** |
| * Constructor This one takes the scope and thus speeds up definition |
| * creation |
| * |
| * @param declaration |
| * the parent declaration |
| * @param definitionScope |
| * the parent scope |
| * @param scope |
| * the scope of this variable |
| * @param structFieldName |
| * the field name |
| * @param fieldNames |
| * the list of fields |
| * @param definitions |
| * the definitions |
| * @since 1.0 |
| */ |
| public StructDefinition(@NonNull StructDeclaration declaration, |
| IDefinitionScope definitionScope, |
| @NonNull ILexicalScope scope, |
| @NonNull String structFieldName, |
| @NonNull Iterable<@NonNull String> fieldNames, |
| Definition[] definitions) { |
| super(declaration, definitionScope, structFieldName, scope); |
| fFieldNames = ImmutableList.copyOf(fieldNames); |
| fDefinitions = definitions; |
| if (fFieldNames.isEmpty()) { |
| fDefinitionsMap = Collections.emptyMap(); |
| } |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Getters/Setters/Predicates |
| // ------------------------------------------------------------------------ |
| |
| @Override |
| public Definition getDefinition(String fieldName) { |
| if (fDefinitionsMap == null) { |
| /* Build the definitions map */ |
| Builder<String, Definition> mapBuilder = new ImmutableMap.Builder<>(); |
| for (int i = 0; i < fFieldNames.size(); i++) { |
| if (fDefinitions[i] != null) { |
| mapBuilder.put(fFieldNames.get(i), fDefinitions[i]); |
| } |
| } |
| fDefinitionsMap = mapBuilder.build(); |
| } |
| return fDefinitionsMap.get(fieldName); |
| } |
| |
| @Override |
| public @NonNull List<@NonNull String> getFieldNames() { |
| return fFieldNames; |
| } |
| |
| @Override |
| public StructDeclaration getDeclaration() { |
| return (StructDeclaration) super.getDeclaration(); |
| } |
| |
| @Override |
| public long size() { |
| long size = 0; |
| for (IDefinition def : fDefinitions) { |
| size = SaturatedArithmetic.add(size, def.size()); |
| } |
| return size; |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Operations |
| // ------------------------------------------------------------------------ |
| |
| @Override |
| public Definition lookupDefinition(String lookupPath) { |
| return lookupDefinition(lookupPath, null); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| |
| builder.append("{ "); //$NON-NLS-1$ |
| |
| List<String> fields = new LinkedList<>(); |
| for (String field : fFieldNames) { |
| String appendee = field + " = " + lookupDefinition(field).toString(); //$NON-NLS-1$ |
| fields.add(appendee); |
| } |
| Joiner joiner = Joiner.on(", ").skipNulls(); //$NON-NLS-1$ |
| builder.append(joiner.join(fields)); |
| |
| builder.append(" }"); //$NON-NLS-1$ |
| |
| return builder.toString(); |
| } |
| |
| /** |
| * Lookup definition while exclusing the caller |
| * |
| * @param lookupPath |
| * the path to lookup |
| * @param defintionToExclude |
| * the definition to exclude, can be null |
| * @return the definition or null |
| * @since 1.1 |
| */ |
| public Definition lookupDefinition(String lookupPath, ScopedDefinition defintionToExclude) { |
| /* |
| * The fields are created in order of appearance, so if a variant or |
| * sequence refers to a field that is after it, the field's definition |
| * will not be there yet in the hashmap. |
| */ |
| int val = fFieldNames.indexOf(lookupPath); |
| if (val != -1) { |
| return fDefinitions[val]; |
| } |
| String lookupUnderscored = "_" + lookupPath; //$NON-NLS-1$ |
| val = fFieldNames.indexOf(lookupUnderscored); |
| if (val != -1) { |
| return fDefinitions[val]; |
| } |
| for (IDefinition child : fDefinitions) { |
| if (child instanceof ScopedDefinition) { |
| if (!child.equals(defintionToExclude)) { |
| IDefinition def = ((ScopedDefinition) child).lookupDefinition(lookupPath); |
| if (def instanceof Definition) { |
| return (Definition) def; |
| } |
| } |
| } |
| } |
| if (getDefinitionScope() instanceof InternalDef) { |
| return (Definition) ((InternalDef) getDefinitionScope()).lookupDefinitionBreakLoop(lookupPath); |
| } |
| return (Definition) getDefinitionScope().lookupDefinition(lookupPath); |
| } |
| |
| } |