1#![doc(hidden)]
11
12#[cfg(not(feature = "compact"))]
13use lexical_parse_integer::algorithm;
14#[cfg(feature = "f16")]
15use lexical_util::bf16::bf16;
16use lexical_util::digit::{char_to_digit_const, char_to_valid_digit_const};
17use lexical_util::error::Error;
18#[cfg(feature = "f16")]
19use lexical_util::f16::f16;
20use lexical_util::format::NumberFormat;
21use lexical_util::iterator::{AsBytes, Bytes, DigitsIter, Iter};
22use lexical_util::result::Result;
23use lexical_util::step::u64_step;
24
25#[cfg(any(feature = "compact", feature = "radix"))]
26use crate::bellerophon::bellerophon;
27#[cfg(feature = "power-of-two")]
28use crate::binary::{binary, slow_binary};
29use crate::float::{extended_to_float, ExtendedFloat80, LemireFloat};
30#[cfg(not(feature = "compact"))]
31use crate::lemire::lemire;
32use crate::number::Number;
33use crate::options::Options;
34use crate::shared;
35use crate::slow::slow_radix;
36
37#[cfg(feature = "power-of-two")]
42macro_rules! is_power_two {
43 ($radix:expr) => {
44 matches!($radix, 2 | 4 | 8 | 16 | 32)
45 };
46}
47
48macro_rules! check_radix {
50 ($format:ident) => {{
51 let format = NumberFormat::<{ $format }> {};
52 #[cfg(feature = "power-of-two")]
53 {
54 if format.radix() != format.exponent_base() {
55 let valid_radix = matches!(
56 (format.radix(), format.exponent_base()),
57 (4, 2) | (8, 2) | (16, 2) | (32, 2) | (16, 4)
58 );
59 if !valid_radix {
60 return Err(Error::InvalidRadix);
61 }
62 }
63 }
64
65 #[cfg(not(feature = "power-of-two"))]
66 {
67 if format.radix() != format.exponent_base() {
68 return Err(Error::InvalidRadix);
69 }
70 }
71 }};
72}
73
74pub trait ParseFloat: LemireFloat {
76 #[cfg_attr(not(feature = "compact"), inline(always))]
78 fn parse_complete<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<Self> {
79 check_radix!(FORMAT);
80 parse_complete::<Self, FORMAT>(bytes, options)
81 }
82
83 #[cfg_attr(not(feature = "compact"), inline(always))]
85 fn parse_partial<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<(Self, usize)> {
86 check_radix!(FORMAT);
87 parse_partial::<Self, FORMAT>(bytes, options)
88 }
89
90 #[cfg_attr(not(feature = "compact"), inline(always))]
93 fn fast_path_complete<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<Self> {
94 check_radix!(FORMAT);
95 fast_path_complete::<Self, FORMAT>(bytes, options)
96 }
97
98 #[cfg_attr(not(feature = "compact"), inline(always))]
101 fn fast_path_partial<const FORMAT: u128>(
102 bytes: &[u8],
103 options: &Options,
104 ) -> Result<(Self, usize)> {
105 check_radix!(FORMAT);
106 fast_path_partial::<Self, FORMAT>(bytes, options)
107 }
108}
109
110macro_rules! parse_float_impl {
111 ($($t:ty)*) => ($(
112 impl ParseFloat for $t {}
113 )*)
114}
115
116parse_float_impl! { f32 f64 }
117
118#[cfg(feature = "f16")]
119macro_rules! parse_float_as_f32 {
120 ($($t:ty)*) => ($(
121 impl ParseFloat for $t {
122 #[cfg_attr(not(feature = "compact"), inline(always))]
123 fn parse_complete<const FORMAT: u128>(bytes: &[u8], options: &Options)
124 -> Result<Self>
125 {
126 Ok(Self::from_f32(parse_complete::<f32, FORMAT>(bytes, options)?))
127 }
128
129 #[cfg_attr(not(feature = "compact"), inline(always))]
130 fn parse_partial<const FORMAT: u128>(bytes: &[u8], options: &Options)
131 -> Result<(Self, usize)>
132 {
133 let (float, count) = parse_partial::<f32, FORMAT>(bytes, options)?;
134 Ok((Self::from_f32(float), count))
135 }
136
137 #[cfg_attr(not(feature = "compact"), inline(always))]
138 fn fast_path_complete<const FORMAT: u128>(bytes: &[u8], options: &Options)
139 -> Result<Self>
140 {
141 Ok(Self::from_f32(fast_path_complete::<f32, FORMAT>(bytes, options)?))
142 }
143
144 #[cfg_attr(not(feature = "compact"), inline(always))]
145 fn fast_path_partial<const FORMAT: u128>(bytes: &[u8], options: &Options)
146 -> Result<(Self, usize)>
147 {
148 let (float, count) = fast_path_partial::<f32, FORMAT>(bytes, options)?;
149 Ok((Self::from_f32(float), count))
150 }
151 }
152 )*)
153}
154
155#[cfg(feature = "f16")]
156parse_float_as_f32! { bf16 f16 }
157
158#[cfg_attr(not(feature = "compact"), inline(always))]
169pub fn parse_mantissa_sign<const FORMAT: u128>(byte: &mut Bytes<'_, FORMAT>) -> Result<bool> {
170 let format = NumberFormat::<{ FORMAT }> {};
171 parse_sign!(
172 byte,
173 true,
174 format.no_positive_mantissa_sign(),
175 format.required_mantissa_sign(),
176 InvalidPositiveSign,
177 MissingSign
178 )
179}
180
181#[cfg_attr(not(feature = "compact"), inline(always))]
183pub fn parse_exponent_sign<const FORMAT: u128>(byte: &mut Bytes<'_, FORMAT>) -> Result<bool> {
184 let format = NumberFormat::<{ FORMAT }> {};
185 parse_sign!(
186 byte,
187 true,
188 format.no_positive_exponent_sign(),
189 format.required_exponent_sign(),
190 InvalidPositiveExponentSign,
191 MissingExponentSign
192 )
193}
194
195macro_rules! parse_number {
203 (
204 $format:ident,
205 $byte:ident,
206 $is_negative:ident,
207 $options:ident,
208 $parse_normal:ident,
209 $parse_special:ident
210 ) => {{
211 match $parse_normal::<$format>($byte.clone(), $is_negative, $options) {
212 Ok(n) => n,
213 Err(e) => {
214 if let Some(value) =
215 $parse_special::<_, $format>($byte.clone(), $is_negative, $options)
216 {
217 return Ok(value);
218 } else {
219 return Err(e);
220 }
221 },
222 }
223 }};
224}
225
226macro_rules! to_native {
231 ($type:ident, $fp:ident, $is_negative:ident) => {{
232 let mut float = extended_to_float::<$type>($fp);
233 if $is_negative {
234 float = -float;
235 }
236 float
237 }};
238}
239
240#[allow(clippy::missing_inline_in_public_items)] pub fn parse_complete<F: LemireFloat, const FORMAT: u128>(
243 bytes: &[u8],
244 options: &Options,
245) -> Result<F> {
246 let mut byte = bytes.bytes::<{ FORMAT }>();
247 let is_negative = parse_mantissa_sign(&mut byte)?;
248 if byte.integer_iter().is_consumed() {
249 if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
250 || NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
251 {
252 return Err(Error::Empty(byte.cursor()));
253 } else {
254 return Ok(F::ZERO);
255 }
256 }
257
258 let num: Number<'_> =
260 parse_number!(FORMAT, byte, is_negative, options, parse_complete_number, parse_special);
261 if let Some(value) = num.try_fast_path::<_, FORMAT>() {
263 return Ok(value);
264 }
265 let mut fp = moderate_path::<F, FORMAT>(&num, options.lossy());
267
268 if fp.exp < 0 {
272 debug_assert!(!options.lossy(), "lossy algorithms never use slow algorithms");
273 fp.exp -= shared::INVALID_FP;
275 fp = slow_path::<F, FORMAT>(num, fp);
276 }
277
278 Ok(to_native!(F, fp, is_negative))
280}
281
282#[allow(clippy::missing_inline_in_public_items)] pub fn fast_path_complete<F: LemireFloat, const FORMAT: u128>(
285 bytes: &[u8],
286 options: &Options,
287) -> Result<F> {
288 let mut byte = bytes.bytes::<{ FORMAT }>();
289 let is_negative = parse_mantissa_sign(&mut byte)?;
290 if byte.integer_iter().is_consumed() {
291 if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
292 || NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
293 {
294 return Err(Error::Empty(byte.cursor()));
295 } else {
296 return Ok(F::ZERO);
297 }
298 }
299
300 let num =
302 parse_number!(FORMAT, byte, is_negative, options, parse_complete_number, parse_special);
303 Ok(num.force_fast_path::<_, FORMAT>())
304}
305
306#[allow(clippy::missing_inline_in_public_items)] pub fn parse_partial<F: LemireFloat, const FORMAT: u128>(
309 bytes: &[u8],
310 options: &Options,
311) -> Result<(F, usize)> {
312 let mut byte = bytes.bytes::<{ FORMAT }>();
313 let is_negative = parse_mantissa_sign(&mut byte)?;
314 if byte.integer_iter().is_consumed() {
315 if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
316 || NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
317 {
318 return Err(Error::Empty(byte.cursor()));
319 } else {
320 return Ok((F::ZERO, byte.cursor()));
321 }
322 }
323
324 let (num, count) = parse_number!(
326 FORMAT,
327 byte,
328 is_negative,
329 options,
330 parse_partial_number,
331 parse_partial_special
332 );
333 if let Some(value) = num.try_fast_path::<_, FORMAT>() {
335 return Ok((value, count));
336 }
337 let mut fp = moderate_path::<F, FORMAT>(&num, options.lossy());
339
340 if fp.exp < 0 {
344 debug_assert!(!options.lossy(), "lossy algorithms never use slow algorithms");
345 fp.exp -= shared::INVALID_FP;
347 fp = slow_path::<F, FORMAT>(num, fp);
348 }
349
350 Ok((to_native!(F, fp, is_negative), count))
352}
353
354#[allow(clippy::missing_inline_in_public_items)] pub fn fast_path_partial<F: LemireFloat, const FORMAT: u128>(
357 bytes: &[u8],
358 options: &Options,
359) -> Result<(F, usize)> {
360 let mut byte = bytes.bytes::<{ FORMAT }>();
361 let is_negative = parse_mantissa_sign(&mut byte)?;
362 if byte.integer_iter().is_consumed() {
363 if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
364 || NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
365 {
366 return Err(Error::Empty(byte.cursor()));
367 } else {
368 return Ok((F::ZERO, byte.cursor()));
369 }
370 }
371
372 let (num, count) = parse_number!(
374 FORMAT,
375 byte,
376 is_negative,
377 options,
378 parse_partial_number,
379 parse_partial_special
380 );
381 Ok((num.force_fast_path::<_, FORMAT>(), count))
382}
383
384#[must_use]
390#[inline(always)]
391pub fn moderate_path<F: LemireFloat, const FORMAT: u128>(
392 num: &Number,
393 lossy: bool,
394) -> ExtendedFloat80 {
395 #[cfg(feature = "compact")]
396 {
397 #[cfg(feature = "power-of-two")]
398 {
399 let format = NumberFormat::<{ FORMAT }> {};
400 if is_power_two!(format.mantissa_radix()) {
401 binary::<F, FORMAT>(num, lossy)
403 } else {
404 bellerophon::<F, FORMAT>(num, lossy)
405 }
406 }
407
408 #[cfg(not(feature = "power-of-two"))]
409 {
410 bellerophon::<F, FORMAT>(num, lossy)
411 }
412 }
413
414 #[cfg(not(feature = "compact"))]
415 {
416 #[cfg(feature = "radix")]
417 {
418 let format = NumberFormat::<{ FORMAT }> {};
419 let radix = format.mantissa_radix();
420 if radix == 10 {
421 lemire::<F>(num, lossy)
422 } else if is_power_two!(radix) {
423 binary::<F, FORMAT>(num, lossy)
425 } else {
426 bellerophon::<F, FORMAT>(num, lossy)
427 }
428 }
429
430 #[cfg(all(feature = "power-of-two", not(feature = "radix")))]
431 {
432 let format = NumberFormat::<{ FORMAT }> {};
433 let radix = format.mantissa_radix();
434 debug_assert!(matches!(radix, 2 | 4 | 8 | 10 | 16 | 32));
435 if radix == 10 {
436 lemire::<F>(num, lossy)
437 } else {
438 binary::<F, FORMAT>(num, lossy)
440 }
441 }
442
443 #[cfg(not(feature = "power-of-two"))]
444 {
445 lemire::<F>(num, lossy)
446 }
447 }
448}
449
450#[must_use]
453#[inline(always)]
454pub fn slow_path<F: LemireFloat, const FORMAT: u128>(
455 num: Number,
456 fp: ExtendedFloat80,
457) -> ExtendedFloat80 {
458 #[cfg(not(feature = "power-of-two"))]
459 {
460 slow_radix::<F, FORMAT>(num, fp)
461 }
462
463 #[cfg(feature = "power-of-two")]
464 {
465 let format = NumberFormat::<{ FORMAT }> {};
466 if is_power_two!(format.mantissa_radix()) {
467 slow_binary::<F, FORMAT>(num)
468 } else {
469 slow_radix::<F, FORMAT>(num, fp)
470 }
471 }
472}
473
474#[cfg_attr(not(feature = "compact"), inline(always))]
482#[allow(unused_mut)] #[allow(clippy::unwrap_used)] #[allow(clippy::collapsible_if)] #[allow(clippy::cast_possible_wrap)] #[allow(clippy::too_many_lines)] pub fn parse_number<'a, const FORMAT: u128, const IS_PARTIAL: bool>(
488 mut byte: Bytes<'a, FORMAT>,
489 is_negative: bool,
490 options: &Options,
491) -> Result<(Number<'a>, usize)> {
492 let format = NumberFormat::<{ FORMAT }> {};
521 let decimal_point = options.decimal_point();
522 let exponent_character = options.exponent();
523 debug_assert!(format.is_valid(), "should have already checked for an invalid number format");
524 debug_assert!(!byte.is_buffer_empty(), "should have previously checked for empty input");
525 let bits_per_digit = shared::log2(format.mantissa_radix()) as i64;
526 let bits_per_base = shared::log2(format.exponent_base()) as i64;
527
528 #[allow(unused_variables)]
532 let mut is_prefix = false;
533 #[cfg(feature = "format")]
534 {
535 let base_prefix = format.base_prefix();
536 let mut iter = byte.integer_iter();
537 if base_prefix != 0 && iter.read_if_value_cased(b'0').is_some() {
538 is_prefix = true;
543 if iter.read_if_value(base_prefix, format.case_sensitive_base_prefix()).is_some()
544 && iter.is_buffer_empty()
545 && format.required_integer_digits()
546 {
547 return Err(Error::EmptyInteger(iter.cursor()));
548 }
549 }
550 }
551
552 let mut mantissa = 0_u64;
554 let start = byte.clone();
555 #[cfg(not(feature = "compact"))]
556 parse_8digits::<_, FORMAT>(byte.integer_iter(), &mut mantissa);
557 parse_digits::<_, _, FORMAT>(byte.integer_iter(), |digit| {
558 mantissa = mantissa.wrapping_mul(format.radix() as u64).wrapping_add(digit as u64);
559 });
560 let mut n_digits = byte.current_count() - start.current_count();
561 #[cfg(feature = "format")]
562 if format.required_integer_digits() && n_digits == 0 {
563 return Err(Error::EmptyInteger(byte.cursor()));
564 }
565
566 let b_digits = if cfg!(feature = "format") && !byte.integer_iter().is_contiguous() {
572 byte.cursor() - start.cursor()
573 } else {
574 n_digits
575 };
576 debug_assert!(
577 b_digits <= start.as_slice().len(),
578 "number of digits parsed must <= buffer length"
579 );
580 let integer_digits = unsafe { start.as_slice().get_unchecked(..b_digits) };
590
591 #[cfg(feature = "format")]
593 if !is_prefix && format.no_float_leading_zeros() {
594 if integer_digits.len() > 1 && integer_digits.first() == Some(&b'0') {
595 return Err(Error::InvalidLeadingZeros(start.cursor()));
596 }
597 }
598
599 let mut n_after_dot = 0;
603 let mut exponent = 0_i64;
604 let mut implicit_exponent: i64;
605 let int_end = n_digits as i64;
606 let mut fraction_digits = None;
607 let has_decimal = byte.first_is_cased(decimal_point);
608 if has_decimal {
609 unsafe { byte.step_unchecked() };
611 let before = byte.clone();
612 #[cfg(not(feature = "compact"))]
613 parse_8digits::<_, FORMAT>(byte.fraction_iter(), &mut mantissa);
614 parse_digits::<_, _, FORMAT>(byte.fraction_iter(), |digit| {
615 mantissa = mantissa.wrapping_mul(format.radix() as u64).wrapping_add(digit as u64);
616 });
617 n_after_dot = byte.current_count() - before.current_count();
618 let b_after_dot = if cfg!(feature = "format") && !byte.fraction_iter().is_contiguous() {
623 byte.cursor() - before.cursor()
624 } else {
625 n_after_dot
626 };
627
628 debug_assert!(
630 b_after_dot <= before.as_slice().len(),
631 "digits after dot must be smaller than buffer"
632 );
633 fraction_digits = Some(unsafe { before.as_slice().get_unchecked(..b_after_dot) });
635
636 implicit_exponent = -(n_after_dot as i64);
638 if format.mantissa_radix() == format.exponent_base() {
639 exponent = implicit_exponent;
640 } else {
641 debug_assert!(bits_per_digit % bits_per_base == 0, "exponent must be a power of base");
642 exponent = implicit_exponent * bits_per_digit / bits_per_base;
643 };
644 #[cfg(feature = "format")]
645 if format.required_fraction_digits() && n_after_dot == 0 {
646 return Err(Error::EmptyFraction(byte.cursor()));
647 }
648 }
649
650 let has_exponent = byte
653 .first_is(exponent_character, format.case_sensitive_exponent() && cfg!(feature = "format"));
654
655 n_digits += n_after_dot;
657 if format.required_mantissa_digits()
658 && (n_digits == 0 || (cfg!(feature = "format") && byte.current_count() == 0))
659 {
660 let any_digits = start.clone().integer_iter().peek().is_some();
661 if has_decimal || has_exponent || !any_digits || IS_PARTIAL {
664 return Err(Error::EmptyMantissa(byte.cursor()));
665 } else {
666 return Err(Error::InvalidDigit(start.cursor()));
667 }
668 }
669
670 let mut explicit_exponent = 0_i64;
674 if has_exponent {
675 unsafe { byte.step_unchecked() };
680
681 #[cfg(feature = "format")]
683 {
684 if format.no_exponent_notation() {
686 return Err(Error::InvalidExponent(byte.cursor() - 1));
687 }
688 if format.no_exponent_without_fraction() && fraction_digits.is_none() {
690 return Err(Error::ExponentWithoutFraction(byte.cursor() - 1));
691 }
692 }
693
694 let is_negative_exponent = parse_exponent_sign(&mut byte)?;
695 let before = byte.current_count();
696 parse_digits::<_, _, FORMAT>(byte.exponent_iter(), |digit| {
697 if explicit_exponent < 0x10000000 {
698 explicit_exponent *= format.radix() as i64;
699 explicit_exponent += digit as i64;
700 }
701 });
702 if format.required_exponent_digits() && byte.current_count() - before == 0 {
703 return Err(Error::EmptyExponent(byte.cursor()));
704 }
705 explicit_exponent = if is_negative_exponent {
707 -explicit_exponent
708 } else {
709 explicit_exponent
710 };
711 exponent += explicit_exponent;
712 } else if cfg!(feature = "format") && format.required_exponent_notation() {
713 return Err(Error::MissingExponent(byte.cursor()));
714 }
715
716 #[allow(unused_variables)]
720 let base_suffix = format.base_suffix();
721 #[cfg(feature = "format")]
722 if base_suffix != 0 {
723 if byte.first_is(base_suffix, format.case_sensitive_base_suffix()) {
724 unsafe { byte.step_unchecked() };
726 }
727 }
728
729 let end = byte.cursor();
733 let mut step = u64_step(format.radix());
734 let mut many_digits = false;
735 #[cfg(feature = "format")]
736 if !format.required_mantissa_digits() && n_digits == 0 {
737 exponent = 0;
738 }
739 if n_digits <= step {
740 return Ok((
741 Number {
742 exponent,
743 mantissa,
744 is_negative,
745 many_digits: false,
746 integer: integer_digits,
747 fraction: fraction_digits,
748 },
749 end,
750 ));
751 }
752
753 n_digits -= step;
755 let mut zeros = start.clone();
756 let mut zeros_integer = zeros.integer_iter();
757 n_digits = n_digits.saturating_sub(zeros_integer.skip_zeros());
758 if zeros.first_is_cased(decimal_point) {
759 unsafe { zeros.step_unchecked() };
761 }
762 let mut zeros_fraction = zeros.fraction_iter();
763 n_digits = n_digits.saturating_sub(zeros_fraction.skip_zeros());
764
765 if n_digits > 0 {
769 many_digits = true;
771 mantissa = 0;
772 let mut integer = integer_digits.bytes::<{ FORMAT }>();
773 let mut integer_iter = integer.integer_iter();
775 integer_iter.skip_zeros();
776 parse_u64_digits::<_, FORMAT>(integer_iter, &mut mantissa, &mut step);
777 implicit_exponent = if step == 0
786 || (cfg!(feature = "format") && !byte.is_contiguous() && fraction_digits.is_none())
787 {
788 int_end - integer.current_count() as i64
790 } else {
791 let mut fraction = fraction_digits.unwrap().bytes::<{ FORMAT }>();
797 let mut fraction_iter = fraction.fraction_iter();
798 if mantissa == 0 {
800 fraction_iter.skip_zeros();
801 }
802 parse_u64_digits::<_, FORMAT>(fraction_iter, &mut mantissa, &mut step);
803 -(fraction.current_count() as i64)
804 };
805 if format.mantissa_radix() == format.exponent_base() {
806 exponent = implicit_exponent;
807 } else {
808 debug_assert!(bits_per_digit % bits_per_base == 0, "exponent must be a power of base");
809 exponent = implicit_exponent * bits_per_digit / bits_per_base;
810 };
811 exponent += explicit_exponent;
813 }
814
815 Ok((
816 Number {
817 exponent,
818 mantissa,
819 is_negative,
820 many_digits,
821 integer: integer_digits,
822 fraction: fraction_digits,
823 },
824 end,
825 ))
826}
827
828pub fn parse_partial_number<'a, const FORMAT: u128>(
829 byte: Bytes<'a, FORMAT>,
830 is_negative: bool,
831 options: &Options,
832) -> Result<(Number<'a>, usize)> {
833 parse_number::<FORMAT, true>(byte, is_negative, options)
834}
835
836#[inline(always)]
838pub fn parse_complete_number<'a, const FORMAT: u128>(
839 byte: Bytes<'a, FORMAT>,
840 is_negative: bool,
841 options: &Options,
842) -> Result<Number<'a>> {
843 let length = byte.buffer_length();
845 let (float, count) = parse_number::<FORMAT, false>(byte, is_negative, options)?;
846 if count == length {
847 Ok(float)
848 } else {
849 Err(Error::InvalidDigit(count))
850 }
851}
852
853#[inline(always)]
858pub fn parse_digits<'a, Iter, Cb, const FORMAT: u128>(mut iter: Iter, mut cb: Cb)
859where
860 Iter: DigitsIter<'a>,
861 Cb: FnMut(u32),
862{
863 let format = NumberFormat::<{ FORMAT }> {};
864 let radix = format.radix();
865 while let Some(&c) = iter.peek() {
866 match char_to_digit_const(c, radix) {
867 Some(v) => cb(v),
868 None => break,
869 }
870 unsafe { iter.step_unchecked() };
874 iter.increment_count();
875 }
876}
877
878#[inline(always)]
880#[cfg(not(feature = "compact"))]
881pub fn parse_8digits<'a, Iter, const FORMAT: u128>(mut iter: Iter, mantissa: &mut u64)
882where
883 Iter: DigitsIter<'a>,
884{
885 let format = NumberFormat::<{ FORMAT }> {};
886 let radix: u64 = format.radix() as u64;
887 if can_try_parse_multidigit!(iter, radix) {
888 debug_assert!(radix < 16, "radices over 16 will overflow with radix^8");
889 let radix8 = format.radix8() as u64;
890 while let Some(v) = algorithm::try_parse_8digits::<u64, _, FORMAT>(&mut iter) {
893 *mantissa = mantissa.wrapping_mul(radix8).wrapping_add(v);
894 }
895 }
896}
897
898#[cfg_attr(not(feature = "compact"), inline(always))]
904pub fn parse_u64_digits<'a, Iter, const FORMAT: u128>(
905 mut iter: Iter,
906 mantissa: &mut u64,
907 step: &mut usize,
908) where
909 Iter: DigitsIter<'a>,
910{
911 let format = NumberFormat::<{ FORMAT }> {};
912 let radix = format.radix() as u64;
913
914 #[cfg(not(feature = "compact"))]
916 if can_try_parse_multidigit!(iter, radix) {
917 debug_assert!(radix < 16, "radices over 16 will overflow with radix^8");
918 let radix8 = format.radix8() as u64;
919 while *step > 8 {
920 if let Some(v) = algorithm::try_parse_8digits::<u64, _, FORMAT>(&mut iter) {
921 *mantissa = mantissa.wrapping_mul(radix8).wrapping_add(v);
922 *step -= 8;
923 } else {
924 break;
925 }
926 }
927 }
928
929 while let Some(&c) = iter.peek() {
931 if *step > 0 {
932 let digit = char_to_valid_digit_const(c, radix as u32);
933 *mantissa = *mantissa * radix + digit as u64;
934 *step -= 1;
935 unsafe { iter.step_unchecked() };
937 iter.increment_count();
938 } else {
939 break;
940 }
941 }
942}
943
944#[must_use]
950#[inline(always)]
951pub fn is_special_eq<const FORMAT: u128>(mut byte: Bytes<FORMAT>, string: &'static [u8]) -> usize {
952 let format = NumberFormat::<{ FORMAT }> {};
953 if cfg!(feature = "format") && format.case_sensitive_special() {
954 if shared::starts_with(byte.special_iter(), string.iter()) {
955 byte.special_iter().peek();
957 return byte.cursor();
958 }
959 } else if shared::starts_with_uncased(byte.special_iter(), string.iter()) {
960 byte.special_iter().peek();
962 return byte.cursor();
963 }
964 0
965}
966
967#[must_use]
969#[cfg_attr(not(feature = "compact"), inline(always))]
970pub fn parse_positive_special<F, const FORMAT: u128>(
971 byte: Bytes<FORMAT>,
972 options: &Options,
973) -> Option<(F, usize)>
974where
975 F: LemireFloat,
976{
977 let format = NumberFormat::<{ FORMAT }> {};
978 if cfg!(feature = "format") && format.no_special() {
979 return None;
980 }
981
982 let cursor = byte.cursor();
983 let length = byte.buffer_length() - cursor;
984 if let Some(nan_string) = options.nan_string() {
985 if length >= nan_string.len() {
986 let count = is_special_eq::<FORMAT>(byte.clone(), nan_string);
987 if count != 0 {
988 return Some((F::NAN, count));
989 }
990 }
991 }
992 if let Some(infinity_string) = options.infinity_string() {
993 if length >= infinity_string.len() {
994 let count = is_special_eq::<FORMAT>(byte.clone(), infinity_string);
995 if count != 0 {
996 return Some((F::INFINITY, count));
997 }
998 }
999 }
1000 if let Some(inf_string) = options.inf_string() {
1001 if length >= inf_string.len() {
1002 let count = is_special_eq::<FORMAT>(byte.clone(), inf_string);
1003 if count != 0 {
1004 return Some((F::INFINITY, count));
1005 }
1006 }
1007 }
1008
1009 None
1010}
1011
1012#[must_use]
1014#[inline(always)]
1015pub fn parse_partial_special<F, const FORMAT: u128>(
1016 byte: Bytes<FORMAT>,
1017 is_negative: bool,
1018 options: &Options,
1019) -> Option<(F, usize)>
1020where
1021 F: LemireFloat,
1022{
1023 let (mut float, count) = parse_positive_special::<F, FORMAT>(byte, options)?;
1024 if is_negative {
1025 float = -float;
1026 }
1027 Some((float, count))
1028}
1029
1030#[must_use]
1032#[inline(always)]
1033pub fn parse_special<F, const FORMAT: u128>(
1034 byte: Bytes<FORMAT>,
1035 is_negative: bool,
1036 options: &Options,
1037) -> Option<F>
1038where
1039 F: LemireFloat,
1040{
1041 let length = byte.buffer_length();
1042 if let Some((float, count)) = parse_partial_special::<F, FORMAT>(byte, is_negative, options) {
1043 if count == length {
1044 return Some(float);
1045 }
1046 }
1047 None
1048}