From bfbbaa4e458735b6410c686a806c512f6fac7e2a 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.

---
 opends/src/server/org/opends/server/admin/SizeUnit.java |  199 ++++++++++++++++++++++++++++++++++---------------
 1 files changed, 137 insertions(+), 62 deletions(-)

diff --git a/opends/src/server/org/opends/server/admin/SizeUnit.java b/opends/src/server/org/opends/server/admin/SizeUnit.java
index df735b2..8f58bbf 100644
--- a/opends/src/server/org/opends/server/admin/SizeUnit.java
+++ b/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() {

--
Gitblit v1.10.0