@@ -565,123 +565,134 @@ mod imp {
565565}
566566impl_Exp ! ( i128 , u128 as u128 via to_u128 named exp_u128) ;
567567
568+ const U128_MAX_DEC_N : usize = u128:: MAX . ilog ( 10 ) as usize + 1 ;
569+
568570#[ stable( feature = "rust1" , since = "1.0.0" ) ]
569571impl fmt:: Display for u128 {
570572 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) )
572576 }
573577}
574578
575579#[ stable( feature = "rust1" , since = "1.0.0" ) ]
576580impl fmt:: Display for i128 {
577581 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) )
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+ // Optimize common-case zero, which would also need special treatment due to
602+ // its "leading" zero.
603+ if self == 0 {
604+ return "0" ;
605+ }
590606
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 )
608611 } 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) ;
615614
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+ } ;
625626
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+ }
636647
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+ }
652663
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+ }
669680
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+ }
680691}
681692
682693/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
683694/// 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 ) {
685696 // Consume the least-significant decimals from a working copy.
686697 let mut remain = n;
687698
0 commit comments