@@ -211,11 +211,47 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
211211 8081828384858687888990919293949596979899";
212212
213213macro_rules! impl_Display {
214- ( $( $t: ident) ,* as $u: ident via $conv_fn: ident named $name: ident) => {
214+ ( $( $t: ident => $size: literal $( as $positive: ident in $other: ident) ? => named $name: ident, ) * ; as $u: ident via $conv_fn: ident named $gen_name: ident) => {
215+
216+ $(
217+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
218+ impl fmt:: Display for $t {
219+ #[ allow( unused_comparisons) ]
220+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
221+ // If it's a signed integer.
222+ $(
223+ let is_nonnegative = * self >= 0 ;
224+
225+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
226+ {
227+ if !is_nonnegative {
228+ // convert the negative num to positive by summing 1 to it's 2 complement
229+ return $other( ( !self as $positive) . wrapping_add( 1 ) , false , f) ;
230+ }
231+ }
232+ #[ cfg( feature = "optimize_for_size" ) ]
233+ {
234+ if !is_nonnegative {
235+ // convert the negative num to positive by summing 1 to it's 2 complement
236+ return $other( ( !self . $conv_fn( ) ) . wrapping_add( 1 ) , false , f) ;
237+ }
238+ }
239+ ) ?
240+ // If it's an unsigned integer.
241+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
242+ {
243+ $name( * self , true , f)
244+ }
245+ #[ cfg( feature = "optimize_for_size" ) ]
246+ {
247+ $gen_name( * self , true , f)
248+ }
249+ }
250+ }
251+
215252 #[ cfg( not( feature = "optimize_for_size" ) ) ]
216- fn $name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
217- // 2^128 is about 3*10^38, so 39 gives an extra byte of space
218- let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 39 ] ;
253+ fn $name( mut n: $t, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
254+ let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; $size] ;
219255 let mut curr = buf. len( ) ;
220256 let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
221257 let lut_ptr = DEC_DIGITS_LUT . as_ptr( ) ;
@@ -229,58 +265,64 @@ macro_rules! impl_Display {
229265 // is safe to access.
230266 unsafe {
231267 // need at least 16 bits for the 4-characters-at-a-time to work.
232- assert!( crate :: mem:: size_of:: <$u>( ) >= 2 ) ;
233-
234- // eagerly decode 4 characters at a time
235- while n >= 10000 {
236- let rem = ( n % 10000 ) as usize ;
237- n /= 10000 ;
238-
239- let d1 = ( rem / 100 ) << 1 ;
240- let d2 = ( rem % 100 ) << 1 ;
241- curr -= 4 ;
242-
243- // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
244- // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
245- // which is `10^40 > 2^128 > n`.
246- ptr:: copy_nonoverlapping( lut_ptr. add( d1) , buf_ptr. add( curr) , 2 ) ;
247- ptr:: copy_nonoverlapping( lut_ptr. add( d2) , buf_ptr. add( curr + 2 ) , 2 ) ;
268+ #[ allow( overflowing_literals) ]
269+ #[ allow( unused_comparisons) ]
270+ // This block should be removed for smaller types at compile time so it
271+ // should be ok.
272+ if core:: mem:: size_of:: <$t>( ) >= 2 {
273+ // eagerly decode 4 characters at a time
274+ while n >= 10000 {
275+ let rem = ( n % 10000 ) as u16 ;
276+ n /= 10000 ;
277+
278+ let d1 = ( rem / 100 ) << 1 ;
279+ let d2 = ( rem % 100 ) << 1 ;
280+ curr -= 4 ;
281+
282+ // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
283+ // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
284+ // which is `10^40 > 2^128 > n`.
285+ ptr:: copy_nonoverlapping( lut_ptr. add( d1 as usize ) , buf_ptr. add( curr) , 2 ) ;
286+ ptr:: copy_nonoverlapping( lut_ptr. add( d2 as usize ) , buf_ptr. add( curr + 2 ) , 2 ) ;
287+ }
248288 }
249289
250290 // if we reach here numbers are <= 9999, so at most 4 chars long
251- let mut n = n as usize ; // possibly reduce 64bit math
291+ let mut n = n as u16 ; // possibly reduce 64bit math
252292
253293 // decode 2 more chars, if > 2 chars
254294 if n >= 100 {
255295 let d1 = ( n % 100 ) << 1 ;
256296 n /= 100 ;
257297 curr -= 2 ;
258- ptr:: copy_nonoverlapping( lut_ptr. add( d1) , buf_ptr. add( curr) , 2 ) ;
298+ ptr:: copy_nonoverlapping( lut_ptr. add( d1 as usize ) , buf_ptr. add( curr) , 2 ) ;
259299 }
260300
301+ // if we reach here numbers are <= 100, so at most 2 chars long
302+ // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough.
303+ let n = n as u8 ;
261304 // decode last 1 or 2 chars
262305 if n < 10 {
263306 curr -= 1 ;
264- * buf_ptr. add( curr) = ( n as u8 ) + b'0' ;
307+ * buf_ptr. add( curr) = n + b'0' ;
265308 } else {
266309 let d1 = n << 1 ;
267310 curr -= 2 ;
268- ptr:: copy_nonoverlapping( lut_ptr. add( d1) , buf_ptr. add( curr) , 2 ) ;
311+ ptr:: copy_nonoverlapping( lut_ptr. add( d1 as usize ) , buf_ptr. add( curr) , 2 ) ;
269312 }
270313 }
271314
272315 // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
273316 // UTF-8 since `DEC_DIGITS_LUT` is
274317 let buf_slice = unsafe {
275- str :: from_utf8_unchecked(
318+ core :: str :: from_utf8_unchecked(
276319 slice:: from_raw_parts( buf_ptr. add( curr) , buf. len( ) - curr) )
277320 } ;
278321 f. pad_integral( is_nonnegative, "" , buf_slice)
279- }
322+ } ) *
280323
281324 #[ cfg( feature = "optimize_for_size" ) ]
282- fn $name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
283- // 2^128 is about 3*10^38, so 39 gives an extra byte of space
325+ fn $gen_name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
284326 let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 39 ] ;
285327 let mut curr = buf. len( ) ;
286328 let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
@@ -309,27 +351,12 @@ macro_rules! impl_Display {
309351 } ;
310352 f. pad_integral( is_nonnegative, "" , buf_slice)
311353 }
312-
313- $( #[ stable( feature = "rust1" , since = "1.0.0" ) ]
314- impl fmt:: Display for $t {
315- #[ allow( unused_comparisons) ]
316- fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
317- let is_nonnegative = * self >= 0 ;
318- let n = if is_nonnegative {
319- self . $conv_fn( )
320- } else {
321- // convert the negative num to positive by summing 1 to it's 2 complement
322- ( !self . $conv_fn( ) ) . wrapping_add( 1 )
323- } ;
324- $name( n, is_nonnegative, f)
325- }
326- } ) *
327354 } ;
328355}
329356
330357macro_rules! impl_Exp {
331- ( $( $t: ident) , * as $u: ident via $conv_fn: ident named $name: ident) => {
332- fn $name(
358+ ( $( $t: ident => $size : literal , ) * ; as $u: ident via $conv_fn: ident named $name: ident) => {
359+ fn $name< const SIZE : usize > (
333360 mut n: $u,
334361 is_nonnegative: bool ,
335362 upper: bool ,
@@ -377,10 +404,9 @@ macro_rules! impl_Exp {
377404 ( n, exponent, exponent, added_precision)
378405 } ;
379406
380- // 39 digits (worst case u128) + . = 40
381407 // Since `curr` always decreases by the number of digits copied, this means
382408 // that `curr >= 0`.
383- let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 40 ] ;
409+ let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; SIZE ] ;
384410 let mut curr = buf. len( ) ; //index for buf
385411 let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
386412 let lut_ptr = DEC_DIGITS_LUT . as_ptr( ) ;
@@ -398,7 +424,7 @@ macro_rules! impl_Exp {
398424 exponent += 2 ;
399425 }
400426 // n is <= 99, so at most 2 chars long
401- let mut n = n as isize ; // possibly reduce 64bit math
427+ let mut n = n as i8 ; // possibly reduce 64bit math
402428 // decode second-to-last character
403429 if n >= 10 {
404430 curr -= 1 ;
@@ -475,7 +501,7 @@ macro_rules! impl_Exp {
475501 // convert the negative num to positive by summing 1 to it's 2 complement
476502 ( !self . $conv_fn( ) ) . wrapping_add( 1 )
477503 } ;
478- $name( n, is_nonnegative, false , f)
504+ $name:: <$size> ( n, is_nonnegative, false , f)
479505 }
480506 } ) *
481507 $(
@@ -490,7 +516,7 @@ macro_rules! impl_Exp {
490516 // convert the negative num to positive by summing 1 to it's 2 complement
491517 ( !self . $conv_fn( ) ) . wrapping_add( 1 )
492518 } ;
493- $name( n, is_nonnegative, true , f)
519+ $name:: <$size> ( n, is_nonnegative, true , f)
494520 }
495521 } ) *
496522 } ;
@@ -502,24 +528,70 @@ macro_rules! impl_Exp {
502528mod imp {
503529 use super :: * ;
504530 impl_Display ! (
505- i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , usize , isize
506- as u64 via to_u64 named fmt_u64
531+ i8 => 3 as u8 in fmt_u8 => named fmt_i8,
532+ u8 => 3 => named fmt_u8,
533+ i16 => 5 as u16 in fmt_u16 => named fmt_i16,
534+ u16 => 5 => named fmt_u16,
535+ i32 => 9 as u32 in fmt_u32 => named fmt_i32,
536+ u32 => 9 => named fmt_u32,
537+ i64 => 20 as u64 in fmt_u64 => named fmt_i64,
538+ u64 => 20 => named fmt_u64,
539+ isize => 20 as usize in fmt_usize => named fmt_isize,
540+ usize => 20 => named fmt_usize,
541+ ; as u64 via to_u64 named fmt_u64
507542 ) ;
508543 impl_Exp ! (
509- i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , usize , isize
510- as u64 via to_u64 named exp_u64
544+ i8 => 5 ,
545+ u8 => 4 ,
546+ i16 => 7 ,
547+ u16 => 6 ,
548+ i32 => 11 ,
549+ u32 => 10 ,
550+ i64 => 21 ,
551+ u64 => 21 ,
552+ isize => 21 ,
553+ usize => 21 ,
554+ ; as u64 via to_u64 named exp_u64
511555 ) ;
512556}
513557
514558#[ cfg( not( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ) ]
515559mod imp {
516560 use super :: * ;
517- impl_Display ! ( i8 , u8 , i16 , u16 , i32 , u32 , isize , usize as u32 via to_u32 named fmt_u32) ;
518- impl_Display ! ( i64 , u64 as u64 via to_u64 named fmt_u64) ;
519- impl_Exp ! ( i8 , u8 , i16 , u16 , i32 , u32 , isize , usize as u32 via to_u32 named exp_u32) ;
520- impl_Exp ! ( i64 , u64 as u64 via to_u64 named exp_u64) ;
561+ impl_Display ! (
562+ i8 => 3 as u8 in fmt_u8 => named fmt_i8,
563+ u8 => 3 => named fmt_u8,
564+ i16 => 5 as u16 in fmt_u16 => named fmt_i16,
565+ u16 => 5 => named fmt_u16,
566+ i32 => 9 as u32 in fmt_u32 => named fmt_i32,
567+ u32 => 9 => named fmt_u32,
568+ isize => 9 as usize in fmt_usize => named fmt_isize,
569+ usize => 9 => named fmt_usize,
570+ ; as u32 via to_u32 named fmt_u32) ;
571+ impl_Display ! (
572+ i64 => 20 as u64 in fmt_u64 => named fmt_i64,
573+ u64 => 20 => named fmt_u64,
574+ ; as u64 via to_u64 named fmt_u64) ;
575+
576+ impl_Exp ! (
577+ i8 => 5 ,
578+ u8 => 4 ,
579+ i16 => 7 ,
580+ u16 => 6 ,
581+ i32 => 11 ,
582+ u32 => 10 ,
583+ isize => 11 ,
584+ usize => 10 ,
585+ ; as u32 via to_u32 named exp_u32) ;
586+ impl_Exp ! (
587+ i64 => 21 ,
588+ u64 => 21 ,
589+ ; as u64 via to_u64 named exp_u64) ;
521590}
522- impl_Exp ! ( i128 , u128 as u128 via to_u128 named exp_u128) ;
591+ impl_Exp ! (
592+ i128 => 40 ,
593+ u128 => 39 ,
594+ ; as u128 via to_u128 named exp_u128) ;
523595
524596/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
525597fn parse_u64_into < const N : usize > ( mut n : u64 , buf : & mut [ MaybeUninit < u8 > ; N ] , curr : & mut usize ) {
0 commit comments