Skip to content

Commit e07da7b

Browse files
Optimize ToString implementation for integers
1 parent 820bfff commit e07da7b

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
@@ -2783,7 +2783,54 @@ impl SpecToString for bool {
27832783
}
27842784
}
27852785

2786+
macro_rules! impl_to_string {
2787+
($($signed:ident, $unsigned:ident,)*) => {
2788+
$(
2789+
#[cfg(not(no_global_oom_handling))]
2790+
#[cfg(not(feature = "optimize_for_size"))]
2791+
impl SpecToString for $signed {
2792+
#[inline]
2793+
fn spec_to_string(&self) -> String {
2794+
const SIZE: usize = $signed::MAX.ilog(10) as usize + 1;
2795+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE];
2796+
// Only difference between signed and unsigned are these 8 lines.
2797+
let mut out;
2798+
if *self < 0 {
2799+
out = String::with_capacity(SIZE + 1);
2800+
out.push('-');
2801+
} else {
2802+
out = String::with_capacity(SIZE);
2803+
}
2804+
2805+
out.push_str(self.unsigned_abs()._fmt(&mut buf));
2806+
out
2807+
}
2808+
}
2809+
#[cfg(not(no_global_oom_handling))]
2810+
#[cfg(not(feature = "optimize_for_size"))]
2811+
impl SpecToString for $unsigned {
2812+
#[inline]
2813+
fn spec_to_string(&self) -> String {
2814+
const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1;
2815+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE];
2816+
2817+
self._fmt(&mut buf).to_string()
2818+
}
2819+
}
2820+
)*
2821+
}
2822+
}
2823+
2824+
impl_to_string! {
2825+
i8, u8,
2826+
i16, u16,
2827+
i32, u32,
2828+
i64, u64,
2829+
isize, usize,
2830+
}
2831+
27862832
#[cfg(not(no_global_oom_handling))]
2833+
#[cfg(feature = "optimize_for_size")]
27872834
impl SpecToString for u8 {
27882835
#[inline]
27892836
fn spec_to_string(&self) -> String {
@@ -2803,6 +2850,7 @@ impl SpecToString for u8 {
28032850
}
28042851

28052852
#[cfg(not(no_global_oom_handling))]
2853+
#[cfg(feature = "optimize_for_size")]
28062854
impl SpecToString for i8 {
28072855
#[inline]
28082856
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)