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
48#[cfg(feature = "power-of-two")]
50macro_rules! check_radix {
51 ($format:ident) => {{
52 let format = NumberFormat::<{ $format }> {};
53 if format.error() != Error::Success {
54 return Err(Error::InvalidRadix);
55 } else if format.radix() != format.exponent_base() {
56 let valid_radix = matches!(
57 (format.radix(), format.exponent_base()),
58 (4, 2) | (8, 2) | (16, 2) | (32, 2) | (16, 4)
59 );
60 if !valid_radix {
61 return Err(Error::InvalidRadix);
62 }
63 }
64 }};
65}
66
67#[cfg(not(feature = "power-of-two"))]
69macro_rules! check_radix {
70 ($format:ident) => {{
71 let format = NumberFormat::<{ $format }> {};
72 if format.error() != Error::Success {
73 return Err(Error::InvalidRadix);
74 }
75 }};
76}
77
78pub trait ParseFloat: LemireFloat {
80 #[cfg_attr(not(feature = "compact"), inline(always))]
82 fn parse_complete<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<Self> {
83 check_radix!(FORMAT);
84 parse_complete::<Self, FORMAT>(bytes, options)
85 }
86
87 #[cfg_attr(not(feature = "compact"), inline(always))]
89 fn parse_partial<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<(Self, usize)> {
90 check_radix!(FORMAT);
91 parse_partial::<Self, FORMAT>(bytes, options)
92 }
93
94 #[cfg_attr(not(feature = "compact"), inline(always))]
97 fn fast_path_complete<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<Self> {
98 check_radix!(FORMAT);
99 fast_path_complete::<Self, FORMAT>(bytes, options)
100 }
101
102 #[cfg_attr(not(feature = "compact"), inline(always))]
105 fn fast_path_partial<const FORMAT: u128>(
106 bytes: &[u8],
107 options: &Options,
108 ) -> Result<(Self, usize)> {
109 check_radix!(FORMAT);
110 fast_path_partial::<Self, FORMAT>(bytes, options)
111 }
112}
113
114macro_rules! parse_float_impl {
115 ($($t:ty)*) => ($(
116 impl ParseFloat for $t {}
117 )*)
118}
119
120parse_float_impl! { f32 f64 }
121
122#[cfg(feature = "f16")]
123macro_rules! parse_float_as_f32 {
124 ($($t:ty)*) => ($(
125 impl ParseFloat for $t {
126 #[cfg_attr(not(feature = "compact"), inline(always))]
127 fn parse_complete<const FORMAT: u128>(bytes: &[u8], options: &Options)
128 -> Result<Self>
129 {
130 Ok(Self::from_f32(parse_complete::<f32, FORMAT>(bytes, options)?))
131 }
132
133 #[cfg_attr(not(feature = "compact"), inline(always))]
134 fn parse_partial<const FORMAT: u128>(bytes: &[u8], options: &Options)
135 -> Result<(Self, usize)>
136 {
137 let (float, count) = parse_partial::<f32, FORMAT>(bytes, options)?;
138 Ok((Self::from_f32(float), count))
139 }
140
141 #[cfg_attr(not(feature = "compact"), inline(always))]
142 fn fast_path_complete<const FORMAT: u128>(bytes: &[u8], options: &Options)
143 -> Result<Self>
144 {
145 Ok(Self::from_f32(fast_path_complete::<f32, FORMAT>(bytes, options)?))
146 }
147
148 #[cfg_attr(not(feature = "compact"), inline(always))]
149 fn fast_path_partial<const FORMAT: u128>(bytes: &[u8], options: &Options)
150 -> Result<(Self, usize)>
151 {
152 let (float, count) = fast_path_partial::<f32, FORMAT>(bytes, options)?;
153 Ok((Self::from_f32(float), count))
154 }
155 }
156 )*)
157}
158
159#[cfg(feature = "f16")]
160parse_float_as_f32! { bf16 f16 }
161
162#[cfg_attr(not(feature = "compact"), inline(always))]
173pub fn parse_mantissa_sign<const FORMAT: u128>(byte: &mut Bytes<'_, FORMAT>) -> Result<bool> {
174 let format = NumberFormat::<{ FORMAT }> {};
175 parse_sign!(
176 byte,
177 true,
178 format.no_positive_mantissa_sign(),
179 format.required_mantissa_sign(),
180 InvalidPositiveSign,
181 MissingSign
182 )
183}
184
185#[cfg_attr(not(feature = "compact"), inline(always))]
187pub fn parse_exponent_sign<const FORMAT: u128>(byte: &mut Bytes<'_, FORMAT>) -> Result<bool> {
188 let format = NumberFormat::<{ FORMAT }> {};
189 parse_sign!(
190 byte,
191 true,
192 format.no_positive_exponent_sign(),
193 format.required_exponent_sign(),
194 InvalidPositiveExponentSign,
195 MissingExponentSign
196 )
197}
198
199macro_rules! parse_number {
207 (
208 $format:ident,
209 $byte:ident,
210 $is_negative:ident,
211 $options:ident,
212 $parse_normal:ident,
213 $parse_special:ident
214 ) => {{
215 match $parse_normal::<$format>($byte.clone(), $is_negative, $options) {
216 Ok(n) => n,
217 Err(e) => {
218 if let Some(value) =
219 $parse_special::<_, $format>($byte.clone(), $is_negative, $options)
220 {
221 return Ok(value);
222 } else {
223 return Err(e);
224 }
225 },
226 }
227 }};
228}
229
230macro_rules! to_native {
235 ($type:ident, $fp:ident, $is_negative:ident) => {{
236 let mut float = extended_to_float::<$type>($fp);
237 if $is_negative {
238 float = -float;
239 }
240 float
241 }};
242}
243
244#[inline(always)]
246#[allow(clippy::missing_inline_in_public_items)] pub fn parse_complete<F: LemireFloat, const FORMAT: u128>(
248 bytes: &[u8],
249 options: &Options,
250) -> Result<F> {
251 let mut byte = bytes.bytes::<{ FORMAT }>();
252 let is_negative = parse_mantissa_sign(&mut byte)?;
253 if byte.integer_iter().is_consumed() {
254 if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
255 || NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
256 {
257 return Err(Error::Empty(byte.cursor()));
258 } else {
259 return Ok(F::ZERO);
260 }
261 }
262
263 let num: Number<'_> =
265 parse_number!(FORMAT, byte, is_negative, options, parse_complete_number, parse_special);
266 if let Some(value) = num.try_fast_path::<_, FORMAT>() {
268 return Ok(value);
269 }
270 let mut fp = moderate_path::<F, FORMAT>(&num, options.lossy());
272
273 if fp.exp < 0 {
277 debug_assert!(!options.lossy(), "lossy algorithms never use slow algorithms");
278 fp.exp -= shared::INVALID_FP;
280 fp = slow_path::<F, FORMAT>(num, fp);
281 }
282
283 Ok(to_native!(F, fp, is_negative))
285}
286
287#[inline(always)]
289#[allow(clippy::missing_inline_in_public_items)] pub fn fast_path_complete<F: LemireFloat, const FORMAT: u128>(
291 bytes: &[u8],
292 options: &Options,
293) -> Result<F> {
294 let mut byte = bytes.bytes::<{ FORMAT }>();
295 let is_negative = parse_mantissa_sign(&mut byte)?;
296 if byte.integer_iter().is_consumed() {
297 if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
298 || NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
299 {
300 return Err(Error::Empty(byte.cursor()));
301 } else {
302 return Ok(F::ZERO);
303 }
304 }
305
306 let num =
308 parse_number!(FORMAT, byte, is_negative, options, parse_complete_number, parse_special);
309 Ok(num.force_fast_path::<_, FORMAT>())
310}
311
312#[inline(always)]
314#[allow(clippy::missing_inline_in_public_items)] pub fn parse_partial<F: LemireFloat, const FORMAT: u128>(
316 bytes: &[u8],
317 options: &Options,
318) -> Result<(F, usize)> {
319 let mut byte = bytes.bytes::<{ FORMAT }>();
320 let is_negative = parse_mantissa_sign(&mut byte)?;
321 if byte.integer_iter().is_consumed() {
322 if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
323 || NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
324 {
325 return Err(Error::Empty(byte.cursor()));
326 } else {
327 return Ok((F::ZERO, byte.cursor()));
328 }
329 }
330
331 let (num, count) = parse_number!(
333 FORMAT,
334 byte,
335 is_negative,
336 options,
337 parse_partial_number,
338 parse_partial_special
339 );
340 if let Some(value) = num.try_fast_path::<_, FORMAT>() {
342 return Ok((value, count));
343 }
344 let mut fp = moderate_path::<F, FORMAT>(&num, options.lossy());
346
347 if fp.exp < 0 {
351 debug_assert!(!options.lossy(), "lossy algorithms never use slow algorithms");
352 fp.exp -= shared::INVALID_FP;
354 fp = slow_path::<F, FORMAT>(num, fp);
355 }
356
357 Ok((to_native!(F, fp, is_negative), count))
359}
360
361#[inline(always)]
363#[allow(clippy::missing_inline_in_public_items)] pub fn fast_path_partial<F: LemireFloat, const FORMAT: u128>(
365 bytes: &[u8],
366 options: &Options,
367) -> Result<(F, usize)> {
368 let mut byte = bytes.bytes::<{ FORMAT }>();
369 let is_negative = parse_mantissa_sign(&mut byte)?;
370 if byte.integer_iter().is_consumed() {
371 if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
372 || NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
373 {
374 return Err(Error::Empty(byte.cursor()));
375 } else {
376 return Ok((F::ZERO, byte.cursor()));
377 }
378 }
379
380 let (num, count) = parse_number!(
382 FORMAT,
383 byte,
384 is_negative,
385 options,
386 parse_partial_number,
387 parse_partial_special
388 );
389 Ok((num.force_fast_path::<_, FORMAT>(), count))
390}
391
392#[must_use]
398#[inline(always)]
399pub fn moderate_path<F: LemireFloat, const FORMAT: u128>(
400 num: &Number,
401 lossy: bool,
402) -> ExtendedFloat80 {
403 #[cfg(feature = "compact")]
404 {
405 #[cfg(feature = "power-of-two")]
406 {
407 let format = NumberFormat::<{ FORMAT }> {};
408 if is_power_two!(format.mantissa_radix()) {
409 binary::<F, FORMAT>(num, lossy)
411 } else {
412 bellerophon::<F, FORMAT>(num, lossy)
413 }
414 }
415
416 #[cfg(not(feature = "power-of-two"))]
417 {
418 bellerophon::<F, FORMAT>(num, lossy)
419 }
420 }
421
422 #[cfg(not(feature = "compact"))]
423 {
424 #[cfg(feature = "radix")]
425 {
426 let format = NumberFormat::<{ FORMAT }> {};
427 let radix = format.mantissa_radix();
428 if radix == 10 {
429 lemire::<F>(num, lossy)
430 } else if is_power_two!(radix) {
431 binary::<F, FORMAT>(num, lossy)
433 } else {
434 bellerophon::<F, FORMAT>(num, lossy)
435 }
436 }
437
438 #[cfg(all(feature = "power-of-two", not(feature = "radix")))]
439 {
440 let format = NumberFormat::<{ FORMAT }> {};
441 let radix = format.mantissa_radix();
442 debug_assert!(matches!(radix, 2 | 4 | 8 | 10 | 16 | 32));
443 if radix == 10 {
444 lemire::<F>(num, lossy)
445 } else {
446 binary::<F, FORMAT>(num, lossy)
448 }
449 }
450
451 #[cfg(not(feature = "power-of-two"))]
452 {
453 lemire::<F>(num, lossy)
454 }
455 }
456}
457
458#[must_use]
461#[inline(always)]
462pub fn slow_path<F: LemireFloat, const FORMAT: u128>(
463 num: Number,
464 fp: ExtendedFloat80,
465) -> ExtendedFloat80 {
466 #[cfg(not(feature = "power-of-two"))]
467 {
468 slow_radix::<F, FORMAT>(num, fp)
469 }
470
471 #[cfg(feature = "power-of-two")]
472 {
473 let format = NumberFormat::<{ FORMAT }> {};
474 if is_power_two!(format.mantissa_radix()) {
475 slow_binary::<F, FORMAT>(num)
476 } else {
477 slow_radix::<F, FORMAT>(num, fp)
478 }
479 }
480}
481
482#[cfg_attr(not(feature = "compact"), inline(always))]
490#[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>(
496 mut byte: Bytes<'a, FORMAT>,
497 is_negative: bool,
498 options: &Options,
499) -> Result<(Number<'a>, usize)> {
500 let format = NumberFormat::<{ FORMAT }> {};
529 let decimal_point = options.decimal_point();
530 let exponent_character = options.exponent();
531 debug_assert!(format.is_valid(), "should have already checked for an invalid number format");
532 debug_assert!(!byte.is_buffer_empty(), "should have previously checked for empty input");
533 let bits_per_digit = shared::log2(format.mantissa_radix()) as i64;
534 let bits_per_base = shared::log2(format.exponent_base()) as i64;
535
536 #[allow(unused_variables)]
540 let mut is_prefix = false;
541 #[cfg(feature = "format")]
542 {
543 let base_prefix = format.base_prefix();
544 let mut iter = byte.integer_iter();
545 if base_prefix != 0 && iter.read_if_value_cased(b'0').is_some() {
546 is_prefix = true;
551 if iter.read_if_value(base_prefix, format.case_sensitive_base_prefix()).is_some()
552 && iter.is_buffer_empty()
553 && format.required_integer_digits()
554 {
555 return Err(Error::EmptyInteger(iter.cursor()));
556 }
557 }
558 }
559
560 let mut mantissa = 0_u64;
562 let start = byte.clone();
563 #[cfg(not(feature = "compact"))]
564 parse_8digits::<_, FORMAT>(byte.integer_iter(), &mut mantissa);
565 parse_digits(byte.integer_iter(), format.mantissa_radix(), |digit| {
566 mantissa = mantissa.wrapping_mul(format.radix() as u64).wrapping_add(digit as u64);
567 });
568 let mut n_digits = byte.current_count() - start.current_count();
569 #[cfg(feature = "format")]
570 if format.required_integer_digits() && n_digits == 0 {
571 return Err(Error::EmptyInteger(byte.cursor()));
572 }
573
574 let b_digits = if cfg!(feature = "format") && !byte.integer_iter().is_contiguous() {
580 byte.cursor() - start.cursor()
581 } else {
582 n_digits
583 };
584 debug_assert!(
585 b_digits <= start.as_slice().len(),
586 "number of digits parsed must <= buffer length"
587 );
588 let integer_digits = unsafe { start.as_slice().get_unchecked(..b_digits) };
598
599 #[cfg(feature = "format")]
601 if !is_prefix && format.no_float_leading_zeros() {
602 if integer_digits.len() > 1 && integer_digits.first() == Some(&b'0') {
603 return Err(Error::InvalidLeadingZeros(start.cursor()));
604 }
605 }
606
607 let mut n_after_dot = 0;
611 let mut exponent = 0_i64;
612 let mut implicit_exponent: i64;
613 let int_end = n_digits as i64;
614 let mut fraction_digits = None;
615 let has_decimal = byte.first_is_cased(decimal_point);
616 if has_decimal {
617 unsafe { byte.step_unchecked() };
619 let before = byte.clone();
620 #[cfg(not(feature = "compact"))]
621 parse_8digits::<_, FORMAT>(byte.fraction_iter(), &mut mantissa);
622 parse_digits(byte.fraction_iter(), format.mantissa_radix(), |digit| {
623 mantissa = mantissa.wrapping_mul(format.radix() as u64).wrapping_add(digit as u64);
624 });
625 n_after_dot = byte.current_count() - before.current_count();
626 let b_after_dot = if cfg!(feature = "format") && !byte.fraction_iter().is_contiguous() {
631 byte.cursor() - before.cursor()
632 } else {
633 n_after_dot
634 };
635
636 debug_assert!(
638 b_after_dot <= before.as_slice().len(),
639 "digits after dot must be smaller than buffer"
640 );
641 fraction_digits = Some(unsafe { before.as_slice().get_unchecked(..b_after_dot) });
643
644 implicit_exponent = -(n_after_dot as i64);
646 if format.mantissa_radix() == format.exponent_base() {
647 exponent = implicit_exponent;
648 } else {
649 debug_assert!(bits_per_digit % bits_per_base == 0, "exponent must be a power of base");
650 exponent = implicit_exponent * bits_per_digit / bits_per_base;
651 };
652 #[cfg(feature = "format")]
653 if format.required_fraction_digits() && n_after_dot == 0 {
654 return Err(Error::EmptyFraction(byte.cursor()));
655 }
656 }
657
658 let has_exponent = byte
661 .first_is(exponent_character, format.case_sensitive_exponent() && cfg!(feature = "format"));
662
663 n_digits += n_after_dot;
665 if format.required_mantissa_digits()
666 && (n_digits == 0 || (cfg!(feature = "format") && byte.current_count() == 0))
667 {
668 let any_digits = start.clone().integer_iter().peek().is_some();
669 if has_decimal || has_exponent || !any_digits || IS_PARTIAL {
672 return Err(Error::EmptyMantissa(byte.cursor()));
673 } else {
674 return Err(Error::InvalidDigit(start.cursor()));
675 }
676 }
677
678 let mut explicit_exponent = 0_i64;
682 if has_exponent {
683 unsafe { byte.step_unchecked() };
688
689 #[cfg(feature = "format")]
691 {
692 if format.no_exponent_notation() {
694 return Err(Error::InvalidExponent(byte.cursor() - 1));
695 }
696 if format.no_exponent_without_fraction() && fraction_digits.is_none() {
698 return Err(Error::ExponentWithoutFraction(byte.cursor() - 1));
699 }
700 }
701
702 let is_negative_exponent = parse_exponent_sign(&mut byte)?;
703 let before = byte.current_count();
704 parse_digits(byte.exponent_iter(), format.exponent_radix(), |digit| {
705 if explicit_exponent < 0x10000000 {
706 explicit_exponent *= format.exponent_radix() as i64;
707 explicit_exponent += digit as i64;
708 }
709 });
710 if format.required_exponent_digits() && byte.current_count() - before == 0 {
711 return Err(Error::EmptyExponent(byte.cursor()));
712 }
713 explicit_exponent = if is_negative_exponent {
715 -explicit_exponent
716 } else {
717 explicit_exponent
718 };
719 exponent += explicit_exponent;
720 } else if cfg!(feature = "format") && format.required_exponent_notation() {
721 return Err(Error::MissingExponent(byte.cursor()));
722 }
723
724 #[allow(unused_variables)]
728 let base_suffix = format.base_suffix();
729 #[cfg(feature = "format")]
730 if base_suffix != 0 {
731 if byte.first_is(base_suffix, format.case_sensitive_base_suffix()) {
732 unsafe { byte.step_unchecked() };
734 }
735 }
736
737 let end = byte.cursor();
741 let mut step = u64_step(format.mantissa_radix());
742 let mut many_digits = false;
743 #[cfg(feature = "format")]
744 if !format.required_mantissa_digits() && n_digits == 0 {
745 exponent = 0;
746 }
747 if n_digits <= step {
748 return Ok((
749 Number {
750 exponent,
751 mantissa,
752 is_negative,
753 many_digits: false,
754 integer: integer_digits,
755 fraction: fraction_digits,
756 },
757 end,
758 ));
759 }
760
761 n_digits -= step;
763 let mut zeros = start.clone();
764 let mut zeros_integer = zeros.integer_iter();
765 n_digits = n_digits.saturating_sub(zeros_integer.skip_zeros());
766 if zeros.first_is_cased(decimal_point) {
767 unsafe { zeros.step_unchecked() };
769 }
770 let mut zeros_fraction = zeros.fraction_iter();
771 n_digits = n_digits.saturating_sub(zeros_fraction.skip_zeros());
772
773 if n_digits > 0 {
777 many_digits = true;
779 mantissa = 0;
780 let mut integer = integer_digits.bytes::<{ FORMAT }>();
781 let mut integer_iter = integer.integer_iter();
783 integer_iter.skip_zeros();
784 parse_u64_digits::<_, FORMAT>(integer_iter, &mut mantissa, &mut step);
785 implicit_exponent = if step == 0
794 || (cfg!(feature = "format") && !byte.is_contiguous() && fraction_digits.is_none())
795 {
796 int_end - integer.current_count() as i64
798 } else {
799 let mut fraction = fraction_digits.unwrap().bytes::<{ FORMAT }>();
805 let mut fraction_iter = fraction.fraction_iter();
806 if mantissa == 0 {
808 fraction_iter.skip_zeros();
809 }
810 parse_u64_digits::<_, FORMAT>(fraction_iter, &mut mantissa, &mut step);
811 -(fraction.current_count() as i64)
812 };
813 if format.mantissa_radix() == format.exponent_base() {
814 exponent = implicit_exponent;
815 } else {
816 debug_assert!(bits_per_digit % bits_per_base == 0, "exponent must be a power of base");
817 exponent = implicit_exponent * bits_per_digit / bits_per_base;
818 };
819 exponent += explicit_exponent;
821 }
822
823 Ok((
824 Number {
825 exponent,
826 mantissa,
827 is_negative,
828 many_digits,
829 integer: integer_digits,
830 fraction: fraction_digits,
831 },
832 end,
833 ))
834}
835
836#[inline(always)]
837pub fn parse_partial_number<'a, const FORMAT: u128>(
838 byte: Bytes<'a, FORMAT>,
839 is_negative: bool,
840 options: &Options,
841) -> Result<(Number<'a>, usize)> {
842 parse_number::<FORMAT, true>(byte, is_negative, options)
843}
844
845#[inline(always)]
847pub fn parse_complete_number<'a, const FORMAT: u128>(
848 byte: Bytes<'a, FORMAT>,
849 is_negative: bool,
850 options: &Options,
851) -> Result<Number<'a>> {
852 let length = byte.buffer_length();
854 let (float, count) = parse_number::<FORMAT, false>(byte, is_negative, options)?;
855 if count == length {
856 Ok(float)
857 } else {
858 Err(Error::InvalidDigit(count))
859 }
860}
861
862#[inline(always)]
867pub fn parse_digits<'a, Iter, Cb>(mut iter: Iter, radix: u32, mut cb: Cb)
868where
869 Iter: DigitsIter<'a>,
870 Cb: FnMut(u32),
871{
872 while let Some(&c) = iter.peek() {
873 match char_to_digit_const(c, radix) {
874 Some(v) => cb(v),
875 None => break,
876 }
877 unsafe { iter.step_unchecked() };
881 iter.increment_count();
882 }
883}
884
885#[inline(always)]
891#[cfg(not(feature = "compact"))]
892pub fn parse_8digits<'a, Iter, const FORMAT: u128>(mut iter: Iter, mantissa: &mut u64)
893where
894 Iter: DigitsIter<'a>,
895{
896 let format = NumberFormat::<{ FORMAT }> {};
897 let radix: u64 = format.radix() as u64;
898 if can_try_parse_multidigit!(iter, radix) {
899 debug_assert!(radix < 16, "radices over 16 will overflow with radix^8");
900 let radix8 = format.radix8() as u64;
901 while let Some(v) = algorithm::try_parse_8digits::<u64, _, FORMAT>(&mut iter) {
904 *mantissa = mantissa.wrapping_mul(radix8).wrapping_add(v);
905 }
906 }
907}
908
909#[cfg_attr(not(feature = "compact"), inline(always))]
916pub fn parse_u64_digits<'a, Iter, const FORMAT: u128>(
917 mut iter: Iter,
918 mantissa: &mut u64,
919 step: &mut usize,
920) where
921 Iter: DigitsIter<'a>,
922{
923 let format = NumberFormat::<{ FORMAT }> {};
924 let radix = format.radix() as u64;
925
926 #[cfg(not(feature = "compact"))]
928 if can_try_parse_multidigit!(iter, radix) {
929 debug_assert!(radix < 16, "radices over 16 will overflow with radix^8");
930 let radix8 = format.radix8() as u64;
931 while *step > 8 {
932 if let Some(v) = algorithm::try_parse_8digits::<u64, _, FORMAT>(&mut iter) {
933 *mantissa = mantissa.wrapping_mul(radix8).wrapping_add(v);
934 *step -= 8;
935 } else {
936 break;
937 }
938 }
939 }
940
941 while let Some(&c) = iter.peek() {
943 if *step > 0 {
944 let digit = char_to_valid_digit_const(c, radix as u32);
945 *mantissa = *mantissa * radix + digit as u64;
946 *step -= 1;
947 unsafe { iter.step_unchecked() };
949 iter.increment_count();
950 } else {
951 break;
952 }
953 }
954}
955
956#[must_use]
962#[inline(always)]
963pub fn is_special_eq<const FORMAT: u128>(mut byte: Bytes<FORMAT>, string: &'static [u8]) -> usize {
964 let format = NumberFormat::<{ FORMAT }> {};
965 if cfg!(feature = "format") && format.case_sensitive_special() {
966 if shared::starts_with(byte.special_iter(), string.iter()) {
967 byte.special_iter().peek();
969 return byte.cursor();
970 }
971 } else if shared::starts_with_uncased(byte.special_iter(), string.iter()) {
972 byte.special_iter().peek();
974 return byte.cursor();
975 }
976 0
977}
978
979#[must_use]
981#[cfg_attr(not(feature = "compact"), inline(always))]
982pub fn parse_positive_special<F, const FORMAT: u128>(
983 byte: Bytes<FORMAT>,
984 options: &Options,
985) -> Option<(F, usize)>
986where
987 F: LemireFloat,
988{
989 let format = NumberFormat::<{ FORMAT }> {};
990 if cfg!(feature = "format") && format.no_special() {
991 return None;
992 }
993
994 let cursor = byte.cursor();
995 let length = byte.buffer_length() - cursor;
996 if let Some(nan_string) = options.nan_string() {
997 if length >= nan_string.len() {
998 let count = is_special_eq::<FORMAT>(byte.clone(), nan_string);
999 if count != 0 {
1000 return Some((F::NAN, count));
1001 }
1002 }
1003 }
1004 if let Some(infinity_string) = options.infinity_string() {
1005 if length >= infinity_string.len() {
1006 let count = is_special_eq::<FORMAT>(byte.clone(), infinity_string);
1007 if count != 0 {
1008 return Some((F::INFINITY, count));
1009 }
1010 }
1011 }
1012 if let Some(inf_string) = options.inf_string() {
1013 if length >= inf_string.len() {
1014 let count = is_special_eq::<FORMAT>(byte.clone(), inf_string);
1015 if count != 0 {
1016 return Some((F::INFINITY, count));
1017 }
1018 }
1019 }
1020
1021 None
1022}
1023
1024#[must_use]
1026#[inline(always)]
1027pub fn parse_partial_special<F, const FORMAT: u128>(
1028 byte: Bytes<FORMAT>,
1029 is_negative: bool,
1030 options: &Options,
1031) -> Option<(F, usize)>
1032where
1033 F: LemireFloat,
1034{
1035 let (mut float, count) = parse_positive_special::<F, FORMAT>(byte, options)?;
1036 if is_negative {
1037 float = -float;
1038 }
1039 Some((float, count))
1040}
1041
1042#[must_use]
1044#[inline(always)]
1045pub fn parse_special<F, const FORMAT: u128>(
1046 byte: Bytes<FORMAT>,
1047 is_negative: bool,
1048 options: &Options,
1049) -> Option<F>
1050where
1051 F: LemireFloat,
1052{
1053 let length = byte.buffer_length();
1054 if let Some((float, count)) = parse_partial_special::<F, FORMAT>(byte, is_negative, options) {
1055 if count == length {
1056 return Some(float);
1057 }
1058 }
1059 None
1060}