Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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.
  • Loading branch information
fitzgen committed Feb 7, 2019
commit da5a0cd69c64e0772960caee32f36b11bca1b498
69 changes: 38 additions & 31 deletions src/libcore/fmt/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,45 +178,36 @@ 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\
6061626364656667686970717273747576777879\
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);
let lut_ptr = DEC_DIGITS_LUT.as_ptr();

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);

// 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);
}
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
Expand Down Expand Up @@ -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);