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