Skip to content

Commit 5c377e8

Browse files
Optimize ToString implementation for integers
1 parent 7d7de5b commit 5c377e8

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
@@ -2824,7 +2824,54 @@ impl SpecToString for bool {
28242824
}
28252825
}
28262826

2827+
macro_rules! impl_to_string {
2828+
($($signed:ident, $unsigned:ident,)*) => {
2829+
$(
2830+
#[cfg(not(no_global_oom_handling))]
2831+
#[cfg(not(feature = "optimize_for_size"))]
2832+
impl SpecToString for $signed {
2833+
#[inline]
2834+
fn spec_to_string(&self) -> String {
2835+
const SIZE: usize = $signed::MAX.ilog(10) as usize + 1;
2836+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE];
2837+
// Only difference between signed and unsigned are these 8 lines.
2838+
let mut out;
2839+
if *self < 0 {
2840+
out = String::with_capacity(SIZE + 1);
2841+
out.push('-');
2842+
} else {
2843+
out = String::with_capacity(SIZE);
2844+
}
2845+
2846+
out.push_str(self.unsigned_abs()._fmt(&mut buf));
2847+
out
2848+
}
2849+
}
2850+
#[cfg(not(no_global_oom_handling))]
2851+
#[cfg(not(feature = "optimize_for_size"))]
2852+
impl SpecToString for $unsigned {
2853+
#[inline]
2854+
fn spec_to_string(&self) -> String {
2855+
const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1;
2856+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE];
2857+
2858+
self._fmt(&mut buf).to_string()
2859+
}
2860+
}
2861+
)*
2862+
}
2863+
}
2864+
2865+
impl_to_string! {
2866+
i8, u8,
2867+
i16, u16,
2868+
i32, u32,
2869+
i64, u64,
2870+
isize, usize,
2871+
}
2872+
28272873
#[cfg(not(no_global_oom_handling))]
2874+
#[cfg(feature = "optimize_for_size")]
28282875
impl SpecToString for u8 {
28292876
#[inline]
28302877
fn spec_to_string(&self) -> String {
@@ -2844,6 +2891,7 @@ impl SpecToString for u8 {
28442891
}
28452892

28462893
#[cfg(not(no_global_oom_handling))]
2894+
#[cfg(feature = "optimize_for_size")]
28472895
impl SpecToString for i8 {
28482896
#[inline]
28492897
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 = "specialized method meant to only be used by `SpecToString` implemtation",
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)