# HG changeset patch # User claes.redestad@oracle.com # Date 1402870137 -7200 # Mon Jun 16 00:08:57 2014 +0200 # Node ID 91e6785dc8a4554464876f31000de8ba6ac97670 # Parent 28d1de89ff27981924765614bd6fb2d981fcc889 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 @@ -527,14 +527,39 @@ * does not contain a parsable {@code int}. */ public static int parseInt(String s, int radix) - throws NumberFormatException - { + throws NumberFormatException { + return parseInt(s, radix, 0); + } + + /** + * Extend upon Integer.parseInt(String, int) by providing a start offset to enable parsing + * substrings without creating intermediary objects + * @see java.lang.Integer#parseInt(String, int) + * + * @param start the start position in s to parse from, inclusive + */ + static int parseInt(CharSequence s, int radix, int start) + throws NumberFormatException { + if (s == null) { + throw new NumberFormatException("null"); + } + return parseInt(s, radix, start, s.length()); + } + + /** + * Extend upon Integer.parseInt(String, int) by providing a start and end offset to enable parsing + * substrings without creating intermediary objects + * @see java.lang.Integer#parseInt(String, int) + * @param start the start position in s to parse from, inclusive + * @param end the end position in s to parse to, exclusive + */ + static int parseInt(CharSequence s, int radix, int start, int end) + 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"); } @@ -549,44 +574,59 @@ " greater than Character.MAX_RADIX"); } + if (start < 0 || start > end) { + throw new NumberFormatException("start position out of bounds"); + } + + if (start == end) { + throw NumberFormatException.forInputString(""); + } + + if (end > s.length()) { + throw new NumberFormatException("end position out of bounds"); + } + int result = 0; boolean negative = false; - int i = 0, len = s.length(); + int i = start; 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); + char firstChar = s.charAt(start); + if (firstChar < '0') { // Possible leading "+" or "-" + if (firstChar == '-') { + negative = true; + limit = Integer.MIN_VALUE; + } else if (firstChar != '+') { + throw NumberFormatException.forInputString( + s.subSequence(start, end).toString()); + } - if (len == 1) // Cannot have lone "+" or "-" - throw NumberFormatException.forInputString(s); - i++; + if (end == start + 1) { // Cannot have lone "+" or "-" + throw NumberFormatException.forInputString( + s.subSequence(start, end).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++; + } + 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.subSequence(start, end).toString()); } - } else { - throw NumberFormatException.forInputString(s); + if (result < multmin) { + throw NumberFormatException.forInputString( + s.subSequence(start, end).toString()); + } + result *= radix; + if (result < limit + digit) { + throw NumberFormatException.forInputString( + s.subSequence(start, end).toString()); + } + result -= digit; } return negative ? result : -result; } @@ -657,13 +697,38 @@ */ public static int parseUnsignedInt(String s, int radix) throws NumberFormatException { - if (s == null) { + return parseUnsignedInt(s, radix, 0); + } + + /** + * Extend upon parseUnsignedInt(String, int) by providing a start offset + * to enable parsing substrings without creating intermediary objects + * @see java.lang.Integer#parseUnsignedInt(String, int) + * @param start the start position in s to parse from, inclusive + */ + static int parseUnsignedInt(CharSequence s, int radix, int start) + throws NumberFormatException { + if (s == null) { throw new NumberFormatException("null"); } + return parseUnsignedInt(s, radix, start, s.length()); + } - int len = s.length(); + /** + * Extend upon parseUnsignedInt(String, int) by providing a start and end + * offset to enable parsing substrings without creating intermediary objects + * @see java.lang.Integer#parseUnsignedInt(String, int) + * @param start the start position in s to parse from, inclusive + * @param end the end position in s to parse to, exclusive + */ + static int parseUnsignedInt(CharSequence s, int radix, int start, int end) + throws NumberFormatException { + if (s == null) { + throw new NumberFormatException("null"); + } + int len = end - start; if (len > 0) { - char firstChar = s.charAt(0); + char firstChar = s.charAt(start); if (firstChar == '-') { throw new NumberFormatException(String.format("Illegal leading minus sign " + @@ -671,9 +736,9 @@ } 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); + return parseInt(s, radix, start, end); } else { - long ell = Long.parseLong(s, radix); + long ell = Long.parseLong(s, radix, start, end); if ((ell & 0xffff_ffff_0000_0000L) == 0) { return (int) ell; } else { @@ -684,7 +749,7 @@ } } } else { - throw NumberFormatException.forInputString(s); + throw NumberFormatException.forInputString(s.toString()); } } 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 @@ -546,59 +546,100 @@ * parsable {@code long}. */ public static long parseLong(String s, int radix) - throws NumberFormatException - { + throws NumberFormatException { + return parseLong(s, radix, 0); + } + + /** + * Extend upon Long.parseLong(String, int) by providing a start offset to enable parsing + * substrings without creating intermediary objects + * @see java.lang.Long#parseLong(String, int) + * + * @param start the start position in s to parse from, inclusive + */ + static long parseLong(CharSequence s, int radix, int start) + throws NumberFormatException { + if (s == null) { + throw new NumberFormatException("null"); + } + return parseLong(s, radix, start, s.length()); + } + + /** + * Extend upon Long.parseLong(String, int) by providing a start and end offset to enable parsing + * substrings without creating intermediary objects + * @see java.lang.Long#parseLong(String, int) + * @param start the start position in s to parse from, inclusive + * @param end the end position in s to parse to, exclusive + */ + static long parseLong(CharSequence s, int radix, int start, int end) + throws NumberFormatException { if (s == null) { throw new NumberFormatException("null"); } if (radix < Character.MIN_RADIX) { throw new NumberFormatException("radix " + radix + - " less than Character.MIN_RADIX"); + " less than Character.MIN_RADIX"); } + if (radix > Character.MAX_RADIX) { throw new NumberFormatException("radix " + radix + - " greater than Character.MAX_RADIX"); + " greater than Character.MAX_RADIX"); + } + + if (start < 0 || start >= end) { + throw new NumberFormatException("start position out of bounds"); + } + + if (start == end) { + throw NumberFormatException.forInputString(""); + } + + if (end > s.length()) { + throw new NumberFormatException("end position out of bounds"); } long result = 0; boolean negative = false; - int i = 0, len = s.length(); + int i = start; 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.subSequence(start, end).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; + if (end == start + 1) { // Cannot have lone "+" or "-" + throw NumberFormatException.forInputString( + s.subSequence(start, end).toString()); } - } else { - throw NumberFormatException.forInputString(s); + i++; + } + 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.subSequence(start, end).toString()); + } + if (result < multmin) { + throw NumberFormatException.forInputString( + s.subSequence(start, end).toString()); + } + result *= radix; + if (result < limit + digit) { + throw NumberFormatException.forInputString( + s.subSequence(start, end).toString()); + } + result -= digit; } return negative ? result : -result; } @@ -679,87 +720,127 @@ if (s == null) { throw new NumberFormatException("null"); } + return parseUnsignedLong(s, radix, 0); + } - 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)); - } 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); - } + /** + * Extend upon Long.parseUnsignedLong(String, int) by providing a start offset + * to enable parsing substrings without creating intermediary objects + * @see java.lang.Long#parseUnsignedLong(String, int) + * @param start the start position in s to parse from, inclusive + */ + static long parseUnsignedLong(CharSequence s, int radix, int start) { + if (s == null) { + throw new NumberFormatException("null"); + } + return parseUnsignedLong(s, radix, start, s.length()); + } - // 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); - if (second < 0) { - throw new NumberFormatException("Bad digit at end of " + s); - } - long result = first * radix + second; + /** + * Extend upon Long.parseUnsignedLong(String, int) by providing a start offset to enable parsing + * substrings without creating intermediary objects + * @see java.lang.Long#parseUnsignedLong(String, int) + * @param start the start position in s to parse from, inclusive + * @param end the end position in s to parse to, exclusive + */ + static long parseUnsignedLong(CharSequence s, int radix, int start, int end) { + if (s == null) { + throw new NumberFormatException("null"); + } + 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"); + } + + if (start < 0 || start > end) { + throw new NumberFormatException("start position out of bounds"); + } + + if (end <= start || end > s.length()) { + throw new NumberFormatException("end position out of bounds"); + } + + int count = end - start; + char firstChar = s.charAt(start); + if (firstChar == '-') { + throw new NumberFormatException(String.format("Illegal leading minus sign " + + "on unsigned string %s.", s.subSequence(start, end))); + } else { + if (count <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits + (radix == 10 && count <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits + return parseLong(s, radix, start, end); + } + + // No need for range checks on end due to testing above. + long first = parseLong(s, radix, start, end - 1); + int second = Character.digit(s.charAt(end - 1), radix); + if (second < 0) { + throw new NumberFormatException("Bad digit at end of " + s.subSequence(start, end)); + } + 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)) { /* - * 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. + * 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. */ - 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)); - } - return result; + throw new NumberFormatException(String.format("String value %s exceeds " + + "range of unsigned long.", s.subSequence(start, end))); } - } else { - throw NumberFormatException.forInputString(s); + return result; } } 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,36 @@ public void invokeFinalize(Object o) throws Throwable { o.finalize(); } + public int parseInt(String s, int radix, int start) { + return Integer.parseInt(s, radix, start); + } + public int parseInt(String s, int radix, int start, int end) { + return Integer.parseInt(s, radix, start, end); + } + public int parseUnsignedInt(String s, int radix, int start) { + return Integer.parseUnsignedInt(s, radix, start); + } + public int parseUnsignedInt(String s, int radix, int start, int end) { + return Integer.parseUnsignedInt(s, radix, start, end); + } + public long parseLong(String s, int radix, int start) { + return Long.parseLong(s, radix, start); + } + public long parseLong(String s, int radix, int start, int end) { + return Long.parseLong(s, radix, start, end); + } + public long parseUnsignedLong(String s, int radix, int start) { + return Long.parseUnsignedLong(s, radix, start); + } + public long parseUnsignedLong(String s, int radix, int start, int end) { + return Long.parseUnsignedLong(s, radix, start, end); + } + 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,54 @@ * Invokes the finalize method of the given object. */ void invokeFinalize(Object o) throws Throwable; + + /** + * Invokes Integer.parseInt(s, radix, start) + */ + int parseInt(String s, int radix, int start); + + /** + * Invokes Integer.parseInt(s, radix, start, end) + */ + int parseInt(String s, int radix, int start, int end); + + /** + * Invokes Integer.parseUnsignedInt(s, radix, start) + */ + int parseUnsignedInt(String s, int radix, int start); + + /** + * Invokes Integer.parseUnsignedInt(s, radix, start, end) + */ + int parseUnsignedInt(String s, int radix, int start, int end); + + /** + * Invokes Long.parseLong(s, radix, start) + */ + long parseLong(String s, int radix, int start); + + /** + * Invokes Long.parseLong(s, radix, start, end) + */ + long parseLong(String s, int radix, int start, int end); + + /** + * Invokes Long.parseUnsignedLong(s, radix, start) + */ + long parseUnsignedLong(String s, int radix, int start); + + /** + * Invokes Long.parseUnsignedLong(s, radix, start, end) + */ + long parseUnsignedLong(String s, int radix, int start, int end); + + /** + * 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,11 +23,13 @@ /* * @test - * @bug 5017980 6576055 + * @bug 5017980 6576055 8041972 * @summary Test parsing methods * @author Joseph D. Darcy */ +import sun.misc.SharedSecrets; +import sun.misc.JavaLangAccess; /** * There are six methods in java.lang.Integer which transform strings @@ -43,9 +45,16 @@ * 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. + * + * Internally, parseInt(String, int, int, int) has been added to + * support parsing subsequences without explicit substrings. These will also + * be tested here */ public class ParsingTest { + + private static JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + public static void main(String... argv) { check("+100", +100); check("-100", -100); @@ -55,6 +64,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 +84,22 @@ checkFailure("+-6"); checkFailure("-+6"); checkFailure("*100"); + + check("test-00000", 0, 4, 10); + check("test-12345", -12345, 4, 10); + check("xx12345yy", 12345, 2, 7); + + checkFailure("+00000", 0, 7); + checkFailure("-00000", 0, 7); + checkFailure("-00000", 6, 6); + checkFailure("-00000", 6, 0); + checkFailure("+-6", 0, 3); } 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 +113,22 @@ ; // Expected } } + + private static void checkFailure(String val, int start, int end) { + int n = 0; + try { + n = jla.parseInt(val, 10, start, end); + System.err.println("parseInt(" + val + ") incorrectly returned " + n); + throw new RuntimeException(); + } catch (NumberFormatException nfe) { + ; // Expected + } + } + + private static void check(String val, int expected, int start, int end) { + int n = jla.parseInt(val, 10, start, end); + if (n != expected) + throw new RuntimeException("Integer.parsedInt failed. String:" + + val + " 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,6 +28,8 @@ * @author Joseph D. Darcy */ +import sun.misc.SharedSecrets; +import sun.misc.JavaLangAccess; /** * There are six methods in java.lang.Long which transform strings @@ -43,9 +45,16 @@ * 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. + * + * Internally, parseLong(String, int, int, int) has been added to + * support parsing subsequences without explicit substrings. These will also + * be tested here */ public class ParsingTest { + + private static JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + public static void main(String... argv) { check("+100", +100L); check("-100", -100L); @@ -72,12 +81,23 @@ 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); + + checkFailure("+00000", 0, 7); + checkFailure("-00000", 0, 7); + checkFailure("-00000", 6, 6); + checkFailure("-00000", 6, 0); + checkFailure("+-6", 0, 3); } 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 +111,22 @@ ; // Expected } } + + private static void checkFailure(String val, int start, int end) { + long n = 0L; + try { + n = jla.parseLong(val, 10, start, end); + System.err.println("parseLong(" + val + ") incorrectly returned " + n); + throw new RuntimeException(); + } catch (NumberFormatException nfe) { + ; // Expected + } + } + + private static void check(String val, long expected, int start, int end) { + long n = jla.parseLong(val, 10, start, end); + if (n != expected) + throw new RuntimeException("Long.parseLong failed. String:" + + val + " Result:" + n); + } }