@@ -568,120 +568,133 @@ impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
568568#[ stable( feature = "rust1" , since = "1.0.0" ) ]
569569impl fmt:: Display for u128 {
570570 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) )
572575 }
573576}
574577
575578#[ stable( feature = "rust1" , since = "1.0.0" ) ]
576579impl fmt:: Display for i128 {
577580 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) )
579588 }
580589}
581590
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+ }
590608
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 )
608613 } 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) ;
615616
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+ } ;
625628
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+ }
636649
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+ }
652665
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+ }
669682
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+ }
680693}
681694
682695/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
683696/// 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 ) {
685698 // Consume the least-significant decimals from a working copy.
686699 let mut remain = n;
687700
0 commit comments