Browse Source

Cleaned out some allocations

Alan Liddell 7 years ago
parent
commit
38ee1304bb
1 changed files with 103 additions and 137 deletions
  1. 103 137
      complex/src/lib.rs

+ 103 - 137
complex/src/lib.rs

@@ -755,123 +755,89 @@ impl<T> FromStr for Complex<T> where
             _ => 'j'
         };
 
-        let mut a = String::with_capacity(s.len());
         let mut b = String::with_capacity(s.len());
-
         let mut first = true;
+
         let mut char_indices = s.char_indices();
         let mut pc = ' ';
+        let mut split_index = s.len();
 
         loop {
             match char_indices.next() {
                 Some(t) => {
                     let i = t.0;
                     let cc = t.1;
-                    if cc == '+' {
-                        // handle exponents
-                        if pc != 'e' && pc != 'E' {
+
+                    if cc == '+' && pc != 'e' && pc != 'E' {
+                        // ignore '+' if part of an exponent
+                        if first {
+                            split_index = i;
                             first = false;
-                            // don't carry '+' over into b
-                            pc = ' ';
-                            continue;
                         }
-                    } else if cc == '-' {
-                        // handle exponents and negative numbers
-                        if i > 0 && pc != 'e' && pc != 'E' {
+                        // don't carry '+' over into b
+                        pc = ' ';
+                        continue;
+                    } else if cc == '-' && pc != 'e' && pc != 'E' && i > 0 {
+                        // ignore '-' if part of an exponent or begins the string
+                        if first {
+                            split_index = i;
                             first = false;
-                            // DO carry '-' over into b
                         }
+                        // DO carry '-' over into b
                     }
 
-                    if !first && cc == ' ' && pc == '-' {
+                    if pc == '-' && cc == ' ' && !first {
                         // ignore whitespace between minus sign and next number
                         continue;
                     }
 
-                    if first {
-                        a.push(cc);
-                    } else {
+                    if !first {
                         b.push(cc);
                     }
-
                     pc = cc;
                 },
                 None => break,
             }
         }
 
-        a = a.trim_right().to_string();
-        b = b.trim_left().to_string();
-
+        // split off real and imaginary parts, trim whitespace
+        let (a, _) = s.split_at(split_index);
+        let a = a.trim_right();
+        let mut b = b.trim_left();
+        // input was either pure real or pure imaginary
         if b.is_empty() {
-            b = match a.rfind(imag) {
-                None => "0i".to_string(),
-                _ => "0".to_string()
+            b = match a.ends_with(imag) {
+                false => "0i",
+                true => "0"
             };
         }
 
-        let re = match a.rfind(imag) {
-            None => {
-                try!(T::from_str(&a)
-                    .map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
-            },
-            _ => {
-                try!(T::from_str(&b)
-                    .map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
-            }
-        };
-
-        let im = match a.rfind(imag) {
-            None => {
-                // a is real
-                match b.pop() {
-                    // b was empty
-                    None => return Err(ParseComplexError { kind: ComplexErrorKind::ParseError }),
-                    Some(c) => {
-                        if c == imag {
-                            // b is imaginary
-                            if b.is_empty() {
-                                // b was just 'imag'
-                                b = "1".to_string();
-                            } else if b == "-" {
-                                // b was just '-imag'
-                                b = "-1".to_string();
-                            }
-                        } else {
-                            // given a sum or difference of two reals
-                            return Err(ParseComplexError { kind: ComplexErrorKind::ParseError });
-                        }
-                    }
-                }
+        let re;
+        let im;
+        if a.ends_with(imag) {
+            im = a; re = b;
+        } else if b.ends_with(imag) {
+            re = a; im = b;
+        } else {
+            return Err(ParseComplexError { kind: ComplexErrorKind::ParseError });
+        }
 
-                try!(T::from_str(&b)
-                    .map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
-            },
-            _ => {
-                // a contains imag
-                match a.pop() {
-                    None => return Err(ParseComplexError { kind: ComplexErrorKind::ParseError }),
-                    Some(c) => {
-                        if c == imag {
-                            // a is imaginary
-                            if a.is_empty() {
-                                // a was just 'imag'
-                                a = "1".to_string();
-                            } else if a == "-" {
-                                // a was just '-imag'
-                                a = "-1".to_string();
-                            }
-                        } else {
-                            // given a sum or difference of two reals
-                            return Err(ParseComplexError { kind: ComplexErrorKind::ParseError });
-                        }
-                    }
-                }
+        // parse re
+        let re = try!(T::from_str(re)
+            .map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }));
+
+        // pop imaginary unit off
+        let mut im = &im[..im.len()-1];
+        // handle im == "i" or im == "-i"
+        if im.is_empty() {
+            im = "1";
+        } else if im == "-" {
+            im = "-1";
+        }
 
-                try!(T::from_str(&a)
-                    .map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
-            }
-        };
+        // parse im
+        let im = try!(T::from_str(im)
+            .map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }));
 
         Ok(Complex::new(re, im))
     }
@@ -1570,61 +1536,61 @@ mod test {
 
     #[test]
     fn test_from_str() {
-        fn test(z: Complex64, s: String) {
-            assert_eq!(FromStr::from_str(&s), Ok(z));
+        fn test(z: Complex64, s: &str) {
+            assert_eq!(FromStr::from_str(s), Ok(z));
         }
-        test(_0_0i, "0 + 0i".to_string());
-        test(_0_0i, "0+0j".to_string());
-        test(_0_0i, "0 - 0j".to_string());
-        test(_0_0i, "0-0i".to_string());
-        test(_0_0i, "0i + 0".to_string());
-        test(_0_0i, "0".to_string());
-        test(_0_0i, "-0".to_string());
-        test(_0_0i, "0i".to_string());
-        test(_0_0i, "0j".to_string());
-        test(_0_0i, "-0i".to_string());
-
-        test(_1_0i, "1 + 0i".to_string());
-        test(_1_0i, "1+0j".to_string());
-        test(_1_0i, "1 - 0j".to_string());
-        test(_1_0i, "1-0i".to_string());
-        test(_1_0i, "-0j+1".to_string());
-        test(_1_0i, "1".to_string());
-
-        test(_1_1i, "1 + i".to_string());
-        test(_1_1i, "1+j".to_string());
-        test(_1_1i, "1 + 1j".to_string());
-        test(_1_1i, "1+1i".to_string());
-        test(_1_1i, "i + 1".to_string());
-        test(_1_1i, "1i+1".to_string());
-        test(_1_1i, "j+1".to_string());
-
-        test(_0_1i, "0 + i".to_string());
-        test(_0_1i, "0+j".to_string());
-        test(_0_1i, "-0 + j".to_string());
-        test(_0_1i, "-0+i".to_string());
-        test(_0_1i, "0 + 1i".to_string());
-        test(_0_1i, "0+1j".to_string());
-        test(_0_1i, "-0 + 1j".to_string());
-        test(_0_1i, "-0+1i".to_string());
-        test(_0_1i, "j + 0".to_string());
-        test(_0_1i, "i".to_string());
-        test(_0_1i, "j".to_string());
-        test(_0_1i, "1j".to_string());
-
-        test(_neg1_1i, "-1 + i".to_string());
-        test(_neg1_1i, "-1+j".to_string());
-        test(_neg1_1i, "-1 + 1j".to_string());
-        test(_neg1_1i, "-1+1i".to_string());
-        test(_neg1_1i, "1i-1".to_string());
-        test(_neg1_1i, "j + -1".to_string());
-
-        test(_05_05i, "0.5 + 0.5i".to_string());
-        test(_05_05i, "0.5+0.5j".to_string());
-        test(_05_05i, "5e-1+0.5j".to_string());
-        test(_05_05i, "5E-1 + 0.5j".to_string());
-        test(_05_05i, "5E-1i + 0.5".to_string());
-        test(_05_05i, "0.05e+1j + 50E-2".to_string());
+        test(_0_0i, "0 + 0i");
+        test(_0_0i, "0+0j");
+        test(_0_0i, "0 - 0j");
+        test(_0_0i, "0-0i");
+        test(_0_0i, "0i + 0");
+        test(_0_0i, "0");
+        test(_0_0i, "-0");
+        test(_0_0i, "0i");
+        test(_0_0i, "0j");
+        test(_0_0i, "-0i");
+
+        test(_1_0i, "1 + 0i");
+        test(_1_0i, "1+0j");
+        test(_1_0i, "1 - 0j");
+        test(_1_0i, "1-0i");
+        test(_1_0i, "-0j+1");
+        test(_1_0i, "1");
+
+        test(_1_1i, "1 + i");
+        test(_1_1i, "1+j");
+        test(_1_1i, "1 + 1j");
+        test(_1_1i, "1+1i");
+        test(_1_1i, "i + 1");
+        test(_1_1i, "1i+1");
+        test(_1_1i, "j+1");
+
+        test(_0_1i, "0 + i");
+        test(_0_1i, "0+j");
+        test(_0_1i, "-0 + j");
+        test(_0_1i, "-0+i");
+        test(_0_1i, "0 + 1i");
+        test(_0_1i, "0+1j");
+        test(_0_1i, "-0 + 1j");
+        test(_0_1i, "-0+1i");
+        test(_0_1i, "j + 0");
+        test(_0_1i, "i");
+        test(_0_1i, "j");
+        test(_0_1i, "1j");
+
+        test(_neg1_1i, "-1 + i");
+        test(_neg1_1i, "-1+j");
+        test(_neg1_1i, "-1 + 1j");
+        test(_neg1_1i, "-1+1i");
+        test(_neg1_1i, "1i-1");
+        test(_neg1_1i, "j + -1");
+
+        test(_05_05i, "0.5 + 0.5i");
+        test(_05_05i, "0.5+0.5j");
+        test(_05_05i, "5e-1+0.5j");
+        test(_05_05i, "5E-1 + 0.5j");
+        test(_05_05i, "5E-1i + 0.5");
+        test(_05_05i, "0.05e+1j + 50E-2");
     }
 
     #[test]