Remove iterator overgeneralization from lexical

This commit is contained in:
David Tolnay 2020-06-05 21:57:30 -07:00
parent a65034cfef
commit 5b6215bbee
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
4 changed files with 40 additions and 56 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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)
}
}

View File

@ -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]