]> git.proxmox.com Git - rustc.git/blob - src/libcore/fmt/float.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / src / libcore / fmt / float.rs
1 use crate::fmt::{Debug, Display, Formatter, LowerExp, Result, UpperExp};
2 use crate::mem::MaybeUninit;
3 use crate::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>(
9 fmt: &mut Formatter<'_>,
10 num: &T,
11 sign: flt2dec::Sign,
12 precision: usize,
13 ) -> Result
14 where
15 T: flt2dec::DecodableFloat,
16 {
17 // SAFETY: Possible undefined behavior, see FIXME(#53491)
18 unsafe {
19 let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
20 let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit();
21 // FIXME(#53491): This is calling `get_mut` on an uninitialized
22 // `MaybeUninit` (here and elsewhere in this file). Revisit this once
23 // we decided whether that is valid or not.
24 // We can do this only because we are libstd and coupled to the compiler.
25 // (FWIW, using `freeze` would not be enough; `flt2dec::Part` is an enum!)
26 let formatted = flt2dec::to_exact_fixed_str(
27 flt2dec::strategy::grisu::format_exact,
28 *num,
29 sign,
30 precision,
31 buf.get_mut(),
32 parts.get_mut(),
33 );
34 fmt.pad_formatted_parts(&formatted)
35 }
36 }
37
38 // Don't inline this so callers that call both this and the above won't wind
39 // up using the combined stack space of both functions in some cases.
40 #[inline(never)]
41 fn float_to_decimal_common_shortest<T>(
42 fmt: &mut Formatter<'_>,
43 num: &T,
44 sign: flt2dec::Sign,
45 precision: usize,
46 ) -> Result
47 where
48 T: flt2dec::DecodableFloat,
49 {
50 // SAFETY: Possible undefined behavior, see FIXME(#53491)
51 unsafe {
52 // enough for f32 and f64
53 let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
54 let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit();
55 // FIXME(#53491)
56 let formatted = flt2dec::to_shortest_str(
57 flt2dec::strategy::grisu::format_shortest,
58 *num,
59 sign,
60 precision,
61 buf.get_mut(),
62 parts.get_mut(),
63 );
64 fmt.pad_formatted_parts(&formatted)
65 }
66 }
67
68 // Common code of floating point Debug and Display.
69 fn float_to_decimal_common<T>(
70 fmt: &mut Formatter<'_>,
71 num: &T,
72 negative_zero: bool,
73 min_precision: usize,
74 ) -> Result
75 where
76 T: flt2dec::DecodableFloat,
77 {
78 let force_sign = fmt.sign_plus();
79 let sign = match (force_sign, negative_zero) {
80 (false, false) => flt2dec::Sign::Minus,
81 (false, true) => flt2dec::Sign::MinusRaw,
82 (true, false) => flt2dec::Sign::MinusPlus,
83 (true, true) => flt2dec::Sign::MinusPlusRaw,
84 };
85
86 if let Some(precision) = fmt.precision {
87 float_to_decimal_common_exact(fmt, num, sign, precision)
88 } else {
89 float_to_decimal_common_shortest(fmt, num, sign, min_precision)
90 }
91 }
92
93 // Don't inline this so callers don't use the stack space this function
94 // requires unless they have to.
95 #[inline(never)]
96 fn float_to_exponential_common_exact<T>(
97 fmt: &mut Formatter<'_>,
98 num: &T,
99 sign: flt2dec::Sign,
100 precision: usize,
101 upper: bool,
102 ) -> Result
103 where
104 T: flt2dec::DecodableFloat,
105 {
106 // SAFETY: Possible undefined behavior, see FIXME(#53491)
107 unsafe {
108 let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
109 let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit();
110 // FIXME(#53491)
111 let formatted = flt2dec::to_exact_exp_str(
112 flt2dec::strategy::grisu::format_exact,
113 *num,
114 sign,
115 precision,
116 upper,
117 buf.get_mut(),
118 parts.get_mut(),
119 );
120 fmt.pad_formatted_parts(&formatted)
121 }
122 }
123
124 // Don't inline this so callers that call both this and the above won't wind
125 // up using the combined stack space of both functions in some cases.
126 #[inline(never)]
127 fn float_to_exponential_common_shortest<T>(
128 fmt: &mut Formatter<'_>,
129 num: &T,
130 sign: flt2dec::Sign,
131 upper: bool,
132 ) -> Result
133 where
134 T: flt2dec::DecodableFloat,
135 {
136 // SAFETY: Possible undefined behavior, see FIXME(#53491)
137 unsafe {
138 // enough for f32 and f64
139 let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
140 let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit();
141 // FIXME(#53491)
142 let formatted = flt2dec::to_shortest_exp_str(
143 flt2dec::strategy::grisu::format_shortest,
144 *num,
145 sign,
146 (0, 0),
147 upper,
148 buf.get_mut(),
149 parts.get_mut(),
150 );
151 fmt.pad_formatted_parts(&formatted)
152 }
153 }
154
155 // Common code of floating point LowerExp and UpperExp.
156 fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
157 where
158 T: flt2dec::DecodableFloat,
159 {
160 let force_sign = fmt.sign_plus();
161 let sign = match force_sign {
162 false => flt2dec::Sign::Minus,
163 true => flt2dec::Sign::MinusPlus,
164 };
165
166 if let Some(precision) = fmt.precision {
167 // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
168 float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
169 } else {
170 float_to_exponential_common_shortest(fmt, num, sign, upper)
171 }
172 }
173
174 macro_rules! floating {
175 ($ty:ident) => {
176 #[stable(feature = "rust1", since = "1.0.0")]
177 impl Debug for $ty {
178 fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
179 float_to_decimal_common(fmt, self, true, 1)
180 }
181 }
182
183 #[stable(feature = "rust1", since = "1.0.0")]
184 impl Display for $ty {
185 fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
186 float_to_decimal_common(fmt, self, false, 0)
187 }
188 }
189
190 #[stable(feature = "rust1", since = "1.0.0")]
191 impl LowerExp for $ty {
192 fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
193 float_to_exponential_common(fmt, self, false)
194 }
195 }
196
197 #[stable(feature = "rust1", since = "1.0.0")]
198 impl UpperExp for $ty {
199 fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
200 float_to_exponential_common(fmt, self, true)
201 }
202 }
203 };
204 }
205
206 floating! { f32 }
207 floating! { f64 }