com.thimbleware.jmemcached.util.Bytes Maven / Gradle / Ivy
/**
* Taken and adapted from the Apache Wicket source.
*/
/*
* ==============================================================================
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.thimbleware.jmemcached.util;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Represents an immutable byte count. These static factory methods allow easy
* construction of value objects using either long values like bytes(2034) or
* megabytes(3):
*
*
* - Bytes.bytes(long)
*
- Bytes.kilobytes(long)
*
- Bytes.megabytes(long)
*
- Bytes.gigabytes(long)
*
- Bytes.terabytes(long)
*
*
* or double precision floating point values like megabytes(3.2):
*
*
* - Bytes.bytes(double)
*
- Bytes.kilobytes(double)
*
- Bytes.megabytes(double)
*
- Bytes.gigabytes(double)
*
- Bytes.terabytes(double)
*
*
* In the case of bytes(double), the value will be rounded off to the nearest
* integer byte count using Math.round().
*
* The precise number of bytes in a Bytes object can be retrieved by calling
* bytes(). Approximate values for different units can be retrieved as double
* precision values using these methods:
*
*
* - kilobytes()
*
- megabytes()
*
- gigabytes()
*
- terabytes()
*
*
* Also, value objects can be constructed from strings, optionally using a
* Locale with valueOf(String) and valueOf(String,Locale). The string may
* contain a decimal or floating point number followed by optional whitespace
* followed by a unit (nothing for bytes, K for kilobyte, M for megabytes, G for
* gigabytes or T for terabytes) optionally followed by a B (for bytes). Any of
* these letters can be any case. So, examples of permissible string values are:
*
*
* - 37 (37 bytes)
*
- 2.3K (2.3 kilobytes)
*
- 2.5 kb (2.5 kilobytes)
*
- 4k (4 kilobytes)
*
- 35.2GB (35.2 gigabytes)
*
- 1024M (1024 megabytes)
*
*
* Note that if the Locale was not US, the values might substitute "," for "."
* as that is the custom in Euroland.
*
* The toString() methods is smart enough to convert a
* given value object to the most appropriate units for the given value.
*
* @author Jonathan Locke
*/
public final class Bytes
{
/** Pattern for string parsing. */
private static final Pattern valuePattern = Pattern.compile(
"([0-9]+([\\.,][0-9]+)?)\\s*(|K|M|G|T)B?", Pattern.CASE_INSENSITIVE);
/** Maximum bytes value */
public static Bytes MAX = bytes(Long.MAX_VALUE);
private long value;
/**
* Private constructor forces use of static factory methods.
*
* @param bytes
* Number of bytes
*/
private Bytes(final long bytes)
{
this.value = bytes;
}
/**
* Instantiate immutable Bytes value object..
*
* @param bytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes bytes(final long bytes)
{
return new Bytes(bytes);
}
/**
* Instantiate immutable Bytes value object..
*
* @param kilobytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes kilobytes(final long kilobytes)
{
return bytes(kilobytes * 1024);
}
/**
* Instantiate immutable Bytes value object..
*
* @param megabytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes megabytes(final long megabytes)
{
return kilobytes(megabytes * 1024);
}
/**
* Instantiate immutable Bytes value object..
*
* @param gigabytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes gigabytes(final long gigabytes)
{
return megabytes(gigabytes * 1024);
}
/**
* Instantiate immutable Bytes value object..
*
* @param terabytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes terabytes(final long terabytes)
{
return gigabytes(terabytes * 1024);
}
/**
* Instantiate immutable Bytes value object..
*
* @param bytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes bytes(final double bytes)
{
return bytes(Math.round(bytes));
}
/**
* Instantiate immutable Bytes value object..
*
* @param kilobytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes kilobytes(final double kilobytes)
{
return bytes(kilobytes * 1024.0);
}
/**
* Instantiate immutable Bytes value object..
*
* @param megabytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes megabytes(final double megabytes)
{
return kilobytes(megabytes * 1024.0);
}
/**
* Instantiate immutable Bytes value object..
*
* @param gigabytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes gigabytes(final double gigabytes)
{
return megabytes(gigabytes * 1024.0);
}
/**
* Instantiate immutable Bytes value object..
*
* @param terabytes
* Value to convert
* @return Input as Bytes
*/
public static Bytes terabytes(final double terabytes)
{
return gigabytes(terabytes * 1024.0);
}
/**
* Gets the byte count represented by this value object.
*
* @return Byte count
*/
public final long bytes()
{
return value;
}
/**
* Gets the byte count in kilobytes.
*
* @return The value in kilobytes
*/
public final double kilobytes()
{
return value / 1024.0;
}
/**
* Gets the byte count in megabytes.
*
* @return The value in megabytes
*/
public final double megabytes()
{
return kilobytes() / 1024.0;
}
/**
* Gets the byte count in gigabytes.
*
* @return The value in gigabytes
*/
public final double gigabytes()
{
return megabytes() / 1024.0;
}
/**
* Gets the byte count in terabytes.
*
* @return The value in terabytes
*/
public final double terabytes()
{
return gigabytes() / 1024.0;
}
/**
* Converts a string to a number of bytes. Strings consist of a floating
* point value followed by K, M, G or T for kilobytes, megabytes, gigabytes
* or terabytes, respectively. The abbreviations KB, MB, GB and TB are also
* accepted. Matching is case insensitive.
*
* @param string
* The string to convert
* @param locale
* The Locale to be used for transformation
* @return The Bytes value for the string
* @throws NumberFormatException
*/
public static Bytes valueOf(final String string, final Locale locale)
throws NumberFormatException
{
final Matcher matcher = valuePattern.matcher(string);
// Valid input?
if (matcher.matches())
{
try
{
// Get double precision value
final double value = NumberFormat.getNumberInstance(locale).parse(matcher.group(1))
.doubleValue();
// Get units specified
final String units = matcher.group(3);
if (units.equalsIgnoreCase(""))
{
return bytes(value);
}
else if (units.equalsIgnoreCase("K"))
{
return kilobytes(value);
}
else if (units.equalsIgnoreCase("M"))
{
return megabytes(value);
}
else if (units.equalsIgnoreCase("G"))
{
return gigabytes(value);
}
else if (units.equalsIgnoreCase("T"))
{
return terabytes(value);
}
else
{
throw new NumberFormatException("Units not recognized: " + string);
}
}
catch (ParseException e)
{
throw new NumberFormatException("Unable to parse numeric part: " + string);
}
}
else
{
throw new NumberFormatException("Unable to parse bytes: " + string);
}
}
/**
* Converts a string to a number of bytes. Strings consist of a floating
* point value followed by K, M, G or T for kilobytes, megabytes, gigabytes
* or terabytes, respectively. The abbreviations KB, MB, GB and TB are also
* accepted. Matching is case insensitive.
*
* @param string
* The string to convert
* @return The Bytes value for the string
* @throws NumberFormatException
*/
public static Bytes valueOf(final String string) throws NumberFormatException
{
return valueOf(string, Locale.getDefault());
}
/**
* Converts this byte count to a string using the given locale.
*
* @return The string for this byte count
*/
public String toString()
{
if (value >= 0)
{
if (terabytes() >= 1.0)
{
return unitString(gigabytes(), "T");
}
if (gigabytes() >= 1.0)
{
return unitString(gigabytes(), "G");
}
if (megabytes() >= 1.0)
{
return unitString(megabytes(), "M");
}
if (kilobytes() >= 1.0)
{
return unitString(kilobytes(), "K");
}
return Long.toString(value) + " bytes";
}
else
{
return "N/A";
}
}
/**
* Convert value to formatted floating point number and units.
*
* @param value
* The value
* @param units
* The units
* @return The formatted string
*/
private String unitString(final double value, final String units)
{
return "" + units;
}
}