# HG changeset patch # User claes.redestad@oracle.com # Date 1403197484 -7200 # Thu Jun 19 19:04:44 2014 +0200 # Node ID 3c0a5e68d8f232d05368229067b48a1a4469a5ec # Parent d02b062bc827f28082f5decacace58f61656f164 8041972: Add improved parse/format methods for Long/Integer Contributed-by: redestad diff --git a/src/share/classes/java/lang/Integer.java b/src/share/classes/java/lang/Integer.java --- a/src/share/classes/java/lang/Integer.java +++ b/src/share/classes/java/lang/Integer.java @@ -25,6 +25,8 @@ package java.lang; +import java.lang.IllegalArgumentException; +import java.lang.NullPointerException; import java.lang.annotation.Native; /** @@ -527,23 +529,85 @@ * does not contain a parsable {@code int}. */ public static int parseInt(String s, int radix) - throws NumberFormatException - { + throws NumberFormatException { + requireNonEmpty(s); + return parseInt(s, radix, 0, 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 the end of the sequence. + * + *

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 IllegalArgumentException if {@code beginIndex} is greater + * than or equal to {@code s.length()}. + * @throws IndexOutOfBoundsException if {@code beginIndex} is negative. + * @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}. + * + *

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 IllegalArgumentException if {@code beginIndex} is greater + * than or equal to {@code endIndex}. + * @throws IndexOutOfBoundsException if {@code beginIndex} is + * negative, {@code endIndex} is negative or {@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 { /* * WARNING: This method may be invoked early during VM initialization * before IntegerCache is initialized. Care must be taken to not use * the valueOf method. */ - - if (s == null) { - throw new NumberFormatException("null"); + s.getClass(); // null check + if (beginIndex >= endIndex) { + throw new IllegalArgumentException("beginIndex must be less than endIndex"); } - 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"); @@ -551,42 +615,39 @@ int result = 0; boolean negative = false; - int i = 0, len = s.length(); + int i = beginIndex, end = endIndex; int limit = -Integer.MAX_VALUE; int multmin; int digit; - if (len > 0) { - char firstChar = s.charAt(0); - if (firstChar < '0') { // Possible leading "+" or "-" - if (firstChar == '-') { - negative = true; - limit = Integer.MIN_VALUE; - } else if (firstChar != '+') - throw NumberFormatException.forInputString(s); - - if (len == 1) // Cannot have lone "+" or "-" - throw NumberFormatException.forInputString(s); - i++; + char firstChar = s.charAt(i); + if (firstChar < '0') { // Possible leading "+" or "-" + if (firstChar == '-') { + negative = true; + limit = Integer.MIN_VALUE; + } else if (firstChar != '+') { + throw NumberFormatException.forInputString(s.toString()); } - multmin = limit / radix; - 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) { - throw NumberFormatException.forInputString(s); - } - result *= radix; - if (result < limit + digit) { - throw NumberFormatException.forInputString(s); - } - result -= digit; + i++; + if (end == i) { // Cannot have lone "+" or "-" + throw NumberFormatException.forInputString(s.toString()); } - } else { - throw NumberFormatException.forInputString(s); + } + multmin = limit / radix; + while (i < end) { + // Accumulating negatively avoids surprises near MAX_VALUE + digit = Character.digit(s.charAt(i++), radix); + if (digit < 0) { + throw NumberFormatException.forInputString(s.toString()); + } + if (result < multmin) { + throw NumberFormatException.forInputString(s.toString()); + } + result *= radix; + if (result < limit + digit) { + throw NumberFormatException.forInputString(s.toString()); + } + result -= digit; } return negative ? result : -result; } @@ -609,7 +670,8 @@ * parsable integer. */ public static int parseInt(String s) throws NumberFormatException { - return parseInt(s,10); + requireNonEmpty(s); + return parseInt(s, 10, 0, s.length()); } /** @@ -657,34 +719,96 @@ */ public static int parseUnsignedInt(String s, int radix) throws NumberFormatException { - if (s == null) { - throw new NumberFormatException("null"); + requireNonEmpty(s); + return parseUnsignedInt(s, radix, 0, 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 the end of the sequence. + * + *

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 IllegalArgumentException if {@code beginIndex} is greater + * than or equal to {@code s.length()}. + * @throws IndexOutOfBoundsException if {@code beginIndex} is negative. + * @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}. + * + *

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 IllegalArgumentException if {@code beginIndex} is greater + * than or equal to {@code endIndex}. + * @throws IndexOutOfBoundsException if {@code beginIndex} is + * negative, {@code endIndex} is negative or {@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.getClass(); // null check + if (beginIndex >= endIndex) { + throw new IllegalArgumentException("beginIndex must be less than endIndex"); } - - int len = s.length(); - if (len > 0) { - char firstChar = s.charAt(0); - if (firstChar == '-') { - throw new - NumberFormatException(String.format("Illegal leading minus sign " + - "on unsigned string %s.", s)); + int start = beginIndex, len = endIndex - beginIndex; + // forces an implicit null check + 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 { - 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); + long ell = Long.parseLong(s, radix, start, start + len); + if ((ell & 0xffff_ffff_0000_0000L) == 0) { + return (int) ell; } else { - long ell = Long.parseLong(s, radix); - 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)); - } + throw new + NumberFormatException(String.format("String value %s exceeds " + + "range of unsigned int.", s)); } } - } else { - throw NumberFormatException.forInputString(s); } } @@ -705,7 +829,17 @@ * @since 1.8 */ public static int parseUnsignedInt(String s) throws NumberFormatException { - return parseUnsignedInt(s, 10); + requireNonEmpty(s); + return parseUnsignedInt(s, 10, 0, s.length()); + } + + static void requireNonEmpty(String s) { + if (s == null) { + throw new NumberFormatException("null"); + } + if (s.isEmpty()) { + throw new NumberFormatException(""); + } } /** @@ -734,7 +868,8 @@ * does not contain a parsable {@code int}. */ public static Integer valueOf(String s, int radix) throws NumberFormatException { - return Integer.valueOf(parseInt(s,radix)); + requireNonEmpty(s); + return Integer.valueOf(parseInt(s, radix, 0, s.length())); } /** @@ -760,7 +895,8 @@ * as an integer. */ public static Integer valueOf(String s) throws NumberFormatException { - return Integer.valueOf(parseInt(s, 10)); + requireNonEmpty(s); + return Integer.valueOf(parseInt(s, 10, 0, s.length())); } /** @@ -861,7 +997,8 @@ * @see java.lang.Integer#parseInt(java.lang.String, int) */ public Integer(String s) throws NumberFormatException { - this.value = parseInt(s, 10); + requireNonEmpty(s); + this.value = parseInt(s, 10, 0, s.length()); } /** diff --git a/src/share/classes/java/lang/Long.java b/src/share/classes/java/lang/Long.java --- a/src/share/classes/java/lang/Long.java +++ b/src/share/classes/java/lang/Long.java @@ -26,6 +26,7 @@ package java.lang; import java.lang.annotation.Native; +import static java.lang.Integer.requireNonEmpty; import java.math.*; @@ -546,12 +547,76 @@ * parsable {@code long}. */ public static long parseLong(String s, int radix) - throws NumberFormatException - { - if (s == null) { - throw new NumberFormatException("null"); + throws NumberFormatException { + requireNonEmpty(s); + return parseLong(s, radix, 0, 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 the end of the sequence. + * + *

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 IllegalArgumentException if {@code beginIndex} is greater + * than or equal to {@code s.length()}. + * @throws IndexOutOfBoundsException if {@code beginIndex} is negative. + * @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}. + * + *

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 IllegalArgumentException if {@code beginIndex} is greater + * than or equal to {@code endIndex}. + * @throws IndexOutOfBoundsException if {@code beginIndex} is + * negative, {@code endIndex} is negative or {@code endIndex} + * 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, int endIndex) + throws NumberFormatException { + s.getClass(); // null check + if (beginIndex >= endIndex) { + throw new IllegalArgumentException("beginIndex must be less than endIndex"); } - if (radix < Character.MIN_RADIX) { throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); @@ -563,42 +628,36 @@ long result = 0; boolean negative = false; - int i = 0, len = s.length(); + int i = beginIndex, end = endIndex; long limit = -Long.MAX_VALUE; long multmin; int digit; - if (len > 0) { - char firstChar = s.charAt(0); - if (firstChar < '0') { // Possible leading "+" or "-" - if (firstChar == '-') { - negative = true; - limit = Long.MIN_VALUE; - } else if (firstChar != '+') - throw NumberFormatException.forInputString(s); - - if (len == 1) // Cannot have lone "+" or "-" - throw NumberFormatException.forInputString(s); - i++; + char firstChar = s.charAt(i); + if (firstChar < '0') { // Possible leading "+" or "-" + if (firstChar == '-') { + negative = true; + limit = Long.MIN_VALUE; + } else if (firstChar != '+') { + throw NumberFormatException.forInputString(s.toString()); } - multmin = limit / radix; - 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) { - throw NumberFormatException.forInputString(s); - } - result *= radix; - if (result < limit + digit) { - throw NumberFormatException.forInputString(s); - } - result -= digit; + i++; + if (end == i) { // Cannot have lone "+" or "-" + throw NumberFormatException.forInputString(s.toString()); } - } else { - throw NumberFormatException.forInputString(s); + } + multmin = limit / radix; + while (i < end) { + // Accumulating negatively avoids surprises near MAX_VALUE + digit = Character.digit(s.charAt(i++), radix); + if (digit < 0 || result < multmin) { + throw NumberFormatException.forInputString(s.toString()); + } + result *= radix; + if (result < limit + digit) { + throw NumberFormatException.forInputString(s.toString()); + } + result -= digit; } return negative ? result : -result; } @@ -628,7 +687,8 @@ * parsable {@code long}. */ public static long parseLong(String s) throws NumberFormatException { - return parseLong(s, 10); + requireNonEmpty(s); + return parseLong(s, 10, 0, s.length()); } /** @@ -676,28 +736,93 @@ */ public static long parseUnsignedLong(String s, int radix) throws NumberFormatException { - if (s == null) { - throw new NumberFormatException("null"); + requireNonEmpty(s); + return parseUnsignedLong(s, radix, 0); + } + + /** + * 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. + * + *

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 IllegalArgumentException if {@code beginIndex} is greater + * than or equal to {@code s.length()}. + * @throws IndexOutOfBoundsException if {@code beginIndex} is negative. + * @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}. + * + *

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 IllegalArgumentException if {@code beginIndex} is greater + * than or equal to {@code endIndex}. + * @throws IndexOutOfBoundsException if {@code beginIndex} is + * negative, {@code endIndex} is negative or {@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.getClass(); // null check + if (beginIndex >= endIndex) { + throw new IllegalArgumentException("beginIndex must be less than endIndex"); } - - int len = s.length(); + int start = beginIndex, len = endIndex - beginIndex; if (len > 0) { - char firstChar = s.charAt(0); + char firstChar = s.charAt(start); if (firstChar == '-') { - throw new - NumberFormatException(String.format("Illegal leading minus sign " + - "on unsigned string %s.", s)); + 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); + (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 len due to testing above. - long first = parseLong(s.substring(0, len - 1), radix); - int second = Character.digit(s.charAt(len - 1), radix); + // 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); + throw new NumberFormatException("Bad digit at end of " + + s.subSequence(start, start + len)); } long result = first * radix + second; @@ -714,7 +839,7 @@ */ int guard = radix * (int) (first >>> 57); if (guard >= 128 || - (result >= 0 && guard >= 128 - Character.MAX_RADIX)) { + (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 @@ -754,12 +879,12 @@ * result >= 0 implies overflow given C and D. */ throw new NumberFormatException(String.format("String value %s exceeds " + - "range of unsigned long.", s)); + "range of unsigned long.", s.subSequence(start, start + len))); } return result; } } else { - throw NumberFormatException.forInputString(s); + throw NumberFormatException.forInputString(""); } } @@ -780,7 +905,8 @@ * @since 1.8 */ public static long parseUnsignedLong(String s) throws NumberFormatException { - return parseUnsignedLong(s, 10); + requireNonEmpty(s); + return parseUnsignedLong(s, 10, 0, s.length()); } /** @@ -810,7 +936,8 @@ * contain a parsable {@code long}. */ public static Long valueOf(String s, int radix) throws NumberFormatException { - return Long.valueOf(parseLong(s, radix)); + requireNonEmpty(s); + return Long.valueOf(parseLong(s, radix, 0, s.length())); } /** @@ -835,9 +962,9 @@ * @throws NumberFormatException If the string cannot be parsed * as a {@code long}. */ - public static Long valueOf(String s) throws NumberFormatException - { - return Long.valueOf(parseLong(s, 10)); + public static Long valueOf(String s) throws NumberFormatException { + requireNonEmpty(s); + return Long.valueOf(parseLong(s, 10, 0, s.length())); } private static class LongCache { @@ -999,7 +1126,8 @@ * @see java.lang.Long#parseLong(java.lang.String, int) */ public Long(String s) throws NumberFormatException { - this.value = parseLong(s, 10); + requireNonEmpty(s); + this.value = parseLong(s, 10, 0, s.length()); } /** diff --git a/src/share/classes/java/lang/System.java b/src/share/classes/java/lang/System.java --- a/src/share/classes/java/lang/System.java +++ b/src/share/classes/java/lang/System.java @@ -1263,6 +1263,12 @@ public void invokeFinalize(Object o) throws Throwable { o.finalize(); } + public int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) { + return Long.formatUnsignedLong(val, shift, buf, offset, len); + } + public int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) { + return Integer.formatUnsignedInt(val, shift, buf, offset, len); + } }); } } diff --git a/src/share/classes/sun/misc/JavaLangAccess.java b/src/share/classes/sun/misc/JavaLangAccess.java --- a/src/share/classes/sun/misc/JavaLangAccess.java +++ b/src/share/classes/sun/misc/JavaLangAccess.java @@ -132,4 +132,14 @@ * Invokes the finalize method of the given object. */ void invokeFinalize(Object o) throws Throwable; + + /** + * Invokes Long.formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) + */ + int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len); + + /** + * Invokes Integer.formatUnsignedInt(long val, int shift, char[] buf, int offset, int len) + */ + int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len); } diff --git a/test/java/lang/Integer/ParsingTest.java b/test/java/lang/Integer/ParsingTest.java --- a/test/java/lang/Integer/ParsingTest.java +++ b/test/java/lang/Integer/ParsingTest.java @@ -23,29 +23,36 @@ /* * @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; /** - * 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,6 +62,9 @@ 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); @@ -72,12 +82,37 @@ checkFailure("+-6"); checkFailure("-+6"); checkFailure("*100"); + + check("test-00000", 0, 4, 10); + check("test-12345", -12345, 4, 10); + check("xx12345yy", 12345, 2, 7); + + checkNumberFormatException("+-6", 10, 0, 3); + checkNumberFormatException("1000000", Character.MAX_RADIX + 1, 0, 2); + checkNumberFormatException("1000000", Character.MIN_RADIX - 1, 0, 2); + checkNumberFormatException("1000000", Character.MAX_RADIX + 1, -1, 2); + checkNumberFormatException("1000000", Character.MIN_RADIX - 1, -1, 2); + + checkIllegalArgumentException("1000000", 10, 7, 7); + checkIllegalArgumentException("1000000", 10, 10, 4); + checkIllegalArgumentException("1000000", Character.MAX_RADIX + 1, 10, 2); + checkIllegalArgumentException("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 +126,60 @@ ; // 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 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 checkIllegalArgumentException(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 (IllegalArgumentException nfe) { + ; // 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); + } } diff --git a/test/java/lang/Long/ParsingTest.java b/test/java/lang/Long/ParsingTest.java --- a/test/java/lang/Long/ParsingTest.java +++ b/test/java/lang/Long/ParsingTest.java @@ -28,24 +28,26 @@ * @author Joseph D. Darcy */ - /** * There are six 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); @@ -72,12 +74,38 @@ 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("+-6", 10, 0, 3); + checkNumberFormatException("1000000", Character.MAX_RADIX + 1, 0, 2); + checkNumberFormatException("1000000", Character.MIN_RADIX - 1, 0, 2); + checkNumberFormatException("1000000", Character.MAX_RADIX + 1, -1, 2); + checkNumberFormatException("1000000", Character.MIN_RADIX - 1, -1, 2); + + checkIllegalArgumentException("1000000", 10, 7, 7); + checkIllegalArgumentException("1000000", 10, 10, 4); + checkIllegalArgumentException("1000000", Character.MAX_RADIX + 1, 10, 2); + checkIllegalArgumentException("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, 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 +119,59 @@ ; // 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 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 checkIllegalArgumentException(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 (IllegalArgumentException nfe) { + ; // 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); + } }