Rollup merge of #58272 - fitzgen:num-format-code-size, r=Mark-Simulacrum
Cut down on number formating code size r? @alexcrichton
This commit is contained in:
commit
c0d507d73b
@ -1036,6 +1036,27 @@ pub fn write(output: &mut dyn Write, args: Arguments) -> Result {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Padding after the end of something. Returned by `Formatter::padding`.
|
||||
#[must_use = "don't forget to write the post padding"]
|
||||
struct PostPadding {
|
||||
fill: char,
|
||||
padding: usize,
|
||||
}
|
||||
|
||||
impl PostPadding {
|
||||
fn new(fill: char, padding: usize) -> PostPadding {
|
||||
PostPadding { fill, padding }
|
||||
}
|
||||
|
||||
/// Write this post padding.
|
||||
fn write(self, buf: &mut dyn Write) -> Result {
|
||||
for _ in 0..self.padding {
|
||||
buf.write_char(self.fill)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Formatter<'a> {
|
||||
fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c>
|
||||
where 'b: 'c, F: FnOnce(&'b mut (dyn Write+'b)) -> &'c mut (dyn Write+'c)
|
||||
@ -1153,47 +1174,56 @@ impl<'a> Formatter<'a> {
|
||||
sign = Some('+'); width += 1;
|
||||
}
|
||||
|
||||
let prefixed = self.alternate();
|
||||
if prefixed {
|
||||
let prefix = if self.alternate() {
|
||||
width += prefix.chars().count();
|
||||
}
|
||||
Some(prefix)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Writes the sign if it exists, and then the prefix if it was requested
|
||||
let write_prefix = |f: &mut Formatter| {
|
||||
#[inline(never)]
|
||||
fn write_prefix(f: &mut Formatter, sign: Option<char>, prefix: Option<&str>) -> Result {
|
||||
if let Some(c) = sign {
|
||||
f.buf.write_char(c)?;
|
||||
}
|
||||
if prefixed { f.buf.write_str(prefix) }
|
||||
else { Ok(()) }
|
||||
};
|
||||
if let Some(prefix) = prefix {
|
||||
f.buf.write_str(prefix)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// The `width` field is more of a `min-width` parameter at this point.
|
||||
match self.width {
|
||||
// If there's no minimum length requirements then we can just
|
||||
// write the bytes.
|
||||
None => {
|
||||
write_prefix(self)?; self.buf.write_str(buf)
|
||||
write_prefix(self, sign, prefix)?;
|
||||
self.buf.write_str(buf)
|
||||
}
|
||||
// Check if we're over the minimum width, if so then we can also
|
||||
// just write the bytes.
|
||||
Some(min) if width >= min => {
|
||||
write_prefix(self)?; self.buf.write_str(buf)
|
||||
write_prefix(self, sign, prefix)?;
|
||||
self.buf.write_str(buf)
|
||||
}
|
||||
// The sign and prefix goes before the padding if the fill character
|
||||
// is zero
|
||||
Some(min) if self.sign_aware_zero_pad() => {
|
||||
self.fill = '0';
|
||||
self.align = rt::v1::Alignment::Right;
|
||||
write_prefix(self)?;
|
||||
self.with_padding(min - width, rt::v1::Alignment::Right, |f| {
|
||||
f.buf.write_str(buf)
|
||||
})
|
||||
write_prefix(self, sign, prefix)?;
|
||||
let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
|
||||
self.buf.write_str(buf)?;
|
||||
post_padding.write(self.buf)
|
||||
}
|
||||
// Otherwise, the sign and prefix goes after the padding
|
||||
Some(min) => {
|
||||
self.with_padding(min - width, rt::v1::Alignment::Right, |f| {
|
||||
write_prefix(f)?; f.buf.write_str(buf)
|
||||
})
|
||||
let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
|
||||
write_prefix(self, sign, prefix)?;
|
||||
self.buf.write_str(buf)?;
|
||||
post_padding.write(self.buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1264,19 +1294,21 @@ impl<'a> Formatter<'a> {
|
||||
// up the minimum width with the specified string + some alignment.
|
||||
Some(width) => {
|
||||
let align = rt::v1::Alignment::Left;
|
||||
self.with_padding(width - s.chars().count(), align, |me| {
|
||||
me.buf.write_str(s)
|
||||
})
|
||||
let post_padding = self.padding(width - s.chars().count(), align)?;
|
||||
self.buf.write_str(s)?;
|
||||
post_padding.write(self.buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs a callback, emitting the correct padding either before or
|
||||
/// afterwards depending on whether right or left alignment is requested.
|
||||
fn with_padding<F>(&mut self, padding: usize, default: rt::v1::Alignment,
|
||||
f: F) -> Result
|
||||
where F: FnOnce(&mut Formatter) -> Result,
|
||||
{
|
||||
/// Write the pre-padding and return the unwritten post-padding. Callers are
|
||||
/// responsible for ensuring post-padding is written after the thing that is
|
||||
/// being padded.
|
||||
fn padding(
|
||||
&mut self,
|
||||
padding: usize,
|
||||
default: rt::v1::Alignment
|
||||
) -> result::Result<PostPadding, Error> {
|
||||
let align = match self.align {
|
||||
rt::v1::Alignment::Unknown => default,
|
||||
_ => self.align
|
||||
@ -1289,20 +1321,11 @@ impl<'a> Formatter<'a> {
|
||||
rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
|
||||
};
|
||||
|
||||
let mut fill = [0; 4];
|
||||
let fill = self.fill.encode_utf8(&mut fill);
|
||||
|
||||
for _ in 0..pre_pad {
|
||||
self.buf.write_str(fill)?;
|
||||
self.buf.write_char(self.fill)?;
|
||||
}
|
||||
|
||||
f(self)?;
|
||||
|
||||
for _ in 0..post_pad {
|
||||
self.buf.write_str(fill)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(PostPadding::new(self.fill, post_pad))
|
||||
}
|
||||
|
||||
/// Takes the formatted parts and applies the padding.
|
||||
@ -1334,9 +1357,9 @@ impl<'a> Formatter<'a> {
|
||||
let ret = if width <= len { // no padding
|
||||
self.write_formatted_parts(&formatted)
|
||||
} else {
|
||||
self.with_padding(width - len, align, |f| {
|
||||
f.write_formatted_parts(&formatted)
|
||||
})
|
||||
let post_padding = self.padding(width - len, align)?;
|
||||
self.write_formatted_parts(&formatted)?;
|
||||
post_padding.write(self.buf)
|
||||
};
|
||||
self.fill = old_fill;
|
||||
self.align = old_align;
|
||||
|
@ -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,41 @@ 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);
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
impl_Display!(isize, usize: to_u16);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
impl_Display!(isize, usize: to_u32);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl_Display!(isize, usize: to_u64);
|
||||
// Include wasm32 in here since it doesn't reflect the native pointer size, and
|
||||
// often cares strongly about getting a smaller code size.
|
||||
#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
|
||||
mod imp {
|
||||
use super::*;
|
||||
impl_Display!(
|
||||
i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
|
||||
as u64 via to_u64 named fmt_u64
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
|
||||
mod imp {
|
||||
use super::*;
|
||||
impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize 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);
|
||||
|
10
src/test/run-make/wasm-stringify-ints-small/Makefile
Normal file
10
src/test/run-make/wasm-stringify-ints-small/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
-include ../../run-make-fulldeps/tools.mk
|
||||
|
||||
ifeq ($(TARGET),wasm32-unknown-unknown)
|
||||
all:
|
||||
$(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown
|
||||
wc -c < $(TMPDIR)/foo.wasm
|
||||
[ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "20500" ]
|
||||
else
|
||||
all:
|
||||
endif
|
33
src/test/run-make/wasm-stringify-ints-small/foo.rs
Normal file
33
src/test/run-make/wasm-stringify-ints-small/foo.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![crate_type = "cdylib"]
|
||||
|
||||
extern "C" {
|
||||
fn observe(ptr: *const u8, len: usize);
|
||||
}
|
||||
|
||||
macro_rules! s {
|
||||
( $( $f:ident -> $t:ty );* $(;)* ) => {
|
||||
$(
|
||||
extern "C" {
|
||||
fn $f() -> $t;
|
||||
}
|
||||
let s = $f().to_string();
|
||||
observe(s.as_ptr(), s.len());
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn foo() {
|
||||
s! {
|
||||
get_u8 -> u8;
|
||||
get_i8 -> i8;
|
||||
get_u16 -> u16;
|
||||
get_i16 -> i16;
|
||||
get_u32 -> u32;
|
||||
get_i32 -> i32;
|
||||
get_u64 -> u64;
|
||||
get_i64 -> i64;
|
||||
get_usize -> usize;
|
||||
get_isize -> isize;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user