Skip to content

Commit f5cc342

Browse files
Optimize ToString implementation for integers
1 parent 0c478fd commit f5cc342

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
@@ -2795,7 +2795,54 @@ impl SpecToString for bool {
27952795
}
27962796
}
27972797

2798+
macro_rules! impl_to_string {
2799+
($($signed:ident, $unsigned:ident,)*) => {
2800+
$(
2801+
#[cfg(not(no_global_oom_handling))]
2802+
#[cfg(not(feature = "optimize_for_size"))]
2803+
impl SpecToString for $signed {
2804+
#[inline]
2805+
fn spec_to_string(&self) -> String {
2806+
const SIZE: usize = $signed::MAX.ilog(10) as usize + 1;
2807+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE];
2808+
// Only difference between signed and unsigned are these 8 lines.
2809+
let mut out;
2810+
if *self < 0 {
2811+
out = String::with_capacity(SIZE + 1);
2812+
out.push('-');
2813+
} else {
2814+
out = String::with_capacity(SIZE);
2815+
}
2816+
2817+
out.push_str(self.unsigned_abs()._fmt(&mut buf));
2818+
out
2819+
}
2820+
}
2821+
#[cfg(not(no_global_oom_handling))]
2822+
#[cfg(not(feature = "optimize_for_size"))]
2823+
impl SpecToString for $unsigned {
2824+
#[inline]
2825+
fn spec_to_string(&self) -> String {
2826+
const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1;
2827+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE];
2828+
2829+
self._fmt(&mut buf).to_string()
2830+
}
2831+
}
2832+
)*
2833+
}
2834+
}
2835+
2836+
impl_to_string! {
2837+
i8, u8,
2838+
i16, u16,
2839+
i32, u32,
2840+
i64, u64,
2841+
isize, usize,
2842+
}
2843+
27982844
#[cfg(not(no_global_oom_handling))]
2845+
#[cfg(feature = "optimize_for_size")]
27992846
impl SpecToString for u8 {
28002847
#[inline]
28012848
fn spec_to_string(&self) -> String {
@@ -2815,6 +2862,7 @@ impl SpecToString for u8 {
28152862
}
28162863

28172864
#[cfg(not(no_global_oom_handling))]
2865+
#[cfg(feature = "optimize_for_size")]
28182866
impl SpecToString for i8 {
28192867
#[inline]
28202868
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)