38
38
import java .util .Objects ;
39
39
import java .util .Optional ;
40
40
41
+ import static java .lang .Character .digit ;
41
42
import static java .lang .String .COMPACT_STRINGS ;
42
43
import static java .lang .String .LATIN1 ;
43
44
import static java .lang .String .UTF16 ;
@@ -538,8 +539,7 @@ static int stringSize(int x) {
538
539
* does not contain a parsable {@code int}.
539
540
*/
540
541
public static int parseInt (String s , int radix )
541
- throws NumberFormatException
542
- {
542
+ throws NumberFormatException {
543
543
/*
544
544
* WARNING: This method may be invoked early during VM initialization
545
545
* before IntegerCache is initialized. Care must be taken to not use
@@ -551,52 +551,41 @@ public static int parseInt(String s, int radix)
551
551
}
552
552
553
553
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 ) );
556
556
}
557
557
558
558
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 ) );
561
561
}
562
562
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 ;
582
575
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 ;
595
586
}
596
- return negative ? result : -result ;
597
- } else {
598
- throw NumberFormatException .forInputString (s , radix );
599
587
}
588
+ throw NumberFormatException .forInputString (s , radix );
600
589
}
601
590
602
591
/**
@@ -632,55 +621,47 @@ public static int parseInt(CharSequence s, int beginIndex, int endIndex, int rad
632
621
Objects .checkFromToIndex (beginIndex , endIndex , s .length ());
633
622
634
623
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 ) );
637
626
}
627
+
638
628
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 ) );
641
631
}
642
632
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 ;
644
643
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 ;
663
650
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 ;
679
661
}
680
- return negative ? result : -result ;
681
- } else {
682
- throw NumberFormatException .forInputString ("" , radix );
683
662
}
663
+ throw NumberFormatException .forCharSequence (s , beginIndex ,
664
+ endIndex , i - (digit < -1 ? 0 : 1 ));
684
665
}
685
666
686
667
/**
@@ -701,7 +682,7 @@ public static int parseInt(CharSequence s, int beginIndex, int endIndex, int rad
701
682
* parsable integer.
702
683
*/
703
684
public static int parseInt (String s ) throws NumberFormatException {
704
- return parseInt (s ,10 );
685
+ return parseInt (s , 10 );
705
686
}
706
687
707
688
/**
@@ -753,31 +734,48 @@ public static int parseUnsignedInt(String s, int radix)
753
734
throw new NumberFormatException ("Cannot parse null string" );
754
735
}
755
736
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
+
756
747
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 ;
777
769
}
778
- } else {
770
+ if (inRange && i == len && digit >= 0 ) {
771
+ return result ;
772
+ }
773
+ }
774
+ if (digit < 0 ) {
779
775
throw NumberFormatException .forInputString (s , radix );
780
776
}
777
+ throw new NumberFormatException (String .format (
778
+ "String value %s exceeds range of unsigned int." , s ));
781
779
}
782
780
783
781
/**
@@ -812,32 +810,54 @@ public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex,
812
810
Objects .requireNonNull (s );
813
811
Objects .checkFromToIndex (beginIndex , endIndex , s .length ());
814
812
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 ) {
839
830
throw new NumberFormatException ("" );
840
831
}
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 ));
841
861
}
842
862
843
863
/**
0 commit comments