1use crate::scan::word;
4use crate::{Error, ErrorKind};
5
6#[derive(Clone, Copy)]
12pub struct Number<'a> {
13 input: &'a str,
15 start: usize,
16 end: usize,
17 negative: bool,
18 digits: u64,
20 exact: bool,
21 scale: i64,
23 integer: bool,
25}
26
27#[derive(Clone, Copy, Default)]
29pub(crate) struct Parts {
30 negative: bool,
31 digits: u64,
32 count: usize,
33 scale: i64,
34 integer: bool,
35}
36
37const EXACT: u64 = 1 << 53;
39
40const POW10: [f64; 23] = [
42 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
43 1e21, 1e22,
44];
45
46const POW10_U64: [u64; 20] = [
48 1,
49 10,
50 100,
51 1_000,
52 10_000,
53 100_000,
54 1_000_000,
55 10_000_000,
56 100_000_000,
57 1_000_000_000,
58 10_000_000_000,
59 100_000_000_000,
60 1_000_000_000_000,
61 10_000_000_000_000,
62 100_000_000_000_000,
63 1_000_000_000_000_000,
64 10_000_000_000_000_000,
65 100_000_000_000_000_000,
66 1_000_000_000_000_000_000,
67 10_000_000_000_000_000_000,
68];
69
70impl<'a> Number<'a> {
71 #[inline]
72 pub(crate) fn new(input: &'a str, start: usize, end: usize, p: Parts) -> Self {
73 Number {
74 input,
75 start,
76 end,
77 negative: p.negative,
78 digits: p.digits,
79 exact: p.count <= 19,
80 scale: p.scale,
81 integer: p.integer,
82 }
83 }
84
85 #[inline]
87 pub fn text(&self) -> &'a str {
88 self.input.get(self.start..self.end).unwrap_or_default()
90 }
91
92 #[inline]
95 pub fn is_integer(&self) -> bool {
96 self.integer
97 }
98
99 #[inline]
103 pub fn as_i64(&self) -> Option<i64> {
104 if !self.exact {
105 return whole_from_text(self.text());
106 }
107 let digits = self.digits;
108 let magnitude = if digits == 0 {
109 0
110 } else if self.scale >= 0 {
111 digits.checked_mul(*POW10_U64.get(self.scale as usize)?)?
112 } else {
113 let p = *POW10_U64.get(self.scale.unsigned_abs() as usize)?;
115 if digits % p != 0 {
116 return None;
117 }
118 digits / p
119 };
120 signed(self.negative, magnitude)
121 }
122
123 #[inline]
131 pub fn as_f64(&self) -> f64 {
132 if self.exact {
133 let digits = self.digits;
134 let fast = if digits > EXACT {
135 None
136 } else if (-22..=0).contains(&self.scale) {
137 Some(digits as f64 / POW10[self.scale.unsigned_abs() as usize])
138 } else if (0..=22).contains(&self.scale) {
139 Some(digits as f64 * POW10[self.scale as usize])
140 } else if (23..=22 + 15).contains(&self.scale) {
141 digits
142 .checked_mul(POW10_U64[self.scale as usize - 22])
143 .filter(|&m| m <= EXACT)
144 .map(|m| m as f64 * 1e22)
145 } else {
146 None
147 };
148 if let Some(v) = fast {
149 return if self.negative { -v } else { v };
150 }
151 }
152 parse(self.text())
153 }
154}
155
156impl PartialEq for Number<'_> {
158 fn eq(&self, other: &Self) -> bool {
159 self.text() == other.text()
160 }
161}
162
163impl Eq for Number<'_> {}
164
165impl core::fmt::Debug for Number<'_> {
166 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167 f.debug_tuple("Number").field(&self.text()).finish()
168 }
169}
170
171#[cold]
174#[inline(never)]
175fn parse(text: &str) -> f64 {
176 text.parse().unwrap_or(f64::NAN)
177}
178
179#[inline]
181fn signed(negative: bool, magnitude: u64) -> Option<i64> {
182 if negative {
183 (magnitude <= 1 << 63).then(|| 0u64.wrapping_sub(magnitude) as i64)
184 } else {
185 i64::try_from(magnitude).ok()
186 }
187}
188
189#[cold]
192#[inline(never)]
193fn whole_from_text(text: &str) -> Option<i64> {
194 let b = text.as_bytes();
195 let negative = b.first() == Some(&b'-');
196 let body = &b[usize::from(negative)..];
197 let (mantissa, exponent) = match body.iter().position(|&c| c == b'e' || c == b'E') {
198 Some(e) => (&body[..e], &body[e + 1..]),
199 None => (body, &b""[..]),
200 };
201 let exponent = match exponent {
202 [b'-', d @ ..] => -saturating_digits(d),
203 [b'+', d @ ..] | d => saturating_digits(d),
204 };
205 let (int, frac) = match mantissa.iter().position(|&c| c == b'.') {
206 Some(p) => (&mantissa[..p], &mantissa[p + 1..]),
207 None => (mantissa, &b""[..]),
208 };
209 let digit = |i: usize| if i < int.len() { int[i] } else { frac[i - int.len()] };
210 let len = int.len() + frac.len();
211 let Some(first) = (0..len).find(|&i| digit(i) != b'0') else {
212 return Some(0);
213 };
214 let last = (0..len).rev().find(|&i| digit(i) != b'0')?;
215 if last - first >= 19 {
216 return None;
217 }
218 let scale = exponent
220 .saturating_sub(frac.len() as i64)
221 .saturating_add((len - 1 - last) as i64);
222 let mut magnitude: u64 = 0;
223 for i in first..=last {
224 magnitude = magnitude * 10 + u64::from(digit(i) - b'0');
225 }
226 signed(
227 negative,
228 magnitude.checked_mul(*POW10_U64.get(usize::try_from(scale).ok()?)?)?,
230 )
231}
232
233fn saturating_digits(d: &[u8]) -> i64 {
234 d.iter()
235 .fold(0i64, |v, &c| v.saturating_mul(10).saturating_add(i64::from(c - b'0')))
236}
237
238#[inline(always)]
241pub(crate) fn read<const VALUE: bool>(bytes: &[u8], start: usize) -> Result<(usize, Parts), Error> {
242 let bad = Error::new(ErrorKind::Number, start);
243 let mut p = Parts {
244 integer: true,
245 ..Parts::default()
246 };
247 let mut at = start;
248 if bytes.get(at) == Some(&b'-') {
249 p.negative = true;
250 at += 1;
251 }
252 match bytes.get(at) {
253 Some(b'0') => {
254 at += 1;
255 p.count = 1;
256 }
257 Some(b'1'..=b'9') => {
258 let end = digits::<VALUE>(bytes, at, &mut p.digits);
259 p.count = end - at;
260 at = end;
261 }
262 _ => return Err(bad),
263 }
264 let mut fraction = 0;
265 if bytes.get(at) == Some(&b'.') {
266 at += 1;
267 let end = digits::<VALUE>(bytes, at, &mut p.digits);
268 fraction = end - at;
269 if fraction == 0 {
270 return Err(bad);
271 }
272 at = end;
273 p.count += fraction;
274 p.integer = false;
275 }
276 let mut exponent: i64 = 0;
277 if let Some(b'e' | b'E') = bytes.get(at) {
278 at += 1;
279 p.integer = false;
280 let down = match bytes.get(at) {
281 Some(b'-') => {
282 at += 1;
283 true
284 }
285 Some(b'+') => {
286 at += 1;
287 false
288 }
289 _ => false,
290 };
291 let from = at;
292 while let Some(&d @ b'0'..=b'9') = bytes.get(at) {
293 if VALUE {
294 exponent = exponent.saturating_mul(10).saturating_add(i64::from(d - b'0'));
295 }
296 at += 1;
297 }
298 if at == from {
299 return Err(bad);
300 }
301 if down {
302 exponent = -exponent;
303 }
304 }
305 p.scale = exponent.saturating_sub(fraction as i64);
306 Ok((at, p))
308}
309
310const ZEROS: u64 = 0x3030_3030_3030_3030;
311
312#[inline(always)]
316fn digits<const VALUE: bool>(bytes: &[u8], mut at: usize, value: &mut u64) -> usize {
317 while let Some(w) = bytes.get(at..at + 8) {
318 let word = word(w);
319 let n = leading_digits(word);
320 if n < 8 {
321 if !VALUE {
322 return at + n;
323 }
324 break;
325 }
326 if VALUE {
327 *value = value.wrapping_mul(100_000_000).wrapping_add(eight_digits(word));
328 }
329 at += 8;
330 }
331 while let Some(&d @ b'0'..=b'9') = bytes.get(at) {
333 if VALUE {
334 *value = value.wrapping_mul(10).wrapping_add(u64::from(d - b'0'));
335 }
336 at += 1;
337 }
338 at
339}
340
341#[inline(always)]
343fn leading_digits(word: u64) -> usize {
344 const HIGH_NIBBLES: u64 = 0xF0F0_F0F0_F0F0_F0F0;
347 let off = ((word & HIGH_NIBBLES) ^ ZEROS) | ((word.wrapping_add(0x0606_0606_0606_0606) & HIGH_NIBBLES) ^ ZEROS);
348 (off.trailing_zeros() / 8) as usize
349}
350
351#[inline(always)]
354fn eight_digits(word: u64) -> u64 {
355 const MASK: u64 = 0x0000_00FF_0000_00FF;
356 const MUL1: u64 = 100 + (1_000_000 << 32);
357 const MUL2: u64 = 1 + (10_000 << 32);
358 let v = word - ZEROS;
359 let v = v * 10 + (v >> 8);
361 (v & MASK)
362 .wrapping_mul(MUL1)
363 .wrapping_add(((v >> 16) & MASK).wrapping_mul(MUL2))
364 >> 32
365}
366
367#[cfg(test)]
368mod tests {
369 use super::{eight_digits, leading_digits};
370 use crate::scan::word;
371 use crate::testing::Rng;
372
373 const OTHERS: [u8; 12] = [b'/', b':', b'.', b'e', b'-', b' ', b'"', 0x00, 0x2f, 0x3a, 0xfa, 0xff];
375
376 #[test]
377 fn leading_digits_counts_to_the_first_byte_that_is_not_one() {
378 let mut rng = Rng(0x853C_49E6_748F_EA9B);
379 for n in 0..=8 {
380 for &other in &OTHERS {
381 for _ in 0..200 {
382 let mut b = [0u8; 8];
383 for (i, byte) in b.iter_mut().enumerate() {
384 let r = rng.next();
385 *byte = if i < n {
386 b'0' + (r % 10) as u8
387 } else if i == n {
388 other
389 } else {
390 (r >> 8) as u8
392 };
393 }
394 assert_eq!(leading_digits(word(&b)), n, "{b:?}");
395 }
396 }
397 }
398 }
399
400 #[test]
401 fn eight_digits_read_in_a_word_have_their_value() {
402 let mut rng = Rng(0x2545_F491_4F6C_DD1D);
403 for _ in 0..100_000 {
404 let r = rng.next();
405 let mut b = [0u8; 8];
406 let mut value = 0u64;
407 for (i, byte) in b.iter_mut().enumerate() {
408 let d = ((r >> (i * 4)) % 10) as u8;
409 *byte = b'0' + d;
410 value = value * 10 + u64::from(d);
411 }
412 assert_eq!(eight_digits(word(&b)), value, "{b:?}");
413 }
414 assert_eq!(eight_digits(word(b"99999999")), 99_999_999);
415 assert_eq!(eight_digits(word(b"00000000")), 0);
416 }
417}