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.
This commit is contained in:
parent
5a0078520e
commit
a21f61685d
1 changed files with 66 additions and 16 deletions
|
@ -11,6 +11,35 @@
|
||||||
use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
|
use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
|
||||||
use num::flt2dec;
|
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.
|
// Common code of floating point Debug and Display.
|
||||||
fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result
|
fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result
|
||||||
where T: flt2dec::DecodableFloat
|
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,
|
(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 buf = [0; 1024]; // enough for f32 and f64
|
||||||
let mut parts = [flt2dec::Part::Zero(0); 16];
|
let mut parts = [flt2dec::Part::Zero(0); 16];
|
||||||
let formatted = if let Some(precision) = fmt.precision {
|
let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact,
|
||||||
flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign,
|
*num, sign, precision,
|
||||||
precision, false, &mut buf, &mut parts)
|
upper, &mut buf, &mut parts);
|
||||||
} else {
|
fmt.pad_formatted_parts(&formatted)
|
||||||
flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
|
}
|
||||||
0, false, &mut buf, &mut parts)
|
|
||||||
};
|
// 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)
|
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,
|
true => flt2dec::Sign::MinusPlus,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = [0; 1024]; // enough for f32 and f64
|
if let Some(precision) = fmt.precision {
|
||||||
let mut parts = [flt2dec::Part::Zero(0); 16];
|
|
||||||
let formatted = if let Some(precision) = fmt.precision {
|
|
||||||
// 1 integral digit + `precision` fractional digits = `precision + 1` total digits
|
// 1 integral digit + `precision` fractional digits = `precision + 1` total digits
|
||||||
flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign,
|
float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
|
||||||
precision + 1, upper, &mut buf, &mut parts)
|
|
||||||
} else {
|
} else {
|
||||||
flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
|
float_to_exponential_common_shortest(fmt, num, sign, upper)
|
||||||
(0, 0), upper, &mut buf, &mut parts)
|
}
|
||||||
};
|
|
||||||
fmt.pad_formatted_parts(&formatted)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! floating {
|
macro_rules! floating {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue