Small optimization for integers Display implementation · qinheping/verify-rust-std@c4be3da (original) (raw)
`@@ -208,11 +208,46 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
`
208
208
` 8081828384858687888990919293949596979899";
`
209
209
``
210
210
`macro_rules! impl_Display {
`
211
``
`-
($($t:ident),* as u:identviau:ident via u:identviaconv_fn:ident named $name:ident) => {
`
``
211
`+
($($t:ident => size:literalsize:literal size:literal(as positive:identinpositive:ident in positive:identinother:ident)? => named name:ident,)∗;asname:ident,)* ; as name:ident,)∗;asu:ident via convfn:identnamedconv_fn:ident named convfn:identnamedgen_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((!selfasother((!self as other((!selfaspositive).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.other((!self.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
+
212
248
` #[cfg(not(feature = "optimize_for_size"))]
`
213
``
`-
fn name(mutn:name(mut n: name(mutn: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::::uninit(); 39];
`
``
249
`+
fn name(mutn:name(mut n: name(mutn:t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
`
``
250
`+
let mut buf = [MaybeUninit::::uninit(); $size];
`
216
251
`let mut curr = buf.len();
`
217
252
`let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
`
218
253
`let lut_ptr = DEC_DIGITS_LUT.as_ptr();
`
`@@ -226,22 +261,26 @@ macro_rules! impl_Display {
`
226
261
`// is safe to access.
`
227
262
`unsafe {
`
228
263
`// 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
`+
}
`
245
284
`}
`
246
285
``
247
286
`// if we reach here numbers are <= 9999, so at most 4 chars long
`
`@@ -255,6 +294,8 @@ macro_rules! impl_Display {
`
255
294
` ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
`
256
295
`}
`
257
296
``
``
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.
``
258
299
`// decode last 1 or 2 chars
`
259
300
`if n < 10 {
`
260
301
` curr -= 1;
`
`@@ -273,11 +314,10 @@ macro_rules! impl_Display {
`
273
314
` slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
`
274
315
`};
`
275
316
` f.pad_integral(is_nonnegative, "", buf_slice)
`
276
``
`-
}
`
``
317
`+
})*
`
277
318
``
278
319
` #[cfg(feature = "optimize_for_size")]
`
279
``
`-
fn name(mutn:name(mut n: name(mutn: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 genname(mutn:gen_name(mut n: genname(mutn:u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
`
281
321
`let mut buf = [MaybeUninit::::uninit(); 39];
`
282
322
`let mut curr = buf.len();
`
283
323
`let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
`
`@@ -306,21 +346,6 @@ macro_rules! impl_Display {
`
306
346
`};
`
307
347
` f.pad_integral(is_nonnegative, "", buf_slice)
`
308
348
`}
`
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
``
`-
})*
`
324
349
`};
`
325
350
`}
`
326
351
``
`@@ -374,7 +399,6 @@ macro_rules! impl_Exp {
`
374
399
`(n, exponent, exponent, added_precision)
`
375
400
`};
`
376
401
``
377
``
`-
// 39 digits (worst case u128) + . = 40
`
378
402
`` // Since curr
always decreases by the number of digits copied, this means
``
379
403
`` // that curr >= 0
.
``
380
404
`let mut buf = [MaybeUninit::::uninit(); 40];
`
`@@ -469,7 +493,7 @@ macro_rules! impl_Exp {
`
469
493
`let n = if is_nonnegative {
`
470
494
`self.$conv_fn()
`
471
495
`} 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
`
473
497
`(!self.$conv_fn()).wrapping_add(1)
`
474
498
`};
`
475
499
` $name(n, is_nonnegative, false, f)
`
`@@ -484,7 +508,7 @@ macro_rules! impl_Exp {
`
484
508
`let n = if is_nonnegative {
`
485
509
`self.$conv_fn()
`
486
510
`} 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
`
488
512
`(!self.$conv_fn()).wrapping_add(1)
`
489
513
`};
`
490
514
` $name(n, is_nonnegative, true, f)
`
`@@ -499,8 +523,17 @@ macro_rules! impl_Exp {
`
499
523
`mod imp {
`
500
524
`use super::*;
`
501
525
`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
`
504
537
`);
`
505
538
`impl_Exp!(
`
506
539
`i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
`
`@@ -511,8 +544,21 @@ mod imp {
`
511
544
`#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
`
512
545
`mod imp {
`
513
546
`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
+
516
562
`impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
`
517
563
`impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
`
518
564
`}
`
`@@ -619,7 +665,7 @@ impl fmt::Display for i128 {
`
619
665
`let n = if is_nonnegative {
`
620
666
`self.to_u128()
`
621
667
`} 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
`
623
669
`(!self.to_u128()).wrapping_add(1)
`
624
670
`};
`
625
671
`fmt_u128(n, is_nonnegative, f)
`