--- a/jdk/src/share/classes/java/lang/Integer.java Thu Jul 17 11:08:50 2014 -0700
+++ b/jdk/src/share/classes/java/lang/Integer.java Sat Jul 12 01:36:25 2014 +0200
@@ -26,6 +26,7 @@
package java.lang;
import java.lang.annotation.Native;
+import java.util.Objects;
/**
* The {@code Integer} class wraps a value of the primitive type
@@ -549,12 +550,9 @@
" greater than Character.MAX_RADIX");
}
- int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
- int multmin;
- int digit;
if (len > 0) {
char firstChar = s.charAt(0);
@@ -562,21 +560,21 @@
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
- } else if (firstChar != '+')
+ } else if (firstChar != '+') {
throw NumberFormatException.forInputString(s);
+ }
- if (len == 1) // Cannot have lone "+" or "-"
+ if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
+ }
i++;
}
- multmin = limit / radix;
+ int multmin = limit / radix;
+ int result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
- digit = Character.digit(s.charAt(i++),radix);
- if (digit < 0) {
- throw NumberFormatException.forInputString(s);
- }
- if (result < multmin) {
+ int digit = Character.digit(s.charAt(i++), radix);
+ if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
@@ -585,10 +583,126 @@
}
result -= digit;
}
+ return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s);
}
- return negative ? result : -result;
+ }
+
+ /**
+ * Parses the {@link CharSequence} argument as a signed {@code int} in the
+ * specified {@code radix}, beginning at the specified {@code beginIndex}
+ * and extending to the end of the sequence.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the {@code int}
+ * representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @return the signed {@code int} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable {@code int} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static int parseInt(CharSequence s, int radix, int beginIndex)
+ throws NumberFormatException {
+ // forces an implicit null check of s
+ return parseInt(s, radix, beginIndex, s.length());
+ }
+
+ /**
+ * Parses the {@link CharSequence} argument as a signed {@code int} in the
+ * specified {@code radix}, beginning at the specified {@code beginIndex}
+ * and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the {@code int}
+ * representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @return the signed {@code int} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code endIndex} or if {@code endIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable {@code int} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static int parseInt(CharSequence s, int radix, int beginIndex, int endIndex)
+ throws NumberFormatException {
+ s = Objects.requireNonNull(s);
+
+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (radix < Character.MIN_RADIX) {
+ throw new NumberFormatException("radix " + radix +
+ " less than Character.MIN_RADIX");
+ }
+ if (radix > Character.MAX_RADIX) {
+ throw new NumberFormatException("radix " + radix +
+ " greater than Character.MAX_RADIX");
+ }
+
+ boolean negative = false;
+ int i = beginIndex;
+ int limit = -Integer.MAX_VALUE;
+
+ if (i < endIndex) {
+ char firstChar = s.charAt(i);
+ if (firstChar < '0') { // Possible leading "+" or "-"
+ if (firstChar == '-') {
+ negative = true;
+ limit = Integer.MIN_VALUE;
+ } else if (firstChar != '+') {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ i++;
+ if (i == endIndex) { // Cannot have lone "+" or "-"
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ }
+ int multmin = limit / radix;
+ int result = 0;
+ while (i < endIndex) {
+ // Accumulating negatively avoids surprises near MAX_VALUE
+ int digit = Character.digit(s.charAt(i++), radix);
+ if (digit < 0 || result < multmin) {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ result *= radix;
+ if (result < limit + digit) {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ result -= digit;
+ }
+ return negative ? result : -result;
+ } else {
+ throw NumberFormatException.forInputString("");
+ }
}
/**
@@ -689,6 +803,99 @@
}
/**
+ * Parses the {@link CharSequence} argument as an unsigned {@code int} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to the end of the sequence.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the unsigned
+ * {@code int} representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @return the unsigned {@code int} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable unsigned {@code int} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static int parseUnsignedInt(CharSequence s, int radix, int beginIndex)
+ throws NumberFormatException {
+ // forces an implicit null check of s
+ return parseUnsignedInt(s, radix, beginIndex, s.length());
+ }
+
+ /**
+ * Parses the {@link CharSequence} argument as an unsigned {@code int} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the unsigned
+ * {@code int} representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @return the unsigned {@code int} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code endIndex} or if {@code endIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable unsigned {@code int} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static int parseUnsignedInt(CharSequence s, int radix, int beginIndex, int endIndex)
+ throws NumberFormatException {
+ s = Objects.requireNonNull(s);
+
+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ int start = beginIndex, len = endIndex - beginIndex;
+
+ if (len > 0) {
+ char firstChar = s.charAt(start);
+ if (firstChar == '-') {
+ throw new
+ NumberFormatException(String.format("Illegal leading minus sign " +
+ "on unsigned string %s.", s));
+ } else {
+ if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
+ (radix == 10 && len <= 9)) { // Integer.MAX_VALUE in base 10 is 10 digits
+ return parseInt(s, radix, start, start + len);
+ } else {
+ long ell = Long.parseLong(s, radix, start, start + len);
+ if ((ell & 0xffff_ffff_0000_0000L) == 0) {
+ return (int) ell;
+ } else {
+ throw new
+ NumberFormatException(String.format("String value %s exceeds " +
+ "range of unsigned int.", s));
+ }
+ }
+ }
+ } else {
+ throw new NumberFormatException("");
+ }
+ }
+
+ /**
* Parses the string argument as an unsigned decimal integer. The
* characters in the string must all be decimal digits, except
* that the first character may be an an ASCII plus sign {@code
--- a/jdk/src/share/classes/java/lang/Long.java Thu Jul 17 11:08:50 2014 -0700
+++ b/jdk/src/share/classes/java/lang/Long.java Sat Jul 12 01:36:25 2014 +0200
@@ -27,6 +27,7 @@
import java.lang.annotation.Native;
import java.math.*;
+import java.util.Objects;
/**
@@ -561,12 +562,9 @@
" greater than Character.MAX_RADIX");
}
- long result = 0;
boolean negative = false;
int i = 0, len = s.length();
long limit = -Long.MAX_VALUE;
- long multmin;
- int digit;
if (len > 0) {
char firstChar = s.charAt(0);
@@ -574,21 +572,21 @@
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
- } else if (firstChar != '+')
+ } else if (firstChar != '+') {
throw NumberFormatException.forInputString(s);
+ }
- if (len == 1) // Cannot have lone "+" or "-"
+ if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
+ }
i++;
}
- multmin = limit / radix;
+ long multmin = limit / radix;
+ long result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
- digit = Character.digit(s.charAt(i++),radix);
- if (digit < 0) {
- throw NumberFormatException.forInputString(s);
- }
- if (result < multmin) {
+ int digit = Character.digit(s.charAt(i++),radix);
+ if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
@@ -597,10 +595,126 @@
}
result -= digit;
}
+ return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s);
}
- return negative ? result : -result;
+ }
+
+ /**
+ * Parses the {@link CharSequence} argument as a signed {@code long} in
+ * the specified {@code radix}, beginning at the specified {@code beginIndex}
+ * and extending to the end of the sequence.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the {@code long}
+ * representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @return the signed {@code long} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable {@code long} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static long parseLong(CharSequence s, int radix, int beginIndex)
+ throws NumberFormatException {
+ // forces a null check of s
+ return parseLong(s, radix, beginIndex, s.length());
+ }
+
+ /**
+ * Parses the {@link CharSequence} argument as a signed {@code long} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the {@code long}
+ * representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @return the signed {@code long} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code endIndex} or if {@code endIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable {@code int} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex)
+ throws NumberFormatException {
+ s = Objects.requireNonNull(s);
+
+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (radix < Character.MIN_RADIX) {
+ throw new NumberFormatException("radix " + radix +
+ " less than Character.MIN_RADIX");
+ }
+ if (radix > Character.MAX_RADIX) {
+ throw new NumberFormatException("radix " + radix +
+ " greater than Character.MAX_RADIX");
+ }
+
+ boolean negative = false;
+ int i = beginIndex;
+ long limit = -Long.MAX_VALUE;
+
+ if (i < endIndex) {
+ char firstChar = s.charAt(i);
+ if (firstChar < '0') { // Possible leading "+" or "-"
+ if (firstChar == '-') {
+ negative = true;
+ limit = Long.MIN_VALUE;
+ } else if (firstChar != '+') {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ i++;
+ }
+ if (i >= endIndex) { // Cannot have lone "+", "-" or ""
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ long multmin = limit / radix;
+ long result = 0;
+ while (i < endIndex) {
+ // Accumulating negatively avoids surprises near MAX_VALUE
+ int digit = Character.digit(s.charAt(i++), radix);
+ if (digit < 0 || result < multmin) {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ result *= radix;
+ if (result < limit + digit) {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ result -= digit;
+ }
+ return negative ? result : -result;
+ } else {
+ throw new NumberFormatException("");
+ }
}
/**
@@ -694,7 +808,7 @@
}
// No need for range checks on len due to testing above.
- long first = parseLong(s.substring(0, len - 1), radix);
+ long first = parseLong(s, radix, 0, len - 1);
int second = Character.digit(s.charAt(len - 1), radix);
if (second < 0) {
throw new NumberFormatException("Bad digit at end of " + s);
@@ -764,6 +878,155 @@
}
/**
+ * Parses the {@link CharSequence} argument as an unsigned {@code long} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to the end of the sequence.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the unsigned
+ * {@code long} representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @return the unsigned {@code long} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable unsigned {@code long} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex)
+ throws NumberFormatException {
+ // forces a null check of s
+ return parseUnsignedLong(s, radix, beginIndex, s.length());
+ }
+
+ /**
+ * Parses the {@link CharSequence} argument as an unsigned {@code long} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the unsigned
+ * {@code long} representation to be parsed
+ * @param radix the radix to be used while parsing {@code s}.
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @return the unsigned {@code long} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code endIndex} or if {@code endIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable unsigned {@code long} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 1.9
+ */
+ public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex, int endIndex)
+ throws NumberFormatException {
+ s = Objects.requireNonNull(s);
+
+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ int start = beginIndex, len = endIndex - beginIndex;
+
+ if (len > 0) {
+ char firstChar = s.charAt(start);
+ if (firstChar == '-') {
+ throw new NumberFormatException(String.format("Illegal leading minus sign " +
+ "on unsigned string %s.", s.subSequence(start, start + len)));
+ } else {
+ if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
+ (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
+ return parseLong(s, radix, start, start + len);
+ }
+
+ // No need for range checks on end due to testing above.
+ long first = parseLong(s, radix, start, start + len - 1);
+ int second = Character.digit(s.charAt(start + len - 1), radix);
+ if (second < 0) {
+ throw new NumberFormatException("Bad digit at end of " +
+ s.subSequence(start, start + len));
+ }
+ long result = first * radix + second;
+
+ /*
+ * Test leftmost bits of multiprecision extension of first*radix
+ * for overflow. The number of bits needed is defined by
+ * GUARD_BIT = ceil(log2(Character.MAX_RADIX)) + 1 = 7. Then
+ * int guard = radix*(int)(first >>> (64 - GUARD_BIT)) and
+ * overflow is tested by splitting guard in the ranges
+ * guard < 92, 92 <= guard < 128, and 128 <= guard, where
+ * 92 = 128 - Character.MAX_RADIX. Note that guard cannot take
+ * on a value which does not include a prime factor in the legal
+ * radix range.
+ */
+ int guard = radix * (int) (first >>> 57);
+ if (guard >= 128 ||
+ (result >= 0 && guard >= 128 - Character.MAX_RADIX)) {
+ /*
+ * For purposes of exposition, the programmatic statements
+ * below should be taken to be multi-precision, i.e., not
+ * subject to overflow.
+ *
+ * A) Condition guard >= 128:
+ * If guard >= 128 then first*radix >= 2^7 * 2^57 = 2^64
+ * hence always overflow.
+ *
+ * B) Condition guard < 92:
+ * Define left7 = first >>> 57.
+ * Given first = (left7 * 2^57) + (first & (2^57 - 1)) then
+ * result <= (radix*left7)*2^57 + radix*(2^57 - 1) + second.
+ * Thus if radix*left7 < 92, radix <= 36, and second < 36,
+ * then result < 92*2^57 + 36*(2^57 - 1) + 36 = 2^64 hence
+ * never overflow.
+ *
+ * C) Condition 92 <= guard < 128:
+ * first*radix + second >= radix*left7*2^57 + second
+ * so that first*radix + second >= 92*2^57 + 0 > 2^63
+ *
+ * D) Condition guard < 128:
+ * radix*first <= (radix*left7) * 2^57 + radix*(2^57 - 1)
+ * so
+ * radix*first + second <= (radix*left7) * 2^57 + radix*(2^57 - 1) + 36
+ * thus
+ * radix*first + second < 128 * 2^57 + 36*2^57 - radix + 36
+ * whence
+ * radix*first + second < 2^64 + 2^6*2^57 = 2^64 + 2^63
+ *
+ * E) Conditions C, D, and result >= 0:
+ * C and D combined imply the mathematical result
+ * 2^63 < first*radix + second < 2^64 + 2^63. The lower
+ * bound is therefore negative as a signed long, but the
+ * upper bound is too small to overflow again after the
+ * signed long overflows to positive above 2^64 - 1. Hence
+ * result >= 0 implies overflow given C and D.
+ */
+ throw new NumberFormatException(String.format("String value %s exceeds " +
+ "range of unsigned long.", s.subSequence(start, start + len)));
+ }
+ return result;
+ }
+ } else {
+ throw NumberFormatException.forInputString("");
+ }
+ }
+
+ /**
* Parses the string argument as an unsigned decimal {@code long}. The
* characters in the string must all be decimal digits, except
* that the first character may be an an ASCII plus sign {@code
--- a/jdk/src/share/classes/java/lang/NumberFormatException.java Thu Jul 17 11:08:50 2014 -0700
+++ b/jdk/src/share/classes/java/lang/NumberFormatException.java Sat Jul 12 01:36:25 2014 +0200
@@ -56,7 +56,7 @@
}
/**
- * Factory method for making a <code>NumberFormatException</code>
+ * Factory method for making a {@code NumberFormatException}
* given the specified input which caused the error.
*
* @param s the input causing the error
@@ -64,4 +64,20 @@
static NumberFormatException forInputString(String s) {
return new NumberFormatException("For input string: \"" + s + "\"");
}
+
+ /**
+ * Factory method for making a {@code NumberFormatException}
+ * given the specified input which caused the error.
+ *
+ * @param s the input causing the error
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @param errorIndex the index of the first error in s
+ */
+ static NumberFormatException forCharSequence(CharSequence s,
+ int beginIndex, int endIndex, int errorIndex) {
+ return new NumberFormatException("Error at index "
+ + (errorIndex - beginIndex) + " in: \""
+ + s.subSequence(beginIndex, endIndex) + "\"");
+ }
}
--- a/jdk/test/java/lang/Integer/ParsingTest.java Thu Jul 17 11:08:50 2014 -0700
+++ b/jdk/test/java/lang/Integer/ParsingTest.java Sat Jul 12 01:36:25 2014 +0200
@@ -23,29 +23,37 @@
/*
* @test
- * @bug 5017980 6576055
+ * @bug 5017980 6576055 8041972
* @summary Test parsing methods
* @author Joseph D. Darcy
*/
+import java.lang.IllegalArgumentException;
+import java.lang.IndexOutOfBoundsException;
+import java.lang.NullPointerException;
+import java.lang.RuntimeException;
/**
- * There are six methods in java.lang.Integer which transform strings
+ * There are eight methods in java.lang.Integer which transform strings
* into an int or Integer value:
*
* public Integer(String s)
* public static Integer decode(String nm)
+ * public static int parseInt(CharSequence s, int radix, int beginIndex, int endIndex)
+ * public static int parseInt(CharSequence s, int radix, int beginIndex)
* public static int parseInt(String s, int radix)
* public static int parseInt(String s)
* public static Integer valueOf(String s, int radix)
* public static Integer valueOf(String s)
*
* Besides decode, all the methods and constructor call down into
- * parseInt(String, int) to do the actual work. Therefore, the
- * behavior of parseInt(String, int) will be tested here.
+ * parseInt(CharSequence, int, int, int) to do the actual work. Therefore, the
+ * behavior of parseInt(CharSequence, int, int, int) will be tested here.
+ *
*/
public class ParsingTest {
+
public static void main(String... argv) {
check("+100", +100);
check("-100", -100);
@@ -55,10 +63,14 @@
check("+00000", 0);
check("-00000", 0);
+ check("+00000", 0, 0, 6);
+ check("-00000", 0, 0, 6);
+
check("0", 0);
check("1", 1);
check("9", 9);
+ checkFailure("");
checkFailure("\u0000");
checkFailure("\u002f");
checkFailure("+");
@@ -72,12 +84,45 @@
checkFailure("+-6");
checkFailure("-+6");
checkFailure("*100");
+
+ check("test-00000", 0, 4, 10);
+ check("test-12345", -12345, 4, 10);
+ check("xx12345yy", 12345, 2, 7);
+
+ checkNumberFormatException("", 10, 0);
+ checkNumberFormatException("100", 10, 3);
+ checkNumberFormatException("+1000000", 10, 8);
+ checkNumberFormatException("-1000000", 10, 8);
+
+ checkNumberFormatException("", 10, 0, 0);
+ checkNumberFormatException("+-6", 10, 0, 3);
+ checkNumberFormatException("1000000", 10, 7);
+ checkNumberFormatException("1000000", 10, 7, 7);
+ checkNumberFormatException("1000000", Character.MAX_RADIX + 1, 0, 2);
+ checkNumberFormatException("1000000", Character.MIN_RADIX - 1, 0, 2);
+
+ checkIndexOutOfBoundsException("1000000", 10, 8);
+ checkIndexOutOfBoundsException("1000000", 10, -1);
+ checkIndexOutOfBoundsException("1000000", 10, 10, 4);
+ checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, -1, 2);
+ checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, -1, 2);
+ checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, 10, 2);
+ checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, 10, 2);
+ checkIndexOutOfBoundsException("-1", 10, 0, 3);
+ checkIndexOutOfBoundsException("-1", 10, 2, 3);
+ checkIndexOutOfBoundsException("-1", 10, -1, 2);
+
+ checkNull(10, 0, 1);
+ checkNull(10, -1, 0);
+ checkNull(10, 0, 0);
+ checkNull(10, 0, -1);
+ checkNull(-1, -1, -1);
}
private static void check(String val, int expected) {
int n = Integer.parseInt(val);
if (n != expected)
- throw new RuntimeException("Integer.parsedInt failed. String:" +
+ throw new RuntimeException("Integer.parseInt failed. String:" +
val + " Result:" + n);
}
@@ -91,4 +136,71 @@
; // Expected
}
}
+
+ private static void checkNumberFormatException(String val, int radix, int start) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val, radix, start);
+ System.err.println("parseInt(" + val + ", " + radix + ", " + start +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NumberFormatException nfe) {
+ ; // Expected
+ }
+ }
+
+ private static void checkNumberFormatException(String val, int radix, int start, int end) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val, radix, start, end);
+ System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NumberFormatException nfe) {
+ ; // Expected
+ }
+ }
+
+ private static void checkIndexOutOfBoundsException(String val, int radix, int start) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val, radix, start);
+ System.err.println("parseInt(" + val + ", " + radix + ", " + start +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (IndexOutOfBoundsException ioob) {
+ ; // Expected
+ }
+ }
+
+ private static void checkIndexOutOfBoundsException(String val, int radix, int start, int end) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val, radix, start, end);
+ System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (IndexOutOfBoundsException ioob) {
+ ; // Expected
+ }
+ }
+
+ private static void checkNull(int radix, int start, int end) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(null, 10, start, end);
+ System.err.println("parseInt(null, " + radix + ", " + start + ", " + end +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NullPointerException npe) {
+ ; // Expected
+ }
+ }
+
+ private static void check(String val, int expected, int start, int end) {
+ int n = Integer.parseInt(val, 10, start, end);
+ if (n != expected)
+ throw new RuntimeException("Integer.parsedInt failed. String:" +
+ val + ", start: " + start + ", end: " + end + " Result:" + n);
+ }
}
--- a/jdk/test/java/lang/Long/ParsingTest.java Thu Jul 17 11:08:50 2014 -0700
+++ b/jdk/test/java/lang/Long/ParsingTest.java Sat Jul 12 01:36:25 2014 +0200
@@ -23,29 +23,31 @@
/*
* @test
- * @bug 5017980 6576055
+ * @bug 5017980 6576055 8041972
* @summary Test parsing methods
* @author Joseph D. Darcy
*/
-
/**
- * There are six methods in java.lang.Long which transform strings
+ * There are eight methods in java.lang.Long which transform strings
* into a long or Long value:
*
* public Long(String s)
* public static Long decode(String nm)
+ * public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex)
+ * public static long parseLong(CharSequence s, int radix, int beginIndex)
* public static long parseLong(String s, int radix)
* public static long parseLong(String s)
* public static Long valueOf(String s, int radix)
* public static Long valueOf(String s)
*
* Besides decode, all the methods and constructor call down into
- * parseLong(String, int) to do the actual work. Therefore, the
- * behavior of parseLong(String, int) will be tested here.
+ * parseLong(CharSequence, int, int, int) to do the actual work. Therefore, the
+ * behavior of parseLong(CharSequence, int, int, int) will be tested here.
*/
public class ParsingTest {
+
public static void main(String... argv) {
check("+100", +100L);
check("-100", -100L);
@@ -59,6 +61,7 @@
check("1", 1L);
check("9", 9L);
+ checkFailure("");
checkFailure("\u0000");
checkFailure("\u002f");
checkFailure("+");
@@ -72,12 +75,44 @@
checkFailure("+-6");
checkFailure("-+6");
checkFailure("*100");
+
+ check("test-00000", 0L, 4, 10);
+ check("test-12345", -12345L, 4, 10);
+ check("xx12345yy", 12345L, 2, 7);
+ check("xx123456789012345yy", 123456789012345L, 2, 17);
+
+ checkNumberFormatException("100", 10, 3);
+ checkNumberFormatException("", 10, 0);
+ checkNumberFormatException("+1000000", 10, 8);
+ checkNumberFormatException("-1000000", 10, 8);
+
+ checkNumberFormatException("", 10, 0, 0);
+ checkNumberFormatException("+-6", 10, 0, 3);
+ checkNumberFormatException("1000000", 10, 7, 7);
+ checkNumberFormatException("1000000", Character.MAX_RADIX + 1, 0, 2);
+ checkNumberFormatException("1000000", Character.MIN_RADIX - 1, 0, 2);
+
+ checkIndexOutOfBoundsException("", 10, 1, 1);
+ checkIndexOutOfBoundsException("1000000", 10, 10, 4);
+ checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, 10, 2);
+ checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, 10, 2);
+ checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, -1, 2);
+ checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, -1, 2);
+ checkIndexOutOfBoundsException("-1", 10, 0, 3);
+ checkIndexOutOfBoundsException("-1", 10, 2, 3);
+ checkIndexOutOfBoundsException("-1", 10, -1, 2);
+
+ checkNull(10, 0, 1);
+ checkNull(10, -1, 0);
+ checkNull(10, 0, 0);
+ checkNull(10, 0, -1);
+ checkNull(-1, -1, -1);
}
private static void check(String val, long expected) {
long n = Long.parseLong(val);
if (n != expected)
- throw new RuntimeException("Long.parsedLong failed. String:" +
+ throw new RuntimeException("Long.parseLong failed. String:" +
val + " Result:" + n);
}
@@ -91,4 +126,71 @@
; // Expected
}
}
+
+ private static void checkNumberFormatException(String val, int radix, int start) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val, radix, start);
+ System.err.println("parseInt(" + val + ", " + radix + ", " + start +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NumberFormatException nfe) {
+ ; // Expected
+ }
+ }
+
+ private static void checkNumberFormatException(String val, int radix, int start, int end) {
+ long n = 0;
+ try {
+ n = Long.parseLong(val, radix, start, end);
+ System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NumberFormatException nfe) {
+ ; // Expected
+ }
+ }
+
+ private static void checkIndexOutOfBoundsException(String val, int radix, int start) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val, radix, start);
+ System.err.println("parseInt(" + val + ", " + radix + ", " + start +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (IndexOutOfBoundsException ioob) {
+ ; // Expected
+ }
+ }
+
+ private static void checkIndexOutOfBoundsException(String val, int radix, int start, int end) {
+ long n = 0;
+ try {
+ n = Long.parseLong(val, radix, start, end);
+ System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (IndexOutOfBoundsException ioob) {
+ ; // Expected
+ }
+ }
+
+ private static void checkNull(int radix, int start, int end) {
+ long n = 0;
+ try {
+ n = Long.parseLong(null, 10, start, end);
+ System.err.println("parseInt(null, " + radix + ", " + start + ", " + end +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NullPointerException npe) {
+ ; // Expected
+ }
+ }
+
+ private static void check(String val, long expected, int start, int end) {
+ long n = Long.parseLong(val, 10, start, end);
+ if (n != expected)
+ throw new RuntimeException("Long.parseLong failed. String:" +
+ val + ", start: " + start + ", end: " + end + " Result:" + n);
+ }
}