@@ -208,11 +208,46 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
208208 8081828384858687888990919293949596979899";
209209
210210macro_rules! impl_Display {
211- ( $( $t: ident) ,* as $u: ident via $conv_fn: ident named $name: ident) => {
211+ ( $( $t: ident => $size: literal $( as $positive: ident in $other: ident) ? => named $name: ident, ) * ; as $u: ident via $conv_fn: ident named $gen_name: ident) => {
212+
213+ $(
214+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
215+ impl fmt:: Display for $t {
216+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
217+ // If it's a signed integer.
218+ $(
219+ let is_nonnegative = * self >= 0 ;
220+
221+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
222+ {
223+ if !is_nonnegative {
224+ // convert the negative num to positive by summing 1 to its 2s complement
225+ return $other( ( !self as $positive) . wrapping_add( 1 ) , false , f) ;
226+ }
227+ }
228+ #[ cfg( feature = "optimize_for_size" ) ]
229+ {
230+ if !is_nonnegative {
231+ // convert the negative num to positive by summing 1 to its 2s complement
232+ return $other( ( !self . $conv_fn( ) ) . wrapping_add( 1 ) , false , f) ;
233+ }
234+ }
235+ ) ?
236+ // If it's a positive integer.
237+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
238+ {
239+ $name( * self , true , f)
240+ }
241+ #[ cfg( feature = "optimize_for_size" ) ]
242+ {
243+ $gen_name( * self , true , f)
244+ }
245+ }
246+ }
247+
212248 #[ cfg( not( feature = "optimize_for_size" ) ) ]
213- fn $name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
214- // 2^128 is about 3*10^38, so 39 gives an extra byte of space
215- let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 39 ] ;
249+ fn $name( mut n: $t, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
250+ let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; $size] ;
216251 let mut curr = buf. len( ) ;
217252 let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
218253 let lut_ptr = DEC_DIGITS_LUT . as_ptr( ) ;
@@ -226,22 +261,26 @@ macro_rules! impl_Display {
226261 // is safe to access.
227262 unsafe {
228263 // need at least 16 bits for the 4-characters-at-a-time to work.
229- assert!( crate :: mem:: size_of:: <$u>( ) >= 2 ) ;
230-
231- // eagerly decode 4 characters at a time
232- while n >= 10000 {
233- let rem = ( n % 10000 ) as usize ;
234- n /= 10000 ;
235-
236- let d1 = ( rem / 100 ) << 1 ;
237- let d2 = ( rem % 100 ) << 1 ;
238- curr -= 4 ;
239-
240- // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
241- // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
242- // which is `10^40 > 2^128 > n`.
243- ptr:: copy_nonoverlapping( lut_ptr. add( d1) , buf_ptr. add( curr) , 2 ) ;
244- ptr:: copy_nonoverlapping( lut_ptr. add( d2) , buf_ptr. add( curr + 2 ) , 2 ) ;
264+ #[ allow( overflowing_literals) ]
265+ #[ allow( unused_comparisons) ]
266+ // This block will be removed for smaller types at compile time and in the worst
267+ // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`.
268+ if core:: mem:: size_of:: <$t>( ) >= 2 {
269+ // eagerly decode 4 characters at a time
270+ while n >= 10000 {
271+ let rem = ( n % 10000 ) as usize ;
272+ n /= 10000 ;
273+
274+ let d1 = ( rem / 100 ) << 1 ;
275+ let d2 = ( rem % 100 ) << 1 ;
276+ curr -= 4 ;
277+
278+ // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
279+ // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
280+ // which is `10^40 > 2^128 > n`.
281+ ptr:: copy_nonoverlapping( lut_ptr. add( d1 as usize ) , buf_ptr. add( curr) , 2 ) ;
282+ ptr:: copy_nonoverlapping( lut_ptr. add( d2 as usize ) , buf_ptr. add( curr + 2 ) , 2 ) ;
283+ }
245284 }
246285
247286 // if we reach here numbers are <= 9999, so at most 4 chars long
@@ -255,6 +294,8 @@ macro_rules! impl_Display {
255294 ptr:: copy_nonoverlapping( lut_ptr. add( d1) , buf_ptr. add( curr) , 2 ) ;
256295 }
257296
297+ // if we reach here numbers are <= 100, so at most 2 chars long
298+ // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough.
258299 // decode last 1 or 2 chars
259300 if n < 10 {
260301 curr -= 1 ;
@@ -273,11 +314,10 @@ macro_rules! impl_Display {
273314 slice:: from_raw_parts( buf_ptr. add( curr) , buf. len( ) - curr) )
274315 } ;
275316 f. pad_integral( is_nonnegative, "" , buf_slice)
276- }
317+ } ) *
277318
278319 #[ cfg( feature = "optimize_for_size" ) ]
279- fn $name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
280- // 2^128 is about 3*10^38, so 39 gives an extra byte of space
320+ fn $gen_name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
281321 let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 39 ] ;
282322 let mut curr = buf. len( ) ;
283323 let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
@@ -306,21 +346,6 @@ macro_rules! impl_Display {
306346 } ;
307347 f. pad_integral( is_nonnegative, "" , buf_slice)
308348 }
309-
310- $( #[ stable( feature = "rust1" , since = "1.0.0" ) ]
311- impl fmt:: Display for $t {
312- #[ allow( unused_comparisons) ]
313- fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
314- let is_nonnegative = * self >= 0 ;
315- let n = if is_nonnegative {
316- self . $conv_fn( )
317- } else {
318- // convert the negative num to positive by summing 1 to it's 2 complement
319- ( !self . $conv_fn( ) ) . wrapping_add( 1 )
320- } ;
321- $name( n, is_nonnegative, f)
322- }
323- } ) *
324349 } ;
325350}
326351
@@ -374,7 +399,6 @@ macro_rules! impl_Exp {
374399 ( n, exponent, exponent, added_precision)
375400 } ;
376401
377- // 39 digits (worst case u128) + . = 40
378402 // Since `curr` always decreases by the number of digits copied, this means
379403 // that `curr >= 0`.
380404 let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 40 ] ;
@@ -469,7 +493,7 @@ macro_rules! impl_Exp {
469493 let n = if is_nonnegative {
470494 self . $conv_fn( )
471495 } else {
472- // convert the negative num to positive by summing 1 to it's 2 complement
496+ // convert the negative num to positive by summing 1 to its 2s complement
473497 ( !self . $conv_fn( ) ) . wrapping_add( 1 )
474498 } ;
475499 $name( n, is_nonnegative, false , f)
@@ -484,7 +508,7 @@ macro_rules! impl_Exp {
484508 let n = if is_nonnegative {
485509 self . $conv_fn( )
486510 } else {
487- // convert the negative num to positive by summing 1 to it's 2 complement
511+ // convert the negative num to positive by summing 1 to its 2s complement
488512 ( !self . $conv_fn( ) ) . wrapping_add( 1 )
489513 } ;
490514 $name( n, is_nonnegative, true , f)
@@ -499,8 +523,17 @@ macro_rules! impl_Exp {
499523mod imp {
500524 use super :: * ;
501525 impl_Display ! (
502- i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , usize , isize
503- as u64 via to_u64 named fmt_u64
526+ i8 => 3 as u8 in fmt_u8 => named fmt_i8,
527+ u8 => 3 => named fmt_u8,
528+ i16 => 5 as u16 in fmt_u16 => named fmt_i16,
529+ u16 => 5 => named fmt_u16,
530+ i32 => 10 as u32 in fmt_u32 => named fmt_i32,
531+ u32 => 10 => named fmt_u32,
532+ i64 => 19 as u64 in fmt_u64 => named fmt_i64,
533+ u64 => 20 => named fmt_u64,
534+ isize => 19 as usize in fmt_usize => named fmt_isize,
535+ usize => 20 => named fmt_usize,
536+ ; as u64 via to_u64 named fmt_u64
504537 ) ;
505538 impl_Exp ! (
506539 i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , usize , isize
@@ -511,8 +544,21 @@ mod imp {
511544#[ cfg( not( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ) ]
512545mod imp {
513546 use super :: * ;
514- impl_Display ! ( i8 , u8 , i16 , u16 , i32 , u32 , isize , usize as u32 via to_u32 named fmt_u32) ;
515- impl_Display ! ( i64 , u64 as u64 via to_u64 named fmt_u64) ;
547+ impl_Display ! (
548+ i8 => 3 as u8 in fmt_u8 => named fmt_i8,
549+ u8 => 3 => named fmt_u8,
550+ i16 => 5 as u16 in fmt_u16 => named fmt_i16,
551+ u16 => 5 => named fmt_u16,
552+ i32 => 10 as u32 in fmt_u32 => named fmt_i32,
553+ u32 => 10 => named fmt_u32,
554+ isize => 10 as usize in fmt_usize => named fmt_isize,
555+ usize => 10 => named fmt_usize,
556+ ; as u32 via to_u32 named fmt_u32) ;
557+ impl_Display ! (
558+ i64 => 19 as u64 in fmt_u64 => named fmt_i64,
559+ u64 => 20 => named fmt_u64,
560+ ; as u64 via to_u64 named fmt_u64) ;
561+
516562 impl_Exp ! ( i8 , u8 , i16 , u16 , i32 , u32 , isize , usize as u32 via to_u32 named exp_u32) ;
517563 impl_Exp ! ( i64 , u64 as u64 via to_u64 named exp_u64) ;
518564}
@@ -619,7 +665,7 @@ impl fmt::Display for i128 {
619665 let n = if is_nonnegative {
620666 self . to_u128 ( )
621667 } else {
622- // convert the negative num to positive by summing 1 to it's 2 complement
668+ // convert the negative num to positive by summing 1 to its 2s complement
623669 ( !self . to_u128 ( ) ) . wrapping_add ( 1 )
624670 } ;
625671 fmt_u128 ( n, is_nonnegative, f)
0 commit comments