/*******************************************************************************
* Copyright (c) 2016 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.tracecompass.common.core.format;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.Format;
import java.text.NumberFormat;
import java.text.ParsePosition;
import org.eclipse.jdt.annotation.NonNull;
/**
* Provides a formatter for data sizes along with the unit of size (KG, MB, GB
* ou TB). It receives a size in bytes and it formats a number in the closest
* thousand's unit, with at most 3 decimals.
*
* @author Matthew Khouzam
* @since 2.0
*/
public class DataSizeWithUnitFormat extends Format {
private static final @NonNull Format INSTANCE = new DataSizeWithUnitFormat();
private static final long serialVersionUID = 3934127385682676804L;
private static final String B = "B"; //$NON-NLS-1$
private static final String K = "K"; //$NON-NLS-1$
private static final String M = "M"; //$NON-NLS-1$
private static final String G = "G"; //$NON-NLS-1$
private static final String T = "T"; //$NON-NLS-1$
private static final long KILO = 1024;
private static final Format FORMAT = new DecimalFormat("#.###"); //$NON-NLS-1$
/**
* Protected constructor
*/
protected DataSizeWithUnitFormat() {
super();
}
/**
* Returns the instance of this formatter
*
* @return The instance of this formatter
*/
public static @NonNull Format getInstance() {
return INSTANCE;
}
@Override
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
if (obj instanceof Number) {
Number num = (Number) obj;
double value = num.doubleValue();
double abs = Math.abs(value);
if (value == 0) {
return toAppendTo.append("0"); //$NON-NLS-1$
}
if (abs >= KILO * KILO * KILO * KILO) {
return toAppendTo.append(FORMAT.format(value / (KILO * KILO * KILO * KILO))).append(' ').append(T).append(B);
}
if (abs >= KILO * KILO * KILO) {
return toAppendTo.append(FORMAT.format(value / (KILO * KILO * KILO))).append(' ').append(G).append(B);
}
if (abs >= KILO * KILO) {
return toAppendTo.append(FORMAT.format(value / (KILO * KILO))).append(' ').append(M).append(B);
}
if (abs >= KILO) {
return toAppendTo.append(FORMAT.format(value / (KILO))).append(' ').append(K).append(B);
}
return toAppendTo.append(FORMAT.format(value)).append(' ').append(B);
}
return toAppendTo.append(obj);
}
/**
* @since 2.2
*/
@Override
public Number parseObject(String source, ParsePosition pos) {
Number number = NumberFormat.getInstance().parse(source, pos);
if (number == null) {
return null;
}
String unit = source.substring(pos.getIndex()).trim().toUpperCase();
long multiplier = 1;
if (!unit.isEmpty()) {
if (unit.startsWith(K)) {
multiplier = KILO;
} else if (unit.startsWith(M)) {
multiplier = KILO * KILO;
} else if (unit.startsWith(G)) {
multiplier = KILO * KILO * KILO;
} else if (unit.startsWith(T)) {
multiplier = KILO * KILO * KILO * KILO;
}
}
if (multiplier != 1 && Double.isFinite(number.doubleValue())) {
BigDecimal bd = new BigDecimal(number.toString());
bd = bd.multiply(BigDecimal.valueOf(multiplier));
if (bd.remainder(BigDecimal.ONE).equals(BigDecimal.ZERO) &&
bd.abs().compareTo(new BigDecimal(Long.MAX_VALUE)) < 0) {
return bd.longValue();
}
return bd.doubleValue();
}
return number;
}
}