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