001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package java.lang;
017:
018: import com.google.gwt.core.client.JavaScriptObject;
019:
020: import java.io.Serializable;
021:
022: /**
023: * Abstract base class for numeric wrapper classes.
024: */
025: public abstract class Number implements Serializable {
026:
027: /**
028: * Stores a regular expression object to verify format of float values.
029: */
030: protected static JavaScriptObject floatRegex;
031:
032: // CHECKSTYLE_OFF: A special need to use unusual identifiers to avoid
033: // introducing name collisions.
034:
035: /**
036: * @skip
037: */
038: protected static String[] __hexDigits = new String[] { "0", "1",
039: "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
040: "e", "f" };
041:
042: static {
043: initNative();
044: }
045:
046: private static native void initNative() /*-{
047: @java.lang.Number::floatRegex = /^[+-]?\d*\.?\d*(e[+-]?\d+)?$/i;
048: }-*/;
049:
050: /**
051: * @skip
052: *
053: * This function will determine the radix that the string is expressed in
054: * based on the parsing rules defined in the Javadocs for Integer.decode() and
055: * invoke __parseAndValidateLong.
056: */
057: protected static long __decodeAndValidateLong(String s,
058: long lowerBound, long upperBound)
059: throws NumberFormatException {
060: final boolean negative;
061: if (s.startsWith("-")) {
062: negative = true;
063: s = s.substring(1);
064: } else {
065: negative = false;
066: }
067:
068: final int radix;
069: if (s.startsWith("0x") || s.startsWith("0X")) {
070: s = s.substring(2);
071: radix = 16;
072: } else if (s.startsWith("#")) {
073: s = s.substring(1);
074: radix = 16;
075: } else if (s.startsWith("0")) {
076: radix = 8;
077: } else {
078: radix = 10;
079: }
080:
081: if (negative) {
082: s = "-" + s;
083: }
084:
085: return __parseAndValidateLong(s, radix, lowerBound, upperBound);
086: }
087:
088: /**
089: * @skip
090: *
091: * This function contains common logic for parsing a String in a given
092: * radix and validating the result.
093: */
094: protected static long __parseAndValidateLong(String s, int radix,
095: long lowerBound, long upperBound)
096: throws NumberFormatException {
097:
098: if (s == null) {
099: throw new NumberFormatException("Unable to parse null");
100: }
101: int length = s.length();
102: int startIndex = (length > 0) && (s.charAt(0) == '-') ? 1 : 0;
103:
104: for (int i = startIndex; i < length; i++) {
105: if (Character.digit(s.charAt(i), radix) == -1) {
106: throw new NumberFormatException("Could not parse " + s
107: + " in radix " + radix);
108: }
109: }
110:
111: long toReturn = __parseInt(s, radix);
112: if (__isLongNaN(toReturn)) {
113: throw new NumberFormatException("Unable to parse " + s);
114: } else if (toReturn < lowerBound || toReturn > upperBound) {
115: throw new NumberFormatException("The string " + s
116: + " exceeds the range for the requested data type");
117: }
118:
119: return toReturn;
120: }
121:
122: /**
123: * @skip
124: *
125: * This function contains common logic for parsing a String as a floating-
126: * point number and validating the range.
127: */
128: protected static double __parseAndValidateDouble(String s)
129: throws NumberFormatException {
130:
131: double toReturn = __parseDouble(s);
132:
133: if (__isDoubleNaN(toReturn)) {
134: throw new NumberFormatException("Unable to parse " + s);
135: }
136:
137: return toReturn;
138: }
139:
140: /**
141: * @skip
142: */
143: private static native boolean __isDoubleNaN(double x) /*-{
144: return isNaN(x);
145: }-*/;
146:
147: /**
148: * @skip
149: */
150: private static native boolean __isLongNaN(long x) /*-{
151: return isNaN(x);
152: }-*/;
153:
154: /**
155: * @skip
156: *
157: * Invokes the global JS function <code>parseInt()</code>.
158: */
159: private static native long __parseInt(String s, int radix) /*-{
160: return parseInt(s, radix);
161: }-*/;
162:
163: /**
164: * @skip
165: *
166: * @return The floating-point representation of <code>str</code> or
167: * <code>Number.NaN</code> if the string does not match
168: * {@link floatRegex}.
169: */
170: private static native double __parseDouble(String str) /*-{
171: if (@java.lang.Number::floatRegex.test(str)) {
172: return parseFloat(str);
173: } else {
174: return Number.NaN;
175: }
176: }-*/;
177:
178: // CHECKSTYLE_ON
179:
180: /**
181: * Used by JSNI methods to report badly formatted strings.
182: * @param s the unparseable string
183: * @throws NumberFormatException every time
184: */
185: @SuppressWarnings("unused")
186: // called by JSNI
187: private static void throwNumberFormatException(String s)
188: throws NumberFormatException {
189: throw new NumberFormatException("Could not parse " + s);
190: }
191:
192: public abstract byte byteValue();
193:
194: public abstract double doubleValue();
195:
196: public abstract float floatValue();
197:
198: public abstract int intValue();
199:
200: public abstract long longValue();
201:
202: public abstract short shortValue();
203: }
|