Skip to content

Commit b62e774

Browse files
committed
8317515: Unify the code of the parse*() families of methods in j.l.Integer and j.l.Long
Reviewed-by: redestad
1 parent a64794b commit b62e774

File tree

2 files changed

+291
-362
lines changed

2 files changed

+291
-362
lines changed

src/java.base/share/classes/java/lang/Integer.java

Lines changed: 147 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.Objects;
3939
import java.util.Optional;
4040

41+
import static java.lang.Character.digit;
4142
import static java.lang.String.COMPACT_STRINGS;
4243
import static java.lang.String.LATIN1;
4344
import static java.lang.String.UTF16;
@@ -538,8 +539,7 @@ static int stringSize(int x) {
538539
* does not contain a parsable {@code int}.
539540
*/
540541
public static int parseInt(String s, int radix)
541-
throws NumberFormatException
542-
{
542+
throws NumberFormatException {
543543
/*
544544
* WARNING: This method may be invoked early during VM initialization
545545
* before IntegerCache is initialized. Care must be taken to not use
@@ -551,52 +551,41 @@ public static int parseInt(String s, int radix)
551551
}
552552

553553
if (radix < Character.MIN_RADIX) {
554-
throw new NumberFormatException("radix " + radix +
555-
" less than Character.MIN_RADIX");
554+
throw new NumberFormatException(String.format(
555+
"radix %s less than Character.MIN_RADIX", radix));
556556
}
557557

558558
if (radix > Character.MAX_RADIX) {
559-
throw new NumberFormatException("radix " + radix +
560-
" greater than Character.MAX_RADIX");
559+
throw new NumberFormatException(String.format(
560+
"radix %s greater than Character.MAX_RADIX", radix));
561561
}
562562

563-
boolean negative = false;
564-
int i = 0, len = s.length();
565-
int limit = -Integer.MAX_VALUE;
566-
567-
if (len > 0) {
568-
char firstChar = s.charAt(0);
569-
if (firstChar < '0') { // Possible leading "+" or "-"
570-
if (firstChar == '-') {
571-
negative = true;
572-
limit = Integer.MIN_VALUE;
573-
} else if (firstChar != '+') {
574-
throw NumberFormatException.forInputString(s, radix);
575-
}
576-
577-
if (len == 1) { // Cannot have lone "+" or "-"
578-
throw NumberFormatException.forInputString(s, radix);
579-
}
580-
i++;
581-
}
563+
int len = s.length();
564+
if (len == 0) {
565+
throw new NumberFormatException("");
566+
}
567+
int digit = ~0xFF;
568+
int i = 0;
569+
char firstChar = s.charAt(i++);
570+
if (firstChar != '-' && firstChar != '+') {
571+
digit = digit(firstChar, radix);
572+
}
573+
if (digit >= 0 || digit == ~0xFF && len > 1) {
574+
int limit = firstChar != '-' ? MIN_VALUE + 1 : MIN_VALUE;
582575
int multmin = limit / radix;
583-
int result = 0;
584-
while (i < len) {
585-
// Accumulating negatively avoids surprises near MAX_VALUE
586-
int digit = Character.digit(s.charAt(i++), radix);
587-
if (digit < 0 || result < multmin) {
588-
throw NumberFormatException.forInputString(s, radix);
589-
}
590-
result *= radix;
591-
if (result < limit + digit) {
592-
throw NumberFormatException.forInputString(s, radix);
593-
}
594-
result -= digit;
576+
int result = -(digit & 0xFF);
577+
boolean inRange = true;
578+
/* Accumulating negatively avoids surprises near MAX_VALUE */
579+
while (i < len && (digit = digit(s.charAt(i++), radix)) >= 0
580+
&& (inRange = result > multmin
581+
|| result == multmin && digit <= radix * multmin - limit)) {
582+
result = radix * result - digit;
583+
}
584+
if (inRange && i == len && digit >= 0) {
585+
return firstChar != '-' ? -result : result;
595586
}
596-
return negative ? result : -result;
597-
} else {
598-
throw NumberFormatException.forInputString(s, radix);
599587
}
588+
throw NumberFormatException.forInputString(s, radix);
600589
}
601590

602591
/**
@@ -632,55 +621,47 @@ public static int parseInt(CharSequence s, int beginIndex, int endIndex, int rad
632621
Objects.checkFromToIndex(beginIndex, endIndex, s.length());
633622

634623
if (radix < Character.MIN_RADIX) {
635-
throw new NumberFormatException("radix " + radix +
636-
" less than Character.MIN_RADIX");
624+
throw new NumberFormatException(String.format(
625+
"radix %s less than Character.MIN_RADIX", radix));
637626
}
627+
638628
if (radix > Character.MAX_RADIX) {
639-
throw new NumberFormatException("radix " + radix +
640-
" greater than Character.MAX_RADIX");
629+
throw new NumberFormatException(String.format(
630+
"radix %s greater than Character.MAX_RADIX", radix));
641631
}
642632

643-
boolean negative = false;
633+
/*
634+
* While s can be concurrently modified, it is ensured that each
635+
* of its characters is read at most once, from lower to higher indices.
636+
* This is obtained by reading them using the pattern s.charAt(i++),
637+
* and by not updating i anywhere else.
638+
*/
639+
if (beginIndex == endIndex) {
640+
throw new NumberFormatException("");
641+
}
642+
int digit = ~0xFF;
644643
int i = beginIndex;
645-
int limit = -Integer.MAX_VALUE;
646-
647-
if (i < endIndex) {
648-
char firstChar = s.charAt(i);
649-
if (firstChar < '0') { // Possible leading "+" or "-"
650-
if (firstChar == '-') {
651-
negative = true;
652-
limit = Integer.MIN_VALUE;
653-
} else if (firstChar != '+') {
654-
throw NumberFormatException.forCharSequence(s, beginIndex,
655-
endIndex, i);
656-
}
657-
i++;
658-
if (i == endIndex) { // Cannot have lone "+" or "-"
659-
throw NumberFormatException.forCharSequence(s, beginIndex,
660-
endIndex, i);
661-
}
662-
}
644+
char firstChar = s.charAt(i++);
645+
if (firstChar != '-' && firstChar != '+') {
646+
digit = digit(firstChar, radix);
647+
}
648+
if (digit >= 0 || digit == ~0xFF && endIndex - beginIndex > 1) {
649+
int limit = firstChar != '-' ? MIN_VALUE + 1 : MIN_VALUE;
663650
int multmin = limit / radix;
664-
int result = 0;
665-
while (i < endIndex) {
666-
// Accumulating negatively avoids surprises near MAX_VALUE
667-
int digit = Character.digit(s.charAt(i), radix);
668-
if (digit < 0 || result < multmin) {
669-
throw NumberFormatException.forCharSequence(s, beginIndex,
670-
endIndex, i);
671-
}
672-
result *= radix;
673-
if (result < limit + digit) {
674-
throw NumberFormatException.forCharSequence(s, beginIndex,
675-
endIndex, i);
676-
}
677-
i++;
678-
result -= digit;
651+
int result = -(digit & 0xFF);
652+
boolean inRange = true;
653+
/* Accumulating negatively avoids surprises near MAX_VALUE */
654+
while (i < endIndex && (digit = digit(s.charAt(i++), radix)) >= 0
655+
&& (inRange = result > multmin
656+
|| result == multmin && digit <= radix * multmin - limit)) {
657+
result = radix * result - digit;
658+
}
659+
if (inRange && i == endIndex && digit >= 0) {
660+
return firstChar != '-' ? -result : result;
679661
}
680-
return negative ? result : -result;
681-
} else {
682-
throw NumberFormatException.forInputString("", radix);
683662
}
663+
throw NumberFormatException.forCharSequence(s, beginIndex,
664+
endIndex, i - (digit < -1 ? 0 : 1));
684665
}
685666

686667
/**
@@ -701,7 +682,7 @@ public static int parseInt(CharSequence s, int beginIndex, int endIndex, int rad
701682
* parsable integer.
702683
*/
703684
public static int parseInt(String s) throws NumberFormatException {
704-
return parseInt(s,10);
685+
return parseInt(s, 10);
705686
}
706687

707688
/**
@@ -753,31 +734,48 @@ public static int parseUnsignedInt(String s, int radix)
753734
throw new NumberFormatException("Cannot parse null string");
754735
}
755736

737+
if (radix < Character.MIN_RADIX) {
738+
throw new NumberFormatException(String.format(
739+
"radix %s less than Character.MIN_RADIX", radix));
740+
}
741+
742+
if (radix > Character.MAX_RADIX) {
743+
throw new NumberFormatException(String.format(
744+
"radix %s greater than Character.MAX_RADIX", radix));
745+
}
746+
756747
int len = s.length();
757-
if (len > 0) {
758-
char firstChar = s.charAt(0);
759-
if (firstChar == '-') {
760-
throw new
761-
NumberFormatException(String.format("Illegal leading minus sign " +
762-
"on unsigned string %s.", s));
763-
} else {
764-
if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
765-
(radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
766-
return parseInt(s, radix);
767-
} else {
768-
long ell = Long.parseLong(s, radix);
769-
if ((ell & 0xffff_ffff_0000_0000L) == 0) {
770-
return (int) ell;
771-
} else {
772-
throw new
773-
NumberFormatException(String.format("String value %s exceeds " +
774-
"range of unsigned int.", s));
775-
}
776-
}
748+
if (len == 0) {
749+
throw NumberFormatException.forInputString(s, radix);
750+
}
751+
int i = 0;
752+
char firstChar = s.charAt(i++);
753+
if (firstChar == '-') {
754+
throw new NumberFormatException(String.format(
755+
"Illegal leading minus sign on unsigned string %s.", s));
756+
}
757+
int digit = ~0xFF;
758+
if (firstChar != '+') {
759+
digit = digit(firstChar, radix);
760+
}
761+
if (digit >= 0 || digit == ~0xFF && len > 1) {
762+
int multmax = divideUnsigned(-1, radix); // -1 is max unsigned int
763+
int result = digit & 0xFF;
764+
boolean inRange = true;
765+
while (i < len && (digit = digit(s.charAt(i++), radix)) >= 0
766+
&& (inRange = compareUnsigned(result, multmax) < 0
767+
|| result == multmax && digit < -radix * multmax)) {
768+
result = radix * result + digit;
777769
}
778-
} else {
770+
if (inRange && i == len && digit >= 0) {
771+
return result;
772+
}
773+
}
774+
if (digit < 0) {
779775
throw NumberFormatException.forInputString(s, radix);
780776
}
777+
throw new NumberFormatException(String.format(
778+
"String value %s exceeds range of unsigned int.", s));
781779
}
782780

783781
/**
@@ -812,32 +810,54 @@ public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex,
812810
Objects.requireNonNull(s);
813811
Objects.checkFromToIndex(beginIndex, endIndex, s.length());
814812

815-
int start = beginIndex, len = endIndex - beginIndex;
816-
817-
if (len > 0) {
818-
char firstChar = s.charAt(start);
819-
if (firstChar == '-') {
820-
throw new
821-
NumberFormatException(String.format("Illegal leading minus sign " +
822-
"on unsigned string %s.", s));
823-
} else {
824-
if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
825-
(radix == 10 && len <= 9)) { // Integer.MAX_VALUE in base 10 is 10 digits
826-
return parseInt(s, start, start + len, radix);
827-
} else {
828-
long ell = Long.parseLong(s, start, start + len, radix);
829-
if ((ell & 0xffff_ffff_0000_0000L) == 0) {
830-
return (int) ell;
831-
} else {
832-
throw new
833-
NumberFormatException(String.format("String value %s exceeds " +
834-
"range of unsigned int.", s));
835-
}
836-
}
837-
}
838-
} else {
813+
if (radix < Character.MIN_RADIX) {
814+
throw new NumberFormatException(String.format(
815+
"radix %s less than Character.MIN_RADIX", radix));
816+
}
817+
818+
if (radix > Character.MAX_RADIX) {
819+
throw new NumberFormatException(String.format(
820+
"radix %s greater than Character.MAX_RADIX", radix));
821+
}
822+
823+
/*
824+
* While s can be concurrently modified, it is ensured that each
825+
* of its characters is read at most once, from lower to higher indices.
826+
* This is obtained by reading them using the pattern s.charAt(i++),
827+
* and by not updating i anywhere else.
828+
*/
829+
if (beginIndex == endIndex) {
839830
throw new NumberFormatException("");
840831
}
832+
int i = beginIndex;
833+
char firstChar = s.charAt(i++);
834+
if (firstChar == '-') {
835+
throw new NumberFormatException(
836+
"Illegal leading minus sign on unsigned string " + s + ".");
837+
}
838+
int digit = ~0xFF;
839+
if (firstChar != '+') {
840+
digit = digit(firstChar, radix);
841+
}
842+
if (digit >= 0 || digit == ~0xFF && endIndex - beginIndex > 1) {
843+
int multmax = divideUnsigned(-1, radix); // -1 is max unsigned int
844+
int result = digit & 0xFF;
845+
boolean inRange = true;
846+
while (i < endIndex && (digit = digit(s.charAt(i++), radix)) >= 0
847+
&& (inRange = compareUnsigned(result, multmax) < 0
848+
|| result == multmax && digit < -radix * multmax)) {
849+
result = radix * result + digit;
850+
}
851+
if (inRange && i == endIndex && digit >= 0) {
852+
return result;
853+
}
854+
}
855+
if (digit < 0) {
856+
throw NumberFormatException.forCharSequence(s, beginIndex,
857+
endIndex, i - (digit < -1 ? 0 : 1));
858+
}
859+
throw new NumberFormatException(String.format(
860+
"String value %s exceeds range of unsigned int.", s));
841861
}
842862

843863
/**

0 commit comments

Comments
 (0)