Skip to content

Commit 85c1cec

Browse files
Simplify impl_Display macro
1 parent c4be3da commit 85c1cec

File tree

1 file changed

+90
-87
lines changed

1 file changed

+90
-87
lines changed

core/src/fmt/num.rs

+90-87
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
208208
8081828384858687888990919293949596979899";
209209

210210
macro_rules! impl_Display {
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) => {
211+
($($t:ident => $size:literal $(as $positive:ident)? named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
212212

213213
$(
214214
#[stable(feature = "rust1", since = "1.0.0")]
@@ -222,102 +222,105 @@ macro_rules! impl_Display {
222222
{
223223
if !is_nonnegative {
224224
// convert the negative num to positive by summing 1 to its 2s complement
225-
return $other((!self as $positive).wrapping_add(1), false, f);
225+
return (!self as $positive).wrapping_add(1)._fmt(false, f);
226226
}
227227
}
228228
#[cfg(feature = "optimize_for_size")]
229229
{
230230
if !is_nonnegative {
231231
// convert the negative num to positive by summing 1 to its 2s complement
232-
return $other((!self.$conv_fn()).wrapping_add(1), false, f);
232+
return $gen_name((!self.$conv_fn()).wrapping_add(1), false, f);
233233
}
234234
}
235235
)?
236236
// If it's a positive integer.
237237
#[cfg(not(feature = "optimize_for_size"))]
238238
{
239-
$name(*self, true, f)
239+
self._fmt(true, f)
240240
}
241241
#[cfg(feature = "optimize_for_size")]
242242
{
243-
$gen_name(*self, true, f)
243+
$gen_name(self.$conv_fn(), true, f)
244244
}
245245
}
246246
}
247247

248248
#[cfg(not(feature = "optimize_for_size"))]
249-
fn $name(mut n: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250-
let mut buf = [MaybeUninit::<u8>::uninit(); $size];
251-
let mut curr = buf.len();
252-
let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
253-
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
254-
255-
// SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we
256-
// can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show
257-
// that it's OK to copy into `buf_ptr`, notice that at the beginning
258-
// `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
259-
// each step this is kept the same as `n` is divided. Since `n` is always
260-
// non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
261-
// is safe to access.
262-
unsafe {
263-
// need at least 16 bits for the 4-characters-at-a-time to work.
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);
249+
impl $t {
250+
fn _fmt(mut self: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251+
let mut buf = [MaybeUninit::<u8>::uninit(); $size];
252+
let mut curr = $size;
253+
let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
254+
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
255+
256+
// SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we
257+
// can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show
258+
// that it's OK to copy into `buf_ptr`, notice that at the beginning
259+
// `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
260+
// each step this is kept the same as `n` is divided. Since `n` is always
261+
// non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
262+
// is safe to access.
263+
unsafe {
264+
// need at least 16 bits for the 4-characters-at-a-time to work.
265+
#[allow(overflowing_literals)]
266+
#[allow(unused_comparisons)]
267+
// This block will be removed for smaller types at compile time and in the worst
268+
// case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`.
269+
if core::mem::size_of::<$t>() >= 2 {
270+
// eagerly decode 4 characters at a time
271+
while self >= 10000 {
272+
let rem = (self % 10000) as usize;
273+
self /= 10000;
274+
275+
let d1 = (rem / 100) << 1;
276+
let d2 = (rem % 100) << 1;
277+
curr -= 4;
278+
279+
// We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
280+
// otherwise `curr < 0`. But then `n` was originally at least `10000^10`
281+
// which is `10^40 > 2^128 > n`.
282+
ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2);
283+
ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2);
284+
}
283285
}
284-
}
285286

286-
// if we reach here numbers are <= 9999, so at most 4 chars long
287-
let mut n = n as usize; // possibly reduce 64bit math
287+
// if we reach here numbers are <= 9999, so at most 4 chars long
288+
let mut n = self as usize; // possibly reduce 64bit math
288289

289-
// decode 2 more chars, if > 2 chars
290-
if n >= 100 {
291-
let d1 = (n % 100) << 1;
292-
n /= 100;
293-
curr -= 2;
294-
ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
295-
}
290+
// decode 2 more chars, if > 2 chars
291+
if n >= 100 {
292+
let d1 = (n % 100) << 1;
293+
n /= 100;
294+
curr -= 2;
295+
ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
296+
}
296297

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.
299-
// decode last 1 or 2 chars
300-
if n < 10 {
301-
curr -= 1;
302-
*buf_ptr.add(curr) = (n as u8) + b'0';
303-
} else {
304-
let d1 = n << 1;
305-
curr -= 2;
306-
ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
298+
// if we reach here numbers are <= 100, so at most 2 chars long
299+
// The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough.
300+
// decode last 1 or 2 chars
301+
if n < 10 {
302+
curr -= 1;
303+
*buf_ptr.add(curr) = (n as u8) + b'0';
304+
} else {
305+
let d1 = n << 1;
306+
curr -= 2;
307+
ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
308+
}
307309
}
308-
}
309310

310-
// SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
311-
// UTF-8 since `DEC_DIGITS_LUT` is
312-
let buf_slice = unsafe {
313-
str::from_utf8_unchecked(
314-
slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
315-
};
316-
f.pad_integral(is_nonnegative, "", buf_slice)
311+
// SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
312+
// UTF-8 since `DEC_DIGITS_LUT` is
313+
let buf_slice = unsafe {
314+
str::from_utf8_unchecked(
315+
slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
316+
};
317+
f.pad_integral(is_nonnegative, "", buf_slice)
318+
}
317319
})*
318320

319321
#[cfg(feature = "optimize_for_size")]
320322
fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
323+
// 2^128 is about 3*10^38, so 39 gives an extra byte of space
321324
let mut buf = [MaybeUninit::<u8>::uninit(); 39];
322325
let mut curr = buf.len();
323326
let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
@@ -523,16 +526,16 @@ macro_rules! impl_Exp {
523526
mod imp {
524527
use super::*;
525528
impl_Display!(
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,
529+
i8 => 3 as u8 named fmt_i8,
530+
u8 => 3 named fmt_u8,
531+
i16 => 5 as u16 named fmt_i16,
532+
u16 => 5 named fmt_u16,
533+
i32 => 10 as u32 named fmt_i32,
534+
u32 => 10 named fmt_u32,
535+
i64 => 19 as u64 named fmt_i64,
536+
u64 => 20 named fmt_u64,
537+
isize => 19 as usize named fmt_isize,
538+
usize => 20 named fmt_usize,
536539
; as u64 via to_u64 named fmt_u64
537540
);
538541
impl_Exp!(
@@ -545,18 +548,18 @@ mod imp {
545548
mod imp {
546549
use super::*;
547550
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,
551+
i8 => 3 as u8 named fmt_i8,
552+
u8 => 3 named fmt_u8,
553+
i16 => 5 as u16 named fmt_i16,
554+
u16 => 5 named fmt_u16,
555+
i32 => 10 as u32 named fmt_i32,
556+
u32 => 10 named fmt_u32,
557+
isize => 19 as usize named fmt_isize,
558+
usize => 20 named fmt_usize,
556559
; as u32 via to_u32 named fmt_u32);
557560
impl_Display!(
558-
i64 => 19 as u64 in fmt_u64 => named fmt_i64,
559-
u64 => 20 => named fmt_u64,
561+
i64 => 19 as u64 named fmt_i64,
562+
u64 => 20 named fmt_u64,
560563
; as u64 via to_u64 named fmt_u64);
561564

562565
impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);

0 commit comments

Comments
 (0)