Create SizeUnit class.

Summary: Utility class for converting between sizes and parsing sizes.

Test Plan: Unit tests
diff --git a/src/com/facebook/buck/util/unit/SizeUnit.java b/src/com/facebook/buck/util/unit/SizeUnit.java
new file mode 100644
index 0000000..0a2c5ff
--- /dev/null
+++ b/src/com/facebook/buck/util/unit/SizeUnit.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2013-present Facebook, Inc.
+ *
+ * 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.facebook.buck.util.unit;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+
+import java.math.BigDecimal;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public enum SizeUnit {
+  BYTES(0),
+  KILOBYTES(1),
+  MEGABYTES(2),
+  GIGABYTES(3),
+  TERABYTES(4);
+
+  private final int ordinal;
+
+  private SizeUnit(int ordinal) {
+    this.ordinal = ordinal;
+  }
+
+  public int getOrdinal() {
+    return ordinal;
+  }
+
+  private static long multiplyByByteOrderOfMagnitude(double size, int magnitude) {
+    if (magnitude == 0) {
+      return (long) size;
+    } else if (magnitude > 0) {
+      return BigDecimal.valueOf(size).multiply(BigDecimal.valueOf(1024).pow(magnitude)).longValue();
+    } else {
+      return BigDecimal.valueOf(size).divide(
+          BigDecimal.valueOf(1024).pow(-1 * magnitude)).longValue();
+    }
+  }
+
+  private static ImmutableMap<String, SizeUnit> SHORT_TO_CODE =
+      ImmutableMap.<String, SizeUnit>builder()
+        .put("b", BYTES)
+        .put("kb", KILOBYTES)
+        .put("kilobytes", KILOBYTES)
+        .put("mb", MEGABYTES)
+        .put("megabytes", MEGABYTES)
+        .put("gb", GIGABYTES)
+        .put("gigabytes", GIGABYTES)
+        .put("tb", TERABYTES)
+        .put("terabytes", TERABYTES)
+        .build();
+
+  private static Pattern SIZE_PATTERN = Pattern.compile("([\\d]+(?:\\.[\\d]+)?)\\s*((?:" +
+      Joiner.on(")|(?:").join(SHORT_TO_CODE.keySet()) + "))",
+      Pattern.CASE_INSENSITIVE);
+
+  /**
+   * Parses a string that represents a size into the number of bytes represented by that string.
+   */
+  public static long parseBytes(String input) throws NumberFormatException {
+    Matcher matcher = SIZE_PATTERN.matcher(input);
+    if (matcher.find()) {
+      String number = matcher.group(1);
+      SizeUnit sizeUnit = SHORT_TO_CODE.get(matcher.group(2).toLowerCase());
+      if (sizeUnit != null) {
+        try {
+          double value = Double.parseDouble(number);
+          return sizeUnit.toBytes(value);
+        } catch (NumberFormatException e) {
+          // If the number was so large as to overflow Long.MAX_VALUE, return LONG.MAX_VALUE.
+          return Long.MAX_VALUE;
+        }
+      }
+    }
+    throw new NumberFormatException(String.format("%s is not a valid file size", input));
+  }
+
+  public long toBytes(double size) {
+    return multiplyByByteOrderOfMagnitude(size, getOrdinal() - BYTES.getOrdinal());
+  }
+
+  public long toKilobytes(double size) {
+    return multiplyByByteOrderOfMagnitude(size, getOrdinal() - KILOBYTES.getOrdinal());
+  }
+
+  public long toMegabytes(double size) {
+    return multiplyByByteOrderOfMagnitude(size, getOrdinal() - MEGABYTES.getOrdinal());
+  }
+
+  public long toGigabytes(double size) {
+    return multiplyByByteOrderOfMagnitude(size, getOrdinal() - GIGABYTES.getOrdinal());
+  }
+
+  public long toTerabytes(double size) {
+    return multiplyByByteOrderOfMagnitude(size, getOrdinal() - TERABYTES.getOrdinal());
+  }
+}
diff --git a/test/com/facebook/buck/util/unit/SizeUnitTest.java b/test/com/facebook/buck/util/unit/SizeUnitTest.java
new file mode 100644
index 0000000..e10eda3
--- /dev/null
+++ b/test/com/facebook/buck/util/unit/SizeUnitTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013-present Facebook, Inc.
+ *
+ * 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.facebook.buck.util.unit;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class SizeUnitTest {
+
+  @Test(expected = NumberFormatException.class)
+  public void testInvalidParseBytes() {
+    SizeUnit.parseBytes("foobar");
+  }
+
+  @Test
+  public void testParseBytes() {
+    assertEquals(Long.MAX_VALUE, SizeUnit.parseBytes(
+        Long.toString(Long.MAX_VALUE) + "00 B"));
+    assertEquals(0L, SizeUnit.parseBytes("0GB"));
+    assertEquals(123L, SizeUnit.parseBytes("123 B"));
+    assertEquals(123L, SizeUnit.parseBytes("123 Bytes"));
+
+    assertEquals(1024L, SizeUnit.parseBytes("1 kb"));
+    assertEquals(1536L, SizeUnit.parseBytes("1.5 kb"));
+    assertEquals(1024L, SizeUnit.parseBytes("1 kilobytes"));
+
+    assertEquals(10L * 1024L * 1024L, SizeUnit.parseBytes("10 mb"));
+    assertEquals(2L * 1024L * 1024L, SizeUnit.parseBytes("2 megabytes"));
+
+    assertEquals(10L * 1024L * 1024L * 1024L, SizeUnit.parseBytes("10 gb"));
+    assertEquals(2L * 1024L * 1024L * 1024L, SizeUnit.parseBytes("2 gigabytes"));
+
+    assertEquals(10L * 1024L * 1024L * 1024L * 1024L, SizeUnit.parseBytes("10 tb"));
+    assertEquals(42L * 1024L * 1024L * 1024L * 1024L, SizeUnit.parseBytes("42 terabytes"));
+  }
+
+  @Test
+  public void testBytes()  {
+    assertEquals(4L, SizeUnit.BYTES.toBytes(4L));
+    assertEquals(0L, SizeUnit.BYTES.toKilobytes(4L));
+    assertEquals(2L, SizeUnit.BYTES.toKilobytes(2048L));
+    assertEquals(10L, SizeUnit.BYTES.toMegabytes(10L * 1024L * 1024L));
+    assertEquals(10L, SizeUnit.BYTES.toGigabytes(10L * 1024L * 1024L * 1024L));
+    assertEquals(10L, SizeUnit.BYTES.toTerabytes(10L * 1024L * 1024L * 1024L * 1024L));
+  }
+
+  @Test
+  public void testKilobytes() {
+    assertEquals(2048L, SizeUnit.KILOBYTES.toBytes(2L));
+    assertEquals(2048L, SizeUnit.KILOBYTES.toKilobytes(2048L));
+    assertEquals(0L, SizeUnit.KILOBYTES.toMegabytes(4L));
+    assertEquals(10L, SizeUnit.KILOBYTES.toMegabytes(10L * 1024L));
+    assertEquals(10L, SizeUnit.KILOBYTES.toGigabytes(10L * 1024L * 1024L));
+    assertEquals(10L, SizeUnit.KILOBYTES.toTerabytes(10L * 1024L * 1024L * 1024L));
+  }
+
+  @Test
+  public void testMegabytes() {
+    assertEquals(1024L * 1024L, SizeUnit.MEGABYTES.toBytes(1L));
+    assertEquals(2048L, SizeUnit.MEGABYTES.toKilobytes(2L));
+    assertEquals(42L, SizeUnit.MEGABYTES.toMegabytes(42L));
+    assertEquals(0L, SizeUnit.MEGABYTES.toGigabytes(4L));
+    assertEquals(10L, SizeUnit.MEGABYTES.toGigabytes(10L* 1024L));
+    assertEquals(10L, SizeUnit.MEGABYTES.toTerabytes(10L * 1024L * 1024L));
+  }
+
+  @Test
+  public void testGigabytes() {
+    assertEquals(1024L * 1024L * 1024L, SizeUnit.GIGABYTES.toBytes(1L));
+    assertEquals(2 * 1024L * 1024L, SizeUnit.GIGABYTES.toKilobytes(2L));
+    assertEquals(2048L, SizeUnit.GIGABYTES.toMegabytes(2L));
+    assertEquals(42L, SizeUnit.GIGABYTES.toGigabytes(42L));
+    assertEquals(0L, SizeUnit.GIGABYTES.toTerabytes(4L));
+    assertEquals(10L, SizeUnit.GIGABYTES.toTerabytes(10L * 1024L));
+  }
+
+  @Test
+  public void testTerabytes() {
+    assertEquals(1024L * 1024L * 1024L * 1024L, SizeUnit.TERABYTES.toBytes(1L));
+    assertEquals(2 * 1024L * 1024L * 1024L, SizeUnit.TERABYTES.toKilobytes(2L));
+    assertEquals(2L * 1024L * 1024L, SizeUnit.TERABYTES.toMegabytes(2L));
+    assertEquals(2048L, SizeUnit.TERABYTES.toGigabytes(2L));
+    assertEquals(42L, SizeUnit.TERABYTES.toTerabytes(42L));
+  }
+}