| /******************************************************************************* |
| * 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); |
| } |
| } |