blob: ada5076704ad3a409966e7375dd3167ec5affdd5 [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
*******************************************************************************/
package org.eclipse.tracecompass.ctf.core.event.types;
import java.nio.ByteOrder;
import org.eclipse.jdt.annotation.NonNullByDefault;
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;
/**
* A CTF float declaration.
*
* The declaration of a floating point basic data type.
*
* @version 1.0
* @author Matthew Khouzam
*/
@NonNullByDefault
public final class FloatDeclaration extends Declaration implements ISimpleDatatypeDeclaration {
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
private final int fMantissa;
private final int fExponent;
private final boolean fIsByteOrderSet;
private final ByteOrder fByteOrder;
private final long fAlignement;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Constructor
*
* @param exponent
* The exponent size in bits
* @param mantissa
* The mantissa size in bits (+1 for sign) (see CTF spec)
* @param byteOrder
* The byte order
* @param alignment
* The alignment. Should be ≥ 1
*/
public FloatDeclaration(int exponent, int mantissa, @Nullable ByteOrder byteOrder,
long alignment) {
fMantissa = mantissa;
fExponent = exponent;
fIsByteOrderSet = byteOrder != null;
fByteOrder = (byteOrder == null) ? ByteOrder.nativeOrder() : byteOrder;
fAlignement = Math.max(alignment, 1);
}
// ------------------------------------------------------------------------
// Getters/Setters/Predicates
// ------------------------------------------------------------------------
/**
* @return the mantissa
*/
public int getMantissa() {
return fMantissa;
}
/**
* @return the exponent
*/
public int getExponent() {
return fExponent;
}
/**
* @since 2.0
*/
@Override
public boolean isByteOrderSet() {
return fIsByteOrderSet;
}
@Override
public ByteOrder getByteOrder() {
return fByteOrder;
}
@Override
public long getAlignment() {
return fAlignement;
}
@Override
public int getMaximumSize() {
return fMantissa + fExponent + 1;
}
// ------------------------------------------------------------------------
// Operations
// ------------------------------------------------------------------------
@Override
public FloatDefinition createDefinition(@Nullable IDefinitionScope definitionScope,
String fieldName, BitBuffer input) throws CTFException {
ByteOrder byteOrder = input.getByteOrder();
input.setByteOrder(fByteOrder);
double value = read(input);
input.setByteOrder(byteOrder);
return new FloatDefinition(this, definitionScope, fieldName, value);
}
@Override
public String toString() {
/* Only used for debugging */
return "[declaration] float[" + Integer.toHexString(hashCode()) + ']'; //$NON-NLS-1$
}
private double read(BitBuffer input) throws CTFException {
/* Offset the buffer position wrt the current alignment */
alignRead(input);
final int exp = getExponent();
final int mant = getMantissa();
double value = Double.NaN;
if ((exp + mant) == 32) {
value = readRawFloat32(input, mant, exp);
} else if ((exp + mant) == 64) {
value = readRawFloat64(input, mant, exp);
}
return value;
}
private static double readRawFloat32(BitBuffer input, final int manBits,
final int expBits) throws CTFException {
long temp = input.get(32, false);
return createFloat(temp, manBits - 1, expBits);
}
private static double readRawFloat64(BitBuffer input, final int manBits,
final int expBits) throws CTFException {
long temp = input.get(64, false);
return createFloat(temp, manBits - 1, expBits);
}
/**
* Create a float from the raw value, Mathematicians beware.
*
* @param rawValue
* The raw value( up to 64 bits)
* @param manBits
* number of bits in the mantissa
* @param expBits
* number of bits in the exponent
*/
private static double createFloat(long rawValue, final int manBits,
final int expBits) {
long manShift = 1L << (manBits);
long manMask = manShift - 1;
long expMask = (1L << expBits) - 1;
boolean isNegative = (rawValue & (1L << (manBits + expBits))) != 0;
int exp = (int) ((rawValue >> (manBits)) & expMask) + 1;
long man = (rawValue & manMask);
final int offsetExponent = exp - (1 << (expBits - 1));
double expPow = Math.pow(2.0, offsetExponent);
double ret = man * 1.0f;
ret /= manShift;
ret += 1.0;
ret *= expPow;
return isNegative ? -ret : ret;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (fAlignement ^ (fAlignement >>> 32));
// don't evaluate object but string
result = prime * result + fByteOrder.toString().hashCode();
result = prime * result + fExponent;
result = prime * result + fMantissa;
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;
}
FloatDeclaration other = (FloatDeclaration) obj;
if (fAlignement != other.fAlignement) {
return false;
}
if (!fByteOrder.equals(other.fByteOrder)) {
return false;
}
if (fExponent != other.fExponent) {
return false;
}
return (fMantissa == other.fMantissa);
}
@Override
public boolean isBinaryEquivalent(@Nullable IDeclaration obj) {
return equals(obj);
}
}