diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 213f32a1d182c..fa8f7c9ad939c 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -36,7 +36,7 @@ use std::io::extensions::u64_from_be_bytes; use std::io; use std::collections::hashmap::HashMap; use std::rc::Rc; -use std::u64; +use std::str; use rbml::reader; use rbml; use serialize::Decodable; @@ -215,7 +215,9 @@ fn each_reexport(d: rbml::Doc, f: |rbml::Doc| -> bool) -> bool { fn variant_disr_val(d: rbml::Doc) -> Option { reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| { - reader::with_doc_data(val_doc, |data| u64::parse_bytes(data, 10u)) + reader::with_doc_data(val_doc, |data| { + str::from_utf8(data).and_then(from_str) + }) }) } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index a52d02ccca773..6e7a6dfa09448 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -23,7 +23,6 @@ use middle::ty; use std::rc::Rc; use std::str; use std::string::String; -use std::uint; use syntax::abi; use syntax::ast; use syntax::ast::*; @@ -615,12 +614,12 @@ pub fn parse_def_id(buf: &[u8]) -> ast::DefId { let crate_part = buf[0u..colon_idx]; let def_part = buf[colon_idx + 1u..len]; - let crate_num = match uint::parse_bytes(crate_part, 10u) { + let crate_num = match str::from_utf8(crate_part).and_then(from_str::) { Some(cn) => cn as ast::CrateNum, None => panic!("internal error: parse_def_id: crate number expected, found {}", crate_part) }; - let def_num = match uint::parse_bytes(def_part, 10u) { + let def_num = match str::from_utf8(def_part).and_then(from_str::) { Some(dn) => dn as ast::NodeId, None => panic!("internal error: parse_def_id: id expected, found {}", def_part) diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 0b2f17b8f93cc..63c3956ef2412 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -333,35 +333,10 @@ pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> String { r } -/// Convert a string in base 16 to a float. -/// Accepts an optional binary exponent. -/// -/// This function accepts strings such as -/// -/// * 'a4.fe' -/// * '+a4.fe', equivalent to 'a4.fe' -/// * '-a4.fe' -/// * '2b.aP128', or equivalently, '2b.ap128' -/// * '2b.aP-128' -/// * '.' (understood as 0) -/// * 'c.' -/// * '.c', or, equivalently, '0.c' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `None` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `[num]`. #[inline] -pub fn from_str_hex(num: &str) -> Option { - strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false, false) +#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] +pub fn from_str_hex(src: &str) -> Option { + strconv::from_str_radix_float(src, 16) } impl FromStr for f32 { @@ -384,16 +359,15 @@ impl FromStr for f32 { /// /// # Arguments /// - /// * num - A string + /// * src - A string /// /// # Return value /// /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `num`. + /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str(val: &str) -> Option { - strconv::from_str_common(val, 10u, true, true, true, - strconv::ExpDec, false, false) + fn from_str(src: &str) -> Option { + strconv::from_str_radix_float(src, 10u) } } @@ -408,17 +382,16 @@ impl num::FromStrRadix for f32 { /// /// # Arguments /// - /// * num - A string + /// * src - A string /// * radix - The base to use. Must lie in the range [2 .. 36] /// /// # Return value /// /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `num`. + /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str_radix(val: &str, rdx: uint) -> Option { - strconv::from_str_common(val, rdx, true, true, false, - strconv::ExpNone, false, false) + fn from_str_radix(src: &str, radix: uint) -> Option { + strconv::from_str_radix_float(src, radix) } } @@ -710,8 +683,8 @@ mod tests { fn test_ldexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f32 = from_str_hex("1p-123").unwrap(); - let f2: f32 = from_str_hex("1p-111").unwrap(); + let f1: f32 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); + let f2: f32 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); assert_eq!(FloatMath::ldexp(1f32, -123), f1); assert_eq!(FloatMath::ldexp(1f32, -111), f2); @@ -730,8 +703,8 @@ mod tests { fn test_frexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f32 = from_str_hex("1p-123").unwrap(); - let f2: f32 = from_str_hex("1p-111").unwrap(); + let f1: f32 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); + let f2: f32 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); let (x1, exp1) = f1.frexp(); let (x2, exp2) = f2.frexp(); assert_eq!((x1, exp1), (0.5f32, -122)); diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 35555b140815a..6e8e92eb91d03 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -341,92 +341,60 @@ pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> String { r } -/// Convert a string in base 16 to a float. -/// Accepts an optional binary exponent. -/// -/// This function accepts strings such as -/// -/// * 'a4.fe' -/// * '+a4.fe', equivalent to 'a4.fe' -/// * '-a4.fe' -/// * '2b.aP128', or equivalently, '2b.ap128' -/// * '2b.aP-128' -/// * '.' (understood as 0) -/// * 'c.' -/// * '.c', or, equivalently, '0.c' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `None` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `[num]`. #[inline] -pub fn from_str_hex(num: &str) -> Option { - strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false, false) +#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] +pub fn from_str_hex(src: &str) -> Option { + strconv::from_str_radix_float(src, 16) } impl FromStr for f64 { /// Convert a string in base 10 to a float. /// Accepts an optional decimal exponent. /// - /// This function accepts strings such as + /// This function accepts strings such as: /// /// * '3.14' - /// * '+3.14', equivalent to '3.14' /// * '-3.14' /// * '2.5E10', or equivalently, '2.5e10' /// * '2.5E-10' /// * '.' (understood as 0) /// * '5.' /// * '.5', or, equivalently, '0.5' - /// * '+inf', 'inf', '-inf', 'NaN' + /// * inf', '-inf', 'NaN' /// /// Leading and trailing whitespace represent an error. /// /// # Arguments /// - /// * num - A string + /// * src - A string /// /// # Return value /// /// `none` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `num`. + /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str(val: &str) -> Option { - strconv::from_str_common(val, 10u, true, true, true, - strconv::ExpDec, false, false) + fn from_str(src: &str) -> Option { + strconv::from_str_radix_float(src, 10u) } } impl num::FromStrRadix for f64 { /// Convert a string in a given base to a float. /// - /// Due to possible conflicts, this function does **not** accept - /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** - /// does it recognize exponents of any kind. - /// /// Leading and trailing whitespace represent an error. /// /// # Arguments /// - /// * num - A string + /// * src - A string /// * radix - The base to use. Must lie in the range [2 .. 36] /// /// # Return value /// /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `num`. + /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str_radix(val: &str, rdx: uint) -> Option { - strconv::from_str_common(val, rdx, true, true, false, - strconv::ExpNone, false, false) + fn from_str_radix(src: &str, radix: uint) -> Option { + strconv::from_str_radix_float(src, radix) } } @@ -712,8 +680,8 @@ mod tests { fn test_ldexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f64 = from_str_hex("1p-123").unwrap(); - let f2: f64 = from_str_hex("1p-111").unwrap(); + let f1: f64 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); + let f2: f64 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); assert_eq!(FloatMath::ldexp(1f64, -123), f1); assert_eq!(FloatMath::ldexp(1f64, -111), f2); @@ -732,8 +700,8 @@ mod tests { fn test_frexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f64 = from_str_hex("1p-123").unwrap(); - let f2: f64 = from_str_hex("1p-111").unwrap(); + let f1: f64 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); + let f2: f64 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); let (x1, exp1) = f1.frexp(); let (x2, exp2) = f2.frexp(); assert_eq!((x1, exp1), (0.5f64, -122)); diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index ca45b40e687a1..9ae146c840ae8 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -14,31 +14,11 @@ macro_rules! int_module (($T:ty) => ( -// String conversion functions and impl str -> num - -/// Parse a byte slice as a number in the given base -/// -/// Yields an `Option` because `buf` may or may not actually be parseable. -/// -/// # Examples -/// -/// ``` -/// let num = std::i64::parse_bytes([49,50,51,52,53,54,55,56,57], 10); -/// assert!(num == Some(123456789)); -/// ``` -#[inline] -#[experimental = "might need to return Result"] -pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> { - strconv::from_str_bytes_common(buf, radix, true, false, false, - strconv::ExpNone, false, false) -} - #[experimental = "might need to return Result"] impl FromStr for $T { #[inline] fn from_str(s: &str) -> Option<$T> { - strconv::from_str_common(s, 10u, true, false, false, - strconv::ExpNone, false, false) + strconv::from_str_radix_int(s, 10) } } @@ -46,18 +26,14 @@ impl FromStr for $T { impl FromStrRadix for $T { #[inline] fn from_str_radix(s: &str, radix: uint) -> Option<$T> { - strconv::from_str_common(s, radix, true, false, false, - strconv::ExpNone, false, false) + strconv::from_str_radix_int(s, radix) } } #[cfg(test)] mod tests { use prelude::*; - use super::*; - - use i32; - use str::StrSlice; + use num::FromStrRadix; #[test] fn test_from_str() { @@ -73,33 +49,33 @@ mod tests { assert_eq!(from_str::("-123456789"), Some(-123456789 as i32)); assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T)); - assert!(from_str::<$T>(" ").is_none()); - assert!(from_str::<$T>("x").is_none()); + assert_eq!(from_str::<$T>(""), None); + assert_eq!(from_str::<$T>(" "), None); + assert_eq!(from_str::<$T>("x"), None); } #[test] - fn test_parse_bytes() { - use str::StrSlice; - assert_eq!(parse_bytes("123".as_bytes(), 10u), Some(123 as $T)); - assert_eq!(parse_bytes("1001".as_bytes(), 2u), Some(9 as $T)); - assert_eq!(parse_bytes("123".as_bytes(), 8u), Some(83 as $T)); - assert_eq!(i32::parse_bytes("123".as_bytes(), 16u), Some(291 as i32)); - assert_eq!(i32::parse_bytes("ffff".as_bytes(), 16u), Some(65535 as i32)); - assert_eq!(i32::parse_bytes("FFFF".as_bytes(), 16u), Some(65535 as i32)); - assert_eq!(parse_bytes("z".as_bytes(), 36u), Some(35 as $T)); - assert_eq!(parse_bytes("Z".as_bytes(), 36u), Some(35 as $T)); - - assert_eq!(parse_bytes("-123".as_bytes(), 10u), Some(-123 as $T)); - assert_eq!(parse_bytes("-1001".as_bytes(), 2u), Some(-9 as $T)); - assert_eq!(parse_bytes("-123".as_bytes(), 8u), Some(-83 as $T)); - assert_eq!(i32::parse_bytes("-123".as_bytes(), 16u), Some(-291 as i32)); - assert_eq!(i32::parse_bytes("-ffff".as_bytes(), 16u), Some(-65535 as i32)); - assert_eq!(i32::parse_bytes("-FFFF".as_bytes(), 16u), Some(-65535 as i32)); - assert_eq!(parse_bytes("-z".as_bytes(), 36u), Some(-35 as $T)); - assert_eq!(parse_bytes("-Z".as_bytes(), 36u), Some(-35 as $T)); - - assert!(parse_bytes("Z".as_bytes(), 35u).is_none()); - assert!(parse_bytes("-9".as_bytes(), 2u).is_none()); + fn test_from_str_radix() { + assert_eq!(FromStrRadix::from_str_radix("123", 10), Some(123 as $T)); + assert_eq!(FromStrRadix::from_str_radix("1001", 2), Some(9 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 8), Some(83 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 16), Some(291 as i32)); + assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Some(65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("FFFF", 16), Some(65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("z", 36), Some(35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("Z", 36), Some(35 as $T)); + + assert_eq!(FromStrRadix::from_str_radix("-123", 10), Some(-123 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-1001", 2), Some(-9 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 8), Some(-83 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 16), Some(-291 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-ffff", 16), Some(-65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-FFFF", 16), Some(-65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-z", 36), Some(-35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-Z", 36), Some(-35 as $T)); + + assert_eq!(FromStrRadix::from_str_radix("Z", 35), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("-9", 2), None::<$T>); } #[test] @@ -133,35 +109,35 @@ mod tests { fn test_int_from_str_overflow() { let mut i8_val: i8 = 127_i8; assert_eq!(from_str::("127"), Some(i8_val)); - assert!(from_str::("128").is_none()); + assert_eq!(from_str::("128"), None); i8_val += 1 as i8; assert_eq!(from_str::("-128"), Some(i8_val)); - assert!(from_str::("-129").is_none()); + assert_eq!(from_str::("-129"), None); let mut i16_val: i16 = 32_767_i16; assert_eq!(from_str::("32767"), Some(i16_val)); - assert!(from_str::("32768").is_none()); + assert_eq!(from_str::("32768"), None); i16_val += 1 as i16; assert_eq!(from_str::("-32768"), Some(i16_val)); - assert!(from_str::("-32769").is_none()); + assert_eq!(from_str::("-32769"), None); let mut i32_val: i32 = 2_147_483_647_i32; assert_eq!(from_str::("2147483647"), Some(i32_val)); - assert!(from_str::("2147483648").is_none()); + assert_eq!(from_str::("2147483648"), None); i32_val += 1 as i32; assert_eq!(from_str::("-2147483648"), Some(i32_val)); - assert!(from_str::("-2147483649").is_none()); + assert_eq!(from_str::("-2147483649"), None); let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; assert_eq!(from_str::("9223372036854775807"), Some(i64_val)); - assert!(from_str::("9223372036854775808").is_none()); + assert_eq!(from_str::("9223372036854775808"), None); i64_val += 1 as i64; assert_eq!(from_str::("-9223372036854775808"), Some(i64_val)); - assert!(from_str::("-9223372036854775809").is_none()); + assert_eq!(from_str::("-9223372036854775809"), None); } } diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 30ecf2284df76..7a02d8d77b0b1 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -13,14 +13,14 @@ #![allow(missing_docs)] use char; -use clone::Clone; -use num::{NumCast, Zero, One, cast, Int}; -use num::{Float, FPNaN, FPInfinite, ToPrimitive}; +use char::Char; +use from_str::from_str; +use iter::Iterator; use num; -use ops::{Add, Sub, Mul, Div, Rem, Neg}; +use num::{Int, Bounded}; +use num::{Float, FPNaN, FPInfinite, ToPrimitive}; use option::{None, Option, Some}; use slice::{ImmutableSlice, MutableSlice, CloneableVector}; -use std::cmp::{PartialOrd, PartialEq}; use str::StrSlice; use string::String; use vec::Vec; @@ -67,81 +67,6 @@ pub enum SignFormat { SignAll, } -/// Encompasses functions used by the string converter. -pub trait NumStrConv { - /// Returns the NaN value. - fn nan() -> Option; - - /// Returns the infinite value. - fn inf() -> Option; - - /// Returns the negative infinite value. - fn neg_inf() -> Option; - - /// Returns -0.0. - fn neg_zero() -> Option; - - /// Rounds the number toward zero. - fn round_to_zero(&self) -> Self; - - /// Returns the fractional part of the number. - fn fractional_part(&self) -> Self; -} - -macro_rules! impl_NumStrConv_Floating (($t:ty) => ( - impl NumStrConv for $t { - #[inline] - fn nan() -> Option<$t> { Some( 0.0 / 0.0) } - #[inline] - fn inf() -> Option<$t> { Some( 1.0 / 0.0) } - #[inline] - fn neg_inf() -> Option<$t> { Some(-1.0 / 0.0) } - #[inline] - fn neg_zero() -> Option<$t> { Some(-0.0 ) } - - #[inline] - fn round_to_zero(&self) -> $t { self.trunc() } - #[inline] - fn fractional_part(&self) -> $t { self.fract() } - } -)) - -macro_rules! impl_NumStrConv_Integer (($t:ty) => ( - impl NumStrConv for $t { - #[inline] fn nan() -> Option<$t> { None } - #[inline] fn inf() -> Option<$t> { None } - #[inline] fn neg_inf() -> Option<$t> { None } - #[inline] fn neg_zero() -> Option<$t> { None } - - #[inline] fn round_to_zero(&self) -> $t { *self } - #[inline] fn fractional_part(&self) -> $t { 0 } - } -)) - -// FIXME: #4955 -// Replace by two generic impls for traits 'Integral' and 'Floating' -impl_NumStrConv_Floating!(f32) -impl_NumStrConv_Floating!(f64) - -impl_NumStrConv_Integer!(int) -impl_NumStrConv_Integer!(i8) -impl_NumStrConv_Integer!(i16) -impl_NumStrConv_Integer!(i32) -impl_NumStrConv_Integer!(i64) - -impl_NumStrConv_Integer!(uint) -impl_NumStrConv_Integer!(u8) -impl_NumStrConv_Integer!(u16) -impl_NumStrConv_Integer!(u32) -impl_NumStrConv_Integer!(u64) - - -// 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 @@ -170,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 @@ -255,8 +180,7 @@ fn int_to_str_bytes_common(num: T, radix: uint, sign: SignFormat, f: |u8 * - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict * between digit and exponent sign `'p'`. */ -pub fn float_to_str_bytes_common+Neg+Rem+Mul>( +pub fn float_to_str_bytes_common( num: T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool ) -> (Vec, bool) { @@ -271,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); } @@ -293,7 +217,7 @@ pub fn float_to_str_bytes_common (num, 0i32), @@ -302,12 +226,12 @@ pub fn float_to_str_bytes_common (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()) } } }; @@ -488,8 +412,7 @@ pub fn float_to_str_bytes_common+Neg+Rem+Mul>( +pub fn float_to_str_common( num: T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool ) -> (String, bool) { @@ -501,311 +424,228 @@ pub fn float_to_str_common 36. - * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict - * between digit and exponent sign `'e'`. - * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict - * between digit and exponent sign `'p'`. - * - Fails if `radix` > 18 and `special == true` due to conflict - * between digit and lowest first character in `inf` and `NaN`, the `'i'`. - */ -pub fn from_str_bytes_common+ - Mul+Sub+Neg+Add+ - NumStrConv+Clone>( - buf: &[u8], radix: uint, negative: bool, fractional: bool, - special: bool, exponent: ExponentFormat, empty_zero: bool, - ignore_underscores: bool - ) -> Option { - match exponent { - ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' - => panic!("from_str_bytes_common: radix {} incompatible with \ - use of 'e' as decimal exponent", radix), - ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p' - => panic!("from_str_bytes_common: radix {} incompatible with \ - use of 'p' as binary exponent", radix), - _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf' - => panic!("from_str_bytes_common: radix {} incompatible with \ - special values 'inf' and 'NaN'", radix), - _ if (radix as int) < 2 - => panic!("from_str_bytes_common: radix {} to low, \ - must lie in the range [2, 36]", radix), - _ if (radix as int) > 36 - => panic!("from_str_bytes_common: radix {} to high, \ - must lie in the range [2, 36]", radix), - _ => () - } - - let _0: T = Zero::zero(); - let _1: T = One::one(); - let radix_gen: T = cast(radix as int).unwrap(); - - let len = buf.len(); - - if len == 0 { - if empty_zero { - return Some(_0); - } else { - return None; - } +pub fn from_str_radix_float(src: &str, radix: uint) -> Option { + assert!(radix >= 2 && radix <= 36, + "from_str_radix_float: must lie in the range `[2, 36]` - found {}", + radix); + + let _0: T = num::zero(); + let _1: T = num::one(); + let radix_t: T = num::cast(radix as int).unwrap(); + + // Special values + 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 NumStrConv::inf(); - } else if buf == NEG_INF_BUF { - if negative { - return NumStrConv::neg_inf(); - } else { - return None; - } - } else if buf == NAN_BUF { - return NumStrConv::nan(); - } - } - - let (start, accum_positive) = match buf[0] as char { - '-' if !negative => return None, - '-' => (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; - - // Parse integer part of number - while i < len { - let c = buf[i] as char; - - match char::to_digit(c, radix) { + // The significand to accumulate + let mut sig = if is_positive { _0 } else { -_1 }; + // Necessary to detect overflow + let mut prev_sig = sig; + let mut cs = src.chars().enumerate(); + // Exponent prefix and exponent index offset + let mut exp_info = None::<(char, uint)>; + + // Parse the integer part of the significand + for (i, c) in cs { + match c.to_digit(radix) { Some(digit) => { - // shift accum one digit left - accum = accum * radix_gen.clone(); + // shift significand one digit left + sig = sig * radix_t; // add/subtract current digit depending on sign - if accum_positive { - accum = accum + cast(digit as int).unwrap(); + if is_positive { + sig = sig + num::cast(digit as int).unwrap(); } else { - accum = accum - cast(digit as int).unwrap(); + sig = sig - num::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 NumStrConv::inf(); } - if !accum_positive && accum >= last_accum { return NumStrConv::neg_inf(); } + if prev_sig != _0 { + if is_positive && sig <= prev_sig + { return Some(Float::infinity()); } + if !is_positive && sig >= prev_sig + { 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 NumStrConv::inf(); - } - if !accum_positive && - (last_accum != ((accum + cast(digit as int).unwrap())/radix_gen.clone())) { - return NumStrConv::neg_inf(); - } + let digit: T = num::cast(digit as int).unwrap(); + if is_positive && (prev_sig != ((sig - digit) / radix_t)) + { return Some(Float::infinity()); } + if !is_positive && (prev_sig != ((sig + digit) / radix_t)) + { return Some(Float::neg_infinity()); } } - last_accum = accum.clone(); - } + prev_sig = sig; + }, None => match c { - '_' if ignore_underscores => {} 'e' | 'E' | 'p' | 'P' => { - exp_found = true; - break; // start of exponent - } - '.' if fractional => { - i += 1u; // skip the '.' - break; // start of fractional part - } - _ => return None // invalid number - } + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + '.' => { + break; // start of fractional part + }, + _ => { + return None; + }, + }, } - - 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) { + // If we are not yet at the exponent parse the fractional + // part of the significand + if exp_info.is_none() { + let mut power = _1; + for (i, c) in cs { + match c.to_digit(radix) { Some(digit) => { + let digit: T = num::cast(digit).unwrap(); // Decrease power one order of magnitude - power = power / radix_gen; - - let digit_t: T = cast(digit).unwrap(); - + power = power / radix_t; // add/subtract current digit depending on sign - if accum_positive { - accum = accum + digit_t * power; + sig = if is_positive { + sig + digit * power } else { - accum = accum - digit_t * power; - } - + sig - digit * power + }; // Detect overflow by comparing to last value - if accum_positive && accum < last_accum { return NumStrConv::inf(); } - if !accum_positive && accum > last_accum { return NumStrConv::neg_inf(); } - last_accum = accum.clone(); - } + if is_positive && sig < prev_sig + { return Some(Float::infinity()); } + if !is_positive && sig > prev_sig + { return Some(Float::neg_infinity()); } + prev_sig = sig; + }, None => match c { - '_' if ignore_underscores => {} 'e' | 'E' | 'p' | 'P' => { - exp_found = true; - break; // start of exponent - } - _ => return None // invalid number - } + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + _ => { + 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 { - if empty_zero { - return Some(_0); - } else { - return None; - } - } + // Parse and calculate the exponent + let exp = match exp_info { + Some((c, offset)) => { + let base: T = match c { + 'E' | 'e' if radix == 10 => num::cast(10u).unwrap(), + 'P' | 'p' if radix == 16 => num::cast(2u).unwrap(), + _ => return None, + }; - let mut multiplier = _1.clone(); + // Parse the exponent as decimal integer + let src = src[offset..]; + let (is_positive, exp) = match src.slice_shift_char() { + (Some('-'), src) => (false, from_str::(src)), + (Some('+'), src) => (true, from_str::(src)), + (Some(_), _) => (true, from_str::(src)), + (None, _) => return None, + }; - 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 - }; + match (is_positive, exp) { + (true, Some(exp)) => num::pow(base, exp), + (false, Some(exp)) => _1 / num::pow(base, exp), + (_, None) => return None, + } + }, + None => _1, // no exponent + }; + + Some(sig * exp) +} - // parse remaining bytes as decimal integer, - // skipping the exponent char - let exp: Option = from_str_bytes_common( - buf[i+1..len], 10, true, false, false, ExpNone, false, - ignore_underscores); +pub fn from_str_radix_int(src: &str, radix: uint) -> Option { + assert!(radix >= 2 && radix <= 36, + "from_str_radix_int: must lie in the range `[2, 36]` - found {}", + radix); - match exp { - Some(exp_pow) => { - multiplier = if exp_pow < 0 { - _1 / num::pow(base, (-exp_pow.to_int().unwrap()) as uint) - } else { - num::pow(base, exp_pow.to_int().unwrap() as uint) - } - } - None => return None // invalid exponent -> invalid number - } + fn cast(x: uint) -> T { + num::cast(x).unwrap() } - Some(accum * multiplier) -} + let _0: T = num::zero(); + let _1: T = num::one(); + let is_signed = _0 > Bounded::min_value(); -/** - * Parses a string as a number. This is a wrapper for - * `from_str_bytes_common()`, for details see there. - */ -#[inline] -pub fn from_str_common+Mul+ - Sub+Neg+Add+NumStrConv+Clone>( - buf: &str, radix: uint, negative: bool, fractional: bool, - special: bool, exponent: ExponentFormat, empty_zero: bool, - ignore_underscores: bool - ) -> Option { - from_str_bytes_common(buf.as_bytes(), radix, negative, - fractional, special, exponent, empty_zero, - ignore_underscores) + let (is_positive, src) = match src.slice_shift_char() { + (Some('-'), src) if is_signed => (false, src), + (Some(_), _) => (true, src), + (None, _) => return None, + }; + + let mut xs = src.chars().map(|c| { + c.to_digit(radix).map(cast) + }); + let radix = cast(radix); + let mut result = _0; + + if is_positive { + for x in xs { + let x = match x { + Some(x) => x, + None => return None, + }; + result = match result.checked_mul(&radix) { + Some(result) => result, + None => return None, + }; + result = match result.checked_add(&x) { + Some(result) => result, + None => return None, + }; + } + } else { + for x in xs { + let x = match x { + Some(x) => x, + None => return None, + }; + result = match result.checked_mul(&radix) { + Some(result) => result, + None => return None, + }; + result = match result.checked_sub(&x) { + Some(result) => result, + None => return None, + }; + } + } + + Some(result) } #[cfg(test)] mod test { use super::*; use option::*; - - #[test] - fn from_str_ignore_underscores() { - let s : Option = from_str_common("__1__", 2, false, false, false, - ExpNone, false, true); - assert_eq!(s, Some(1u8)); - - let n : Option = from_str_common("__1__", 2, false, false, false, - ExpNone, false, false); - assert_eq!(n, None); - - let f : Option = from_str_common("_1_._5_e_1_", 10, false, true, false, - ExpDec, false, true); - assert_eq!(f, Some(1.5e1f32)); - } - - #[test] - fn from_str_issue5770() { - // try to parse 0b1_1111_1111 = 511 as a u8. Caused problems - // since 255*2+1 == 255 (mod 256) so the overflow wasn't - // detected. - let n : Option = from_str_common("111111111", 2, false, false, false, - ExpNone, false, false); - assert_eq!(n, None); - } + use num::Float; #[test] fn from_str_issue7588() { - let u : Option = from_str_common("1000", 10, false, false, false, - ExpNone, false, false); + let u : Option = from_str_radix_int("1000", 10); assert_eq!(u, None); - let s : Option = from_str_common("80000", 10, false, false, false, - ExpNone, false, false); + let s : Option = from_str_radix_int("80000", 10); assert_eq!(s, None); - let f : Option = from_str_common( - "10000000000000000000000000000000000000000", 10, false, false, false, - ExpNone, false, false); - assert_eq!(f, NumStrConv::inf()) - let fe : Option = from_str_common("1e40", 10, false, false, false, - ExpDec, false, false); - assert_eq!(fe, NumStrConv::inf()) + let f : Option = from_str_radix_float("10000000000000000000000000000000000000000", 10); + assert_eq!(f, Some(Float::infinity())) + let fe : Option = from_str_radix_float("1e40", 10); + assert_eq!(fe, Some(Float::infinity())) } } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index c69c3ffa41c0e..aa8e58bab0286 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -15,31 +15,11 @@ macro_rules! uint_module (($T:ty) => ( -// String conversion functions and impl str -> num - -/// Parse a byte slice as a number in the given base -/// -/// Yields an `Option` because `buf` may or may not actually be parseable. -/// -/// # Examples -/// -/// ``` -/// let num = std::uint::parse_bytes([49,50,51,52,53,54,55,56,57], 10); -/// assert!(num == Some(123456789)); -/// ``` -#[inline] -#[experimental = "might need to return Result"] -pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> { - strconv::from_str_bytes_common(buf, radix, false, false, false, - strconv::ExpNone, false, false) -} - #[experimental = "might need to return Result"] impl FromStr for $T { #[inline] fn from_str(s: &str) -> Option<$T> { - strconv::from_str_common(s, 10u, false, false, false, - strconv::ExpNone, false, false) + strconv::from_str_radix_int(s, 10) } } @@ -47,8 +27,7 @@ impl FromStr for $T { impl FromStrRadix for $T { #[inline] fn from_str_radix(s: &str, radix: uint) -> Option<$T> { - strconv::from_str_common(s, radix, false, false, false, - strconv::ExpNone, false, false) + strconv::from_str_radix_int(s, radix) } } @@ -85,10 +64,7 @@ pub fn to_str_bytes(n: $T, radix: uint, f: |v: &[u8]| -> U) -> U { #[cfg(test)] mod tests { use prelude::*; - use super::*; - - use str::StrSlice; - use u16; + use num::FromStrRadix; #[test] pub fn test_from_str() { @@ -98,23 +74,22 @@ mod tests { assert_eq!(from_str::("123456789"), Some(123456789 as u32)); assert_eq!(from_str::<$T>("00100"), Some(100u as $T)); - assert!(from_str::<$T>("").is_none()); - assert!(from_str::<$T>(" ").is_none()); - assert!(from_str::<$T>("x").is_none()); + assert_eq!(from_str::<$T>(""), None); + assert_eq!(from_str::<$T>(" "), None); + assert_eq!(from_str::<$T>("x"), None); } #[test] pub fn test_parse_bytes() { - use str::StrSlice; - assert_eq!(parse_bytes("123".as_bytes(), 10u), Some(123u as $T)); - assert_eq!(parse_bytes("1001".as_bytes(), 2u), Some(9u as $T)); - assert_eq!(parse_bytes("123".as_bytes(), 8u), Some(83u as $T)); - assert_eq!(u16::parse_bytes("123".as_bytes(), 16u), Some(291u as u16)); - assert_eq!(u16::parse_bytes("ffff".as_bytes(), 16u), Some(65535u as u16)); - assert_eq!(parse_bytes("z".as_bytes(), 36u), Some(35u as $T)); - - assert!(parse_bytes("Z".as_bytes(), 10u).is_none()); - assert!(parse_bytes("_".as_bytes(), 2u).is_none()); + assert_eq!(FromStrRadix::from_str_radix("123", 10), Some(123u as $T)); + assert_eq!(FromStrRadix::from_str_radix("1001", 2), Some(9u as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 8), Some(83u as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 16), Some(291u as u16)); + assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Some(65535u as u16)); + assert_eq!(FromStrRadix::from_str_radix("z", 36), Some(35u as $T)); + + assert_eq!(FromStrRadix::from_str_radix("Z", 10), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("_", 2), None::<$T>); } #[test] @@ -148,35 +123,35 @@ mod tests { fn test_uint_from_str_overflow() { let mut u8_val: u8 = 255_u8; assert_eq!(from_str::("255"), Some(u8_val)); - assert!(from_str::("256").is_none()); + assert_eq!(from_str::("256"), None); u8_val += 1 as u8; assert_eq!(from_str::("0"), Some(u8_val)); - assert!(from_str::("-1").is_none()); + assert_eq!(from_str::("-1"), None); let mut u16_val: u16 = 65_535_u16; assert_eq!(from_str::("65535"), Some(u16_val)); - assert!(from_str::("65536").is_none()); + assert_eq!(from_str::("65536"), None); u16_val += 1 as u16; assert_eq!(from_str::("0"), Some(u16_val)); - assert!(from_str::("-1").is_none()); + assert_eq!(from_str::("-1"), None); let mut u32_val: u32 = 4_294_967_295_u32; assert_eq!(from_str::("4294967295"), Some(u32_val)); - assert!(from_str::("4294967296").is_none()); + assert_eq!(from_str::("4294967296"), None); u32_val += 1 as u32; assert_eq!(from_str::("0"), Some(u32_val)); - assert!(from_str::("-1").is_none()); + assert_eq!(from_str::("-1"), None); let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); - assert!(from_str::("18446744073709551616").is_none()); + assert_eq!(from_str::("18446744073709551616"), None); u64_val += 1 as u64; assert_eq!(from_str::("0"), Some(u64_val)); - assert!(from_str::("-1").is_none()); + assert_eq!(from_str::("-1"), None); } } diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 425b2e3e7140b..7fa13d6074d43 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -24,7 +24,6 @@ extern crate time; use std::os; use std::result::{Ok, Err}; use std::task; -use std::uint; fn fib(n: int) -> int { fn pfib(tx: &Sender, n: int) { @@ -102,8 +101,7 @@ fn main() { if opts.stress { stress(2); } else { - let max = uint::parse_bytes(args[1].as_bytes(), 10u).unwrap() as - int; + let max = from_str::(args[1].as_slice()).unwrap() as int; let num_trials = 10;