Skip to content

Commit a308c00

Browse files
Optimize ToString implementation for integers
1 parent ac91805 commit a308c00

File tree

2 files changed

+67
-9
lines changed

2 files changed

+67
-9
lines changed

library/alloc/src/string.rs

+48
Original file line numberDiff line numberDiff line change
@@ -2808,7 +2808,54 @@ impl SpecToString for bool {
28082808
}
28092809
}
28102810

2811+
macro_rules! impl_to_string {
2812+
($($signed:ident, $unsigned:ident,)*) => {
2813+
$(
2814+
#[cfg(not(no_global_oom_handling))]
2815+
#[cfg(not(feature = "optimize_for_size"))]
2816+
impl SpecToString for $signed {
2817+
#[inline]
2818+
fn spec_to_string(&self) -> String {
2819+
const SIZE: usize = $signed::MAX.ilog(10) as usize + 1;
2820+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE];
2821+
// Only difference between signed and unsigned are these 8 lines.
2822+
let mut out;
2823+
if *self < 0 {
2824+
out = String::with_capacity(SIZE + 1);
2825+
out.push('-');
2826+
} else {
2827+
out = String::with_capacity(SIZE);
2828+
}
2829+
2830+
out.push_str(self.unsigned_abs()._fmt(&mut buf));
2831+
out
2832+
}
2833+
}
2834+
#[cfg(not(no_global_oom_handling))]
2835+
#[cfg(not(feature = "optimize_for_size"))]
2836+
impl SpecToString for $unsigned {
2837+
#[inline]
2838+
fn spec_to_string(&self) -> String {
2839+
const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1;
2840+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE];
2841+
2842+
self._fmt(&mut buf).to_string()
2843+
}
2844+
}
2845+
)*
2846+
}
2847+
}
2848+
2849+
impl_to_string! {
2850+
i8, u8,
2851+
i16, u16,
2852+
i32, u32,
2853+
i64, u64,
2854+
isize, usize,
2855+
}
2856+
28112857
#[cfg(not(no_global_oom_handling))]
2858+
#[cfg(feature = "optimize_for_size")]
28122859
impl SpecToString for u8 {
28132860
#[inline]
28142861
fn spec_to_string(&self) -> String {
@@ -2828,6 +2875,7 @@ impl SpecToString for u8 {
28282875
}
28292876

28302877
#[cfg(not(no_global_oom_handling))]
2878+
#[cfg(feature = "optimize_for_size")]
28312879
impl SpecToString for i8 {
28322880
#[inline]
28332881
fn spec_to_string(&self) -> String {

library/core/src/fmt/num.rs

+19-9
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,11 @@ macro_rules! impl_Display {
208208
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209209
#[cfg(not(feature = "optimize_for_size"))]
210210
{
211-
self._fmt(true, f)
211+
const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1;
212+
// Buffer decimals for $unsigned with right alignment.
213+
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
214+
215+
f.pad_integral(true, "", self._fmt(&mut buf))
212216
}
213217
#[cfg(feature = "optimize_for_size")]
214218
{
@@ -222,7 +226,11 @@ macro_rules! impl_Display {
222226
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223227
#[cfg(not(feature = "optimize_for_size"))]
224228
{
225-
return self.unsigned_abs()._fmt(*self >= 0, f);
229+
const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1;
230+
// Buffer decimals for $unsigned with right alignment.
231+
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
232+
233+
f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf))
226234
}
227235
#[cfg(feature = "optimize_for_size")]
228236
{
@@ -233,10 +241,13 @@ macro_rules! impl_Display {
233241

234242
#[cfg(not(feature = "optimize_for_size"))]
235243
impl $unsigned {
236-
fn _fmt(self, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237-
const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1;
238-
// Buffer decimals for $unsigned with right alignment.
239-
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
244+
#[doc(hidden)]
245+
#[unstable(
246+
feature = "fmt_internals",
247+
reason = "internal routines only exposed for testing",
248+
issue = "none"
249+
)]
250+
pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::<u8>]) -> &'a str {
240251
// Count the number of bytes in buf that are not initialized.
241252
let mut offset = buf.len();
242253
// Consume the least-significant decimals from a working copy.
@@ -301,13 +312,12 @@ macro_rules! impl_Display {
301312
// SAFETY: All buf content since offset is set.
302313
let written = unsafe { buf.get_unchecked(offset..) };
303314
// SAFETY: Writes use ASCII from the lookup table exclusively.
304-
let as_str = unsafe {
315+
unsafe {
305316
str::from_utf8_unchecked(slice::from_raw_parts(
306317
MaybeUninit::slice_as_ptr(written),
307318
written.len(),
308319
))
309-
};
310-
f.pad_integral(is_nonnegative, "", as_str)
320+
}
311321
}
312322
})*
313323

0 commit comments

Comments
 (0)