package org.embulk.spi.unit;
import java.util.Objects;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.base.Preconditions;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public class ByteSize
implements Comparable<ByteSize>
{
private static final Pattern PATTERN = Pattern.compile("\\A(\\d+(?:\\.\\d+)?)\\s?([a-zA-Z]*)\\z");
private final long bytes;
private final Unit displayUnit;
public ByteSize(double size, Unit unit)
{
Preconditions.checkArgument(!Double.isInfinite(size), "size is infinite");
Preconditions.checkArgument(!Double.isNaN(size), "size is not a number");
Preconditions.checkArgument(size >= 0, "size is negative");
Preconditions.checkNotNull(unit, "unit is null");
Preconditions.checkArgument(size * unit.getFactor() <= (double) Long.MAX_VALUE, "size is large than (2^63)-1 in bytes");
this.bytes = (long) (size * unit.getFactor());
this.displayUnit = unit;
}
@JsonCreator
public ByteSize(long bytes)
{
Preconditions.checkArgument(bytes >= 0, "size is negative");
this.bytes = bytes;
this.displayUnit = Unit.BYTES;
}
public long getBytes()
{
return bytes;
}
public int getBytesInt()
{
if (bytes > Integer.MAX_VALUE) {
throw new RuntimeException("Byte size is too large (must be smaller than 2GB)");
}
return (int) bytes;
}
public long roundTo(Unit unit)
{
return (long) Math.floor(getValue(unit) + 0.5);
}
public double getValue(Unit unit)
{
return bytes / (double) unit.getFactor();
}
@JsonCreator
public static ByteSize parseByteSize(String size)
{
Preconditions.checkNotNull(size, "size is null");
Preconditions.checkArgument(!size.isEmpty(), "size is empty");
Matcher matcher = PATTERN.matcher(size);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid byte size string '" + size + "'");
}
double value = Double.parseDouble(matcher.group(1)); // NumberFormatException extends IllegalArgumentException.
String unitString = matcher.group(2);
if (unitString.isEmpty()) {
return new ByteSize(value, Unit.BYTES);
} else {
String upperUnitString = unitString.toUpperCase(Locale.ENGLISH);
for (Unit unit : Unit.values()) {
if (unit.getUnitString().toUpperCase(Locale.ENGLISH).equals(upperUnitString)) {
return new ByteSize(value, unit);
}
}
}
throw new IllegalArgumentException("Unknown unit '" + unitString + "'");
}
@JsonValue
@Override
public String toString()
{
double value = getValue(displayUnit);
String integer = String.format(Locale.ENGLISH, "%d", (long) value);
String decimal = String.format(Locale.ENGLISH, "%.2f", value);
if (decimal.equals(integer + ".00")) {
return integer + displayUnit.getUnitString();
} else {
return decimal + displayUnit.getUnitString();
}
}
@Override
public int compareTo(ByteSize o)
{
return Long.compare(bytes, o.bytes);
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if (!(obj instanceof ByteSize)) {
return false;
}
ByteSize o = (ByteSize) obj;
return this.bytes == o.bytes;
}
@Override
public int hashCode()
{
return Objects.hashCode(bytes);
}
public enum Unit
{
BYTES(1L, "B"),
KB(1L << 10, "KB"),
MB(1L << 20, "MB"),
GB(1L << 30, "GB"),
TB(1L << 40, "TB"),
PT(1L << 50, "PB");
private final long factor;
private final String unitString;
Unit(long factor, String unitString)
{
this.factor = factor;
this.unitString = unitString;
}
long getFactor()
{
return factor;
}
String getUnitString()
{
return unitString;
}
}
}