Skip to content

Commit

Permalink
8317515: Unify the code of the parse*() families of methods in j.l.In…
Browse files Browse the repository at this point in the history
…teger and j.l.Long

Reviewed-by: redestad
  • Loading branch information
rgiulietti committed Oct 6, 2023
1 parent a64794b commit b62e774
Show file tree
Hide file tree
Showing 2 changed files with 291 additions and 362 deletions.
274 changes: 147 additions & 127 deletions src/java.base/share/classes/java/lang/Integer.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
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;
Expand Down Expand Up @@ -538,8 +539,7 @@ static int stringSize(int x) {
* 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
Expand All @@ -551,52 +551,41 @@ public static int parseInt(String s, int radix)
}

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);
}

/**
Expand Down Expand Up @@ -632,55 +621,47 @@ public static int parseInt(CharSequence s, int beginIndex, int endIndex, int rad
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);
}
}
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 = 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;
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;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString("", radix);
}
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i - (digit < -1 ? 0 : 1));
}

/**
Expand All @@ -701,7 +682,7 @@ public static int parseInt(CharSequence s, int beginIndex, int endIndex, int rad
* parsable integer.
*/
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
return parseInt(s, 10);
}

/**
Expand Down Expand Up @@ -753,31 +734,48 @@ public static int parseUnsignedInt(String s, int radix)
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));
}
}
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;
}
} else {
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));
}

/**
Expand Down Expand Up @@ -812,32 +810,54 @@ public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex,
Objects.requireNonNull(s);
Objects.checkFromToIndex(beginIndex, endIndex, s.length());

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, 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.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));
}

/*
* 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));
}

/**
Expand Down
Loading

1 comment on commit b62e774

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.