Skip to content

Commit 84f4b58

Browse files
committed
Clean up from_str_float and use iterators
1 parent 251fdc8 commit 84f4b58

File tree

1 file changed

+125
-156
lines changed

1 file changed

+125
-156
lines changed

src/libstd/num/strconv.rs

+125-156
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@
1414

1515
use char;
1616
use char::Char;
17-
use clone::Clone;
1817
use from_str::from_str;
1918
use iter::Iterator;
2019
use num;
21-
use num::{Zero, One, cast, Int, Bounded};
20+
use num::{Int, Bounded};
2221
use num::{Float, FPNaN, FPInfinite, ToPrimitive};
2322
use option::{None, Option, Some};
2423
use slice::{ImmutableSlice, MutableSlice, CloneableVector};
25-
use str::{Str, StrSlice};
24+
use str::StrSlice;
2625
use string::String;
2726
use vec::Vec;
2827

@@ -68,12 +67,6 @@ pub enum SignFormat {
6867
SignAll,
6968
}
7069

71-
// Special value strings as [u8] consts.
72-
static INF_BUF: [u8, ..3] = [b'i', b'n', b'f'];
73-
static POS_INF_BUF: [u8, ..4] = [b'+', b'i', b'n', b'f'];
74-
static NEG_INF_BUF: [u8, ..4] = [b'-', b'i', b'n', b'f'];
75-
static NAN_BUF: [u8, ..3] = [b'N', b'a', b'N'];
76-
7770
/**
7871
* Converts an integral number to its string representation as a byte vector.
7972
* 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'];
10295
fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f: |u8|) {
10396
assert!(2 <= radix && radix <= 36);
10497

105-
let _0: T = Zero::zero();
98+
let _0: T = num::zero();
10699

107100
let neg = num < _0;
108-
let radix_gen: T = cast(radix).unwrap();
101+
let radix_gen: T = num::cast(radix).unwrap();
109102

110103
let mut deccum = num;
111104
// 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>(
202195
_ => ()
203196
}
204197

205-
let _0: T = Zero::zero();
206-
let _1: T = One::one();
198+
let _0: T = num::zero();
199+
let _1: T = num::one();
207200

208201
match num.classify() {
209202
FPNaN => { return (b"NaN".to_vec(), true); }
@@ -224,7 +217,7 @@ pub fn float_to_str_bytes_common<T: Float>(
224217

225218
let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
226219
let mut buf = Vec::new();
227-
let radix_gen: T = cast(radix as int).unwrap();
220+
let radix_gen: T = num::cast(radix as int).unwrap();
228221

229222
let (num, exp) = match exp_format {
230223
ExpNone => (num, 0i32),
@@ -233,12 +226,12 @@ pub fn float_to_str_bytes_common<T: Float>(
233226
(num, 0i32)
234227
} else {
235228
let (exp, exp_base) = match exp_format {
236-
ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
237-
ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
229+
ExpDec => (num.abs().log10().floor(), num::cast::<f64, T>(10.0f64).unwrap()),
230+
ExpBin => (num.abs().log2().floor(), num::cast::<f64, T>(2.0f64).unwrap()),
238231
ExpNone => unreachable!()
239232
};
240233

241-
(num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
234+
(num / exp_base.powf(exp), num::cast::<T, i32>(exp).unwrap())
242235
}
243236
}
244237
};
@@ -490,163 +483,139 @@ pub fn from_str_float<T: Float>(
490483
_ => ()
491484
}
492485

493-
let _0: T = Zero::zero();
494-
let _1: T = One::one();
495-
let radix_gen: T = cast(radix as int).unwrap();
496-
let buf = src.as_bytes();
497-
498-
let len = buf.len();
499-
500-
if len == 0 {
501-
return None;
502-
}
486+
let _0: T = num::zero();
487+
let _1: T = num::one();
488+
let radix_gen: T = num::cast(radix as int).unwrap();
503489

504-
if special {
505-
if buf == INF_BUF || buf == POS_INF_BUF {
506-
return Some(Float::infinity());
507-
} else if buf == NEG_INF_BUF {
508-
return Some(Float::neg_infinity());
509-
} else if buf == NAN_BUF {
510-
return Some(Float::nan());
511-
}
490+
match src {
491+
"inf" => return Some(Float::infinity()),
492+
"-inf" => return Some(Float::neg_infinity()),
493+
"NaN" => return Some(Float::nan()),
494+
_ => {},
512495
}
513496

514-
let (start, accum_positive) = match buf[0] as char {
515-
'-' => (1u, false),
516-
'+' => (1u, true),
517-
_ => (0u, true)
497+
let (is_positive, src) = match src.slice_shift_char() {
498+
(None, _) => return None,
499+
(Some('-'), "") => return None,
500+
(Some('-'), src) => (false, src),
501+
(Some(_), _) => (true, src),
518502
};
519503

520504
// Initialize accumulator with signed zero for floating point parsing to
521505
// work
522-
let mut accum = if accum_positive { _0.clone() } else { -_1 * _0};
523-
let mut last_accum = accum.clone(); // Necessary to detect overflow
524-
let mut i = start;
525-
let mut exp_found = false;
506+
let mut accum = if is_positive { _0 } else { -_1 };
507+
let mut last_accum = accum; // Necessary to detect overflow
508+
let mut cs = src.chars().enumerate();
509+
let mut exp = None::<(char, uint)>;
526510

527511
// Parse integer part of number
528-
while i < len {
529-
let c = buf[i] as char;
530-
531-
match char::to_digit(c, radix) {
532-
Some(digit) => {
533-
// shift accum one digit left
534-
accum = accum * radix_gen.clone();
535-
536-
// add/subtract current digit depending on sign
537-
if accum_positive {
538-
accum = accum + cast(digit as int).unwrap();
539-
} else {
540-
accum = accum - cast(digit as int).unwrap();
541-
}
542-
543-
// Detect overflow by comparing to last value, except
544-
// if we've not seen any non-zero digits.
545-
if last_accum != _0 {
546-
if accum_positive && accum <= last_accum { return Some(Float::infinity()); }
547-
if !accum_positive && accum >= last_accum { return Some(Float::neg_infinity()); }
548-
549-
// Detect overflow by reversing the shift-and-add process
550-
if accum_positive &&
551-
(last_accum != ((accum - cast(digit as int).unwrap())/radix_gen.clone())) {
552-
return Some(Float::infinity());
553-
}
554-
if !accum_positive &&
555-
(last_accum != ((accum + cast(digit as int).unwrap())/radix_gen.clone())) {
556-
return Some(Float::neg_infinity());
557-
}
558-
}
559-
last_accum = accum.clone();
560-
}
561-
None => match c {
562-
'e' | 'E' | 'p' | 'P' => {
563-
exp_found = true;
564-
break; // start of exponent
565-
}
566-
'.' => {
567-
i += 1u; // skip the '.'
568-
break; // start of fractional part
569-
}
570-
_ => return None // invalid number
571-
}
572-
}
573-
574-
i += 1u;
575-
}
576-
577-
// Parse fractional part of number
578-
// Skip if already reached start of exponent
579-
if !exp_found {
580-
let mut power = _1.clone();
581-
582-
while i < len {
583-
let c = buf[i] as char;
584-
585-
match char::to_digit(c, radix) {
512+
for (i, c) in cs {
513+
match c {
514+
'e' | 'E' | 'p' | 'P' => {
515+
exp = Some((c, i + 1));
516+
break; // start of exponent
517+
},
518+
'.' => {
519+
break; // start of fractional part
520+
},
521+
c => match c.to_digit(radix) {
586522
Some(digit) => {
587-
// Decrease power one order of magnitude
588-
power = power / radix_gen;
589-
590-
let digit_t: T = cast(digit).unwrap();
523+
// shift accum one digit left
524+
accum = accum * radix_gen;
591525

592526
// add/subtract current digit depending on sign
593-
if accum_positive {
594-
accum = accum + digit_t * power;
527+
if is_positive {
528+
accum = accum + num::cast(digit as int).unwrap();
595529
} else {
596-
accum = accum - digit_t * power;
530+
accum = accum - num::cast(digit as int).unwrap();
597531
}
598532

599-
// Detect overflow by comparing to last value
600-
if accum_positive && accum < last_accum { return Some(Float::infinity()); }
601-
if !accum_positive && accum > last_accum { return Some(Float::neg_infinity()); }
602-
last_accum = accum.clone();
603-
}
604-
None => match c {
605-
'e' | 'E' | 'p' | 'P' => {
606-
exp_found = true;
607-
break; // start of exponent
533+
// Detect overflow by comparing to last value, except
534+
// if we've not seen any non-zero digits.
535+
if last_accum != _0 {
536+
if is_positive && accum <= last_accum { return Some(Float::infinity()); }
537+
if !is_positive && accum >= last_accum { return Some(Float::neg_infinity()); }
538+
539+
// Detect overflow by reversing the shift-and-add process
540+
if is_positive &&
541+
(last_accum != ((accum - num::cast(digit as int).unwrap()) / radix_gen)) {
542+
return Some(Float::infinity());
543+
}
544+
if !is_positive &&
545+
(last_accum != ((accum + num::cast(digit as int).unwrap()) / radix_gen)) {
546+
return Some(Float::neg_infinity());
547+
}
608548
}
609-
_ => return None // invalid number
610-
}
611-
}
612-
613-
i += 1u;
549+
last_accum = accum;
550+
},
551+
None => {
552+
return None; // invalid number
553+
},
554+
},
614555
}
615556
}
616557

617-
// Special case: buf not empty, but does not contain any digit in front
618-
// of the exponent sign -> number is empty string
619-
if i == start {
620-
return None;
558+
// Parse fractional part of number
559+
// Skip if already reached start of exponent
560+
if exp.is_none() {
561+
let mut power = _1;
562+
for (i, c) in cs {
563+
match c {
564+
'e' | 'E' | 'p' | 'P' => {
565+
exp = Some((c, i + 1));
566+
break; // start of exponent
567+
},
568+
c => match c.to_digit(radix) {
569+
Some(digit) => {
570+
let digit: T = num::cast(digit).unwrap();
571+
572+
// Decrease power one order of magnitude
573+
power = power / radix_gen;
574+
// add/subtract current digit depending on sign
575+
accum = if is_positive {
576+
accum + digit * power
577+
} else {
578+
accum - digit * power
579+
};
580+
// Detect overflow by comparing to last value
581+
if is_positive && accum < last_accum { return Some(Float::infinity()); }
582+
if !is_positive && accum > last_accum { return Some(Float::neg_infinity()); }
583+
last_accum = accum;
584+
},
585+
None => {
586+
return None; // invalid number
587+
},
588+
},
589+
}
590+
}
621591
}
622592

623-
let mut multiplier = _1.clone();
624-
625-
if exp_found {
626-
let c = buf[i] as char;
627-
let base: T = match (c, exponent) {
628-
// c is never _ so don't need to handle specially
629-
('e', ExpDec) | ('E', ExpDec) => cast(10u).unwrap(),
630-
('p', ExpBin) | ('P', ExpBin) => cast(2u).unwrap(),
631-
_ => return None // char doesn't fit given exponent format
632-
};
633-
634-
// parse remaining bytes as decimal integer,
635-
// skipping the exponent char
636-
let exp = from_str::<int>(String::from_utf8_lossy(buf[i+1..len]).as_slice());
637-
638-
match exp {
639-
Some(exp_pow) => {
640-
multiplier = if exp_pow < 0 {
593+
let multiplier = match exp {
594+
None => {
595+
_1 // no exponent
596+
},
597+
Some((c, offset)) => {
598+
let base: T = match (c, exponent) {
599+
// c is never _ so don't need to handle specially
600+
('e', ExpDec) | ('E', ExpDec) => num::cast(10u).unwrap(),
601+
('p', ExpBin) | ('P', ExpBin) => num::cast(2u).unwrap(),
602+
_ => return None, // char doesn't fit given exponent format
603+
};
604+
// parse remaining string as decimal integer
605+
let exp = from_str::<int>(src[offset..]);
606+
match exp {
607+
Some(exp_pow) if exp_pow < 0 => {
641608
_1 / num::pow(base, (-exp_pow.to_int().unwrap()) as uint)
642-
} else {
609+
},
610+
Some(exp_pow) => {
643611
num::pow(base, exp_pow.to_int().unwrap() as uint)
644-
}
612+
},
613+
None => {
614+
return None; // invalid exponent
615+
},
645616
}
646-
None => return None // invalid exponent -> invalid number
647-
}
648-
}
649-
617+
},
618+
};
650619
Some(accum * multiplier)
651620
}
652621

@@ -659,9 +628,9 @@ pub fn from_str_radix_int<T: Int>(src: &str, radix: uint) -> Option<T> {
659628
let _1: T = num::one();
660629
let is_signed = _0 > Bounded::min_value();
661630

662-
let (is_negative, src) = match src.slice_shift_char() {
663-
(Some('-'), src) if is_signed => (true, src),
664-
(Some(_), _) => (false, src),
631+
let (is_positive, src) = match src.slice_shift_char() {
632+
(Some('-'), src) if is_signed => (false, src),
633+
(Some(_), _) => (true, src),
665634
(None, _) => return None,
666635
};
667636

@@ -671,7 +640,7 @@ pub fn from_str_radix_int<T: Int>(src: &str, radix: uint) -> Option<T> {
671640
let radix = cast(radix);
672641
let mut result = _0;
673642

674-
if is_negative {
643+
if is_positive {
675644
for x in xs {
676645
let x = match x {
677646
Some(x) => x,
@@ -681,7 +650,7 @@ pub fn from_str_radix_int<T: Int>(src: &str, radix: uint) -> Option<T> {
681650
Some(result) => result,
682651
None => return None,
683652
};
684-
result = match result.checked_sub(&x) {
653+
result = match result.checked_add(&x) {
685654
Some(result) => result,
686655
None => return None,
687656
};
@@ -696,7 +665,7 @@ pub fn from_str_radix_int<T: Int>(src: &str, radix: uint) -> Option<T> {
696665
Some(result) => result,
697666
None => return None,
698667
};
699-
result = match result.checked_add(&x) {
668+
result = match result.checked_sub(&x) {
700669
Some(result) => result,
701670
None => return None,
702671
};

0 commit comments

Comments
 (0)