@@ -211,11 +211,47 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
211
211
8081828384858687888990919293949596979899";
212
212
213
213
macro_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 + 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
+
215
252
#[ 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] ;
219
255
let mut curr = buf. len( ) ;
220
256
let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
221
257
let lut_ptr = DEC_DIGITS_LUT . as_ptr( ) ;
@@ -229,58 +265,64 @@ macro_rules! impl_Display {
229
265
// is safe to access.
230
266
unsafe {
231
267
// 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
+ }
248
288
}
249
289
250
290
// 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
252
292
253
293
// decode 2 more chars, if > 2 chars
254
294
if n >= 100 {
255
295
let d1 = ( n % 100 ) << 1 ;
256
296
n /= 100 ;
257
297
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 ) ;
259
299
}
260
300
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 ;
261
304
// decode last 1 or 2 chars
262
305
if n < 10 {
263
306
curr -= 1 ;
264
- * buf_ptr. add( curr) = ( n as u8 ) + b'0' ;
307
+ * buf_ptr. add( curr) = n + b'0' ;
265
308
} else {
266
309
let d1 = n << 1 ;
267
310
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 ) ;
269
312
}
270
313
}
271
314
272
315
// SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
273
316
// UTF-8 since `DEC_DIGITS_LUT` is
274
317
let buf_slice = unsafe {
275
- str :: from_utf8_unchecked(
318
+ core :: str :: from_utf8_unchecked(
276
319
slice:: from_raw_parts( buf_ptr. add( curr) , buf. len( ) - curr) )
277
320
} ;
278
321
f. pad_integral( is_nonnegative, "" , buf_slice)
279
- }
322
+ } ) *
280
323
281
324
#[ 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 {
284
326
let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 39 ] ;
285
327
let mut curr = buf. len( ) ;
286
328
let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
@@ -309,27 +351,12 @@ macro_rules! impl_Display {
309
351
} ;
310
352
f. pad_integral( is_nonnegative, "" , buf_slice)
311
353
}
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
- } ) *
327
354
} ;
328
355
}
329
356
330
357
macro_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 > (
333
360
mut n: $u,
334
361
is_nonnegative: bool ,
335
362
upper: bool ,
@@ -377,10 +404,9 @@ macro_rules! impl_Exp {
377
404
( n, exponent, exponent, added_precision)
378
405
} ;
379
406
380
- // 39 digits (worst case u128) + . = 40
381
407
// Since `curr` always decreases by the number of digits copied, this means
382
408
// that `curr >= 0`.
383
- let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 40 ] ;
409
+ let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; SIZE ] ;
384
410
let mut curr = buf. len( ) ; //index for buf
385
411
let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
386
412
let lut_ptr = DEC_DIGITS_LUT . as_ptr( ) ;
@@ -398,7 +424,7 @@ macro_rules! impl_Exp {
398
424
exponent += 2 ;
399
425
}
400
426
// 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
402
428
// decode second-to-last character
403
429
if n >= 10 {
404
430
curr -= 1 ;
@@ -475,7 +501,7 @@ macro_rules! impl_Exp {
475
501
// convert the negative num to positive by summing 1 to it's 2 complement
476
502
( !self . $conv_fn( ) ) . wrapping_add( 1 )
477
503
} ;
478
- $name( n, is_nonnegative, false , f)
504
+ $name:: <$size> ( n, is_nonnegative, false , f)
479
505
}
480
506
} ) *
481
507
$(
@@ -490,7 +516,7 @@ macro_rules! impl_Exp {
490
516
// convert the negative num to positive by summing 1 to it's 2 complement
491
517
( !self . $conv_fn( ) ) . wrapping_add( 1 )
492
518
} ;
493
- $name( n, is_nonnegative, true , f)
519
+ $name:: <$size> ( n, is_nonnegative, true , f)
494
520
}
495
521
} ) *
496
522
} ;
@@ -502,24 +528,70 @@ macro_rules! impl_Exp {
502
528
mod imp {
503
529
use super :: * ;
504
530
impl_Display ! (
505
- i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , usize , isize
506
- as u64 via to_u64 named fmt_u64
531
+ i8 => 4 as u8 in fmt_u8 => named fmt_i8,
532
+ u8 => 3 => named fmt_u8,
533
+ i16 => 6 as u16 in fmt_u16 => named fmt_i16,
534
+ u16 => 5 => named fmt_u16,
535
+ i32 => 10 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 u64 in fmt_u64 => named fmt_isize,
540
+ usize => 20 => named fmt_usize,
541
+ ; as u64 via to_u64 named fmt_u64
507
542
) ;
508
543
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
511
555
) ;
512
556
}
513
557
514
558
#[ cfg( not( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ) ]
515
559
mod imp {
516
560
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 => 4 as u8 in fmt_u8 => named fmt_i8,
563
+ u8 => 3 => named fmt_u8,
564
+ i16 => 6 as u16 in fmt_u16 => named fmt_i16,
565
+ u16 => 5 => named fmt_u16,
566
+ i32 => 10 as u32 in fmt_u32 => named fmt_i32,
567
+ u32 => 9 => named fmt_u32,
568
+ isize => 10 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) ;
521
590
}
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) ;
523
595
524
596
/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
525
597
fn parse_u64_into < const N : usize > ( mut n : u64 , buf : & mut [ MaybeUninit < u8 > ; N ] , curr : & mut usize ) {
0 commit comments