forked from chirino/lmdbjni
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1943ca5
commit 2213c89
Showing
1 changed file
with
339 additions
and
0 deletions.
There are no files selected for viewing
339 changes: 339 additions & 0 deletions
339
lmdbjni/src/main/java/org/fusesource/lmdbjni/ByteUnit.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,339 @@ | ||
package org.fusesource.lmdbjni; | ||
|
||
import java.text.DecimalFormat; | ||
import java.text.NumberFormat; | ||
|
||
/** | ||
* A {@code BinaryByteUnit} represents power-of-two byte sizes at a given unit of granularity and | ||
* provides utility methods to convert across units. A {@code BinaryByteUnit} does not maintain | ||
* byte size information, but only helps organize and use byte size representations that may be | ||
* maintained separately across various contexts. | ||
* | ||
* @author Jake Wharton | ||
*/ | ||
public enum ByteUnit { | ||
|
||
/** Byte unit representing one byte. */ | ||
BYTES { | ||
@Override public long convert(long sourceCount, ByteUnit sourceUnit) { | ||
return sourceUnit.toBytes(sourceCount); | ||
} | ||
|
||
public long toBytes(long count) { | ||
return count; | ||
} | ||
|
||
@Override public long toKibibytes(long count) { | ||
return count / (KB / B); | ||
} | ||
|
||
@Override public long toMebibytes(long count) { | ||
return count / (MB / B); | ||
} | ||
|
||
@Override public long toGibibytes(long count) { | ||
return count / (GB / B); | ||
} | ||
|
||
@Override public long toTebibytes(long count) { | ||
return count / (TB / B); | ||
} | ||
|
||
@Override public long toPebibytes(long count) { | ||
return count / (PB / B); | ||
} | ||
}, | ||
|
||
/** A byte unit representing 1024 bytes. */ | ||
KIBIBYTES { | ||
@Override public long convert(long sourceCount, ByteUnit sourceUnit) { | ||
return sourceUnit.toKibibytes(sourceCount); | ||
} | ||
|
||
public long toBytes(long count) { | ||
return multiply(count, KB / B, MAX / (KB / B)); | ||
} | ||
|
||
@Override public long toKibibytes(long count) { | ||
return count; | ||
} | ||
|
||
@Override public long toMebibytes(long count) { | ||
return count / (MB / KB); | ||
} | ||
|
||
@Override public long toGibibytes(long count) { | ||
return count / (GB / KB); | ||
} | ||
|
||
@Override public long toTebibytes(long count) { | ||
return count / (TB / KB); | ||
} | ||
|
||
@Override public long toPebibytes(long count) { | ||
return count / (PB / KB); | ||
} | ||
}, | ||
|
||
/** A byte unit representing 1024 kibibytes. */ | ||
MEBIBYTES { | ||
@Override public long convert(long sourceCount, ByteUnit sourceUnit) { | ||
return sourceUnit.toMebibytes(sourceCount); | ||
} | ||
|
||
public long toBytes(long count) { | ||
return multiply(count, MB / B, MAX / (MB / B)); | ||
} | ||
|
||
@Override public long toKibibytes(long count) { | ||
return multiply(count, MB / KB, MAX / (MB / KB)); | ||
} | ||
|
||
@Override public long toMebibytes(long count) { | ||
return count; | ||
} | ||
|
||
@Override public long toGibibytes(long count) { | ||
return count / (GB / MB); | ||
} | ||
|
||
@Override public long toTebibytes(long count) { | ||
return count / (TB / MB); | ||
} | ||
|
||
@Override public long toPebibytes(long count) { | ||
return count / (PB / MB); | ||
} | ||
}, | ||
|
||
/** A byte unit representing 1024 mebibytes. */ | ||
GIBIBYTES { | ||
@Override public long convert(long sourceCount, ByteUnit sourceUnit) { | ||
return sourceUnit.toGibibytes(sourceCount); | ||
} | ||
|
||
public long toBytes(long count) { | ||
return multiply(count, GB / B, MAX / (GB / B)); | ||
} | ||
|
||
@Override public long toKibibytes(long count) { | ||
return multiply(count, GB / KB, MAX / (GB / KB)); | ||
} | ||
|
||
@Override public long toMebibytes(long count) { | ||
return multiply(count, GB / MB, MAX / (GB / MB)); | ||
} | ||
|
||
@Override public long toGibibytes(long count) { | ||
return count; | ||
} | ||
|
||
@Override public long toTebibytes(long count) { | ||
return count / (TB / GB); | ||
} | ||
|
||
@Override public long toPebibytes(long count) { | ||
return count / (PB / GB); | ||
} | ||
}, | ||
|
||
/** A byte unit representing 1024 gibibytes. */ | ||
TEBIBYTES { | ||
@Override public long convert(long sourceCount, ByteUnit sourceUnit) { | ||
return sourceUnit.toTebibytes(sourceCount); | ||
} | ||
|
||
public long toBytes(long count) { | ||
return multiply(count, TB / B, MAX / (TB / B)); | ||
} | ||
|
||
@Override public long toKibibytes(long count) { | ||
return multiply(count, TB / KB, MAX / (TB / KB)); | ||
} | ||
|
||
@Override public long toMebibytes(long count) { | ||
return multiply(count, TB / MB, MAX / (TB / MB)); | ||
} | ||
|
||
@Override public long toGibibytes(long count) { | ||
return multiply(count, TB / GB, MAX / (TB / GB)); | ||
} | ||
|
||
@Override public long toTebibytes(long count) { | ||
return count; | ||
} | ||
|
||
@Override public long toPebibytes(long count) { | ||
return count / (PB / TB); | ||
} | ||
}, | ||
|
||
/** A byte unit representing 1024 tebibytes. */ | ||
PEBIBYTES { | ||
@Override public long convert(long sourceCount, ByteUnit sourceUnit) { | ||
return sourceUnit.toPebibytes(sourceCount); | ||
} | ||
|
||
public long toBytes(long count) { | ||
return multiply(count, PB / B, MAX / (PB / B)); | ||
} | ||
|
||
@Override public long toKibibytes(long count) { | ||
return multiply(count, PB / KB, MAX / (PB / KB)); | ||
} | ||
|
||
@Override public long toMebibytes(long count) { | ||
return multiply(count, PB / MB, MAX / (PB / MB)); | ||
} | ||
|
||
@Override public long toGibibytes(long count) { | ||
return multiply(count, PB / GB, MAX / (PB / GB)); | ||
} | ||
|
||
@Override public long toTebibytes(long count) { | ||
return multiply(count, PB / TB, MAX / (PB / TB)); | ||
} | ||
|
||
@Override public long toPebibytes(long count) { | ||
return count; | ||
} | ||
}; | ||
|
||
/** | ||
* Converts the given size in the given unit to bytes. Conversions with arguments that would | ||
* numerically overflow saturate to {@code Long.MIN_VALUE} if negative or {@code Long.MAX_VALUE} | ||
* if positive. | ||
* | ||
* @param count the bit count | ||
* @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively | ||
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow. | ||
*/ | ||
abstract long toBytes(long count); | ||
|
||
private static final long B = 1L; | ||
private static final long KB = B * 1024L; | ||
private static final long MB = KB * 1024L; | ||
private static final long GB = MB * 1024L; | ||
private static final long TB = GB * 1024L; | ||
private static final long PB = TB * 1024L; | ||
|
||
private static final long MAX = Long.MAX_VALUE; | ||
|
||
/** | ||
* Converts the given size in the given unit to this unit. Conversions from finer to coarser | ||
* granularities truncate, so lose precision. For example, converting from {@code 999} bytes to | ||
* kibibytes results in {@code 0}. Conversions from coarser to finer granularities with arguments | ||
* that would numerically overflow saturate to {@code Long.MIN_VALUE} if negative or | ||
* {@code Long.MAX_VALUE} if positive. | ||
* <p> | ||
* For example, to convert 10 kilobytes to bytes, use: | ||
* {@code ByteUnit.KIBIBYTES.convert(10, ByteUnit.BYTES)} | ||
* | ||
* @param sourceCount the size in the given {@code sourceUnit}. | ||
* @param sourceUnit the unit of the {@code sourceCount} argument. | ||
* @return the converted size in this unit, or {@code Long.MIN_VALUE} if conversion would | ||
* negatively overflow, or {@code Long.MAX_VALUE} if it would positively overflow. | ||
*/ | ||
public long convert(long sourceCount, ByteUnit sourceUnit) { | ||
throw new AbstractMethodError(); | ||
} | ||
|
||
/** | ||
* Equivalent to {@link #convert(long, ByteUnit) KIBIBYTES.convert(count, this)}. | ||
* @param count the bit count | ||
* @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively | ||
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow. | ||
*/ | ||
public long toKibibytes(long count) { | ||
throw new AbstractMethodError(); | ||
} | ||
|
||
/** | ||
* Equivalent to {@link #convert(long, ByteUnit) MEBIBYTES.convert(count, this)}. | ||
* @param count the bit count | ||
* @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively | ||
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow. | ||
*/ | ||
public long toMebibytes(long count) { | ||
throw new AbstractMethodError(); | ||
} | ||
|
||
/** | ||
* Equivalent to {@link #convert(long, ByteUnit) GIBIBYTES.convert(count, this)}. | ||
* @param count the bit count | ||
* @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively | ||
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow. | ||
*/ | ||
public long toGibibytes(long count) { | ||
throw new AbstractMethodError(); | ||
} | ||
|
||
/** | ||
* Equivalent to {@link #convert(long, ByteUnit) TEBIBYTES.convert(count, this)}. | ||
* @param count the bit count | ||
* @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively | ||
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow. | ||
*/ | ||
public long toTebibytes(long count) { | ||
throw new AbstractMethodError(); | ||
} | ||
|
||
/** | ||
* Equivalent to {@link #convert(long, ByteUnit) PEBIBYTES.convert(count, this)}. | ||
* @param count the bit count | ||
* @return the converted count, or {@code Long.MIN_VALUE} if conversion would negatively | ||
* overflow, or {@code Long.MAX_VALUE} if it would positively overflow. | ||
*/ | ||
public long toPebibytes(long count) { | ||
throw new AbstractMethodError(); | ||
} | ||
|
||
private static final String[] UNITS = { "B", "KiB", "MiB", "GiB", "TiB", "PiB" }; | ||
|
||
/** | ||
* Return {@code bytes} as human-readable size string (e.g., "1.2 GiB". This will use a default | ||
* {@link DecimalFormat} instance for formatting the number. | ||
*/ | ||
public static String format(long bytes) { | ||
return format(bytes, new DecimalFormat(DEFAULT_FORMAT_PATTERN)); | ||
} | ||
|
||
/** | ||
* Return {@code bytes} as human-readable size string (e.g., "1.2 GiB". This will use a | ||
* {@link DecimalFormat} instance with {@code pattern} for formatting the number. | ||
*/ | ||
public static String format(long bytes, String pattern) { | ||
return format(bytes, new DecimalFormat(pattern)); | ||
} | ||
|
||
/** | ||
* Return {@code bytes} as human-readable size string (e.g., "1.2 GiB". This will use {@code | ||
* format} for formatting the number. | ||
*/ | ||
public static String format(long bytes, NumberFormat format) { | ||
if (bytes < 0) { | ||
throw new IllegalArgumentException("bytes < 0: " + bytes); | ||
} | ||
|
||
int unitIndex = 0; | ||
double count = bytes; | ||
while (count >= 1024d && unitIndex < UNITS.length - 1) { | ||
count /= 1024d; | ||
unitIndex += 1; | ||
} | ||
return format.format(count) + ' ' + UNITS[unitIndex]; | ||
} | ||
|
||
static final String DEFAULT_FORMAT_PATTERN = "#,##0.#"; | ||
|
||
/** Multiply {@code size} by {@code factor} accounting for overflow. */ | ||
private static long multiply(long size, long factor, long over) { | ||
if (size > over) { | ||
return Long.MAX_VALUE; | ||
} | ||
if (size < -over) { | ||
return Long.MIN_VALUE; | ||
} | ||
return size * factor; | ||
} | ||
} |