1use alloc::string::String;
17use alloc::vec::Vec;
18
19const EXP_MAX: i32 = 5000; const POW10_INT: [u64; 19] = [
22 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000,
23 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000,
24 1000000000000000000,
25];
26
27#[inline]
28fn at(s: &[u8], i: usize) -> u8 {
29 if i < s.len() { s[i] } else { 0 }
30}
31
32fn ieq_z(s: &[u8], i: usize, word: &[u8]) -> bool {
34 word.iter().enumerate().all(|(k, &w)| {
35 let c = at(s, i + k);
36 c != 0 && c | 32 == w
37 })
38}
39
40#[cfg(not(target_arch = "wasm32"))]
44fn x87_is_real() -> bool {
45 use core::sync::atomic::{AtomicU8, Ordering};
46 static REAL: AtomicU8 = AtomicU8::new(0); match REAL.load(Ordering::Relaxed) {
48 0 => {
49 let real = rt::x87::scale(5, -324).to_bits() == 1
50 && rt::x87::scale(3, 100).to_bits() == 0x54CB_6E83_B85F_253B;
51 REAL.store(if real { 1 } else { 2 }, Ordering::Relaxed);
52 real
53 }
54 r => r == 1,
55 }
56}
57
58fn scale(m: u64, e: i32) -> f64 {
60 #[cfg(not(target_arch = "wasm32"))]
61 if !x87_is_real() {
62 return rt::portable::math::scale(m, e);
63 }
64 rt::x87::scale(m, e)
65}
66
67fn scale_round(v: f64, k: i32) -> i64 {
69 #[cfg(not(target_arch = "wasm32"))]
70 if !x87_is_real() {
71 return rt::portable::math::scale_round(v, k);
72 }
73 rt::x87::scale_round(v, k)
74}
75
76pub fn f64_parse(s: &[u8]) -> (f64, usize) {
78 let mut i = 0;
79 while matches!(at(s, i), b' ' | b'\t') {
80 i += 1;
81 }
82 let mut neg = false;
83 match at(s, i) {
84 b'-' => {
85 neg = true;
86 i += 1;
87 }
88 b'+' => i += 1,
89 _ => {}
90 }
91 let signed = |v: f64| if neg { f64::from_bits(v.to_bits() ^ 1 << 63) } else { v };
92 match at(s, i) | 32 {
93 b'i' => {
94 if at(s, i + 1) | 32 != b'n' || at(s, i + 2) | 32 != b'f' {
95 return (0.0, 0);
96 }
97 i += 3;
98 if ieq_z(s, i, b"inity") {
99 i += 5;
100 }
101 return (signed(f64::INFINITY), i);
102 }
103 b'n' => {
104 if at(s, i + 1) | 32 != b'a' || at(s, i + 2) | 32 != b'n' {
105 return (0.0, 0);
106 }
107 return (signed(f64::from_bits(0x7FF8_0000_0000_0000)), i + 3);
108 }
109 _ => {}
110 }
111 let mut m: u64 = 0; let mut kept = 0;
113 let mut e10: i32 = 0;
114 let mut seen = 0;
115 loop {
116 let d = at(s, i).wrapping_sub(b'0');
117 if d > 9 {
118 break;
119 }
120 seen += 1;
121 i += 1;
122 if m == 0 && d == 0 {
123 continue; }
125 if kept < 18 {
126 m = m * 10 + d as u64;
127 kept += 1;
128 } else if e10 < 100000 {
129 e10 += 1;
130 }
131 }
132 if at(s, i) == b'.' {
133 i += 1;
134 loop {
135 let d = at(s, i).wrapping_sub(b'0');
136 if d > 9 {
137 break;
138 }
139 seen += 1;
140 i += 1;
141 if m == 0 && d == 0 {
142 if e10 > -100000 {
143 e10 -= 1; }
145 continue;
146 }
147 if kept < 18 {
148 m = m * 10 + d as u64;
149 kept += 1;
150 e10 -= 1;
151 }
152 }
153 }
154 if seen == 0 {
155 return (0.0, 0);
156 }
157 if at(s, i) | 32 == b'e' {
158 let mut j = i + 1;
159 let mut eneg = false;
160 match at(s, j) {
161 b'-' => {
162 eneg = true;
163 j += 1;
164 }
165 b'+' => j += 1,
166 _ => {}
167 }
168 if at(s, j).wrapping_sub(b'0') <= 9 {
169 let mut ed: i32 = 0;
170 loop {
171 let d = at(s, j).wrapping_sub(b'0');
172 if d > 9 {
173 break;
174 }
175 if ed < 100000 {
176 ed = ed * 10 + d as i32;
177 }
178 j += 1;
179 }
180 i = j;
181 e10 += if eneg { -ed } else { ed };
182 } }
184 let v = if m == 0 { 0.0 } else { scale(m, e10.clamp(-EXP_MAX, EXP_MAX)) };
185 (signed(v), i)
186}
187
188fn render(mut n: u64, p: usize, e10: i32) -> Vec<u8> {
190 let mut dig = [0u8; 17];
191 for c in (0..p).rev() {
192 dig[c] = b'0' + (n % 10) as u8;
193 n /= 10;
194 }
195 let mut sig = p;
196 while sig > 1 && dig[sig - 1] == b'0' {
197 sig -= 1;
198 }
199 let dig = &dig[..sig];
200 let mut out = Vec::with_capacity(32);
201 if (-5..17).contains(&e10) {
202 if e10 >= 0 {
203 let int = e10 as usize + 1;
204 for c in 0..int {
205 out.push(if c < sig { dig[c] } else { b'0' });
206 }
207 if sig > int {
208 out.push(b'.');
209 out.extend_from_slice(&dig[int..]);
210 }
211 } else {
212 out.extend_from_slice(b"0.");
213 for _ in 0..(-e10 - 1) {
214 out.push(b'0');
215 }
216 out.extend_from_slice(dig);
217 }
218 } else {
219 out.push(dig[0]);
220 if sig > 1 {
221 out.push(b'.');
222 out.extend_from_slice(&dig[1..]);
223 }
224 out.push(b'e');
225 if e10 < 0 {
226 out.push(b'-');
227 }
228 let a = e10.unsigned_abs();
229 if a < 10 {
230 out.push(b'0'); }
232 if a >= 100 {
233 out.push(b'0' + (a / 100) as u8);
234 out.push(b'0' + (a % 100 / 10) as u8);
235 } else if a >= 10 {
236 out.push(b'0' + (a / 10) as u8);
237 }
238 out.push(b'0' + (a % 10) as u8);
239 }
240 out
241}
242
243pub fn f64_format(v: f64) -> String {
245 let bits = v.to_bits();
246 let mut neg = bits >> 63 != 0;
247 let abs = bits & !(1 << 63);
248 let text: Vec<u8> = if abs >> 52 == 0x7FF {
249 if abs << 12 != 0 {
250 neg = false;
251 b"nan".to_vec()
252 } else {
253 b"inf".to_vec()
254 }
255 } else if abs == 0 {
256 b"0".to_vec()
257 } else {
258 let av = f64::from_bits(abs);
259 let mut e10 = rt::x87::log10_round(av); let mut p = 1usize; loop {
262 let mut budget = 4;
263 let n = loop {
264 let k = p as i32 - 1 - e10;
265 let n = scale_round(av, k) as u64;
266 if n >= POW10_INT[p] {
267 e10 += 1; } else if n < POW10_INT[p - 1] {
269 e10 -= 1; } else {
271 break n;
272 }
273 budget -= 1;
274 if budget == 0 {
275 break n;
276 }
277 };
278 let t = render(n, p, e10);
279 if f64_parse(&t).0.to_bits() == abs || p >= 17 {
280 break t;
281 }
282 p += 1;
283 }
284 };
285 let mut s = String::with_capacity(text.len() + 1);
286 if neg {
287 s.push('-');
288 }
289 s.push_str(core::str::from_utf8(&text).unwrap_or("0"));
290 s
291}
292
293pub fn parse_i64(s: &[u8]) -> Option<i64> {
295 const WORDS: [(&[u8], i64); 6] =
296 [(b"true", 1), (b"false", 0), (b"yes", 1), (b"no", 0), (b"on", 1), (b"off", 0)];
297 for (w, v) in WORDS {
298 if ieq_z(s, 0, w) && at(s, w.len()) == 0 {
299 return Some(v);
300 }
301 }
302 let mut i = 0;
303 let mut neg = false;
304 match at(s, 0) {
305 b'-' => {
306 neg = true;
307 i = 1;
308 }
309 b'+' => i = 1,
310 _ => {}
311 }
312 let mut v: u64 = 0;
313 let mut digits = 0;
314 if at(s, i) == b'0' && at(s, i + 1) | 32 == b'x' {
315 i += 2;
316 loop {
317 let c = at(s, i);
318 let d = match c {
319 b'0'..=b'9' => c - b'0',
320 _ if (b'a'..=b'f').contains(&(c | 32)) => (c | 32) - 87,
321 _ => break,
322 };
323 if digits >= 16 {
324 return None; }
326 v = v << 4 | d as u64;
327 digits += 1;
328 i += 1;
329 }
330 if v > i64::MAX as u64 + neg as u64 {
331 return None; }
333 } else {
334 loop {
335 let d = at(s, i).wrapping_sub(b'0');
336 if d > 9 {
337 break;
338 }
339 if v > 922337203685477580 {
340 return None;
341 }
342 v = v * 10 + d as u64;
343 if v > i64::MAX as u64 + neg as u64 {
344 return None; }
346 digits += 1;
347 i += 1;
348 }
349 }
350 if digits == 0 || at(s, i) != 0 {
351 return None;
352 }
353 let v = v as i64;
354 Some(if neg { v.wrapping_neg() } else { v })
355}