De-duplicate number formatting implementations for smaller code size

Instead of inlining the same logic into every number formatting implementation,
pull it out into a function that each of the number formatting impls call into.
This commit is contained in:
Nick Fitzgerald 2019-02-07 12:33:27 +01:00
parent b2c6b8c29f
commit da5a0cd69c

View file

@ -178,7 +178,8 @@ integer! { i32, u32 }
integer! { i64, u64 }
integer! { i128, u128 }
const DEC_DIGITS_LUT: &'static[u8] =
static DEC_DIGITS_LUT: &[u8; 200] =
b"0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
@ -186,18 +187,8 @@ const DEC_DIGITS_LUT: &'static[u8] =
8081828384858687888990919293949596979899";
macro_rules! impl_Display {
($($t:ident),*: $conv_fn:ident) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for $t {
#[allow(unused_comparisons)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let is_nonnegative = *self >= 0;
let mut n = if is_nonnegative {
self.$conv_fn()
} else {
// convert the negative num to positive by summing 1 to it's 2 complement
(!self.$conv_fn()).wrapping_add(1)
};
($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter) -> fmt::Result {
let mut buf = uninitialized_array![u8; 39];
let mut curr = buf.len() as isize;
let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf);
@ -205,18 +196,18 @@ macro_rules! impl_Display {
unsafe {
// need at least 16 bits for the 4-characters-at-a-time to work.
if ::mem::size_of::<$t>() >= 2 {
// eagerly decode 4 characters at a time
while n >= 10000 {
let rem = (n % 10000) as isize;
n /= 10000;
assert!(::mem::size_of::<$u>() >= 2);
let d1 = (rem / 100) << 1;
let d2 = (rem % 100) << 1;
curr -= 4;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
}
// eagerly decode 4 characters at a time
while n >= 10000 {
let rem = (n % 10000) as isize;
n /= 10000;
let d1 = (rem / 100) << 1;
let d2 = (rem % 100) << 1;
curr -= 4;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
}
// if we reach here numbers are <= 9999, so at most 4 chars long
@ -247,15 +238,31 @@ macro_rules! impl_Display {
};
f.pad_integral(is_nonnegative, "", buf_slice)
}
})*);
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for $t {
#[allow(unused_comparisons)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let is_nonnegative = *self >= 0;
let n = if is_nonnegative {
self.$conv_fn()
} else {
// convert the negative num to positive by summing 1 to it's 2 complement
(!self.$conv_fn()).wrapping_add(1)
};
$name(n, is_nonnegative, f)
}
})*
};
}
impl_Display!(i8, u8, i16, u16, i32, u32: to_u32);
impl_Display!(i64, u64: to_u64);
impl_Display!(i128, u128: to_u128);
impl_Display!(i8, u8, i16, u16, i32, u32 as u32 via to_u32 named fmt_u32);
impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64);
impl_Display!(i128, u128 as u128 via to_u128 named fmt_u128);
#[cfg(target_pointer_width = "16")]
impl_Display!(isize, usize: to_u16);
impl_Display!(isize, usize as u16 via to_u16 named fmt_usize);
#[cfg(target_pointer_width = "32")]
impl_Display!(isize, usize: to_u32);
impl_Display!(isize, usize as u32 via to_u32 named fmt_usize);
#[cfg(target_pointer_width = "64")]
impl_Display!(isize, usize: to_u64);
impl_Display!(isize, usize as u64 via to_u64 named fmt_usize);