Author: desruisseaux
Date: Tue Mar 12 16:30:08 2013
New Revision: 1455604
URL: http://svn.apache.org/r1455604
Log:
Simplify the API by removing rarely used (long) and (double) method variants.
This also allow the (Number) variant to do a more precise analysis based on the
value type.
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/NumbersTest.java
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java?rev=1455604&r1=1455603&r2=1455604&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
[UTF-8] (original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
[UTF-8] Tue Mar 12 16:30:08 2013
@@ -26,10 +26,11 @@ import java.util.Collections;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
-
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.collection.CollectionsExt;
+import static java.lang.Double.doubleToLongBits;
+
/**
* Static methods working with {@link Number} objects, and a few primitive
types by extension.
@@ -350,148 +351,116 @@ public final class Numbers extends Stati
}
/**
- * Returns the smallest class capable to hold the specified value. If the
given value is
- * {@code null}, then this method returns {@code null}. Otherwise this
method delegates
- * to {@link #narrowestClass(double)} or {@link #narrowestClass(long)}
depending on the value type.
- *
- * @param value The value to be wrapped in a finer (if possible) {@link
Number}.
- * @return The narrowest type capable to hold the given value.
- *
- * @see #narrowestNumber(Number)
- */
- public static Class<? extends Number> narrowestClass(final Number value) {
- if (value == null) {
- return null;
- }
- if (isPrimitiveInteger(value.getClass())) {
- return narrowestClass(value.longValue());
- } else {
- return narrowestClass(value.doubleValue());
- }
- }
-
- /**
- * Returns the smallest class capable to hold the specified value.
- * This is similar to {@link #narrowestClass(long)}, but extended to
floating point values.
- *
- * @param value The value to be wrapped in a {@link Number}.
- * @return The narrowest type capable to hold the given value.
- *
- * @see #narrowestNumber(double)
- */
- public static Class<? extends Number> narrowestClass(final double value) {
- final long lg = (long) value;
- if (value == lg) {
- return narrowestClass(lg);
- }
- final float fv = (float) value;
- if (Double.doubleToRawLongBits(value) ==
Double.doubleToRawLongBits(fv)) {
- return Float.class;
- }
- return Double.class;
- }
-
- /**
* Returns the smallest class capable to hold the specified value.
- * This method makes the following choice:
+ * This method applies the following choices, in that order:
*
* <ul>
- * <li>If the given value is between {@value java.lang.Byte#MIN_VALUE}
and
+ * <li>If the given value is {@code null}, then this method returns
{@code null}.</li>
+ * <li>Otherwise if the given value can not be casted from {@code
double} to an other type
+ * without precision lost, return {@code Double.class}.</li>
+ * <li>Otherwise if the given value can not be casted from {@code float}
to an other type
+ * without precision lost, return {@code Float.class}.</li>
+ * <li>Otherwise if the given value is between {@value
java.lang.Byte#MIN_VALUE} and
* {@value java.lang.Byte#MAX_VALUE}, then this method returns
{@code Byte.class};</li>
- * <li>If the given value is between {@value java.lang.Short#MIN_VALUE}
and
+ * <li>Otherwise if the given value is between {@value
java.lang.Short#MIN_VALUE} and
* {@value java.lang.Short#MAX_VALUE}, then this method returns
{@code Short.class};</li>
- * <li>If the given value is between {@value
java.lang.Integer#MIN_VALUE} and
+ * <li>Otherwise if the given value is between {@value
java.lang.Integer#MIN_VALUE} and
* {@value java.lang.Integer#MAX_VALUE}, then this method returns
{@code Integer.class};</li>
* <li>Otherwise this method returns {@code Long.class};</li>
* </ul>
*
- * @param value The value to be wrapped in a {@link Number}.
+ * @param value The value to be wrapped in a finer (if possible) {@link
Number}.
* @return The narrowest type capable to hold the given value.
*
- * @see #narrowestNumber(long)
+ * @see #narrowestNumber(Number)
*/
- public static Class<? extends Number> narrowestClass(final long value) {
- // Tests MAX_VALUE before MIN_VALUE because it is more likely to fail.
- if (value <= Byte .MAX_VALUE && value >= Byte .MIN_VALUE) return
Byte.class;
- if (value <= Short .MAX_VALUE && value >= Short .MIN_VALUE) return
Short.class;
- if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) return
Integer.class;
- return Long.class;
+ @SuppressWarnings("fallthrough")
+ public static Class<? extends Number> narrowestClass(final Number value) {
+ if (value == null) {
+ return null;
+ }
+ boolean isFloat = false;
+ final long longValue = value.longValue();
+ switch (getEnumConstant(value.getClass())) {
+ default: {
+ final double doubleValue = value.doubleValue();
+ final float floatValue = (float) doubleValue;
+ isFloat = (doubleToLongBits(floatValue) ==
doubleToLongBits(doubleValue));
+ if (doubleValue != longValue) {
+ return isFloat ? Float.class : Double.class;
+ }
+ // Fall through.
+ }
+ case LONG: if (((int) longValue) != longValue) return isFloat
? Float.class : Long.class;
+ case INTEGER: if (((short) longValue) != longValue) return
Integer.class;
+ case SHORT: if (((byte) longValue) != longValue) return Short
.class;
+ case BYTE: return Byte.class;
+ }
}
/**
* Returns the given number wrapped in the smallest class capable to hold
the specified value.
- * If the given value is {@code null}, then this method returns {@code
null}. Otherwise this
- * method delegates to {@link #narrowestNumber(double)} or {@link
#narrowestNumber(long)}
- * depending on the value type.
+ * This method is equivalent to the following code, in a slightly more
efficient way:
+ *
+ * {@preformat java
+ * return cast(value, narrowestClass(value));
+ * }
*
* @param value The value to be wrapped in a finer (if possible) {@link
Number}.
* @return The narrowest type capable to hold the given value.
*
* @see #narrowestClass(Number)
+ * @see #cast(Number, Class)
*/
+ @SuppressWarnings("fallthrough")
public static Number narrowestNumber(final Number value) {
if (value == null) {
return null;
}
final Number candidate;
- if (isPrimitiveInteger(value.getClass())) {
- candidate = narrowestNumber(value.longValue());
- } else {
- candidate = narrowestNumber(value.doubleValue());
+ boolean isFloat = false;
+ final long longValue = value.longValue();
+ switch (getEnumConstant(value.getClass())) {
+ default: {
+ final double doubleValue = value.doubleValue();
+ final float floatValue = (float) doubleValue;
+ isFloat = (doubleToLongBits(floatValue) ==
doubleToLongBits(doubleValue));
+ if (doubleValue != longValue) {
+ candidate = isFloat ? ((Number) Float .valueOf(floatValue))
+ : ((Number)
Double.valueOf(doubleValue));
+ break;
+ }
+ // Fall through everywhere.
+ }
+ case LONG: {
+ if (((int) longValue) != longValue) {
+ candidate = isFloat ? ((Number) Float.valueOf((float)
longValue))
+ : ((Number) Long.valueOf(longValue));
+ break;
+ }
+ }
+ case INTEGER: {
+ if (((short) longValue) != longValue) {
+ candidate = Integer.valueOf((int) longValue);
+ break;
+ }
+ }
+ case SHORT: {
+ if (((byte) longValue) != longValue) {
+ candidate = Short.valueOf((short) longValue);
+ break;
+ }
+ }
+ case BYTE: {
+ candidate = Byte.valueOf((byte) longValue);
+ break;
+ }
}
// Keep the existing instance if possible.
return value.equals(candidate) ? value : candidate;
}
/**
- * Returns the number of the smallest class capable to hold the specified
value.
- * This is similar to {@link #narrowestNumber(long)}, but extended to
floating point values.
- *
- * @param value The value to be wrapped in a {@link Number}.
- * @return The narrowest type capable to hold the given value.
- *
- * @see #narrowestClass(double)
- */
- public static Number narrowestNumber(final double value) {
- final long lg = (long) value;
- if (value == lg) {
- return narrowestNumber(lg);
- }
- final float fv = (float) value;
- if (Double.doubleToRawLongBits(value) ==
Double.doubleToRawLongBits(fv)) {
- return Float.valueOf(fv);
- }
- return Double.valueOf(value);
- }
-
- /**
- * Returns the number of the smallest type capable to hold the specified
value.
- * This method makes the following choice:
- *
- * <ul>
- * <li>If the given value is between {@value java.lang.Byte#MIN_VALUE}
and
- * {@value java.lang.Byte#MAX_VALUE}, then it is wrapped in a {@link
Byte} object.</li>
- * <li>If the given value is between {@value java.lang.Short#MIN_VALUE}
and
- * {@value java.lang.Short#MAX_VALUE}, then it is wrapped in a
{@link Short} object.</li>
- * <li>If the given value is between {@value
java.lang.Integer#MIN_VALUE} and
- * {@value java.lang.Integer#MAX_VALUE}, then it is wrapped in an
{@link Integer} object.</li>
- * <li>Otherwise the value is wrapped in a {@link Long} object.</li>
- * </ul>
- *
- * @param value The value to be wrapped in a {@link Number}.
- * @return The given value as a number of the narrowest type capable to
hold it.
- *
- * @see #narrowestClass(long)
- */
- public static Number narrowestNumber(final long value) {
- // Tests MAX_VALUE before MIN_VALUE because it is more likely to fail.
- if (value <= Byte .MAX_VALUE && value >= Byte .MIN_VALUE) return
Byte .valueOf((byte) value);
- if (value <= Short .MAX_VALUE && value >= Short .MIN_VALUE) return
Short .valueOf((short) value);
- if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) return
Integer.valueOf((int) value);
- return Long.valueOf(value);
- }
-
- /**
* Returns the smallest number capable to hold the specified value.
*
* @param value The value to be wrapped in a {@link Number}.
@@ -499,8 +468,6 @@ public final class Numbers extends Stati
* @throws NumberFormatException if the given value can not be parsed as a
number.
*
* @see #narrowestNumber(Number)
- * @see #narrowestNumber(double)
- * @see #narrowestNumber(long)
*/
public static Number narrowestNumber(final String value) throws
NumberFormatException {
// Do not trim whitespaces. It is up to the caller to do that if he
wants.
@@ -616,7 +583,7 @@ public final class Numbers extends Stati
case BIG_DECIMAL: return (N) BigDecimal.valueOf(value); // No
need to verify.
default: throw unknownType(type);
}
- if (Double.doubleToLongBits(number.doubleValue()) !=
Double.doubleToLongBits(value)) {
+ if (doubleToLongBits(number.doubleValue()) != doubleToLongBits(value))
{
throw new
IllegalArgumentException(Errors.format(Errors.Keys.CanNotConvertValue_2, value,
type));
}
return number;
Modified:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/NumbersTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/NumbersTest.java?rev=1455604&r1=1455603&r2=1455604&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/NumbersTest.java
[UTF-8] (original)
+++
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/NumbersTest.java
[UTF-8] Tue Mar 12 16:30:08 2013
@@ -148,25 +148,37 @@ public final class NumbersTest extends T
}
/**
- * Tests {@link Numbers#narrowestClass(double)}.
+ * Tests {@link Numbers#narrowestClass(Number)}.
*/
@Test
public void testNarrowestClassForValue() {
- assertEquals(Byte .class, narrowestClass( 10.0));
- assertEquals(Short .class, narrowestClass( 1000.0));
- assertEquals(Integer.class, narrowestClass(100000.0));
- assertEquals(Float .class, narrowestClass( 10.5));
+ assertEquals(Byte .class, narrowestClass( 127.0));
+ assertEquals(Short .class, narrowestClass( 128.0));
+ assertEquals(Integer.class, narrowestClass( 100000.0));
+ assertEquals(Float .class, narrowestClass( 10.5));
+ assertEquals(Byte .class, narrowestClass( -128 ));
+ assertEquals(Short .class, narrowestClass( -129 ));
+ assertEquals(Integer.class, narrowestClass(-100000 ));
+ assertEquals(Integer.class, narrowestClass((double) (1L << 30)));
+ assertEquals(Float .class, narrowestClass((double) (1L << 40)));
+ assertEquals(Double .class, narrowestClass(Math.PI));
}
/**
- * Tests {@link Numbers#narrowestNumber(double)}.
+ * Tests {@link Numbers#narrowestNumber(Number)}.
*/
@Test
public void testNarrowestNumber() {
- assertEquals(Byte .valueOf((byte) 10), narrowestNumber( 10.0));
- assertEquals(Short .valueOf((short) 1000), narrowestNumber( 1000.0));
- assertEquals(Integer.valueOf( 100000), narrowestNumber(100000.0));
- assertEquals(Float .valueOf( 10.5f), narrowestNumber( 10.5));
+ assertEquals(Byte .valueOf((byte) 127), narrowestNumber(
127.0));
+ assertEquals(Short .valueOf((short) 128), narrowestNumber(
128.0));
+ assertEquals(Integer.valueOf( 100000), narrowestNumber(
100000.0));
+ assertEquals(Float .valueOf( 10.5f), narrowestNumber(
10.5));
+ assertEquals(Byte .valueOf((byte) -128), narrowestNumber( -128
));
+ assertEquals(Short .valueOf((short) -129), narrowestNumber( -129
));
+ assertEquals(Integer.valueOf( -100000), narrowestNumber(-100000
));
+ assertEquals(Integer.valueOf(1 << 30), narrowestNumber((double)
(1L << 30)));
+ assertEquals(Float .valueOf(1L << 40), narrowestNumber((double)
(1L << 40)));
+ assertEquals(Double .valueOf(Math.PI), narrowestNumber(Math.PI));
}
/**