diff options
| author | Nathan Froyd <froydnj@gmail.com> | 2017-04-13 15:49:37 -0400 |
|---|---|---|
| committer | Nathan Froyd <froydnj@gmail.com> | 2017-04-28 15:27:08 -0400 |
| commit | a21f61685d4aa2bd93152eaf53c469b29a3a9bee (patch) | |
| tree | 26bf478f97f97695b7400a817c59790296d4c028 /src | |
| parent | 5a0078520e80579307124aca567a70e195637682 (diff) | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libcore/fmt/float.rs | 82 |
1 files changed, 66 insertions, 16 deletions
diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 50248fabfcd..60c291ef845 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -11,6 +11,35 @@ use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug}; use num::flt2dec; +// Don't inline this so callers don't use the stack space this function +// requires unless they have to. +#[inline(never)] +fn float_to_decimal_common_exact<T>(fmt: &mut Formatter, num: &T, + sign: flt2dec::Sign, precision: usize) -> Result + where T: flt2dec::DecodableFloat +{ + let mut buf = [0; 1024]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, + *num, sign, precision, + false, &mut buf, &mut parts); + fmt.pad_formatted_parts(&formatted) +} + +// Don't inline this so callers that call both this and the above won't wind +// up using the combined stack space of both functions in some cases. +#[inline(never)] +fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter, + num: &T, sign: flt2dec::Sign) -> Result + where T: flt2dec::DecodableFloat +{ + let mut buf = [0; flt2dec::MAX_SIG_DIGITS]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, + *num, sign, 0, false, &mut buf, &mut parts); + fmt.pad_formatted_parts(&formatted) +} + // Common code of floating point Debug and Display. fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result where T: flt2dec::DecodableFloat @@ -23,15 +52,41 @@ fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) (true, true) => flt2dec::Sign::MinusPlusRaw, }; + if let Some(precision) = fmt.precision { + float_to_decimal_common_exact(fmt, num, sign, precision) + } else { + float_to_decimal_common_shortest(fmt, num, sign) + } +} + +// Don't inline this so callers don't use the stack space this function +// requires unless they have to. +#[inline(never)] +fn float_to_exponential_common_exact<T>(fmt: &mut Formatter, num: &T, + sign: flt2dec::Sign, precision: usize, + upper: bool) -> Result + where T: flt2dec::DecodableFloat +{ let mut buf = [0; 1024]; // enough for f32 and f64 let mut parts = [flt2dec::Part::Zero(0); 16]; - let formatted = if let Some(precision) = fmt.precision { - flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign, - precision, false, &mut buf, &mut parts) - } else { - flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, - 0, false, &mut buf, &mut parts) - }; + let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, + *num, sign, precision, + upper, &mut buf, &mut parts); + fmt.pad_formatted_parts(&formatted) +} + +// Don't inline this so callers that call both this and the above won't wind +// up using the combined stack space of both functions in some cases. +#[inline(never)] +fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter, + num: &T, sign: flt2dec::Sign, + upper: bool) -> Result + where T: flt2dec::DecodableFloat +{ + let mut buf = [0; flt2dec::MAX_SIG_DIGITS]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, + sign, (0, 0), upper, &mut buf, &mut parts); fmt.pad_formatted_parts(&formatted) } @@ -45,17 +100,12 @@ fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) -> true => flt2dec::Sign::MinusPlus, }; - let mut buf = [0; 1024]; // enough for f32 and f64 - let mut parts = [flt2dec::Part::Zero(0); 16]; - let formatted = if let Some(precision) = fmt.precision { + if let Some(precision) = fmt.precision { // 1 integral digit + `precision` fractional digits = `precision + 1` total digits - flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, - precision + 1, upper, &mut buf, &mut parts) + float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper) } else { - flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, - (0, 0), upper, &mut buf, &mut parts) - }; - fmt.pad_formatted_parts(&formatted) + float_to_exponential_common_shortest(fmt, num, sign, upper) + } } macro_rules! floating { |
