summary refs log tree commit diff
path: root/src/libstd/num/strconv.rs
diff options
context:
space:
mode:
authorBrendan Zabarauskas <bjzaba@yahoo.com.au>2014-11-02 21:39:55 +1100
committerBrendan Zabarauskas <bjzaba@yahoo.com.au>2014-11-04 00:20:37 +1100
commit84f4b58eeb12f1fcf46c67029f09a21dd6506b22 (patch)
tree6eb2b472850a060fdccd8edf9b252411c7ae2774 /src/libstd/num/strconv.rs
parent251fdc877c0b2e3fdff61cbe083d1ba513f8e11b (diff)
downloadrust-84f4b58eeb12f1fcf46c67029f09a21dd6506b22.tar.gz
rust-84f4b58eeb12f1fcf46c67029f09a21dd6506b22.zip
Clean up from_str_float and use iterators
Diffstat (limited to 'src/libstd/num/strconv.rs')
-rw-r--r--src/libstd/num/strconv.rs281
1 files changed, 125 insertions, 156 deletions
diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs
index 07468c37026..0e8d5bc5ba2 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<T: Int>(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<T: Float>(
         _ => ()
     }
 
-    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<T: Float>(
 
     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<T: Float>(
                 (num, 0i32)
             } else {
                 let (exp, exp_base) = match exp_format {
-                    ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
-                    ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
+                    ExpDec => (num.abs().log10().floor(), num::cast::<f64, T>(10.0f64).unwrap()),
+                    ExpBin => (num.abs().log2().floor(), num::cast::<f64, T>(2.0f64).unwrap()),
                     ExpNone => unreachable!()
                 };
 
-                (num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
+                (num / exp_base.powf(exp), num::cast::<T, i32>(exp).unwrap())
             }
         }
     };
@@ -490,163 +483,139 @@ pub fn from_str_float<T: 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 len = buf.len();
-
-    if len == 0 {
-        return None;
-    }
+    let _0: T = num::zero();
+    let _1: T = num::one();
+    let radix_gen: T = num::cast(radix as int).unwrap();
 
-    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());
-        }
+    match src {
+        "inf"   => return Some(Float::infinity()),
+        "-inf"  => return Some(Float::neg_infinity()),
+        "NaN"   => 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;
-
-        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());
-                    }
-                    if !accum_positive &&
-                        (last_accum != ((accum + cast(digit as int).unwrap())/radix_gen.clone())) {
-                        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
-            }
-        }
-
-        i += 1u;
-    }
-
-    // Parse fractional part of number
-    // Skip if already reached start of exponent
-    if !exp_found {
-        let mut power = _1.clone();
-
-        while i < len {
-            let c = buf[i] as char;
-
-            match char::to_digit(c, radix) {
+    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) => {
-                    // Decrease power one order of magnitude
-                    power = power / radix_gen;
-
-                    let digit_t: T = cast(digit).unwrap();
+                    // shift accum one digit left
+                    accum = accum * radix_gen;
 
                     // add/subtract current digit depending on sign
-                    if accum_positive {
-                        accum = accum + digit_t * power;
+                    if is_positive {
+                        accum = accum + num::cast(digit as int).unwrap();
                     } else {
-                        accum = accum - digit_t * power;
+                        accum = accum - num::cast(digit as int).unwrap();
                     }
 
-                    // 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
+                    // 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());
+                        }
                     }
-                    _ => return None             // invalid number
-                }
-            }
-
-            i += 1u;
+                    last_accum = accum;
+                },
+                None => {
+                    return None; // invalid number
+                },
+            },
         }
     }
 
-    // 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;
+    // Parse fractional part of number
+    // Skip if already reached start of exponent
+    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();
+
+                        // 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
+                    },
+                },
+            }
+        }
     }
 
-    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::<int>(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::<int>(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<T: Int>(src: &str, radix: uint) -> Option<T> {
     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<T: Int>(src: &str, radix: uint) -> Option<T> {
     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<T: Int>(src: &str, radix: uint) -> Option<T> {
                 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<T: Int>(src: &str, radix: uint) -> Option<T> {
                 Some(result) => result,
                 None => return None,
             };
-            result = match result.checked_add(&x) {
+            result = match result.checked_sub(&x) {
                 Some(result) => result,
                 None => return None,
             };