blob: 3abdb52502b1d3c77361760af547c1c7163d0041 [file] [log] [blame]
/*******************************************************************************
* 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);
}
}