blob: c6c55c4f69cbdb8cade058b2402ee9dabf1e15da [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 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
*******************************************************************************/
package org.eclipse.tracecompass.internal.ctf.core.event.types;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.util.Collection;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.ctf.core.CTFException;
import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;
import org.eclipse.tracecompass.ctf.core.event.types.AbstractArrayDefinition;
import org.eclipse.tracecompass.ctf.core.event.types.CompoundDeclaration;
import org.eclipse.tracecompass.ctf.core.event.types.Definition;
import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
import org.eclipse.tracecompass.ctf.core.event.types.IDefinition;
import org.eclipse.tracecompass.ctf.core.event.types.IntegerDefinition;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Multimap;
/**
* A CTF sequence declaration.
*
* An array where the size is fixed but declared in the trace, unlike array
* where it is declared with a literal
*
* @author Matthew Khouzam
*/
public class SequenceDeclaration extends CompoundDeclaration {
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
private final IDeclaration fElemType;
private final String fLengthName;
private final transient Multimap<String, String> fPaths = ArrayListMultimap.create();
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Constructor
*
* @param lengthName
* the name of the field describing the length
* @param elemType
* The element type
*/
public SequenceDeclaration(@Nullable String lengthName, IDeclaration elemType) {
fElemType = elemType;
fLengthName = lengthName;
}
// ------------------------------------------------------------------------
// Getters/Setters/Predicates
// ------------------------------------------------------------------------
@Override
public IDeclaration getElementType() {
return fElemType;
}
/**
* Gets the name of the length field
*
* @return the name of the length field
*/
public String getLengthName() {
return fLengthName;
}
// ------------------------------------------------------------------------
// Operations
// ------------------------------------------------------------------------
@Override
public AbstractArrayDefinition createDefinition(
@Nullable IDefinitionScope definitionScope, String fieldName, BitBuffer input) throws CTFException {
IDefinition lenDef = null;
if (definitionScope != null) {
lenDef = definitionScope.lookupDefinition(getLengthName());
}
if (lenDef == null) {
throw new CTFException("Sequence length field not found"); //$NON-NLS-1$
}
if (!(lenDef instanceof IntegerDefinition)) {
throw new CTFException("Sequence length field not integer"); //$NON-NLS-1$
}
IntegerDefinition lengthDefinition = (IntegerDefinition) lenDef;
if (lengthDefinition.getDeclaration().isSigned()) {
throw new CTFException("Sequence length must not be signed"); //$NON-NLS-1$
}
long length = lengthDefinition.getValue();
long maxBits = length * fElemType.getMaximumSize();
if ((length > Integer.MAX_VALUE) || (maxBits > Integer.MAX_VALUE) || (!input.canRead((int) maxBits))) {
throw new CTFException("Sequence length too long " + length); //$NON-NLS-1$
}
if (isAlignedBytes()) {
// Don't create "useless" definitions
byte[] data = new byte[(int) length];
input.get(data);
return new ByteArrayDefinition(this, definitionScope, fieldName, data);
}
Collection<String> collection = fPaths.get(fieldName);
while (collection.size() < length) {
fPaths.put(fieldName, fieldName + '[' + collection.size() + ']');
}
List<String> paths = (List<String>) fPaths.get(fieldName);
Builder<@NonNull Definition> definitions = new ImmutableList.Builder<>();
for (int i = 0; i < length; i++) {
/* We should not have inserted any null values */
String elemName = checkNotNull(paths.get(i));
definitions.add(fElemType.createDefinition(definitionScope, elemName, input));
}
List<@NonNull Definition> list = definitions.build();
return new ArrayDefinition(this, definitionScope, fieldName, list);
}
@Override
public String toString() {
/* Only used for debugging */
return "[declaration] sequence[" + Integer.toHexString(hashCode()) + ']'; //$NON-NLS-1$
}
@Override
public int getMaximumSize() {
return Integer.MAX_VALUE;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + fElemType.hashCode();
result = prime * result + fLengthName.hashCode();
return result;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SequenceDeclaration other = (SequenceDeclaration) obj;
if (!fElemType.equals(other.fElemType)) {
return false;
}
return (fLengthName.equals(other.fLengthName));
}
@Override
public boolean isBinaryEquivalent(@Nullable IDeclaration obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SequenceDeclaration other = (SequenceDeclaration) obj;
if (!fElemType.isBinaryEquivalent(other.fElemType)) {
return false;
}
return (fLengthName.equals(other.fLengthName));
}
}