| /* |
| * Copyright 2007 Google 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 java.lang; |
| |
| import com.google.gwt.core.client.JavaScriptObject; |
| |
| import java.io.Serializable; |
| |
| /** |
| * Abstract base class for numeric wrapper classes. |
| */ |
| public abstract class Number implements Serializable { |
| |
| /** |
| * Stores a regular expression object to verify format of float values. |
| */ |
| protected static JavaScriptObject floatRegex; |
| |
| // CHECKSTYLE_OFF: A special need to use unusual identifiers to avoid |
| // introducing name collisions. |
| |
| static class __Decode { |
| public final String payload; |
| public final int radix; |
| |
| public __Decode(int radix, String payload) { |
| this.radix = radix; |
| this.payload = payload; |
| } |
| } |
| |
| /** |
| * Use nested class to avoid clinit on outer. |
| */ |
| static class __Digits { |
| final static char[] digits = { |
| '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', |
| 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', |
| 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; |
| } |
| |
| /** |
| * Use nested class to avoid clinit on outer. |
| */ |
| static class __ParseLong { |
| /** |
| * The number of digits (excluding minus sign and leading zeros) to process |
| * at a time. The largest value expressible in maxDigits digits as well as |
| * the factor radix^maxDigits must be strictly less than 2^31. |
| */ |
| private static final int[] maxDigitsForRadix = {-1, -1, // unused |
| 30, // base 2 |
| 19, // base 3 |
| 15, // base 4 |
| 13, // base 5 |
| 11, 11, // base 6-7 |
| 10, // base 8 |
| 9, 9, // base 9-10 |
| 8, 8, 8, 8, // base 11-14 |
| 7, 7, 7, 7, 7, 7, 7, // base 15-21 |
| 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // base 22-35 |
| 5 // base 36 |
| }; |
| |
| /** |
| * A table of values radix*maxDigitsForRadix[radix]. |
| */ |
| private static final int[] maxDigitsRadixPower = new int[37]; |
| |
| /** |
| * The largest number of digits (excluding minus sign and leading zeros) that |
| * can fit into a long for a given radix between 2 and 36, inclusive. |
| */ |
| private static final int[] maxLengthForRadix = {-1, -1, // unused |
| 63, // base 2 |
| 40, // base 3 |
| 32, // base 4 |
| 28, // base 5 |
| 25, // base 6 |
| 23, // base 7 |
| 21, // base 8 |
| 20, // base 9 |
| 19, // base 10 |
| 19, // base 11 |
| 18, // base 12 |
| 18, // base 13 |
| 17, // base 14 |
| 17, // base 15 |
| 16, // base 16 |
| 16, // base 17 |
| 16, // base 18 |
| 15, // base 19 |
| 15, // base 20 |
| 15, // base 21 |
| 15, // base 22 |
| 14, // base 23 |
| 14, // base 24 |
| 14, // base 25 |
| 14, // base 26 |
| 14, // base 27 |
| 14, // base 28 |
| 13, // base 29 |
| 13, // base 30 |
| 13, // base 31 |
| 13, // base 32 |
| 13, // base 33 |
| 13, // base 34 |
| 13, // base 35 |
| 13 // base 36 |
| }; |
| |
| /** |
| * A table of floor(MAX_VALUE / maxDigitsRadixPower). |
| */ |
| private static final long[] maxValueForRadix = new long[37]; |
| |
| static { |
| for (int i = 2; i <= 36; i++) { |
| maxDigitsRadixPower[i] = (int) Math.pow(i, maxDigitsForRadix[i]); |
| maxValueForRadix[i] = Long.MAX_VALUE / maxDigitsRadixPower[i]; |
| } |
| } |
| } |
| |
| /** |
| * @skip |
| * |
| * This function will determine the radix that the string is expressed in |
| * based on the parsing rules defined in the Javadocs for Integer.decode() and |
| * invoke __parseAndValidateInt. |
| */ |
| protected static long __decodeAndValidateInt(String s, int lowerBound, |
| int upperBound) throws NumberFormatException { |
| __Decode decode = __decodeNumberString(s); |
| return __parseAndValidateInt(decode.payload, decode.radix, lowerBound, |
| upperBound); |
| } |
| |
| protected static __Decode __decodeNumberString(String s) { |
| final boolean negative; |
| if (s.startsWith("-")) { |
| negative = true; |
| s = s.substring(1); |
| } else { |
| negative = false; |
| } |
| |
| final int radix; |
| if (s.startsWith("0x") || s.startsWith("0X")) { |
| s = s.substring(2); |
| radix = 16; |
| } else if (s.startsWith("#")) { |
| s = s.substring(1); |
| radix = 16; |
| } else if (s.startsWith("0")) { |
| radix = 8; |
| } else { |
| radix = 10; |
| } |
| |
| if (negative) { |
| s = "-" + s; |
| } |
| return new __Decode(radix, s); |
| } |
| |
| /** |
| * @skip |
| * |
| * This function contains common logic for parsing a String as a floating- |
| * point number and validating the range. |
| */ |
| protected static double __parseAndValidateDouble(String s) |
| throws NumberFormatException { |
| |
| double toReturn = __parseDouble(s); |
| |
| if (__isNaN(toReturn)) { |
| throw NumberFormatException.forInputString(s); |
| } |
| |
| return toReturn; |
| } |
| |
| /** |
| * @skip |
| * |
| * This function contains common logic for parsing a String in a given radix |
| * and validating the result. |
| */ |
| protected static int __parseAndValidateInt(String s, int radix, |
| int lowerBound, int upperBound) throws NumberFormatException { |
| |
| if (s == null) { |
| throw new NumberFormatException("null"); |
| } |
| if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) { |
| throw new NumberFormatException("radix " + radix + " out of range"); |
| } |
| |
| int length = s.length(); |
| int startIndex = (length > 0) && (s.charAt(0) == '-') ? 1 : 0; |
| |
| for (int i = startIndex; i < length; i++) { |
| if (Character.digit(s.charAt(i), radix) == -1) { |
| throw NumberFormatException.forInputString(s); |
| } |
| } |
| |
| int toReturn = __parseInt(s, radix); |
| if (__isNaN(toReturn)) { |
| throw NumberFormatException.forInputString(s); |
| } else if (toReturn < lowerBound || toReturn > upperBound) { |
| throw NumberFormatException.forInputString(s); |
| } |
| |
| return toReturn; |
| } |
| |
| /** |
| * @skip |
| * |
| * This function contains common logic for parsing a String in a given radix |
| * and validating the result. |
| */ |
| protected static long __parseAndValidateLong(String s, int radix) |
| throws NumberFormatException { |
| |
| if (s == null) { |
| throw new NumberFormatException("null"); |
| } |
| if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) { |
| throw new NumberFormatException("radix " + radix + " out of range"); |
| } |
| |
| int length = s.length(); |
| boolean negative = (length > 0) && (s.charAt(0) == '-'); |
| if (negative) { |
| s = s.substring(1); |
| length--; |
| } |
| if (length == 0) { |
| throw NumberFormatException.forInputString(s); |
| } |
| |
| // Strip leading zeros |
| while (s.length() > 0 && s.charAt(0) == '0') { |
| s = s.substring(1); |
| length--; |
| } |
| |
| // Immediately eject numbers that are too long -- this avoids more complex |
| // overflow handling below |
| if (length > __ParseLong.maxLengthForRadix[radix]) { |
| throw NumberFormatException.forInputString(s); |
| } |
| |
| // Validate the digits |
| int maxNumericDigit = '0' + Math.min(radix, 10); |
| int maxLowerCaseDigit = radix + 'a' - 10; |
| int maxUpperCaseDigit = radix + 'A' - 10; |
| for (int i = 0; i < length; i++) { |
| char c = s.charAt(i); |
| if (c >= '0' && c < maxNumericDigit) { |
| continue; |
| } |
| if (c >= 'a' && c < maxLowerCaseDigit) { |
| continue; |
| } |
| if (c >= 'A' && c < maxUpperCaseDigit) { |
| continue; |
| } |
| throw NumberFormatException.forInputString(s); |
| } |
| |
| long toReturn = 0; |
| int maxDigits = __ParseLong.maxDigitsForRadix[radix]; |
| long radixPower = __ParseLong.maxDigitsRadixPower[radix]; |
| long maxValue = __ParseLong.maxValueForRadix[radix]; |
| |
| boolean firstTime = true; |
| int head = length % maxDigits; |
| if (head > 0) { |
| toReturn = __parseInt(s.substring(0, head), radix); |
| s = s.substring(head); |
| length -= head; |
| firstTime = false; |
| } |
| |
| while (length >= maxDigits) { |
| head = __parseInt(s.substring(0, maxDigits), radix); |
| s = s.substring(maxDigits); |
| length -= maxDigits; |
| if (!firstTime) { |
| // Check whether multiplying by radixPower will overflow |
| if (toReturn > maxValue) { |
| throw new NumberFormatException(s); |
| } |
| toReturn *= radixPower; |
| } else { |
| firstTime = false; |
| } |
| toReturn += head; |
| } |
| |
| // A negative value means we overflowed Long.MAX_VALUE |
| if (toReturn < 0) { |
| throw NumberFormatException.forInputString(s); |
| } |
| |
| if (negative) { |
| toReturn = -toReturn; |
| } |
| return toReturn; |
| } |
| |
| /** |
| * @skip |
| */ |
| private static native boolean __isNaN(double x) /*-{ |
| return isNaN(x); |
| }-*/; |
| |
| /** |
| * @skip |
| * |
| * @return The floating-point representation of <code>str</code> or |
| * <code>Number.NaN</code> if the string does not match |
| * {@link #floatRegex}. |
| */ |
| private static native double __parseDouble(String str) /*-{ |
| var floatRegex = @java.lang.Number::floatRegex; |
| if (!floatRegex) { |
| // Disallow '.' with no digits on either side |
| floatRegex = @java.lang.Number::floatRegex = /^\s*[+-]?((\d+\.?\d*)|(\.\d+))([eE][+-]?\d+)?[dDfF]?\s*$/i; |
| } |
| if (floatRegex.test(str)) { |
| return parseFloat(str); |
| } else { |
| return Number.NaN; |
| } |
| }-*/; |
| |
| /** |
| * @skip |
| * |
| * Invokes the global JS function <code>parseInt()</code>. |
| */ |
| private static native int __parseInt(String s, int radix) /*-{ |
| return parseInt(s, radix); |
| }-*/; |
| |
| // CHECKSTYLE_ON |
| |
| public byte byteValue() { |
| return (byte) intValue(); |
| } |
| |
| public abstract double doubleValue(); |
| |
| public abstract float floatValue(); |
| |
| public abstract int intValue(); |
| |
| public abstract long longValue(); |
| |
| public short shortValue() { |
| return (short) intValue(); |
| } |
| } |