about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNathan Froyd <froydnj@gmail.com>2017-04-13 15:49:37 -0400
committerNathan Froyd <froydnj@gmail.com>2017-04-28 15:27:08 -0400
commita21f61685d4aa2bd93152eaf53c469b29a3a9bee (patch)
tree26bf478f97f97695b7400a817c59790296d4c028 /src
parent5a0078520e80579307124aca567a70e195637682 (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.rs82
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 {