From 84f4b58eeb12f1fcf46c67029f09a21dd6506b22 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sun, 2 Nov 2014 21:39:55 +1100 Subject: [PATCH] Clean up from_str_float and use iterators --- src/libstd/num/strconv.rs | 279 +++++++++++++++++--------------------- 1 file changed, 124 insertions(+), 155 deletions(-) diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 07468c370263..0e8d5bc5ba22 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -14,15 +14,14 @@ use char; use char::Char; -use clone::Clone; use from_str::from_str; use iter::Iterator; use num; -use num::{Zero, One, cast, Int, Bounded}; +use num::{Int, Bounded}; use num::{Float, FPNaN, FPInfinite, ToPrimitive}; use option::{None, Option, Some}; use slice::{ImmutableSlice, MutableSlice, CloneableVector}; -use str::{Str, StrSlice}; +use str::StrSlice; use string::String; use vec::Vec; @@ -68,12 +67,6 @@ pub enum SignFormat { SignAll, } -// Special value strings as [u8] consts. -static INF_BUF: [u8, ..3] = [b'i', b'n', b'f']; -static POS_INF_BUF: [u8, ..4] = [b'+', b'i', b'n', b'f']; -static NEG_INF_BUF: [u8, ..4] = [b'-', b'i', b'n', b'f']; -static NAN_BUF: [u8, ..3] = [b'N', b'a', b'N']; - /** * Converts an integral number to its string representation as a byte vector. * This is meant to be a common base implementation for all integral string @@ -102,10 +95,10 @@ static NAN_BUF: [u8, ..3] = [b'N', b'a', b'N']; fn int_to_str_bytes_common(num: T, radix: uint, sign: SignFormat, f: |u8|) { assert!(2 <= radix && radix <= 36); - let _0: T = Zero::zero(); + let _0: T = num::zero(); let neg = num < _0; - let radix_gen: T = cast(radix).unwrap(); + let radix_gen: T = num::cast(radix).unwrap(); let mut deccum = num; // This is just for integral types, the largest of which is a u64. The @@ -202,8 +195,8 @@ pub fn float_to_str_bytes_common( _ => () } - let _0: T = Zero::zero(); - let _1: T = One::one(); + let _0: T = num::zero(); + let _1: T = num::one(); match num.classify() { FPNaN => { return (b"NaN".to_vec(), true); } @@ -224,7 +217,7 @@ pub fn float_to_str_bytes_common( let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity()); let mut buf = Vec::new(); - let radix_gen: T = cast(radix as int).unwrap(); + let radix_gen: T = num::cast(radix as int).unwrap(); let (num, exp) = match exp_format { ExpNone => (num, 0i32), @@ -233,12 +226,12 @@ pub fn float_to_str_bytes_common( (num, 0i32) } else { let (exp, exp_base) = match exp_format { - ExpDec => (num.abs().log10().floor(), cast::(10.0f64).unwrap()), - ExpBin => (num.abs().log2().floor(), cast::(2.0f64).unwrap()), + ExpDec => (num.abs().log10().floor(), num::cast::(10.0f64).unwrap()), + ExpBin => (num.abs().log2().floor(), num::cast::(2.0f64).unwrap()), ExpNone => unreachable!() }; - (num / exp_base.powf(exp), cast::(exp).unwrap()) + (num / exp_base.powf(exp), num::cast::(exp).unwrap()) } } }; @@ -490,163 +483,139 @@ pub fn from_str_float( _ => () } - let _0: T = Zero::zero(); - let _1: T = One::one(); - let radix_gen: T = cast(radix as int).unwrap(); - let buf = src.as_bytes(); + let _0: T = num::zero(); + let _1: T = num::one(); + let radix_gen: T = num::cast(radix as int).unwrap(); - let len = buf.len(); - - if len == 0 { - return None; + match src { + "inf" => return Some(Float::infinity()), + "-inf" => return Some(Float::neg_infinity()), + "NaN" => return Some(Float::nan()), + _ => {}, } - if special { - if buf == INF_BUF || buf == POS_INF_BUF { - return Some(Float::infinity()); - } else if buf == NEG_INF_BUF { - return Some(Float::neg_infinity()); - } else if buf == NAN_BUF { - return Some(Float::nan()); - } - } - - let (start, accum_positive) = match buf[0] as char { - '-' => (1u, false), - '+' => (1u, true), - _ => (0u, true) + let (is_positive, src) = match src.slice_shift_char() { + (None, _) => return None, + (Some('-'), "") => return None, + (Some('-'), src) => (false, src), + (Some(_), _) => (true, src), }; // Initialize accumulator with signed zero for floating point parsing to // work - let mut accum = if accum_positive { _0.clone() } else { -_1 * _0}; - let mut last_accum = accum.clone(); // Necessary to detect overflow - let mut i = start; - let mut exp_found = false; + let mut accum = if is_positive { _0 } else { -_1 }; + let mut last_accum = accum; // Necessary to detect overflow + let mut cs = src.chars().enumerate(); + let mut exp = None::<(char, uint)>; // Parse integer part of number - while i < len { - let c = buf[i] as char; + for (i, c) in cs { + match c { + 'e' | 'E' | 'p' | 'P' => { + exp = Some((c, i + 1)); + break; // start of exponent + }, + '.' => { + break; // start of fractional part + }, + c => match c.to_digit(radix) { + Some(digit) => { + // shift accum one digit left + accum = accum * radix_gen; - match char::to_digit(c, radix) { - Some(digit) => { - // shift accum one digit left - accum = accum * radix_gen.clone(); - - // add/subtract current digit depending on sign - if accum_positive { - accum = accum + cast(digit as int).unwrap(); - } else { - accum = accum - cast(digit as int).unwrap(); - } - - // Detect overflow by comparing to last value, except - // if we've not seen any non-zero digits. - if last_accum != _0 { - if accum_positive && accum <= last_accum { return Some(Float::infinity()); } - if !accum_positive && accum >= last_accum { return Some(Float::neg_infinity()); } - - // Detect overflow by reversing the shift-and-add process - if accum_positive && - (last_accum != ((accum - cast(digit as int).unwrap())/radix_gen.clone())) { - return Some(Float::infinity()); + // add/subtract current digit depending on sign + if is_positive { + accum = accum + num::cast(digit as int).unwrap(); + } else { + accum = accum - num::cast(digit as int).unwrap(); } - if !accum_positive && - (last_accum != ((accum + cast(digit as int).unwrap())/radix_gen.clone())) { - return Some(Float::neg_infinity()); + + // Detect overflow by comparing to last value, except + // if we've not seen any non-zero digits. + if last_accum != _0 { + if is_positive && accum <= last_accum { return Some(Float::infinity()); } + if !is_positive && accum >= last_accum { return Some(Float::neg_infinity()); } + + // Detect overflow by reversing the shift-and-add process + if is_positive && + (last_accum != ((accum - num::cast(digit as int).unwrap()) / radix_gen)) { + return Some(Float::infinity()); + } + if !is_positive && + (last_accum != ((accum + num::cast(digit as int).unwrap()) / radix_gen)) { + return Some(Float::neg_infinity()); + } } - } - last_accum = accum.clone(); - } - None => match c { - 'e' | 'E' | 'p' | 'P' => { - exp_found = true; - break; // start of exponent - } - '.' => { - i += 1u; // skip the '.' - break; // start of fractional part - } - _ => return None // invalid number - } + last_accum = accum; + }, + None => { + return None; // invalid number + }, + }, } - - i += 1u; } // Parse fractional part of number // Skip if already reached start of exponent - if !exp_found { - let mut power = _1.clone(); + if exp.is_none() { + let mut power = _1; + for (i, c) in cs { + match c { + 'e' | 'E' | 'p' | 'P' => { + exp = Some((c, i + 1)); + break; // start of exponent + }, + c => match c.to_digit(radix) { + Some(digit) => { + let digit: T = num::cast(digit).unwrap(); - while i < len { - let c = buf[i] as char; - - match char::to_digit(c, radix) { - Some(digit) => { - // Decrease power one order of magnitude - power = power / radix_gen; - - let digit_t: T = cast(digit).unwrap(); - - // add/subtract current digit depending on sign - if accum_positive { - accum = accum + digit_t * power; - } else { - accum = accum - digit_t * power; - } - - // Detect overflow by comparing to last value - if accum_positive && accum < last_accum { return Some(Float::infinity()); } - if !accum_positive && accum > last_accum { return Some(Float::neg_infinity()); } - last_accum = accum.clone(); - } - None => match c { - 'e' | 'E' | 'p' | 'P' => { - exp_found = true; - break; // start of exponent - } - _ => return None // invalid number - } + // Decrease power one order of magnitude + power = power / radix_gen; + // add/subtract current digit depending on sign + accum = if is_positive { + accum + digit * power + } else { + accum - digit * power + }; + // Detect overflow by comparing to last value + if is_positive && accum < last_accum { return Some(Float::infinity()); } + if !is_positive && accum > last_accum { return Some(Float::neg_infinity()); } + last_accum = accum; + }, + None => { + return None; // invalid number + }, + }, } - - i += 1u; } } - // Special case: buf not empty, but does not contain any digit in front - // of the exponent sign -> number is empty string - if i == start { - return None; - } - - let mut multiplier = _1.clone(); - - if exp_found { - let c = buf[i] as char; - let base: T = match (c, exponent) { - // c is never _ so don't need to handle specially - ('e', ExpDec) | ('E', ExpDec) => cast(10u).unwrap(), - ('p', ExpBin) | ('P', ExpBin) => cast(2u).unwrap(), - _ => return None // char doesn't fit given exponent format - }; - - // parse remaining bytes as decimal integer, - // skipping the exponent char - let exp = from_str::(String::from_utf8_lossy(buf[i+1..len]).as_slice()); - - match exp { - Some(exp_pow) => { - multiplier = if exp_pow < 0 { + let multiplier = match exp { + None => { + _1 // no exponent + }, + Some((c, offset)) => { + let base: T = match (c, exponent) { + // c is never _ so don't need to handle specially + ('e', ExpDec) | ('E', ExpDec) => num::cast(10u).unwrap(), + ('p', ExpBin) | ('P', ExpBin) => num::cast(2u).unwrap(), + _ => return None, // char doesn't fit given exponent format + }; + // parse remaining string as decimal integer + let exp = from_str::(src[offset..]); + match exp { + Some(exp_pow) if exp_pow < 0 => { _1 / num::pow(base, (-exp_pow.to_int().unwrap()) as uint) - } else { + }, + Some(exp_pow) => { num::pow(base, exp_pow.to_int().unwrap() as uint) - } + }, + None => { + return None; // invalid exponent + }, } - None => return None // invalid exponent -> invalid number - } - } - + }, + }; Some(accum * multiplier) } @@ -659,9 +628,9 @@ pub fn from_str_radix_int(src: &str, radix: uint) -> Option { let _1: T = num::one(); let is_signed = _0 > Bounded::min_value(); - let (is_negative, src) = match src.slice_shift_char() { - (Some('-'), src) if is_signed => (true, src), - (Some(_), _) => (false, src), + let (is_positive, src) = match src.slice_shift_char() { + (Some('-'), src) if is_signed => (false, src), + (Some(_), _) => (true, src), (None, _) => return None, }; @@ -671,7 +640,7 @@ pub fn from_str_radix_int(src: &str, radix: uint) -> Option { let radix = cast(radix); let mut result = _0; - if is_negative { + if is_positive { for x in xs { let x = match x { Some(x) => x, @@ -681,7 +650,7 @@ pub fn from_str_radix_int(src: &str, radix: uint) -> Option { Some(result) => result, None => return None, }; - result = match result.checked_sub(&x) { + result = match result.checked_add(&x) { Some(result) => result, None => return None, }; @@ -696,7 +665,7 @@ pub fn from_str_radix_int(src: &str, radix: uint) -> Option { Some(result) => result, None => return None, }; - result = match result.checked_add(&x) { + result = match result.checked_sub(&x) { Some(result) => result, None => return None, };