]> git.lizzy.rs Git - rust.git/blob - src/libcore/fmt/float.rs
avoid unnecessary use of MaybeUninit::get_ref, and expand comment on the others
[rust.git] / src / libcore / fmt / float.rs
1 use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
2 use mem::MaybeUninit;
3 use num::flt2dec;
4
5 // Don't inline this so callers don't use the stack space this function
6 // requires unless they have to.
7 #[inline(never)]
8 fn float_to_decimal_common_exact<T>(fmt: &mut Formatter, num: &T,
9                                     sign: flt2dec::Sign, precision: usize) -> Result
10     where T: flt2dec::DecodableFloat
11 {
12     unsafe {
13         let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64
14         let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized();
15         // FIXME(#53491): Technically, this is calling `get_mut` on an uninitialized
16         // `MaybeUninit` (here and elsewhere in this file).  Revisit this once
17         // we decided whether that is valid or not.
18         // Using `freeze` is *not enough*; `flt2dec::Part` is an enum!
19         let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact,
20                                                     *num, sign, precision,
21                                                     false, buf.get_mut(), parts.get_mut());
22         fmt.pad_formatted_parts(&formatted)
23     }
24 }
25
26 // Don't inline this so callers that call both this and the above won't wind
27 // up using the combined stack space of both functions in some cases.
28 #[inline(never)]
29 fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter, num: &T,
30                                        sign: flt2dec::Sign, precision: usize) -> Result
31     where T: flt2dec::DecodableFloat
32 {
33     unsafe {
34         // enough for f32 and f64
35         let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized();
36         let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized();
37         // FIXME(#53491)
38         let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num,
39                                                  sign, precision, false, buf.get_mut(),
40                                                  parts.get_mut());
41         fmt.pad_formatted_parts(&formatted)
42     }
43 }
44
45 // Common code of floating point Debug and Display.
46 fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T,
47                               negative_zero: bool, min_precision: usize) -> Result
48     where T: flt2dec::DecodableFloat
49 {
50     let force_sign = fmt.sign_plus();
51     let sign = match (force_sign, negative_zero) {
52         (false, false) => flt2dec::Sign::Minus,
53         (false, true)  => flt2dec::Sign::MinusRaw,
54         (true,  false) => flt2dec::Sign::MinusPlus,
55         (true,  true)  => flt2dec::Sign::MinusPlusRaw,
56     };
57
58     if let Some(precision) = fmt.precision {
59         float_to_decimal_common_exact(fmt, num, sign, precision)
60     } else {
61         float_to_decimal_common_shortest(fmt, num, sign, min_precision)
62     }
63 }
64
65 // Don't inline this so callers don't use the stack space this function
66 // requires unless they have to.
67 #[inline(never)]
68 fn float_to_exponential_common_exact<T>(fmt: &mut Formatter, num: &T,
69                                         sign: flt2dec::Sign, precision: usize,
70                                         upper: bool) -> Result
71     where T: flt2dec::DecodableFloat
72 {
73     unsafe {
74         let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64
75         let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized();
76         // FIXME(#53491)
77         let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact,
78                                                   *num, sign, precision,
79                                                   upper, buf.get_mut(), parts.get_mut());
80         fmt.pad_formatted_parts(&formatted)
81     }
82 }
83
84 // Don't inline this so callers that call both this and the above won't wind
85 // up using the combined stack space of both functions in some cases.
86 #[inline(never)]
87 fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter,
88                                            num: &T, sign: flt2dec::Sign,
89                                            upper: bool) -> Result
90     where T: flt2dec::DecodableFloat
91 {
92     unsafe {
93         // enough for f32 and f64
94         let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized();
95         let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized();
96         // FIXME(#53491)
97         let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest,
98                                                      *num, sign, (0, 0), upper,
99                                                      buf.get_mut(), parts.get_mut());
100         fmt.pad_formatted_parts(&formatted)
101     }
102 }
103
104 // Common code of floating point LowerExp and UpperExp.
105 fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) -> Result
106     where T: flt2dec::DecodableFloat
107 {
108     let force_sign = fmt.sign_plus();
109     let sign = match force_sign {
110         false => flt2dec::Sign::Minus,
111         true  => flt2dec::Sign::MinusPlus,
112     };
113
114     if let Some(precision) = fmt.precision {
115         // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
116         float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
117     } else {
118         float_to_exponential_common_shortest(fmt, num, sign, upper)
119     }
120 }
121
122 macro_rules! floating {
123     ($ty:ident) => (
124         #[stable(feature = "rust1", since = "1.0.0")]
125         impl Debug for $ty {
126             fn fmt(&self, fmt: &mut Formatter) -> Result {
127                 float_to_decimal_common(fmt, self, true, 1)
128             }
129         }
130
131         #[stable(feature = "rust1", since = "1.0.0")]
132         impl Display for $ty {
133             fn fmt(&self, fmt: &mut Formatter) -> Result {
134                 float_to_decimal_common(fmt, self, false, 0)
135             }
136         }
137
138         #[stable(feature = "rust1", since = "1.0.0")]
139         impl LowerExp for $ty {
140             fn fmt(&self, fmt: &mut Formatter) -> Result {
141                 float_to_exponential_common(fmt, self, false)
142             }
143         }
144
145         #[stable(feature = "rust1", since = "1.0.0")]
146         impl UpperExp for $ty {
147             fn fmt(&self, fmt: &mut Formatter) -> Result {
148                 float_to_exponential_common(fmt, self, true)
149             }
150         }
151     )
152 }
153
154 floating! { f32 }
155 floating! { f64 }