8317515: Unify the code of the parse*() families of methods in j.l.Integer and j.l.Long

Reviewed-by: redestad
This commit is contained in:
Raffaello Giulietti 2023-10-06 16:20:21 +00:00
parent a64794b1ed
commit b62e774e6a
2 changed files with 296 additions and 367 deletions

View File

@ -38,6 +38,7 @@ import java.lang.invoke.MethodHandles;
import java.util.Objects;
import java.util.Optional;
import static java.lang.Character.digit;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
@ -538,8 +539,7 @@ public final class Integer extends Number
* does not contain a parsable {@code int}.
*/
public static int parseInt(String s, int radix)
throws NumberFormatException
{
throws NumberFormatException {
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
@ -551,52 +551,41 @@ public final class Integer extends Number
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
throw new NumberFormatException(String.format(
"radix %s less than Character.MIN_RADIX", radix));
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
throw new NumberFormatException(String.format(
"radix %s greater than Character.MAX_RADIX", radix));
}
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
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, radix);
}
if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s, radix);
}
i++;
}
int len = s.length();
if (len == 0) {
throw new NumberFormatException("");
}
int digit = ~0xFF;
int i = 0;
char firstChar = s.charAt(i++);
if (firstChar != '-' && firstChar != '+') {
digit = digit(firstChar, radix);
}
if (digit >= 0 || digit == ~0xFF && len > 1) {
int limit = firstChar != '-' ? MIN_VALUE + 1 : MIN_VALUE;
int multmin = limit / radix;
int result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s, radix);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s, radix);
}
result -= digit;
int result = -(digit & 0xFF);
boolean inRange = true;
/* Accumulating negatively avoids surprises near MAX_VALUE */
while (i < len && (digit = digit(s.charAt(i++), radix)) >= 0
&& (inRange = result > multmin
|| result == multmin && digit <= radix * multmin - limit)) {
result = radix * result - digit;
}
if (inRange && i == len && digit >= 0) {
return firstChar != '-' ? -result : result;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s, radix);
}
throw NumberFormatException.forInputString(s, radix);
}
/**
@ -632,55 +621,47 @@ public final class Integer extends Number
Objects.checkFromToIndex(beginIndex, endIndex, s.length());
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
throw new NumberFormatException(String.format(
"radix %s less than Character.MIN_RADIX", radix));
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
throw new NumberFormatException(String.format(
"radix %s greater than Character.MAX_RADIX", radix));
}
boolean negative = false;
/*
* While s can be concurrently modified, it is ensured that each
* of its characters is read at most once, from lower to higher indices.
* This is obtained by reading them using the pattern s.charAt(i++),
* and by not updating i anywhere else.
*/
if (beginIndex == endIndex) {
throw new NumberFormatException("");
}
int digit = ~0xFF;
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);
}
i++;
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString("", radix);
char firstChar = s.charAt(i++);
if (firstChar != '-' && firstChar != '+') {
digit = digit(firstChar, radix);
}
if (digit >= 0 || digit == ~0xFF && endIndex - beginIndex > 1) {
int limit = firstChar != '-' ? MIN_VALUE + 1 : MIN_VALUE;
int multmin = limit / radix;
int result = -(digit & 0xFF);
boolean inRange = true;
/* Accumulating negatively avoids surprises near MAX_VALUE */
while (i < endIndex && (digit = digit(s.charAt(i++), radix)) >= 0
&& (inRange = result > multmin
|| result == multmin && digit <= radix * multmin - limit)) {
result = radix * result - digit;
}
if (inRange && i == endIndex && digit >= 0) {
return firstChar != '-' ? -result : result;
}
}
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i - (digit < -1 ? 0 : 1));
}
/**
@ -701,7 +682,7 @@ public final class Integer extends Number
* parsable integer.
*/
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
return parseInt(s, 10);
}
/**
@ -753,31 +734,48 @@ public final class Integer extends Number
throw new NumberFormatException("Cannot parse null string");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException(String.format(
"radix %s less than Character.MIN_RADIX", radix));
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException(String.format(
"radix %s greater than Character.MAX_RADIX", radix));
}
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 <= 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);
} 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));
}
}
}
} else {
if (len == 0) {
throw NumberFormatException.forInputString(s, radix);
}
int i = 0;
char firstChar = s.charAt(i++);
if (firstChar == '-') {
throw new NumberFormatException(String.format(
"Illegal leading minus sign on unsigned string %s.", s));
}
int digit = ~0xFF;
if (firstChar != '+') {
digit = digit(firstChar, radix);
}
if (digit >= 0 || digit == ~0xFF && len > 1) {
int multmax = divideUnsigned(-1, radix); // -1 is max unsigned int
int result = digit & 0xFF;
boolean inRange = true;
while (i < len && (digit = digit(s.charAt(i++), radix)) >= 0
&& (inRange = compareUnsigned(result, multmax) < 0
|| result == multmax && digit < -radix * multmax)) {
result = radix * result + digit;
}
if (inRange && i == len && digit >= 0) {
return result;
}
}
if (digit < 0) {
throw NumberFormatException.forInputString(s, radix);
}
throw new NumberFormatException(String.format(
"String value %s exceeds range of unsigned int.", s));
}
/**
@ -812,32 +810,54 @@ public final class Integer extends Number
Objects.requireNonNull(s);
Objects.checkFromToIndex(beginIndex, endIndex, s.length());
int start = beginIndex, len = endIndex - beginIndex;
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException(String.format(
"radix %s less than Character.MIN_RADIX", radix));
}
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, start, start + len, radix);
} else {
long ell = Long.parseLong(s, start, start + len, 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));
}
}
}
} else {
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException(String.format(
"radix %s greater than Character.MAX_RADIX", radix));
}
/*
* While s can be concurrently modified, it is ensured that each
* of its characters is read at most once, from lower to higher indices.
* This is obtained by reading them using the pattern s.charAt(i++),
* and by not updating i anywhere else.
*/
if (beginIndex == endIndex) {
throw new NumberFormatException("");
}
int i = beginIndex;
char firstChar = s.charAt(i++);
if (firstChar == '-') {
throw new NumberFormatException(
"Illegal leading minus sign on unsigned string " + s + ".");
}
int digit = ~0xFF;
if (firstChar != '+') {
digit = digit(firstChar, radix);
}
if (digit >= 0 || digit == ~0xFF && endIndex - beginIndex > 1) {
int multmax = divideUnsigned(-1, radix); // -1 is max unsigned int
int result = digit & 0xFF;
boolean inRange = true;
while (i < endIndex && (digit = digit(s.charAt(i++), radix)) >= 0
&& (inRange = compareUnsigned(result, multmax) < 0
|| result == multmax && digit < -radix * multmax)) {
result = radix * result + digit;
}
if (inRange && i == endIndex && digit >= 0) {
return result;
}
}
if (digit < 0) {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i - (digit < -1 ? 0 : 1));
}
throw new NumberFormatException(String.format(
"String value %s exceeds range of unsigned int.", s));
}
/**

View File

@ -38,6 +38,7 @@ import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.internal.vm.annotation.Stable;
import static java.lang.Character.digit;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
@ -574,58 +575,47 @@ public final class Long extends Number
* parsable {@code long}.
*/
public static long parseLong(String s, int radix)
throws NumberFormatException
{
throws NumberFormatException {
if (s == null) {
throw new NumberFormatException("Cannot parse null string");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
throw new NumberFormatException(String.format(
"radix %s less than Character.MIN_RADIX", radix));
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
throw new NumberFormatException(String.format(
"radix %s greater than Character.MAX_RADIX", radix));
}
boolean negative = false;
int i = 0, len = s.length();
long limit = -Long.MAX_VALUE;
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, radix);
}
if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s, radix);
}
i++;
}
int len = s.length();
if (len == 0) {
throw new NumberFormatException("");
}
int digit = ~0xFF;
int i = 0;
char firstChar = s.charAt(i++);
if (firstChar != '-' && firstChar != '+') {
digit = digit(firstChar, radix);
}
if (digit >= 0 || digit == ~0xFF && len > 1) {
long limit = firstChar != '-' ? MIN_VALUE + 1 : MIN_VALUE;
long multmin = limit / radix;
long result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++),radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s, radix);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s, radix);
}
result -= digit;
long result = -(digit & 0xFF);
boolean inRange = true;
/* Accumulating negatively avoids surprises near MAX_VALUE */
while (i < len && (digit = digit(s.charAt(i++), radix)) >= 0
&& (inRange = result > multmin
|| result == multmin && digit <= (int) (radix * multmin - limit))) {
result = radix * result - digit;
}
if (inRange && i == len && digit >= 0) {
return firstChar != '-' ? -result : result;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s, radix);
}
throw NumberFormatException.forInputString(s, radix);
}
/**
@ -661,55 +651,47 @@ public final class Long extends Number
Objects.checkFromToIndex(beginIndex, endIndex, s.length());
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
throw new NumberFormatException(String.format(
"radix %s less than Character.MIN_RADIX", radix));
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
throw new NumberFormatException(String.format(
"radix %s greater than Character.MAX_RADIX", 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);
}
i++;
result -= digit;
}
return negative ? result : -result;
} else {
/*
* While s can be concurrently modified, it is ensured that each
* of its characters is read at most once, from lower to higher indices.
* This is obtained by reading them using the pattern s.charAt(i++),
* and by not updating i anywhere else.
*/
if (beginIndex == endIndex) {
throw new NumberFormatException("");
}
int digit = ~0xFF; // ~0xFF means firstChar char is sign
int i = beginIndex;
char firstChar = s.charAt(i++);
if (firstChar != '-' && firstChar != '+') {
digit = digit(firstChar, radix);
}
if (digit >= 0 || digit == ~0xFF && endIndex - beginIndex > 1) {
long limit = firstChar != '-' ? MIN_VALUE + 1 : MIN_VALUE;
long multmin = limit / radix;
long result = -(digit & 0xFF);
boolean inRange = true;
/* Accumulating negatively avoids surprises near MAX_VALUE */
while (i < endIndex && (digit = digit(s.charAt(i++), radix)) >= 0
&& (inRange = result > multmin
|| result == multmin && digit <= (int) (radix * multmin - limit))) {
result = radix * result - digit;
}
if (inRange && i == endIndex && digit >= 0) {
return firstChar != '-' ? -result : result;
}
}
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i - (digit < -1 ? 0 : 1));
}
/**
@ -789,87 +771,48 @@ public final class Long extends Number
throw new NumberFormatException("Cannot parse null string");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException(String.format(
"radix %s less than Character.MIN_RADIX", radix));
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException(String.format(
"radix %s greater than Character.MAX_RADIX", radix));
}
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);
}
// No need for range checks on len due to testing above.
long first = parseLong(s, 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;
/*
* 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));
}
return result;
}
} else {
if (len == 0) {
throw NumberFormatException.forInputString(s, radix);
}
int i = 0;
char firstChar = s.charAt(i++);
if (firstChar == '-') {
throw new NumberFormatException(String.format(
"Illegal leading minus sign on unsigned string %s.", s));
}
int digit = ~0xFF;
if (firstChar != '+') {
digit = digit(firstChar, radix);
}
if (digit >= 0 || digit == ~0xFF && len > 1) {
long multmax = divideUnsigned(-1L, radix); // -1L is max unsigned long
long result = digit & 0xFF;
boolean inRange = true;
while (i < len && (digit = digit(s.charAt(i++), radix)) >= 0
&& (inRange = compareUnsigned(result, multmax) < 0
|| result == multmax && digit < (int) (-radix * multmax))) {
result = radix * result + digit;
}
if (inRange && i == len && digit >= 0) {
return result;
}
}
if (digit < 0) {
throw NumberFormatException.forInputString(s, radix);
}
throw new NumberFormatException(String.format(
"String value %s exceeds range of unsigned long.", s));
}
/**
@ -904,88 +847,54 @@ public final class Long extends Number
Objects.requireNonNull(s);
Objects.checkFromToIndex(beginIndex, endIndex, s.length());
int start = beginIndex, len = endIndex - beginIndex;
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException(String.format(
"radix %s less than Character.MIN_RADIX", radix));
}
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, start, start + len, radix);
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException(String.format(
"radix %s greater than Character.MAX_RADIX", radix));
}
// No need for range checks on end due to testing above.
long first = parseLong(s, start, start + len - 1, radix);
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)));
}
/*
* While s can be concurrently modified, it is ensured that each
* of its characters is read at most once, from lower to higher indices.
* This is obtained by reading them using the pattern s.charAt(i++),
* and by not updating i anywhere else.
*/
if (beginIndex == endIndex) {
throw new NumberFormatException("");
}
int i = beginIndex;
char firstChar = s.charAt(i++);
if (firstChar == '-') {
throw new NumberFormatException(
"Illegal leading minus sign on unsigned string " + s + ".");
}
int digit = ~0xFF;
if (firstChar != '+') {
digit = digit(firstChar, radix);
}
if (digit >= 0 || digit == ~0xFF && endIndex - beginIndex > 1) {
long multmax = divideUnsigned(-1L, radix); // -1L is max unsigned long
long result = digit & 0xFF;
boolean inRange = true;
while (i < endIndex && (digit = digit(s.charAt(i++), radix)) >= 0
&& (inRange = compareUnsigned(result, multmax) < 0
|| result == multmax && digit < (int) (-radix * multmax))) {
result = radix * result + digit;
}
if (inRange && i == endIndex && digit >= 0) {
return result;
}
} else {
throw NumberFormatException.forInputString("", radix);
}
if (digit < 0) {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i - (digit < -1 ? 0 : 1));
}
throw new NumberFormatException(String.format(
"String value %s exceeds range of unsigned long.", s));
}
/**