Remove core::num::strconv
This commit is contained in:
@@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
use mem;
|
use mem;
|
||||||
use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN};
|
use num::{Float, FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN};
|
||||||
use num::{Float, FromStrRadix};
|
use num::from_str_radix;
|
||||||
use num::strconv;
|
|
||||||
use str::FromStr;
|
|
||||||
use option::Option;
|
use option::Option;
|
||||||
|
|
||||||
pub const RADIX: uint = 2u;
|
pub const RADIX: uint = 2u;
|
||||||
@@ -431,61 +429,5 @@ impl Float for f32 {
|
|||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"]
|
#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"]
|
||||||
pub fn from_str_hex(src: &str) -> Option<f32> {
|
pub fn from_str_hex(src: &str) -> Option<f32> {
|
||||||
strconv::from_str_radix_float(src, 16)
|
from_str_radix(src, 16)
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for f32 {
|
|
||||||
/// Convert a string in base 10 to a float.
|
|
||||||
/// Accepts an optional decimal exponent.
|
|
||||||
///
|
|
||||||
/// 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'
|
|
||||||
///
|
|
||||||
/// Leading and trailing whitespace represent an error.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * 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 `src`.
|
|
||||||
#[inline]
|
|
||||||
fn from_str(src: &str) -> Option<f32> {
|
|
||||||
strconv::from_str_radix_float(src, 10u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStrRadix for f32 {
|
|
||||||
/// 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
|
|
||||||
///
|
|
||||||
/// * 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 `src`.
|
|
||||||
#[inline]
|
|
||||||
fn from_str_radix(src: &str, radix: uint) -> Option<f32> {
|
|
||||||
strconv::from_str_radix_float(src, radix)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
use mem;
|
use mem;
|
||||||
use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN};
|
use num::{Float, FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN};
|
||||||
use num::{Float, FromStrRadix};
|
use num::from_str_radix;
|
||||||
use num::strconv;
|
|
||||||
use str::FromStr;
|
|
||||||
use option::Option;
|
use option::Option;
|
||||||
|
|
||||||
// FIXME(#5527): These constants should be deprecated once associated
|
// FIXME(#5527): These constants should be deprecated once associated
|
||||||
@@ -437,56 +435,5 @@ impl Float for f64 {
|
|||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"]
|
#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"]
|
||||||
pub fn from_str_hex(src: &str) -> Option<f64> {
|
pub fn from_str_hex(src: &str) -> Option<f64> {
|
||||||
strconv::from_str_radix_float(src, 16)
|
from_str_radix(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:
|
|
||||||
///
|
|
||||||
/// * '3.14'
|
|
||||||
/// * '-3.14'
|
|
||||||
/// * '2.5E10', or equivalently, '2.5e10'
|
|
||||||
/// * '2.5E-10'
|
|
||||||
/// * '.' (understood as 0)
|
|
||||||
/// * '5.'
|
|
||||||
/// * '.5', or, equivalently, '0.5'
|
|
||||||
/// * inf', '-inf', 'NaN'
|
|
||||||
///
|
|
||||||
/// Leading and trailing whitespace represent an error.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * 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 `src`.
|
|
||||||
#[inline]
|
|
||||||
fn from_str(src: &str) -> Option<f64> {
|
|
||||||
strconv::from_str_radix_float(src, 10u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStrRadix for f64 {
|
|
||||||
/// Convert a string in a given base to a float.
|
|
||||||
///
|
|
||||||
/// Leading and trailing whitespace represent an error.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * 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 `src`.
|
|
||||||
#[inline]
|
|
||||||
fn from_str_radix(src: &str, radix: uint) -> Option<f64> {
|
|
||||||
strconv::from_str_radix_float(src, radix)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,20 +32,4 @@ pub const MIN: $T = (-1 as $T) << (BITS - 1);
|
|||||||
#[unstable]
|
#[unstable]
|
||||||
pub const MAX: $T = !MIN;
|
pub const MAX: $T = !MIN;
|
||||||
|
|
||||||
#[experimental = "might need to return Result"]
|
|
||||||
impl ::str::FromStr for $T {
|
|
||||||
#[inline]
|
|
||||||
fn from_str(s: &str) -> ::option::Option<$T> {
|
|
||||||
::num::strconv::from_str_radix_int(s, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[experimental = "might need to return Result"]
|
|
||||||
impl ::num::FromStrRadix for $T {
|
|
||||||
#[inline]
|
|
||||||
fn from_str_radix(s: &str, radix: uint) -> ::option::Option<$T> {
|
|
||||||
::num::strconv::from_str_radix_int(s, radix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -14,20 +14,21 @@
|
|||||||
|
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use intrinsics;
|
|
||||||
use {int, i8, i16, i32, i64};
|
use {int, i8, i16, i32, i64};
|
||||||
use {uint, u8, u16, u32, u64};
|
use {uint, u8, u16, u32, u64};
|
||||||
use {f32, f64};
|
use {f32, f64};
|
||||||
|
use char::Char;
|
||||||
use clone::Clone;
|
use clone::Clone;
|
||||||
use cmp::{PartialEq, Eq};
|
use cmp::{PartialEq, Eq};
|
||||||
use cmp::{PartialOrd, Ord};
|
use cmp::{PartialOrd, Ord};
|
||||||
|
use intrinsics;
|
||||||
|
use iter::Iterator;
|
||||||
use kinds::Copy;
|
use kinds::Copy;
|
||||||
use mem::size_of;
|
use mem::size_of;
|
||||||
use ops::{Add, Sub, Mul, Div, Rem, Neg};
|
use ops::{Add, Sub, Mul, Div, Rem, Neg};
|
||||||
use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
|
use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
|
||||||
use option::{Option, Some, None};
|
use option::{Option, Some, None};
|
||||||
|
use str::{FromStr, from_str, StrPrelude};
|
||||||
pub mod strconv;
|
|
||||||
|
|
||||||
/// Simultaneous division and remainder
|
/// Simultaneous division and remainder
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1386,6 +1387,278 @@ pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
|
|||||||
FromStrRadix::from_str_radix(str, radix)
|
FromStrRadix::from_str_radix(str, radix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! from_str_radix_float_impl {
|
||||||
|
($T:ty) => {
|
||||||
|
#[experimental = "might need to return Result"]
|
||||||
|
impl FromStr for $T {
|
||||||
|
/// Convert a string in base 10 to a float.
|
||||||
|
/// Accepts an optional decimal exponent.
|
||||||
|
///
|
||||||
|
/// 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'
|
||||||
|
///
|
||||||
|
/// Leading and trailing whitespace represent an error.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * 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 `src`.
|
||||||
|
#[inline]
|
||||||
|
fn from_str(src: &str) -> Option<$T> {
|
||||||
|
from_str_radix(src, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[experimental = "might need to return Result"]
|
||||||
|
impl FromStrRadix for $T {
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// * 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 `src`.
|
||||||
|
fn from_str_radix(src: &str, radix: uint) -> Option<$T> {
|
||||||
|
assert!(radix >= 2 && radix <= 36,
|
||||||
|
"from_str_radix_float: must lie in the range `[2, 36]` - found {}",
|
||||||
|
radix);
|
||||||
|
|
||||||
|
// Special values
|
||||||
|
match src {
|
||||||
|
"inf" => return Some(Float::infinity()),
|
||||||
|
"-inf" => return Some(Float::neg_infinity()),
|
||||||
|
"NaN" => return Some(Float::nan()),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let (is_positive, src) = match src.slice_shift_char() {
|
||||||
|
(None, _) => return None,
|
||||||
|
(Some('-'), "") => return None,
|
||||||
|
(Some('-'), src) => (false, src),
|
||||||
|
(Some(_), _) => (true, src),
|
||||||
|
};
|
||||||
|
|
||||||
|
// The significand to accumulate
|
||||||
|
let mut sig = if is_positive { 0.0 } else { -0.0 };
|
||||||
|
// 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 significand one digit left
|
||||||
|
sig = sig * (radix as $T);
|
||||||
|
|
||||||
|
// add/subtract current digit depending on sign
|
||||||
|
if is_positive {
|
||||||
|
sig = sig + ((digit as int) as $T);
|
||||||
|
} else {
|
||||||
|
sig = sig - ((digit as int) as $T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect overflow by comparing to last value, except
|
||||||
|
// if we've not seen any non-zero digits.
|
||||||
|
if prev_sig != 0.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 is_positive && (prev_sig != (sig - digit as $T) / radix as $T)
|
||||||
|
{ return Some(Float::infinity()); }
|
||||||
|
if !is_positive && (prev_sig != (sig + digit as $T) / radix as $T)
|
||||||
|
{ return Some(Float::neg_infinity()); }
|
||||||
|
}
|
||||||
|
prev_sig = sig;
|
||||||
|
},
|
||||||
|
None => match c {
|
||||||
|
'e' | 'E' | 'p' | 'P' => {
|
||||||
|
exp_info = Some((c, i + 1));
|
||||||
|
break; // start of exponent
|
||||||
|
},
|
||||||
|
'.' => {
|
||||||
|
break; // start of fractional part
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are not yet at the exponent parse the fractional
|
||||||
|
// part of the significand
|
||||||
|
if exp_info.is_none() {
|
||||||
|
let mut power = 1.0;
|
||||||
|
for (i, c) in cs {
|
||||||
|
match c.to_digit(radix) {
|
||||||
|
Some(digit) => {
|
||||||
|
// Decrease power one order of magnitude
|
||||||
|
power = power / (radix as $T);
|
||||||
|
// add/subtract current digit depending on sign
|
||||||
|
sig = if is_positive {
|
||||||
|
sig + (digit as $T) * power
|
||||||
|
} else {
|
||||||
|
sig - (digit as $T) * power
|
||||||
|
};
|
||||||
|
// Detect overflow by comparing to last value
|
||||||
|
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 {
|
||||||
|
'e' | 'E' | 'p' | 'P' => {
|
||||||
|
exp_info = Some((c, i + 1));
|
||||||
|
break; // start of exponent
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return None; // invalid number
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and calculate the exponent
|
||||||
|
let exp = match exp_info {
|
||||||
|
Some((c, offset)) => {
|
||||||
|
let base = match c {
|
||||||
|
'E' | 'e' if radix == 10 => 10u as $T,
|
||||||
|
'P' | 'p' if radix == 16 => 2u as $T,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse the exponent as decimal integer
|
||||||
|
let src = src[offset..];
|
||||||
|
let (is_positive, exp) = match src.slice_shift_char() {
|
||||||
|
(Some('-'), src) => (false, from_str::<uint>(src)),
|
||||||
|
(Some('+'), src) => (true, from_str::<uint>(src)),
|
||||||
|
(Some(_), _) => (true, from_str::<uint>(src)),
|
||||||
|
(None, _) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match (is_positive, exp) {
|
||||||
|
(true, Some(exp)) => base.powi(exp as i32),
|
||||||
|
(false, Some(exp)) => 1.0 / base.powi(exp as i32),
|
||||||
|
(_, None) => return None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => 1.0, // no exponent
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(sig * exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
from_str_radix_float_impl!(f32)
|
||||||
|
from_str_radix_float_impl!(f64)
|
||||||
|
|
||||||
|
macro_rules! from_str_radix_int_impl {
|
||||||
|
($T:ty) => {
|
||||||
|
#[experimental = "might need to return Result"]
|
||||||
|
impl FromStr for $T {
|
||||||
|
#[inline]
|
||||||
|
fn from_str(src: &str) -> Option<$T> {
|
||||||
|
from_str_radix(src, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[experimental = "might need to return Result"]
|
||||||
|
impl FromStrRadix for $T {
|
||||||
|
fn from_str_radix(src: &str, radix: uint) -> Option<$T> {
|
||||||
|
assert!(radix >= 2 && radix <= 36,
|
||||||
|
"from_str_radix_int: must lie in the range `[2, 36]` - found {}",
|
||||||
|
radix);
|
||||||
|
|
||||||
|
let is_signed_ty = (0 as $T) > Int::min_value();
|
||||||
|
|
||||||
|
match src.slice_shift_char() {
|
||||||
|
(Some('-'), src) if is_signed_ty => {
|
||||||
|
// The number is negative
|
||||||
|
let mut result = 0;
|
||||||
|
for c in src.chars() {
|
||||||
|
let x = match c.to_digit(radix) {
|
||||||
|
Some(x) => x,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
result = match result.checked_mul(radix as $T) {
|
||||||
|
Some(result) => result,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
result = match result.checked_sub(x as $T) {
|
||||||
|
Some(result) => result,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Some(result)
|
||||||
|
},
|
||||||
|
(Some(_), _) => {
|
||||||
|
// The number is signed
|
||||||
|
let mut result = 0;
|
||||||
|
for c in src.chars() {
|
||||||
|
let x = match c.to_digit(radix) {
|
||||||
|
Some(x) => x,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
result = match result.checked_mul(radix as $T) {
|
||||||
|
Some(result) => result,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
result = match result.checked_add(x as $T) {
|
||||||
|
Some(result) => result,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Some(result)
|
||||||
|
},
|
||||||
|
(None, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
from_str_radix_int_impl!(int)
|
||||||
|
from_str_radix_int_impl!(i8)
|
||||||
|
from_str_radix_int_impl!(i16)
|
||||||
|
from_str_radix_int_impl!(i32)
|
||||||
|
from_str_radix_int_impl!(i64)
|
||||||
|
from_str_radix_int_impl!(uint)
|
||||||
|
from_str_radix_int_impl!(u8)
|
||||||
|
from_str_radix_int_impl!(u16)
|
||||||
|
from_str_radix_int_impl!(u32)
|
||||||
|
from_str_radix_int_impl!(u64)
|
||||||
|
|
||||||
// DEPRECATED
|
// DEPRECATED
|
||||||
|
|
||||||
macro_rules! trait_impl {
|
macro_rules! trait_impl {
|
||||||
|
|||||||
@@ -1,259 +0,0 @@
|
|||||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
//
|
|
||||||
// ignore-lexer-test FIXME #15679
|
|
||||||
|
|
||||||
#![allow(missing_docs)]
|
|
||||||
|
|
||||||
use char::Char;
|
|
||||||
use iter::Iterator;
|
|
||||||
use num;
|
|
||||||
use num::{Int, Float};
|
|
||||||
use option::{None, Option, Some};
|
|
||||||
use str::{from_str, StrPrelude};
|
|
||||||
|
|
||||||
pub fn from_str_radix_float<T: Float>(src: &str, radix: uint) -> Option<T> {
|
|
||||||
assert!(radix >= 2 && radix <= 36,
|
|
||||||
"from_str_radix_float: must lie in the range `[2, 36]` - found {}",
|
|
||||||
radix);
|
|
||||||
|
|
||||||
let _0: T = Float::zero();
|
|
||||||
let _1: T = Float::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()),
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
let (is_positive, src) = match src.slice_shift_char() {
|
|
||||||
(None, _) => return None,
|
|
||||||
(Some('-'), "") => return None,
|
|
||||||
(Some('-'), src) => (false, src),
|
|
||||||
(Some(_), _) => (true, src),
|
|
||||||
};
|
|
||||||
|
|
||||||
// The significand to accumulate
|
|
||||||
let mut sig = if is_positive { _0 } else { -_0 };
|
|
||||||
// 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 significand one digit left
|
|
||||||
sig = sig * radix_t;
|
|
||||||
|
|
||||||
// add/subtract current digit depending on sign
|
|
||||||
if is_positive {
|
|
||||||
sig = sig + num::cast(digit as int).unwrap();
|
|
||||||
} else {
|
|
||||||
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 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
|
|
||||||
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()); }
|
|
||||||
}
|
|
||||||
prev_sig = sig;
|
|
||||||
},
|
|
||||||
None => match c {
|
|
||||||
'e' | 'E' | 'p' | 'P' => {
|
|
||||||
exp_info = Some((c, i + 1));
|
|
||||||
break; // start of exponent
|
|
||||||
},
|
|
||||||
'.' => {
|
|
||||||
break; // start of fractional part
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
return None;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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_t;
|
|
||||||
// add/subtract current digit depending on sign
|
|
||||||
sig = if is_positive {
|
|
||||||
sig + digit * power
|
|
||||||
} else {
|
|
||||||
sig - digit * power
|
|
||||||
};
|
|
||||||
// Detect overflow by comparing to last value
|
|
||||||
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 {
|
|
||||||
'e' | 'E' | 'p' | 'P' => {
|
|
||||||
exp_info = Some((c, i + 1));
|
|
||||||
break; // start of exponent
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
return None; // invalid number
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse the exponent as decimal integer
|
|
||||||
let src = src[offset..];
|
|
||||||
let (is_positive, exp) = match src.slice_shift_char() {
|
|
||||||
(Some('-'), src) => (false, from_str::<uint>(src)),
|
|
||||||
(Some('+'), src) => (true, from_str::<uint>(src)),
|
|
||||||
(Some(_), _) => (true, from_str::<uint>(src)),
|
|
||||||
(None, _) => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
match (is_positive, exp) {
|
|
||||||
(true, Some(exp)) => base.powi(exp as i32),
|
|
||||||
(false, Some(exp)) => _1 / base.powi(exp as i32),
|
|
||||||
(_, None) => return None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => _1, // no exponent
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(sig * exp)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_str_radix_int<T: Int>(src: &str, radix: uint) -> Option<T> {
|
|
||||||
assert!(radix >= 2 && radix <= 36,
|
|
||||||
"from_str_radix_int: must lie in the range `[2, 36]` - found {}",
|
|
||||||
radix);
|
|
||||||
|
|
||||||
fn cast<T: Int>(x: uint) -> T {
|
|
||||||
num::cast(x).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
let _0: T = Int::zero();
|
|
||||||
let _1: T = Int::one();
|
|
||||||
let is_signed = _0 > Int::min_value();
|
|
||||||
|
|
||||||
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::*;
|
|
||||||
use num::Float;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn from_str_issue7588() {
|
|
||||||
let u : Option<u8> = from_str_radix_int("1000", 10);
|
|
||||||
assert_eq!(u, None);
|
|
||||||
let s : Option<i16> = from_str_radix_int("80000", 10);
|
|
||||||
assert_eq!(s, None);
|
|
||||||
let f : Option<f32> = from_str_radix_float("10000000000000000000000000000000000000000", 10);
|
|
||||||
assert_eq!(f, Some(Float::infinity()))
|
|
||||||
let fe : Option<f32> = from_str_radix_float("1e40", 10);
|
|
||||||
assert_eq!(fe, Some(Float::infinity()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_str_radix_float() {
|
|
||||||
let x1 : Option<f64> = from_str_radix_float("-123.456", 10);
|
|
||||||
assert_eq!(x1, Some(-123.456));
|
|
||||||
let x2 : Option<f32> = from_str_radix_float("123.456", 10);
|
|
||||||
assert_eq!(x2, Some(123.456));
|
|
||||||
let x3 : Option<f32> = from_str_radix_float("-0.0", 10);
|
|
||||||
assert_eq!(x3, Some(-0.0));
|
|
||||||
let x4 : Option<f32> = from_str_radix_float("0.0", 10);
|
|
||||||
assert_eq!(x4, Some(0.0));
|
|
||||||
let x4 : Option<f32> = from_str_radix_float("1.0", 10);
|
|
||||||
assert_eq!(x4, Some(1.0));
|
|
||||||
let x5 : Option<f32> = from_str_radix_float("-1.0", 10);
|
|
||||||
assert_eq!(x5, Some(-1.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,20 +23,4 @@ pub const MIN: $T = 0 as $T;
|
|||||||
#[unstable]
|
#[unstable]
|
||||||
pub const MAX: $T = 0 as $T - 1 as $T;
|
pub const MAX: $T = 0 as $T - 1 as $T;
|
||||||
|
|
||||||
#[experimental = "might need to return Result"]
|
|
||||||
impl ::str::FromStr for $T {
|
|
||||||
#[inline]
|
|
||||||
fn from_str(s: &str) -> ::option::Option<$T> {
|
|
||||||
::num::strconv::from_str_radix_int(s, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[experimental = "might need to return Result"]
|
|
||||||
impl ::num::FromStrRadix for $T {
|
|
||||||
#[inline]
|
|
||||||
fn from_str_radix(s: &str, radix: uint) -> ::option::Option<$T> {
|
|
||||||
::num::strconv::from_str_radix_int(s, radix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
))
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user