@@ -568,120 +568,133 @@ impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
568
568
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
569
569
impl fmt:: Display for u128 {
570
570
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
571
- fmt_u128 ( * self , true , f)
571
+ const MAX_DEC_N : usize = u128:: MAX . ilog ( 10 ) as usize + 1 ;
572
+ let mut buf = [ MaybeUninit :: < u8 > :: uninit ( ) ; MAX_DEC_N ] ;
573
+
574
+ f. pad_integral ( true , "" , self . _fmt ( & mut buf) )
572
575
}
573
576
}
574
577
575
578
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
576
579
impl fmt:: Display for i128 {
577
580
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
578
- fmt_u128 ( self . unsigned_abs ( ) , * self >= 0 , f)
581
+ // This is not a typo, we use the maximum number of digits of `u128`, hence why we use
582
+ // `u128::MAX`.
583
+ const MAX_DEC_N : usize = u128:: MAX . ilog ( 10 ) as usize + 1 ;
584
+ let mut buf = [ MaybeUninit :: < u8 > :: uninit ( ) ; MAX_DEC_N ] ;
585
+
586
+ let is_nonnegative = * self >= 0 ;
587
+ f. pad_integral ( is_nonnegative, "" , self . unsigned_abs ( ) . _fmt ( & mut buf) )
579
588
}
580
589
}
581
590
582
- /// Format optimized for u128. Computation of 128 bits is limited by proccessing
583
- /// in batches of 16 decimals at a time.
584
- fn fmt_u128 ( n : u128 , is_nonnegative : bool , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
585
- // Optimize common-case zero, which would also need special treatment due to
586
- // its "leading" zero.
587
- if n == 0 {
588
- return f. pad_integral ( true , "" , "0" ) ;
589
- }
591
+ impl u128 {
592
+ /// Format optimized for u128. Computation of 128 bits is limited by proccessing
593
+ /// in batches of 16 decimals at a time.
594
+ #[ doc( hidden) ]
595
+ #[ unstable(
596
+ feature = "fmt_internals" ,
597
+ reason = "specialized method meant to only be used by `SpecToString` implementation" ,
598
+ issue = "none"
599
+ ) ]
600
+ pub fn _fmt < ' a > ( self , buf : & ' a mut [ MaybeUninit < u8 > ] ) -> & ' a str {
601
+ const MAX_DEC_N : usize = u128:: MAX . ilog ( 10 ) as usize + 1 ;
602
+
603
+ // Optimize common-case zero, which would also need special treatment due to
604
+ // its "leading" zero.
605
+ if self == 0 {
606
+ return "0" ;
607
+ }
590
608
591
- // U128::MAX has 39 significant-decimals.
592
- const MAX_DEC_N : usize = u128:: MAX . ilog ( 10 ) as usize + 1 ;
593
- // Buffer decimals with right alignment.
594
- let mut buf = [ MaybeUninit :: < u8 > :: uninit ( ) ; MAX_DEC_N ] ;
595
-
596
- // Take the 16 least-significant decimals.
597
- let ( quot_1e16, mod_1e16) = div_rem_1e16 ( n) ;
598
- let ( mut remain, mut offset) = if quot_1e16 == 0 {
599
- ( mod_1e16, MAX_DEC_N )
600
- } else {
601
- // Write digits at buf[23..39].
602
- enc_16lsd :: < { MAX_DEC_N - 16 } > ( & mut buf, mod_1e16) ;
603
-
604
- // Take another 16 decimals.
605
- let ( quot2, mod2) = div_rem_1e16 ( quot_1e16) ;
606
- if quot2 == 0 {
607
- ( mod2, MAX_DEC_N - 16 )
609
+ // Take the 16 least-significant decimals.
610
+ let ( quot_1e16, mod_1e16) = div_rem_1e16 ( self ) ;
611
+ let ( mut remain, mut offset) = if quot_1e16 == 0 {
612
+ ( mod_1e16, MAX_DEC_N )
608
613
} else {
609
- // Write digits at buf[7..23].
610
- enc_16lsd :: < { MAX_DEC_N - 32 } > ( & mut buf, mod2) ;
611
- // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
612
- ( quot2 as u64 , MAX_DEC_N - 32 )
613
- }
614
- } ;
614
+ // Write digits at buf[23..39].
615
+ enc_16lsd :: < { MAX_DEC_N - 16 } > ( buf, mod_1e16) ;
615
616
616
- // Format per four digits from the lookup table.
617
- while remain > 999 {
618
- // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
619
- // and the while condition ensures at least 4 more decimals.
620
- unsafe { core:: hint:: assert_unchecked ( offset >= 4 ) }
621
- // SAFETY: The offset counts down from its initial buf.len()
622
- // without underflow due to the previous precondition.
623
- unsafe { core:: hint:: assert_unchecked ( offset <= buf. len ( ) ) }
624
- offset -= 4 ;
617
+ // Take another 16 decimals.
618
+ let ( quot2, mod2) = div_rem_1e16 ( quot_1e16) ;
619
+ if quot2 == 0 {
620
+ ( mod2, MAX_DEC_N - 16 )
621
+ } else {
622
+ // Write digits at buf[7..23].
623
+ enc_16lsd :: < { MAX_DEC_N - 32 } > ( buf, mod2) ;
624
+ // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
625
+ ( quot2 as u64 , MAX_DEC_N - 32 )
626
+ }
627
+ } ;
625
628
626
- // pull two pairs
627
- let quad = remain % 1_00_00 ;
628
- remain /= 1_00_00 ;
629
- let pair1 = ( quad / 100 ) as usize ;
630
- let pair2 = ( quad % 100 ) as usize ;
631
- buf[ offset + 0 ] . write ( DEC_DIGITS_LUT [ pair1 * 2 + 0 ] ) ;
632
- buf[ offset + 1 ] . write ( DEC_DIGITS_LUT [ pair1 * 2 + 1 ] ) ;
633
- buf[ offset + 2 ] . write ( DEC_DIGITS_LUT [ pair2 * 2 + 0 ] ) ;
634
- buf[ offset + 3 ] . write ( DEC_DIGITS_LUT [ pair2 * 2 + 1 ] ) ;
635
- }
629
+ // Format per four digits from the lookup table.
630
+ while remain > 999 {
631
+ // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
632
+ // and the while condition ensures at least 4 more decimals.
633
+ unsafe { core:: hint:: assert_unchecked ( offset >= 4 ) }
634
+ // SAFETY: The offset counts down from its initial buf.len()
635
+ // without underflow due to the previous precondition.
636
+ unsafe { core:: hint:: assert_unchecked ( offset <= buf. len ( ) ) }
637
+ offset -= 4 ;
638
+
639
+ // pull two pairs
640
+ let quad = remain % 1_00_00 ;
641
+ remain /= 1_00_00 ;
642
+ let pair1 = ( quad / 100 ) as usize ;
643
+ let pair2 = ( quad % 100 ) as usize ;
644
+ buf[ offset + 0 ] . write ( DEC_DIGITS_LUT [ pair1 * 2 + 0 ] ) ;
645
+ buf[ offset + 1 ] . write ( DEC_DIGITS_LUT [ pair1 * 2 + 1 ] ) ;
646
+ buf[ offset + 2 ] . write ( DEC_DIGITS_LUT [ pair2 * 2 + 0 ] ) ;
647
+ buf[ offset + 3 ] . write ( DEC_DIGITS_LUT [ pair2 * 2 + 1 ] ) ;
648
+ }
636
649
637
- // Format per two digits from the lookup table.
638
- if remain > 9 {
639
- // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
640
- // and the if condition ensures at least 2 more decimals.
641
- unsafe { core:: hint:: assert_unchecked ( offset >= 2 ) }
642
- // SAFETY: The offset counts down from its initial buf.len()
643
- // without underflow due to the previous precondition.
644
- unsafe { core:: hint:: assert_unchecked ( offset <= buf. len ( ) ) }
645
- offset -= 2 ;
646
-
647
- let pair = ( remain % 100 ) as usize ;
648
- remain /= 100 ;
649
- buf[ offset + 0 ] . write ( DEC_DIGITS_LUT [ pair * 2 + 0 ] ) ;
650
- buf[ offset + 1 ] . write ( DEC_DIGITS_LUT [ pair * 2 + 1 ] ) ;
651
- }
650
+ // Format per two digits from the lookup table.
651
+ if remain > 9 {
652
+ // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
653
+ // and the if condition ensures at least 2 more decimals.
654
+ unsafe { core:: hint:: assert_unchecked ( offset >= 2 ) }
655
+ // SAFETY: The offset counts down from its initial buf.len()
656
+ // without underflow due to the previous precondition.
657
+ unsafe { core:: hint:: assert_unchecked ( offset <= buf. len ( ) ) }
658
+ offset -= 2 ;
659
+
660
+ let pair = ( remain % 100 ) as usize ;
661
+ remain /= 100 ;
662
+ buf[ offset + 0 ] . write ( DEC_DIGITS_LUT [ pair * 2 + 0 ] ) ;
663
+ buf[ offset + 1 ] . write ( DEC_DIGITS_LUT [ pair * 2 + 1 ] ) ;
664
+ }
652
665
653
- // Format the last remaining digit, if any.
654
- if remain != 0 {
655
- // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
656
- // and the if condition ensures (at least) 1 more decimals.
657
- unsafe { core:: hint:: assert_unchecked ( offset >= 1 ) }
658
- // SAFETY: The offset counts down from its initial buf.len()
659
- // without underflow due to the previous precondition.
660
- unsafe { core:: hint:: assert_unchecked ( offset <= buf. len ( ) ) }
661
- offset -= 1 ;
662
-
663
- // Either the compiler sees that remain < 10, or it prevents
664
- // a boundary check up next.
665
- let last = ( remain & 15 ) as usize ;
666
- buf[ offset] . write ( DEC_DIGITS_LUT [ last * 2 + 1 ] ) ;
667
- // not used: remain = 0;
668
- }
666
+ // Format the last remaining digit, if any.
667
+ if remain != 0 {
668
+ // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
669
+ // and the if condition ensures (at least) 1 more decimals.
670
+ unsafe { core:: hint:: assert_unchecked ( offset >= 1 ) }
671
+ // SAFETY: The offset counts down from its initial buf.len()
672
+ // without underflow due to the previous precondition.
673
+ unsafe { core:: hint:: assert_unchecked ( offset <= buf. len ( ) ) }
674
+ offset -= 1 ;
675
+
676
+ // Either the compiler sees that remain < 10, or it prevents
677
+ // a boundary check up next.
678
+ let last = ( remain & 15 ) as usize ;
679
+ buf[ offset] . write ( DEC_DIGITS_LUT [ last * 2 + 1 ] ) ;
680
+ // not used: remain = 0;
681
+ }
669
682
670
- // SAFETY: All buf content since offset is set.
671
- let written = unsafe { buf. get_unchecked ( offset..) } ;
672
- // SAFETY: Writes use ASCII from the lookup table exclusively.
673
- let as_str = unsafe {
674
- str:: from_utf8_unchecked ( slice:: from_raw_parts (
675
- MaybeUninit :: slice_as_ptr ( written) ,
676
- written. len ( ) ,
677
- ) )
678
- } ;
679
- f . pad_integral ( is_nonnegative , "" , as_str )
683
+ // SAFETY: All buf content since offset is set.
684
+ let written = unsafe { buf. get_unchecked ( offset..) } ;
685
+ // SAFETY: Writes use ASCII from the lookup table exclusively.
686
+ unsafe {
687
+ str:: from_utf8_unchecked ( slice:: from_raw_parts (
688
+ MaybeUninit :: slice_as_ptr ( written) ,
689
+ written. len ( ) ,
690
+ ) )
691
+ }
692
+ }
680
693
}
681
694
682
695
/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
683
696
/// 16 ]`.
684
- fn enc_16lsd < const OFFSET : usize > ( buf : & mut [ MaybeUninit < u8 > ; 39 ] , n : u64 ) {
697
+ fn enc_16lsd < const OFFSET : usize > ( buf : & mut [ MaybeUninit < u8 > ] , n : u64 ) {
685
698
// Consume the least-significant decimals from a working copy.
686
699
let mut remain = n;
687
700
0 commit comments