From cb4693073c437468f1e97ed8ed02b853a3c0e875 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 01 Jun 2007 11:05:50 +0000
Subject: [PATCH] Add a new method for retrieving the "best-fit" size unit appropriate for a given number of bytes. This is intended for use in user interfaces since the value returned maybe a floating point value and subject to small errors. For LDAP encoding/decoding we still have the original getBestFitUnit() method but it has been renamed to getBestFitUnitExact(). Both methods are class methods.
---
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java | 55 ++++++++--
opendj-sdk/opends/src/server/org/opends/server/admin/SizePropertyDefinition.java | 3
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java | 14 ++
opendj-sdk/opends/src/server/org/opends/server/admin/SizeUnit.java | 199 +++++++++++++++++++++++++++------------
4 files changed, 193 insertions(+), 78 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/SizePropertyDefinition.java b/opendj-sdk/opends/src/server/org/opends/server/admin/SizePropertyDefinition.java
index e9d89b7..f30bca0 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/SizePropertyDefinition.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/SizePropertyDefinition.java
@@ -312,9 +312,10 @@
return UNLIMITED;
}
}
+
// Encode the size value using the best-fit unit.
StringBuilder builder = new StringBuilder();
- SizeUnit unit = SizeUnit.BYTES.getBestFitUnit(value);
+ SizeUnit unit = SizeUnit.getBestFitUnitExact(value);
// Cast to a long to remove fractional part (which should not be there
// anyway as the best-fit unit should result in an exact conversion).
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/SizeUnit.java b/opendj-sdk/opends/src/server/org/opends/server/admin/SizeUnit.java
index df735b2..8f58bbf 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/SizeUnit.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/SizeUnit.java
@@ -46,24 +46,9 @@
BYTES(1L, "b", "bytes"),
/**
- * A kilo-byte unit.
+ * A gibi-byte unit.
*/
- KILO_BYTES(1000L, "kb", "kilobytes"),
-
- /**
- * A kibi-byte unit.
- */
- KIBI_BYTES(1024L, "kib", "kibibytes"),
-
- /**
- * A mega-byte unit.
- */
- MEGA_BYTES((long) 1000 * 1000, "mb", "megabytes"),
-
- /**
- * A mebi-byte unit.
- */
- MEBI_BYTES((long) 1024 * 1024, "mib", "mebibytes"),
+ GIBI_BYTES((long) 1024 * 1024 * 1024, "gib", "gibibytes"),
/**
* A giga-byte unit.
@@ -71,19 +56,34 @@
GIGA_BYTES((long) 1000 * 1000 * 1000, "gb", "gigabytes"),
/**
- * A gibi-byte unit.
+ * A kibi-byte unit.
*/
- GIBI_BYTES((long) 1024 * 1024 * 1024, "gib", "gibibytes"),
+ KIBI_BYTES(1024L, "kib", "kibibytes"),
/**
- * A tera-byte unit.
+ * A kilo-byte unit.
*/
- TERA_BYTES((long) 1000 * 1000 * 1000 * 1000, "tb", "terabytes"),
+ KILO_BYTES(1000L, "kb", "kilobytes"),
+
+ /**
+ * A mebi-byte unit.
+ */
+ MEBI_BYTES((long) 1024 * 1024, "mib", "mebibytes"),
+
+ /**
+ * A mega-byte unit.
+ */
+ MEGA_BYTES((long) 1000 * 1000, "mb", "megabytes"),
/**
* A tebi-byte unit.
*/
- TEBI_BYTES((long) 1024 * 1024 * 1024 * 1024, "tib", "tebibytes");
+ TEBI_BYTES((long) 1024 * 1024 * 1024 * 1024, "tib", "tebibytes"),
+
+ /**
+ * A tera-byte unit.
+ */
+ TERA_BYTES((long) 1000 * 1000 * 1000 * 1000, "tb", "terabytes");
// A lookup table for resolving a unit from its name.
private static final Map<String, SizeUnit> nameToUnit;
@@ -99,15 +99,120 @@
/**
+ * Gets the best-fit unit for the specified number of bytes. The
+ * returned unit will be able to represent the number of bytes using
+ * a decimal number comprising of an integer part which is greater
+ * than zero. Bigger units are chosen in preference to smaller units
+ * and binary units are only returned if they are an exact fit. If
+ * the number of bytes is zero then the {@link #BYTES} unit is
+ * always returned. For example:
+ *
+ * <pre>
+ * getBestFitUnit(0) // BYTES
+ * getBestFitUnit(999) // BYTES
+ * getBestFitUnit(1000) // KILO_BYTES
+ * getBestFitUnit(1024) // KIBI_BYTES
+ * getBestFitUnit(1025) // KILO_BYTES
+ * getBestFitUnit(999999) // KILO_BYTES
+ * getBestFitUnit(1000000) // MEGA_BYTES
+ * </pre>
+ *
+ * @param bytes
+ * The number of bytes.
+ * @return Returns the best fit unit.
+ * @throws IllegalArgumentException
+ * If <code>bytes</code> is negative.
+ * @see #getBestFitUnitExact(long)
+ */
+ public static SizeUnit getBestFitUnit(long bytes)
+ throws IllegalArgumentException {
+ if (bytes < 0) {
+ throw new IllegalArgumentException("negative number of bytes: " + bytes);
+ } else if (bytes == 0) {
+ // Always use bytes for zero values.
+ return BYTES;
+ } else {
+ // Determine best fit: prefer non-binary units unless binary
+ // fits exactly.
+ SizeUnit[] nonBinary = new SizeUnit[] { TERA_BYTES, GIGA_BYTES,
+ MEGA_BYTES, KILO_BYTES };
+ SizeUnit[] binary = new SizeUnit[] { TEBI_BYTES, GIBI_BYTES, MEBI_BYTES,
+ KIBI_BYTES };
+
+ for (int i = 0; i < nonBinary.length; i++) {
+ if ((bytes % binary[i].getSize()) == 0) {
+ return binary[i];
+ } else if ((bytes / nonBinary[i].getSize()) > 0) {
+ return nonBinary[i];
+ }
+ }
+
+ return BYTES;
+ }
+ }
+
+
+
+ /**
+ * Gets the best-fit unit for the specified number of bytes which
+ * can represent the provided value using an integral value. Bigger
+ * units are chosen in preference to smaller units. If the number of
+ * bytes is zero then the {@link #BYTES} unit is always returned.
+ * For example:
+ *
+ * <pre>
+ * getBestFitUnitExact(0) // BYTES
+ * getBestFitUnitExact(999) // BYTES
+ * getBestFitUnitExact(1000) // KILO_BYTES
+ * getBestFitUnitExact(1024) // KIBI_BYTES
+ * getBestFitUnitExact(1025) // BYTES
+ * getBestFitUnitExact(999999) // BYTES
+ * getBestFitUnitExact(1000000) // MEGA_BYTES
+ * </pre>
+ *
+ * @param bytes
+ * The number of bytes.
+ * @return Returns the best fit unit can represent the provided
+ * value using an integral value.
+ * @throws IllegalArgumentException
+ * If <code>bytes</code> is negative.
+ * @see #getBestFitUnit(long)
+ */
+ public static SizeUnit getBestFitUnitExact(long bytes)
+ throws IllegalArgumentException {
+ if (bytes < 0) {
+ throw new IllegalArgumentException("negative number of bytes: " + bytes);
+ } else if (bytes == 0) {
+ // Always use bytes for zero values.
+ return BYTES;
+ } else {
+ // Determine best fit.
+ SizeUnit[] units = new SizeUnit[] { TEBI_BYTES, TERA_BYTES, GIBI_BYTES,
+ GIGA_BYTES, MEBI_BYTES, MEGA_BYTES, KIBI_BYTES, KILO_BYTES };
+
+ for (SizeUnit unit : units) {
+ if ((bytes % unit.getSize()) == 0) {
+ return unit;
+ }
+ }
+
+ return BYTES;
+ }
+ }
+
+
+
+ /**
* Get the unit corresponding to the provided unit name.
*
* @param s
- * The name of the unit. Can be the abbreviated or long name and can
- * contain white space and mixed case characters.
+ * The name of the unit. Can be the abbreviated or long
+ * name and can contain white space and mixed case
+ * characters.
* @return Returns the unit corresponding to the provided unit name.
* @throws IllegalArgumentException
- * If the provided name did not correspond to a known memory size
- * unit.
+ * If the provided name did not correspond to a known
+ * memory size unit.
*/
public static SizeUnit getUnit(String s) throws IllegalArgumentException {
SizeUnit unit = nameToUnit.get(s.trim().toLowerCase());
@@ -188,14 +293,14 @@
return unit.toBytes(d);
}
- // The size of the unit in bytes.
- private final long sz;
+ // The long name of the unit.
+ private final String longName;
// The abbreviation of the unit.
private final String shortName;
- // The long name of the unit.
- private final String longName;
+ // The size of the unit in bytes.
+ private final long sz;
@@ -222,37 +327,6 @@
/**
- * Get the best-fit unit for the specified amount in this unit. The returned
- * unit will be able to represent the amount using an integral value (i.e. no
- * fractional part).For example, if this unit is kilo-bytes and the amount
- * 2000 is provided, then the best fit unit is mega-bytes: 2mb. Similarly, if
- * the amount is 0.5, then the best fit unit will by bytes: 500b.
- * <p>
- * Only non-binary units are considered (i.e. kilo, mega, etc).
- *
- * @param amount
- * The amount of this unit.
- * @return Returns the best-fit unit for the specified amount in this unit.
- */
- public SizeUnit getBestFitUnit(double amount) {
- long bytes = toBytes(amount);
- if (bytes == 0) {
- return this;
- } else if (bytes > 0) {
- // use array of SizeUnits; EnumSet iterates in natural order
- for (SizeUnit unit : new SizeUnit[]{TERA_BYTES, GIGA_BYTES, MEGA_BYTES,
- KILO_BYTES }) {
- if ((bytes % unit.sz) == 0) {
- return unit;
- }
- }
- }
- return BYTES;
- }
-
-
-
- /**
* Get the long name of this unit.
*
* @return Returns the long name of this unit.
@@ -301,7 +375,8 @@
/**
* {@inheritDoc}
* <p>
- * This implementation returns the abbreviated name of this size unit.
+ * This implementation returns the abbreviated name of this size
+ * unit.
*/
@Override
public String toString() {
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java
index c8cffa1..796f151 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java
@@ -255,10 +255,11 @@
{1000L, "1kb"},
{1001L, "1001b"},
{1023L, "1023b"},
- {1024L, "1024b"},
+ {1024L, "1kib"},
{1025L, "1025b"},
{1000L * 1000L, "1mb"},
{1000L * 1000L * 1000L, "1gb"},
+ {1024L * 1024L * 1024L, "1gib"},
{1000L * 1000L * 1000L * 1000L, "1tb"}
};
@@ -313,14 +314,20 @@
spd.toString();
}
+ /**
+ * Test comparator method.
+ */
@Test
public void testCompare() {
SizePropertyDefinition.Builder builder = createTestBuilder();
builder.setAllowUnlimited(true);
SizePropertyDefinition spd = buildTestDefinition(builder);
- spd.compare(1L, 2L);
+ assertEquals(spd.compare(1L, 2L), -1);
}
+ /**
+ * Tests default behavior.
+ */
@Test
public void testSetDefaultBehaviorProvider() {
SizePropertyDefinition.Builder builder = createTestBuilder();
@@ -332,6 +339,9 @@
});
}
+ /**
+ * Tests option setting.
+ */
@Test
public void testSetOption() {
SizePropertyDefinition.Builder builder = createTestBuilder();
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java
index 371f0cd..a2db870 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java
@@ -214,28 +214,57 @@
*
* @return data
*/
- @DataProvider(name = "bestFitData")
- public Object[][] createBestFitData() {
+ @DataProvider(name = "bestFitUnitExactData")
+ public Object[][] createBestFitExactData() {
return new Object[][]{
- { SizeUnit.KILO_BYTES, Double.MIN_VALUE, SizeUnit.KILO_BYTES },
- { SizeUnit.KILO_BYTES, 0D, SizeUnit.KILO_BYTES },
- { SizeUnit.KILO_BYTES, 0.5D, SizeUnit.BYTES },
- { SizeUnit.KILO_BYTES, 1999D, SizeUnit.KILO_BYTES },
- { SizeUnit.KILO_BYTES, 2000D, SizeUnit.MEGA_BYTES },
- { SizeUnit.KILO_BYTES, 2001D, SizeUnit.KILO_BYTES },
- // { SizeUnit.KILO_BYTES, Double.MAX_VALUE, SizeUnit.KILO_BYTES } // fails
+ { 0, SizeUnit.BYTES },
+ { 999, SizeUnit.BYTES },
+ { 1000, SizeUnit.KILO_BYTES },
+ { 1024, SizeUnit.KIBI_BYTES },
+ { 1025, SizeUnit.BYTES },
+ { 999999, SizeUnit.BYTES },
+ { 1000000, SizeUnit.MEGA_BYTES },
+ { 1000001, SizeUnit.BYTES }
};
}
/**
* Test best fit
- * @param unit to use
* @param value for which best fit sought
* @param expectedUnit for comparison
*/
- @Test(dataProvider = "bestFitData")
- public void testGetBestFitUnit(SizeUnit unit, double value, SizeUnit expectedUnit) {
- assertEquals(unit.getBestFitUnit(value), expectedUnit);
+ @Test(dataProvider = "bestFitUnitExactData")
+ public void testGetBestFitUnitExact(long value, SizeUnit expectedUnit) {
+ assertEquals(SizeUnit.getBestFitUnitExact(value), expectedUnit);
+ }
+
+ /**
+ * Creates data for testing fromBytes
+ *
+ * @return data
+ */
+ @DataProvider(name = "bestFitUnitData")
+ public Object[][] createBestFitData() {
+ return new Object[][]{
+ { 0, SizeUnit.BYTES },
+ { 999, SizeUnit.BYTES },
+ { 1000, SizeUnit.KILO_BYTES },
+ { 1024, SizeUnit.KIBI_BYTES },
+ { 1025, SizeUnit.KILO_BYTES },
+ { 999999, SizeUnit.KILO_BYTES },
+ { 1000000, SizeUnit.MEGA_BYTES },
+ { 1000001, SizeUnit.MEGA_BYTES }
+ };
+ }
+
+ /**
+ * Test best fit
+ * @param value for which best fit sought
+ * @param expectedUnit for comparison
+ */
+ @Test(dataProvider = "bestFitUnitData")
+ public void testGetBestFitUnit(long value, SizeUnit expectedUnit) {
+ assertEquals(SizeUnit.getBestFitUnit(value), expectedUnit);
}
/**
--
Gitblit v1.10.0