Skip to content

Commit a21f616

Browse files
committed
fmt: reduce the stack space required by float formatting
For the two major entry points for float formatting, we split the exact case and the shortest cases into separate functions. We mark the separate functions as #[inline(never) so the exact cases won't bloat stack space in their callers unnecessarily. The shortest cases are marked so for similar reasons. Fixes #41234.
1 parent 5a00785 commit a21f616

File tree

1 file changed

+66
-16
lines changed

1 file changed

+66
-16
lines changed

src/libcore/fmt/float.rs

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,35 @@
1111
use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
1212
use num::flt2dec;
1313

14+
// Don't inline this so callers don't use the stack space this function
15+
// requires unless they have to.
16+
#[inline(never)]
17+
fn float_to_decimal_common_exact<T>(fmt: &mut Formatter, num: &T,
18+
sign: flt2dec::Sign, precision: usize) -> Result
19+
where T: flt2dec::DecodableFloat
20+
{
21+
let mut buf = [0; 1024]; // enough for f32 and f64
22+
let mut parts = [flt2dec::Part::Zero(0); 16];
23+
let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact,
24+
*num, sign, precision,
25+
false, &mut buf, &mut parts);
26+
fmt.pad_formatted_parts(&formatted)
27+
}
28+
29+
// Don't inline this so callers that call both this and the above won't wind
30+
// up using the combined stack space of both functions in some cases.
31+
#[inline(never)]
32+
fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter,
33+
num: &T, sign: flt2dec::Sign) -> Result
34+
where T: flt2dec::DecodableFloat
35+
{
36+
let mut buf = [0; flt2dec::MAX_SIG_DIGITS]; // enough for f32 and f64
37+
let mut parts = [flt2dec::Part::Zero(0); 16];
38+
let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest,
39+
*num, sign, 0, false, &mut buf, &mut parts);
40+
fmt.pad_formatted_parts(&formatted)
41+
}
42+
1443
// Common code of floating point Debug and Display.
1544
fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result
1645
where T: flt2dec::DecodableFloat
@@ -23,15 +52,41 @@ fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool)
2352
(true, true) => flt2dec::Sign::MinusPlusRaw,
2453
};
2554

55+
if let Some(precision) = fmt.precision {
56+
float_to_decimal_common_exact(fmt, num, sign, precision)
57+
} else {
58+
float_to_decimal_common_shortest(fmt, num, sign)
59+
}
60+
}
61+
62+
// Don't inline this so callers don't use the stack space this function
63+
// requires unless they have to.
64+
#[inline(never)]
65+
fn float_to_exponential_common_exact<T>(fmt: &mut Formatter, num: &T,
66+
sign: flt2dec::Sign, precision: usize,
67+
upper: bool) -> Result
68+
where T: flt2dec::DecodableFloat
69+
{
2670
let mut buf = [0; 1024]; // enough for f32 and f64
2771
let mut parts = [flt2dec::Part::Zero(0); 16];
28-
let formatted = if let Some(precision) = fmt.precision {
29-
flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign,
30-
precision, false, &mut buf, &mut parts)
31-
} else {
32-
flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
33-
0, false, &mut buf, &mut parts)
34-
};
72+
let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact,
73+
*num, sign, precision,
74+
upper, &mut buf, &mut parts);
75+
fmt.pad_formatted_parts(&formatted)
76+
}
77+
78+
// Don't inline this so callers that call both this and the above won't wind
79+
// up using the combined stack space of both functions in some cases.
80+
#[inline(never)]
81+
fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter,
82+
num: &T, sign: flt2dec::Sign,
83+
upper: bool) -> Result
84+
where T: flt2dec::DecodableFloat
85+
{
86+
let mut buf = [0; flt2dec::MAX_SIG_DIGITS]; // enough for f32 and f64
87+
let mut parts = [flt2dec::Part::Zero(0); 16];
88+
let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num,
89+
sign, (0, 0), upper, &mut buf, &mut parts);
3590
fmt.pad_formatted_parts(&formatted)
3691
}
3792

@@ -45,17 +100,12 @@ fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) ->
45100
true => flt2dec::Sign::MinusPlus,
46101
};
47102

48-
let mut buf = [0; 1024]; // enough for f32 and f64
49-
let mut parts = [flt2dec::Part::Zero(0); 16];
50-
let formatted = if let Some(precision) = fmt.precision {
103+
if let Some(precision) = fmt.precision {
51104
// 1 integral digit + `precision` fractional digits = `precision + 1` total digits
52-
flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign,
53-
precision + 1, upper, &mut buf, &mut parts)
105+
float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
54106
} else {
55-
flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
56-
(0, 0), upper, &mut buf, &mut parts)
57-
};
58-
fmt.pad_formatted_parts(&formatted)
107+
float_to_exponential_common_shortest(fmt, num, sign, upper)
108+
}
59109
}
60110

61111
macro_rules! floating {

0 commit comments

Comments
 (0)