#![cfg(not(feature = "compact"))]
#![doc(hidden)]
use crate::shared::is_overflow;
use lexical_util::digit::char_to_digit_const;
use lexical_util::format::NumberFormat;
use lexical_util::iterator::{AsBytes, BytesIter};
use lexical_util::num::{as_cast, Integer, UnsignedInteger};
use lexical_util::result::Result;
use lexical_util::step::min_step;
macro_rules! can_try_parse_multidigits {
($iter:expr, $radix:expr) => {
$iter.is_contiguous() && (cfg!(not(feature = "power-of-two")) || $radix <= 10)
};
}
#[rustfmt::skip]
macro_rules! parse_8digits {
(
$value:ident,
$iter:ident,
$format:ident,
$t:ident
) => {{
let radix: $t = as_cast(NumberFormat::<{ $format }>::MANTISSA_RADIX);
let radix2: $t = radix.wrapping_mul(radix);
let radix4: $t = radix2.wrapping_mul(radix2);
let radix8: $t = radix4.wrapping_mul(radix4);
while let Some(val8) = try_parse_8digits::<$t, _, $format>(&mut $iter) {
$value = $value.wrapping_mul(radix8);
$value = $value.wrapping_add(val8);
}
}};
}
#[rustfmt::skip]
macro_rules! parse_4digits {
(
$value:ident,
$iter:ident,
$format:ident,
$t:ident
) => {{
let radix: $t = as_cast(NumberFormat::<{ $format }>::MANTISSA_RADIX);
let radix2: $t = radix.wrapping_mul(radix);
let radix4: $t = radix2.wrapping_mul(radix2);
while let Some(val4) = try_parse_4digits::<$t, _, $format>(&mut $iter) {
$value = $value.wrapping_mul(radix4);
$value = $value.wrapping_add(val4);
}
}};
}
#[rustfmt::skip]
macro_rules! parse_digits {
(
$value:ident,
$iter:ident,
$format:ident,
$is_negative:ident,
$start_index:ident,
$t:ident,
$u:ident,
$invalid_digit:ident
) => {{
let radix = NumberFormat::<{ $format }>::MANTISSA_RADIX;
if <$t>::BITS == 128 && can_try_parse_multidigits!($iter, radix) {
parse_8digits!($value, $iter, $format, $u);
}
if <$t>::BITS == 64 && can_try_parse_multidigits!($iter, radix) && !<$t>::IS_SIGNED {
parse_8digits!($value, $iter, $format, $u);
}
if <$t>::BITS == 32 && can_try_parse_multidigits!($iter, radix) && !<$t>::IS_SIGNED {
parse_4digits!($value, $iter, $format, $u);
}
parse_1digit!($value, $iter, $format, $is_negative, $start_index, $t, $u, $invalid_digit)
}};
}
#[inline]
pub fn algorithm_complete<T, Unsigned, const FORMAT: u128>(bytes: &[u8]) -> Result<T>
where
T: Integer,
Unsigned: UnsignedInteger,
{
algorithm!(bytes, FORMAT, T, Unsigned, parse_digits, invalid_digit_complete, into_ok_complete)
}
#[inline]
pub fn algorithm_partial<T, Unsigned, const FORMAT: u128>(bytes: &[u8]) -> Result<(T, usize)>
where
T: Integer,
Unsigned: UnsignedInteger,
{
algorithm!(bytes, FORMAT, T, Unsigned, parse_digits, invalid_digit_partial, into_ok_partial)
}
#[inline]
pub fn is_4digits<const FORMAT: u128>(v: u32) -> bool {
let radix = NumberFormat::<{ FORMAT }>::MANTISSA_RADIX;
debug_assert!(radix <= 10);
let add = 0x46 + 10 - radix;
let add = add + (add << 8) + (add << 16) + (add << 24);
let sub = 0x3030_3030;
let a = v.wrapping_add(add);
let b = v.wrapping_sub(sub);
(a | b) & 0x8080_8080 == 0
}
#[inline]
pub fn parse_4digits<const FORMAT: u128>(mut v: u32) -> u32 {
let radix = NumberFormat::<{ FORMAT }>::MANTISSA_RADIX;
debug_assert!(radix <= 10);
v -= 0x3030_3030;
v = (v * radix) + (v >> 8);
v = ((v & 0x0000007f) * radix * radix) + ((v >> 16) & 0x0000007f);
v
}
#[inline]
pub fn try_parse_4digits<'a, T, Iter, const FORMAT: u128>(iter: &mut Iter) -> Option<T>
where
T: Integer,
Iter: BytesIter<'a>,
{
debug_assert!(NumberFormat::<{ FORMAT }>::MANTISSA_RADIX <= 10);
debug_assert!(Iter::IS_CONTIGUOUS);
let bytes = u32::from_le(iter.read::<u32>()?);
if is_4digits::<FORMAT>(bytes) {
unsafe { iter.step_by_unchecked(4) };
Some(T::as_cast(parse_4digits::<FORMAT>(bytes)))
} else {
None
}
}
#[inline]
pub fn is_8digits<const FORMAT: u128>(v: u64) -> bool {
let radix = NumberFormat::<{ FORMAT }>::MANTISSA_RADIX;
debug_assert!(radix <= 10);
let add = 0x46 + 10 - radix;
let add = add + (add << 8) + (add << 16) + (add << 24);
let add = (add as u64) | ((add as u64) << 32);
let sub = 0x3030_3030_3030_3030;
let a = v.wrapping_add(add);
let b = v.wrapping_sub(sub);
(a | b) & 0x8080_8080_8080_8080 == 0
}
#[inline]
pub fn parse_8digits<const FORMAT: u128>(mut v: u64) -> u64 {
let radix = NumberFormat::<{ FORMAT }>::MANTISSA_RADIX as u64;
debug_assert!(radix <= 10);
let radix2 = radix * radix;
let radix4 = radix2 * radix2;
let radix6 = radix2 * radix4;
let mask = 0x0000_00FF_0000_00FFu64;
let mul1 = radix2 + (radix6 << 32);
let mul2 = 1 + (radix4 << 32);
v -= 0x3030_3030_3030_3030;
v = (v * radix) + (v >> 8);
let v1 = (v & mask).wrapping_mul(mul1);
let v2 = ((v >> 16) & mask).wrapping_mul(mul2);
((v1.wrapping_add(v2) >> 32) as u32) as u64
}
#[inline]
pub fn try_parse_8digits<'a, T, Iter, const FORMAT: u128>(iter: &mut Iter) -> Option<T>
where
T: Integer,
Iter: BytesIter<'a>,
{
debug_assert!(NumberFormat::<{ FORMAT }>::MANTISSA_RADIX <= 10);
debug_assert!(Iter::IS_CONTIGUOUS);
let bytes = u64::from_le(iter.read::<u64>()?);
if is_8digits::<FORMAT>(bytes) {
unsafe { iter.step_by_unchecked(8) };
Some(T::as_cast(parse_8digits::<FORMAT>(bytes)))
} else {
None
}
}