mirror of
https://github.com/serde-rs/json.git
synced 2026-02-27 18:39:09 +00:00
Remove iterator overgeneralization from lexical
This commit is contained in:
parent
a65034cfef
commit
5b6215bbee
@ -748,9 +748,9 @@ impl<'de, R: Read<'de>> Deserializer<R> {
|
||||
let fraction = &self.scratch[integer_end..];
|
||||
|
||||
let f = if self.requested_f32 {
|
||||
lexical::parse_float::<f32, _, _>(integer.iter(), fraction.iter(), exponent) as f64
|
||||
lexical::parse_float::<f32>(integer, fraction, exponent) as f64
|
||||
} else {
|
||||
lexical::parse_float::<f64, _, _>(integer.iter(), fraction.iter(), exponent)
|
||||
lexical::parse_float::<f64>(integer, fraction, exponent)
|
||||
};
|
||||
self.scratch.clear();
|
||||
|
||||
|
||||
@ -156,9 +156,9 @@ where
|
||||
///
|
||||
/// Uses the moderate path, if applicable, otherwise, uses the slow path
|
||||
/// as required.
|
||||
pub(crate) fn fallback_path<'a, F, Iter1, Iter2>(
|
||||
integer: Iter1,
|
||||
fraction: Iter2,
|
||||
pub(crate) fn fallback_path<F>(
|
||||
integer: &[u8],
|
||||
fraction: &[u8],
|
||||
mantissa: u64,
|
||||
exponent: i32,
|
||||
mantissa_exponent: i32,
|
||||
@ -166,8 +166,6 @@ pub(crate) fn fallback_path<'a, F, Iter1, Iter2>(
|
||||
) -> F
|
||||
where
|
||||
F: Float,
|
||||
Iter1: Iterator<Item = &'a u8> + Clone,
|
||||
Iter2: Iterator<Item = &'a u8> + Clone,
|
||||
{
|
||||
// Moderate path (use an extended 80-bit representation).
|
||||
let (fp, valid) = moderate_path::<F>(mantissa, mantissa_exponent, truncated);
|
||||
|
||||
@ -17,10 +17,9 @@ use crate::lib::{cmp, mem};
|
||||
/// Parse the full mantissa into a big integer.
|
||||
///
|
||||
/// Max digits is the maximum number of digits plus one.
|
||||
fn parse_mantissa<'a, F, Iter>(mut iter: Iter) -> Bigint
|
||||
fn parse_mantissa<F>(integer: &[u8], fraction: &[u8]) -> Bigint
|
||||
where
|
||||
F: Float,
|
||||
Iter: Iterator<Item = &'a u8> + Clone,
|
||||
{
|
||||
// Main loop
|
||||
let small_powers = POW10_LIMB;
|
||||
@ -32,7 +31,7 @@ where
|
||||
let mut result = Bigint::default();
|
||||
|
||||
// Iteratively process all the data in the mantissa.
|
||||
while let Some(&digit) = iter.next() {
|
||||
for &digit in integer.iter().chain(fraction) {
|
||||
// We've parsed the max digits using small values, add to bignum
|
||||
if counter == step {
|
||||
result.imul_small(small_powers[counter]);
|
||||
@ -64,8 +63,7 @@ where
|
||||
// representation. We also need to return an index.
|
||||
// Since we already trimmed trailing zeros, we know there has
|
||||
// to be a non-zero digit if there are any left.
|
||||
let is_consumed = iter.count() == 0;
|
||||
if !is_consumed {
|
||||
if i < integer.len() + fraction.len() {
|
||||
result.imul_small(10);
|
||||
result.iadd_small(1);
|
||||
}
|
||||
@ -108,10 +106,9 @@ fn round_nearest_tie_even(fp: &mut ExtendedFloat, shift: i32, is_truncated: bool
|
||||
// BHCOMP
|
||||
|
||||
/// Calculate the mantissa for a big integer with a positive exponent.
|
||||
fn large_atof<'a, F, Iter>(iter: Iter, exponent: i32) -> F
|
||||
fn large_atof<F>(mantissa: Bigint, exponent: i32) -> F
|
||||
where
|
||||
F: Float,
|
||||
Iter: Iterator<Item = &'a u8> + Clone,
|
||||
{
|
||||
let bits = mem::size_of::<u64>() * 8;
|
||||
|
||||
@ -119,7 +116,7 @@ where
|
||||
// Now, we can calculate the mantissa and the exponent from this.
|
||||
// The binary exponent is the binary exponent for the mantissa
|
||||
// shifted to the hidden bit.
|
||||
let mut bigmant = parse_mantissa::<F, _>(iter);
|
||||
let mut bigmant = mantissa;
|
||||
bigmant.imul_pow10(exponent.as_u32());
|
||||
|
||||
// Get the exact representation of the float from the big integer.
|
||||
@ -136,13 +133,12 @@ where
|
||||
/// Calculate the mantissa for a big integer with a negative exponent.
|
||||
///
|
||||
/// This invokes the comparison with `b+h`.
|
||||
fn small_atof<'a, F, Iter>(iter: Iter, exponent: i32, f: F) -> F
|
||||
fn small_atof<F>(mantissa: Bigint, exponent: i32, f: F) -> F
|
||||
where
|
||||
F: Float,
|
||||
Iter: Iterator<Item = &'a u8> + Clone,
|
||||
{
|
||||
// Get the significant digits and radix exponent for the real digits.
|
||||
let mut real_digits = parse_mantissa::<F, _>(iter);
|
||||
let mut real_digits = mantissa;
|
||||
let real_exp = exponent;
|
||||
debug_assert!(real_exp < 0);
|
||||
|
||||
@ -198,32 +194,29 @@ where
|
||||
/// The digits iterator must not have any trailing zeros (true for
|
||||
/// `FloatState2`).
|
||||
/// sci_exponent and digits.size_hint() must not overflow i32.
|
||||
pub(crate) fn bhcomp<'a, F, Iter1, Iter2>(b: F, integer: Iter1, fraction: Iter2, exponent: i32) -> F
|
||||
pub(crate) fn bhcomp<F>(b: F, integer: &[u8], mut fraction: &[u8], exponent: i32) -> F
|
||||
where
|
||||
F: Float,
|
||||
Iter1: Iterator<Item = &'a u8> + Clone,
|
||||
Iter2: Iterator<Item = &'a u8> + Clone,
|
||||
{
|
||||
// Calculate the number of integer digits and use that to determine
|
||||
// where the significant digits start in the fraction.
|
||||
let integer_digits = integer.clone().count();
|
||||
let fraction_digits = fraction.clone().count();
|
||||
let digits_start = match integer_digits {
|
||||
0 => fraction.clone().take_while(|&x| x == &b'0').count(),
|
||||
_ => 0,
|
||||
let integer_digits = integer.len();
|
||||
let fraction_digits = fraction.len();
|
||||
let digits_start = if integer_digits == 0 {
|
||||
let start = fraction.iter().take_while(|&x| *x == b'0').count();
|
||||
fraction = &fraction[start..];
|
||||
start
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let sci_exp = scientific_exponent(exponent, integer_digits, digits_start);
|
||||
let count = F::MAX_DIGITS.min(integer_digits + fraction_digits - digits_start);
|
||||
let scaled_exponent = sci_exp + 1 - count.as_i32();
|
||||
|
||||
// We have a finite conversions number of digits for base10.
|
||||
// We need to then limit the iterator over that number of digits.
|
||||
// Skip all leading zeros (can occur if fraction is empty).
|
||||
let iter = integer.chain(fraction).skip(digits_start);
|
||||
|
||||
let mantissa = parse_mantissa::<F>(integer, fraction);
|
||||
if scaled_exponent >= 0 {
|
||||
large_atof(iter, scaled_exponent)
|
||||
large_atof(mantissa, scaled_exponent)
|
||||
} else {
|
||||
small_atof(iter, scaled_exponent, b)
|
||||
small_atof(mantissa, scaled_exponent, b)
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,21 +12,19 @@ use super::num::*;
|
||||
///
|
||||
/// * `integer` - Slice containing the integer digits.
|
||||
/// * `fraction` - Slice containing the fraction digits.
|
||||
fn parse_mantissa<'a, Iter1, Iter2>(mut integer: Iter1, mut fraction: Iter2) -> (u64, usize)
|
||||
where
|
||||
Iter1: Iterator<Item = &'a u8>,
|
||||
Iter2: Iterator<Item = &'a u8>,
|
||||
{
|
||||
fn parse_mantissa(integer: &[u8], fraction: &[u8]) -> (u64, usize) {
|
||||
let mut value: u64 = 0;
|
||||
// On overflow, validate that all the remaining characters are valid
|
||||
// digits, if not, return the first invalid digit. Otherwise,
|
||||
// calculate the number of truncated digits.
|
||||
let mut integer = integer.iter();
|
||||
while let Some(c) = integer.next() {
|
||||
value = match add_digit(value, to_digit(*c).unwrap()) {
|
||||
Some(v) => v,
|
||||
None => return (value, 1 + integer.count() + fraction.count()),
|
||||
None => return (value, 1 + integer.count() + fraction.len()),
|
||||
};
|
||||
}
|
||||
let mut fraction = fraction.iter();
|
||||
while let Some(c) = fraction.next() {
|
||||
value = match add_digit(value, to_digit(*c).unwrap()) {
|
||||
Some(v) => v,
|
||||
@ -38,24 +36,19 @@ where
|
||||
|
||||
/// Parse float from extracted float components.
|
||||
///
|
||||
/// * `integer` - Cloneable, forward iterator over integer digits.
|
||||
/// * `fraction` - Cloneable, forward iterator over integer digits.
|
||||
/// * `integer` - Slice containing the integer digits.
|
||||
/// * `fraction` - Slice containing the fraction digits.
|
||||
/// * `exponent` - Parsed, 32-bit exponent.
|
||||
///
|
||||
/// # Preconditions
|
||||
/// 1). The integer should not have leading zeros.
|
||||
/// 2). The fraction should not have trailing zeros.
|
||||
///
|
||||
/// We cannot efficiently remove trailing zeros while only accepting a
|
||||
/// forward iterator.
|
||||
pub fn parse_float<'a, F, Iter1, Iter2>(integer: Iter1, fraction: Iter2, exponent: i32) -> F
|
||||
pub fn parse_float<F>(integer: &[u8], fraction: &[u8], exponent: i32) -> F
|
||||
where
|
||||
F: Float,
|
||||
Iter1: Iterator<Item = &'a u8> + Clone,
|
||||
Iter2: Iterator<Item = &'a u8> + Clone,
|
||||
{
|
||||
// Parse the mantissa and attempt the fast and moderate-path algorithms.
|
||||
let (mantissa, truncated) = parse_mantissa(integer.clone(), fraction.clone());
|
||||
let (mantissa, truncated) = parse_mantissa(integer, fraction);
|
||||
let is_truncated = truncated != 0;
|
||||
|
||||
// Process the state to a float.
|
||||
@ -66,11 +59,11 @@ where
|
||||
F::ZERO
|
||||
} else if !is_truncated {
|
||||
// Try the fast path, no mantissa truncation.
|
||||
let mant_exp = mantissa_exponent(exponent, fraction.clone().count(), 0);
|
||||
if let Some(float) = fast_path::<F>(mantissa, mant_exp) {
|
||||
let mant_exp = mantissa_exponent(exponent, fraction.len(), 0);
|
||||
if let Some(float) = fast_path(mantissa, mant_exp) {
|
||||
float
|
||||
} else {
|
||||
fallback_path::<F, _, _>(
|
||||
fallback_path(
|
||||
integer,
|
||||
fraction,
|
||||
mantissa,
|
||||
@ -80,8 +73,8 @@ where
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let mant_exp = mantissa_exponent(exponent, fraction.clone().count(), truncated);
|
||||
fallback_path::<F, _, _>(
|
||||
let mant_exp = mantissa_exponent(exponent, fraction.len(), truncated);
|
||||
fallback_path(
|
||||
integer,
|
||||
fraction,
|
||||
mantissa,
|
||||
@ -101,9 +94,9 @@ mod tests {
|
||||
use core::f64;
|
||||
|
||||
fn check_parse_float<F: Float>(integer: &str, fraction: &str, exponent: i32, expected: F) {
|
||||
let integer = integer.as_bytes().iter();
|
||||
let fraction = fraction.as_bytes().iter();
|
||||
assert!(expected == parse_float::<F, _, _>(integer, fraction, exponent));
|
||||
let integer = integer.as_bytes();
|
||||
let fraction = fraction.as_bytes();
|
||||
assert!(expected == parse_float(integer, fraction, exponent));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user