diff --git a/pom.xml b/pom.xml
index 01e4eb3..3f13131 100755
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,21 @@
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ true
+
+ ${version.jdk}
+ ${version.jdk}
+
+
+
+
+
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Byte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Byte.java
index f64ddec..a402188 100644
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Byte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Byte.java
@@ -107,7 +107,7 @@ public final class Byte extends StorageUnit {
}
@Override
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return BigInteger.ONE;
}
@@ -123,4 +123,9 @@ public final class Byte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return 0;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Exabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Exabyte.java
index 9738d51..1babfba 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Exabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Exabyte.java
@@ -19,6 +19,8 @@ public final class Exabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 6846441733771841250L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_EXABYTE);
+
Exabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Exabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_EXABYTE;
}
@@ -128,4 +130,9 @@ public final class Exabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Exbibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Exbibyte.java
index aa00d47..56bfdf9 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Exbibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Exbibyte.java
@@ -19,6 +19,8 @@ public final class Exbibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 5993490571003918471L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_EXBIBYTE);
+
Exbibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -38,7 +40,7 @@ public final class Exbibyte extends StorageUnit {
*/
@CheckReturnValue
public static @NotNull Exbibyte valueOf(final long numberOfBytes) {
- return valueOf(BigInteger.valueOf(numberOfBytes));
+ return valueOf(java.math.BigInteger.valueOf(numberOfBytes));
}
/**
@@ -112,7 +114,7 @@ public final class Exbibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_EXBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Exbibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Gibibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Gibibyte.java
index 2892325..72eb714 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Gibibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Gibibyte.java
@@ -19,6 +19,8 @@ public final class Gibibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = -1104749948510944566L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_GIBIBYTE);
+
Gibibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Gibibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return BYTES_IN_A_GIBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Gibibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Gigabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Gigabyte.java
index 3295fb0..147d7aa 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Gigabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Gigabyte.java
@@ -19,6 +19,8 @@ public final class Gigabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 7581075190529125530L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_GIGABYTE);
+
Gigabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Gigabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return BYTES_IN_A_GIGABYTE;
}
@@ -128,4 +130,9 @@ public final class Gigabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Kibibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Kibibyte.java
index b7f57c3..d8e670f 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Kibibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Kibibyte.java
@@ -19,6 +19,8 @@ public final class Kibibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 3798828851496657978L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_KIBIBYTE);
+
Kibibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Kibibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_KIBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Kibibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Kilobyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Kilobyte.java
index e536ec3..5665325 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Kilobyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Kilobyte.java
@@ -19,6 +19,8 @@ public final class Kilobyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 6952239416014811456L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_KILOBYTE);
+
Kilobyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Kilobyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return BYTES_IN_A_KILOBYTE;
}
@@ -128,4 +130,9 @@ public final class Kilobyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Mebibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Mebibyte.java
index d9ce27e..7d354fb 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Mebibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Mebibyte.java
@@ -19,6 +19,8 @@ public final class Mebibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 7697583678146919524L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_MEBIBYTE);
+
Mebibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Mebibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_MEBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Mebibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Megabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Megabyte.java
index ca8debd..12e4e88 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Megabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Megabyte.java
@@ -19,6 +19,8 @@ public final class Megabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 5901923092058760111L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_MEGABYTE);
+
Megabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Megabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_MEGABYTE;
}
@@ -128,4 +130,9 @@ public final class Megabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Pebibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Pebibyte.java
index acb5691..64f78e2 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Pebibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Pebibyte.java
@@ -19,6 +19,8 @@ public final class Pebibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = -6112472064345339882L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_PEBIBYTE);
+
Pebibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Pebibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_PEBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Pebibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Petabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Petabyte.java
index e61c3f2..9d83211 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Petabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Petabyte.java
@@ -19,6 +19,8 @@ public final class Petabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 5889808368085688387L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_PETABYTE);
+
Petabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Petabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_PETABYTE;
}
@@ -128,4 +130,9 @@ public final class Petabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Qubibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Qubibyte.java
index 0d4f762..98fc0ba 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Qubibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Qubibyte.java
@@ -19,6 +19,8 @@ public final class Qubibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 8611754914470986560L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_QUBIBYTE);
+
Qubibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Qubibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_QUBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Qubibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Quettabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Quettabyte.java
index 55e4ba5..585b4e9 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Quettabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Quettabyte.java
@@ -19,6 +19,8 @@ public final class Quettabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = -7866123408102424489L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_QUETTABYTE);
+
Quettabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Quettabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_QUETTABYTE;
}
@@ -128,4 +130,9 @@ public final class Quettabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Robibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Robibyte.java
index 37e09c0..bfd384e 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Robibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Robibyte.java
@@ -19,6 +19,8 @@ public final class Robibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 3553336770900659080L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_ROBIBYTE);
+
Robibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Robibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_ROBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Robibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Ronnabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Ronnabyte.java
index a700624..ce2b99b 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Ronnabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Ronnabyte.java
@@ -19,6 +19,8 @@ public final class Ronnabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = -7866123408102424489L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_RONNABYTE);
+
Ronnabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Ronnabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_RONNABYTE;
}
@@ -128,4 +130,9 @@ public final class Ronnabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/StorageUnit.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/StorageUnit.java
index 37d4049..dbf39d4 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/StorageUnit.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/StorageUnit.java
@@ -563,6 +563,86 @@ public final long longValue() {
return bytes.longValue();
}
+ /**
+ * Returns the value in this unit.
+ * @param roundingMode - the rounding mode for the division that divides the
+ * underlying byte value by number of bytes in a single measure of this unit.
+ * This parameter has no effect unless the unit has exuberant bytes per unit value.
+ * @return value in this unit.
+ */
+ @CheckReturnValue
+ public final BigDecimal unitValue(RoundingMode roundingMode) {
+ var divisor = new BigDecimal(getNumberOfBytesPerUnit());
+ var result = new BigDecimal(bytes).divide(divisor, conversionScale(), roundingMode).stripTrailingZeros();
+ if (result.scale() < 0) { result = result.setScale(0); }
+ return result;
+ }
+
+ protected abstract int conversionScale();
+
+ protected static int computeFiniteConversionScale(BigInteger bpu) {
+
+ // $TODO Use of static is ugly.
+ // But there is no lazy initialization in this library.
+ // One can stuff this into a final's field assignment, but
+ // assigning final fields from methods is evil. Moving to Kotlin,
+ // would be "better" alternatives.
+
+ // the default implementation is good for units provided by this library,
+ // because it either x1000 or x1024, where the division always yields a
+ // regular fraction. If any unit that has an exuberant BPU is introduced,
+ // they should override this method.
+ if (bpu.compareTo(BigInteger.ZERO) <= 0) {
+ throw new ArithmeticException("Bytes per unit must be positive");
+ }
+
+ BigInteger current = bpu.abs(); // we only care about factors
+ int p2 = current.getLowestSetBit(); // exponent of 2
+ current = current.shiftRight(p2); // divide by 2^p2
+
+ int p5 = 0; // exponent of 5
+ final BigInteger five = BigInteger.valueOf(5);
+ while (current.mod(five).signum() == 0) { // while divisible by 5
+ current = current.divide(five);
+ ++p5;
+ }
+
+ // anything left ≠ 1 ⇒ other prime
+ if (!current.equals(BigInteger.ONE)) {
+ throw new ArithmeticException("bytes per unit contains prime factor other than 2 or 5, you can't use this");
+ }
+
+ return Math.max(p2, p5);
+ }
+
+ /**
+ * Returns the nearest whole value in this unit.
+ * @param roundingMode - the rounding mode for the division that divides the
+ * underlying byte value by number of bytes in a single measure of this unit,
+ * to come to an integer value.
+ * @return the nearest (according to the specified rounding mode) value in this unit.
+ */
+ public final BigInteger wholeUnitValue(RoundingMode roundingMode) {
+ return new BigDecimal(bytes).divide(new BigDecimal(getNumberOfBytesPerUnit()), 0, roundingMode).toBigInteger();
+ }
+
+ /**
+ * Returns the amount of bytes that didn't fit in the whole value of this unit.
+ * @return number of bytes that didn't fill a whole measure of this unit.
+ */
+ public final BigInteger remainder() {
+ return bytes.remainder(getNumberOfBytesPerUnit());
+ }
+
+ /**
+ * Returns the indication of whether this unit is a whole value, i.e., there is no fractional component,
+ * and the number of bytes stored fill this unit up to its byte per unit value.
+ * @return {@code true} if the unit value has no fractional component, {@code false} otherwise
+ */
+ public final boolean isWhole() {
+ return remainder().equals(BigInteger.ZERO);
+ }
+
/**
* @param bytesToAdd The amount of bytes to add.
* @return The new amount of storage in the appropriate type.
@@ -623,7 +703,11 @@ public final long longValue() {
*/
public abstract @NotNull T subtract(@NotNull StorageUnit> storageAmount);
- protected abstract @NotNull BigInteger getNumberOfBytesPerUnit();
+ /**
+ * Number of bytes in this unit.
+ * @return number of bytes in this unit.
+ */
+ public abstract @NotNull BigInteger getNumberOfBytesPerUnit();
protected abstract @NotNull String getSymbol();
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Tebibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Tebibyte.java
index b68be1f..bebbbb3 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Tebibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Tebibyte.java
@@ -19,6 +19,8 @@ public final class Tebibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 3614537130129620881L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_TEBIBYTE);
+
Tebibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Tebibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return BYTES_IN_A_TEBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Tebibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Terabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Terabyte.java
index 37df3e8..7e2d6d4 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Terabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Terabyte.java
@@ -19,6 +19,8 @@ public final class Terabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 2160488069631638952L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_TERABYTE);
+
Terabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Terabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_TERABYTE;
}
@@ -128,4 +130,9 @@ public final class Terabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Yobibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Yobibyte.java
index 633722b..ed15766 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Yobibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Yobibyte.java
@@ -19,6 +19,8 @@ public final class Yobibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = -5606322878020884194L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_YOBIBYTE);
+
Yobibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Yobibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_YOBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Yobibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Yottabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Yottabyte.java
index 52c5aa1..f95c2bb 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Yottabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Yottabyte.java
@@ -19,6 +19,8 @@ public final class Yottabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 2482152459842042316L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_YOTTABYTE);
+
Yottabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Yottabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_YOTTABYTE;
}
@@ -128,4 +130,9 @@ public final class Yottabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Zebibyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Zebibyte.java
index aa65da1..54bd97a 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Zebibyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Zebibyte.java
@@ -19,6 +19,8 @@ public final class Zebibyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 2192254824473341887L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_ZEBIBYTE);
+
Zebibyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Zebibyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return StorageUnit.BYTES_IN_A_ZEBIBYTE;
}
@@ -128,4 +130,9 @@ public final class Zebibyte extends StorageUnit {
return StorageUnits::binaryValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Zettabyte.java b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Zettabyte.java
index aa0b7fb..51f054a 100755
--- a/storage-units-model/src/main/java/wtf/metio/storageunits/model/Zettabyte.java
+++ b/storage-units-model/src/main/java/wtf/metio/storageunits/model/Zettabyte.java
@@ -19,6 +19,8 @@ public final class Zettabyte extends StorageUnit {
@Serial
private static final long serialVersionUID = 8849006574018911826L;
+ private static final int conversionScale = computeFiniteConversionScale(StorageUnit.BYTES_IN_A_ZETTABYTE);
+
Zettabyte(final @NotNull BigInteger numberOfBytes) {
super(numberOfBytes);
}
@@ -112,7 +114,7 @@ public final class Zettabyte extends StorageUnit {
@Override
@CheckReturnValue
- protected @NotNull BigInteger getNumberOfBytesPerUnit() {
+ public @NotNull BigInteger getNumberOfBytesPerUnit() {
return BYTES_IN_A_ZETTABYTE;
}
@@ -128,4 +130,9 @@ public final class Zettabyte extends StorageUnit {
return StorageUnits::decimalValueOf;
}
+ @Override
+ protected int conversionScale() {
+ return conversionScale;
+ }
+
}
diff --git a/storage-units-model/src/test/java/wtf/metio/storageunits/model/StorageUnitArithmeticBigIntegerTest.java b/storage-units-model/src/test/java/wtf/metio/storageunits/model/StorageUnitArithmeticBigIntegerTest.java
index 0c635c9..7b9e064 100755
--- a/storage-units-model/src/test/java/wtf/metio/storageunits/model/StorageUnitArithmeticBigIntegerTest.java
+++ b/storage-units-model/src/test/java/wtf/metio/storageunits/model/StorageUnitArithmeticBigIntegerTest.java
@@ -8,12 +8,17 @@
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
+import java.math.BigDecimal;
import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.Arrays;
+import java.util.function.Function;
import java.util.stream.LongStream;
import java.util.stream.Stream;
class StorageUnitArithmeticBigIntegerTest {
+ private static final int WHOLE_TEST = 42;
private static LongStream numberOfBytes() {
return LongStream.of(1, 2, 3, 5, 8, 13, 100, 500, -500, 123456789);
}
@@ -135,4 +140,57 @@ Stream returnNewInstanceAfterSubtractBigInteger() {
});
}
+ @TestFactory
+ Stream getUnitValue() {
+
+ record D(Function> constructor, RoundingMode rm) {}
+
+ return Arrays.stream(RoundingMode.values()).flatMap(rm->
+ TestObjects.bigIntegerBasedConstructors().stream().map(e->new D(e, rm)))
+ .map(ti -> {
+ final var initialAmount = BigInteger.valueOf(1);
+ final var first = ti.constructor.apply(initialAmount);
+ final var bpu = first.getNumberOfBytesPerUnit();
+ final int digits = first.getNumberOfBytesPerUnit().toString().length();
+
+ return DynamicTest.dynamicTest(String.format("getUnitValue() - %s - %s", first.getClass().getSimpleName(), ti.rm), () -> {
+
+ // fill it up to the brim.
+ StringBuilder sb = new StringBuilder(digits);
+ for (int i = 0; i < digits; i++) { sb.append((char)(i%9+ '1')); }
+ var testValue = new BigInteger(sb.toString());
+ final var real = ti.constructor.apply(testValue);
+
+ // do the math ourselves and compare? What else can we do.
+ // scale value of 1000 - just something that's guaranteed to cover
+ // all defined units, and isn't too large enough to slow JDK down
+ var exp = new BigDecimal(testValue).divide(new BigDecimal(bpu), 1000, ti.rm).stripTrailingZeros();
+ Assertions.assertEquals(exp, real.unitValue(ti.rm), ()->"unitValue() - "+ti.rm + " on "+testValue + ", bpu="+bpu +", scale="+real.conversionScale());
+
+ // make sure we didn't miswire any of the implementations.
+ Assertions.assertEquals(StorageUnit.computeFiniteConversionScale(bpu), real.conversionScale());
+
+ if (ti.rm != RoundingMode.UNNECESSARY) {
+ var wholeExp = new BigDecimal(testValue).divide(new BigDecimal(bpu), 0, ti.rm).toBigInteger();
+ Assertions.assertEquals(wholeExp, real.wholeUnitValue(ti.rm), () -> "wholeUnitValue() - " + ti.rm + " on " + testValue + ", bpu=" + bpu + ", scale=" + real.conversionScale());
+ }
+
+ var remExp = testValue.remainder(bpu);
+ Assertions.assertEquals(remExp, real.remainder());
+
+ if (bpu.equals(BigInteger.ONE)) {
+ Assertions.assertTrue(real.isWhole());
+ } else {
+ Assertions.assertFalse(real.isWhole());
+ var whole = ti.constructor.apply(BigInteger.valueOf(WHOLE_TEST).multiply(bpu));
+ Assertions.assertTrue(whole.isWhole());
+ if (ti.rm == RoundingMode.UNNECESSARY) {
+ Assertions.assertEquals(BigInteger.valueOf(WHOLE_TEST), whole.wholeUnitValue(ti.rm));
+ }
+ }
+
+ });
+ });
+ }
+
}