auto merge of #4957 : Kimundi/rust/incoming, r=catamorphism
Moved them into own module and made them not depend on an Round trait impl for integers and generic math functions that can fail on integers any more.
This commit is contained in:
commit
3e97cce27d
7 changed files with 732 additions and 691 deletions
|
@ -14,6 +14,7 @@ use cmath;
|
|||
use cmp;
|
||||
use libc::{c_float, c_int};
|
||||
use num::NumCast;
|
||||
use num::strconv;
|
||||
use num;
|
||||
use ops;
|
||||
use option::Option;
|
||||
|
@ -376,8 +377,8 @@ impl num::Round for f32 {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str(num: f32) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -390,8 +391,8 @@ pub pure fn to_str(num: f32) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_hex(num: f32) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 16u, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -411,8 +412,8 @@ pub pure fn to_str_hex(num: f32) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_radix(num: f32, rdx: uint) -> ~str {
|
||||
let (r, special) = num::to_str_common(
|
||||
&num, rdx, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!(~"number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
|
@ -429,7 +430,8 @@ pub pure fn to_str_radix(num: f32, rdx: uint) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
|
||||
num::to_str_common(&num, rdx, true, true, num::SignNeg, num::DigAll)
|
||||
strconv::to_str_common(&num, rdx, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -443,8 +445,8 @@ pub pure fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_exact(num: f32, dig: uint) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigExact(dig));
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -459,8 +461,8 @@ pub pure fn to_str_exact(num: f32, dig: uint) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_digits(num: f32, dig: uint) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigMax(dig));
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -505,7 +507,8 @@ impl num::ToStrRadix for f32 {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str(num: &str) -> Option<f32> {
|
||||
num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
|
||||
strconv::from_str_common(num, 10u, true, true, true,
|
||||
strconv::ExpDec, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -537,7 +540,8 @@ pub pure fn from_str(num: &str) -> Option<f32> {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_hex(num: &str) -> Option<f32> {
|
||||
num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
|
||||
strconv::from_str_common(num, 16u, true, true, true,
|
||||
strconv::ExpBin, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -561,7 +565,8 @@ pub pure fn from_str_hex(num: &str) -> Option<f32> {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
|
||||
num::from_str_common(num, rdx, true, true, false, num::ExpNone, false)
|
||||
strconv::from_str_common(num, rdx, true, true, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl from_str::FromStr for f32 {
|
||||
|
|
|
@ -15,6 +15,7 @@ use cmp;
|
|||
use libc::{c_double, c_int};
|
||||
use libc;
|
||||
use num::NumCast;
|
||||
use num::strconv;
|
||||
use num;
|
||||
use ops;
|
||||
use option::Option;
|
||||
|
@ -401,8 +402,8 @@ impl num::Round for f64 {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str(num: f64) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -415,8 +416,8 @@ pub pure fn to_str(num: f64) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_hex(num: f64) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 16u, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -436,8 +437,8 @@ pub pure fn to_str_hex(num: f64) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_radix(num: f64, rdx: uint) -> ~str {
|
||||
let (r, special) = num::to_str_common(
|
||||
&num, rdx, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!(~"number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
|
@ -454,7 +455,8 @@ pub pure fn to_str_radix(num: f64, rdx: uint) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
|
||||
num::to_str_common(&num, rdx, true, true, num::SignNeg, num::DigAll)
|
||||
strconv::to_str_common(&num, rdx, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -468,8 +470,8 @@ pub pure fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_exact(num: f64, dig: uint) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigExact(dig));
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -484,8 +486,8 @@ pub pure fn to_str_exact(num: f64, dig: uint) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_digits(num: f64, dig: uint) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigMax(dig));
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -530,7 +532,8 @@ impl num::ToStrRadix for f64 {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str(num: &str) -> Option<f64> {
|
||||
num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
|
||||
strconv::from_str_common(num, 10u, true, true, true,
|
||||
strconv::ExpDec, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -562,7 +565,8 @@ pub pure fn from_str(num: &str) -> Option<f64> {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_hex(num: &str) -> Option<f64> {
|
||||
num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
|
||||
strconv::from_str_common(num, 16u, true, true, true,
|
||||
strconv::ExpBin, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -586,7 +590,8 @@ pub pure fn from_str_hex(num: &str) -> Option<f64> {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
|
||||
num::from_str_common(num, rdx, true, true, false, num::ExpNone, false)
|
||||
strconv::from_str_common(num, rdx, true, true, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl from_str::FromStr for f64 {
|
||||
|
|
|
@ -26,6 +26,7 @@ use cmp::{Eq, Ord};
|
|||
use cmp;
|
||||
use f64;
|
||||
use num::NumCast;
|
||||
use num::strconv;
|
||||
use num;
|
||||
use ops;
|
||||
use option::{None, Option, Some};
|
||||
|
@ -107,8 +108,8 @@ pub mod consts {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str(num: float) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -121,8 +122,8 @@ pub pure fn to_str(num: float) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_hex(num: float) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 16u, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -142,8 +143,8 @@ pub pure fn to_str_hex(num: float) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_radix(num: float, radix: uint) -> ~str {
|
||||
let (r, special) = num::to_str_common(
|
||||
&num, radix, true, true, num::SignNeg, num::DigAll);
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, radix, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!(~"number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
|
@ -160,7 +161,8 @@ pub pure fn to_str_radix(num: float, radix: uint) -> ~str {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) {
|
||||
num::to_str_common(&num, radix, true, true, num::SignNeg, num::DigAll)
|
||||
strconv::to_str_common(&num, radix, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,8 +176,8 @@ pub pure fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_exact(num: float, digits: uint) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigExact(digits));
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(digits));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -196,8 +198,8 @@ pub fn test_to_str_exact_do_decimal() {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_digits(num: float, digits: uint) -> ~str {
|
||||
let (r, _) = num::to_str_common(
|
||||
&num, 10u, true, true, num::SignNeg, num::DigMax(digits));
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(digits));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -242,7 +244,8 @@ impl num::ToStrRadix for float {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str(num: &str) -> Option<float> {
|
||||
num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
|
||||
strconv::from_str_common(num, 10u, true, true, true,
|
||||
strconv::ExpDec, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -274,7 +277,8 @@ pub pure fn from_str(num: &str) -> Option<float> {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_hex(num: &str) -> Option<float> {
|
||||
num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
|
||||
strconv::from_str_common(num, 16u, true, true, true,
|
||||
strconv::ExpBin, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -298,7 +302,8 @@ pub pure fn from_str_hex(num: &str) -> Option<float> {
|
|||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_radix(num: &str, radix: uint) -> Option<float> {
|
||||
num::from_str_common(num, radix, true, true, false, num::ExpNone, false)
|
||||
strconv::from_str_common(num, radix, true, true, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl from_str::FromStr for float {
|
||||
|
|
|
@ -16,6 +16,7 @@ use cmp;
|
|||
use to_str::ToStr;
|
||||
use from_str::FromStr;
|
||||
use num::{ToStrRadix, FromStrRadix};
|
||||
use num::strconv;
|
||||
use num;
|
||||
use prelude::*;
|
||||
use str;
|
||||
|
@ -176,18 +177,6 @@ impl num::One for T {
|
|||
static pure fn one() -> T { 1 }
|
||||
}
|
||||
|
||||
impl num::Round for T {
|
||||
#[inline(always)]
|
||||
pure fn round(&self, _: num::RoundMode) -> T { *self }
|
||||
|
||||
#[inline(always)]
|
||||
pure fn floor(&self) -> T { *self }
|
||||
#[inline(always)]
|
||||
pure fn ceil(&self) -> T { *self }
|
||||
#[inline(always)]
|
||||
pure fn fract(&self) -> T { 0 }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl ops::Add<T,T> for T {
|
||||
pure fn add(&self, other: &T) -> T { *self + *other }
|
||||
|
@ -218,22 +207,22 @@ impl ops::Neg<T> for T {
|
|||
/// Parse a string as a number in base 10.
|
||||
#[inline(always)]
|
||||
pub pure fn from_str(s: &str) -> Option<T> {
|
||||
num::from_str_common(s, 10u, true, false, false,
|
||||
num::ExpNone, false)
|
||||
strconv::from_str_common(s, 10u, true, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
/// Parse a string as a number in the given base.
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_radix(s: &str, radix: uint) -> Option<T> {
|
||||
num::from_str_common(s, radix, true, false, false,
|
||||
num::ExpNone, false)
|
||||
strconv::from_str_common(s, radix, true, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
/// Parse a byte slice as a number in the given base.
|
||||
#[inline(always)]
|
||||
pub pure fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
|
||||
num::from_str_bytes_common(buf, radix, true, false, false,
|
||||
num::ExpNone, false)
|
||||
strconv::from_str_bytes_common(buf, radix, true, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl FromStr for T {
|
||||
|
@ -255,24 +244,24 @@ impl FromStrRadix for T {
|
|||
/// Convert to a string as a byte slice in a given base.
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
|
||||
let (buf, _) = num::to_str_bytes_common(&n, radix, false, false,
|
||||
num::SignNeg, num::DigAll);
|
||||
let (buf, _) = strconv::to_str_bytes_common(&n, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
f(buf)
|
||||
}
|
||||
|
||||
/// Convert to a string in base 10.
|
||||
#[inline(always)]
|
||||
pub pure fn to_str(num: T) -> ~str {
|
||||
let (buf, _) = num::to_str_common(&num, 10u, false, false,
|
||||
num::SignNeg, num::DigAll);
|
||||
let (buf, _) = strconv::to_str_common(&num, 10u, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
}
|
||||
|
||||
/// Convert to a string in a given base.
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_radix(num: T, radix: uint) -> ~str {
|
||||
let (buf, _) = num::to_str_common(&num, radix, false, false,
|
||||
num::SignNeg, num::DigAll);
|
||||
let (buf, _) = strconv::to_str_common(&num, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
@ -17,6 +17,8 @@ use str;
|
|||
use kinds::Copy;
|
||||
use vec;
|
||||
|
||||
pub mod strconv;
|
||||
|
||||
pub trait IntConvertible {
|
||||
pure fn to_int(&self) -> int;
|
||||
static pure fn from_int(n: int) -> Self;
|
||||
|
@ -42,6 +44,13 @@ pub trait Round {
|
|||
pure fn fract(&self) -> Self;
|
||||
}
|
||||
|
||||
pub enum RoundMode {
|
||||
RoundDown,
|
||||
RoundUp,
|
||||
RoundToZero,
|
||||
RoundFromZero
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a number the the enclosing type
|
||||
*
|
||||
|
@ -80,13 +89,6 @@ pub trait NumCast {
|
|||
pure fn to_float(&self) -> float;
|
||||
}
|
||||
|
||||
pub enum RoundMode {
|
||||
RoundDown,
|
||||
RoundUp,
|
||||
RoundToZero,
|
||||
RoundFromZero
|
||||
}
|
||||
|
||||
pub trait ToStrRadix {
|
||||
pub pure fn to_str_radix(&self, radix: uint) -> ~str;
|
||||
}
|
||||
|
@ -97,62 +99,6 @@ pub trait FromStrRadix {
|
|||
|
||||
// Generic math functions:
|
||||
|
||||
/// Dynamically calculates the value `inf` (`1/0`).
|
||||
/// Can fail on integer types.
|
||||
#[inline(always)]
|
||||
pub pure fn infinity<T:One+Zero+Div<T,T>>() -> T {
|
||||
let _0: T = Zero::zero();
|
||||
let _1: T = One::one();
|
||||
_1 / _0
|
||||
}
|
||||
|
||||
/// Dynamically calculates the value `-inf` (`-1/0`).
|
||||
/// Can fail on integer types.
|
||||
#[inline(always)]
|
||||
pub pure fn neg_infinity<T:One+Zero+Div<T,T>+Neg<T>>() -> T {
|
||||
let _0: T = Zero::zero();
|
||||
let _1: T = One::one();
|
||||
- _1 / _0
|
||||
}
|
||||
|
||||
/// Dynamically calculates the value `NaN` (`0/0`).
|
||||
/// Can fail on integer types.
|
||||
#[inline(always)]
|
||||
pub pure fn NaN<T:Zero+Div<T,T>>() -> T {
|
||||
let _0: T = Zero::zero();
|
||||
_0 / _0
|
||||
}
|
||||
|
||||
/// Returns `true` if `num` has the value `inf` (`1/0`).
|
||||
/// Can fail on integer types.
|
||||
#[inline(always)]
|
||||
pub pure fn is_infinity<T:One+Zero+Eq+Div<T,T>>(num: &T) -> bool {
|
||||
(*num) == (infinity::<T>())
|
||||
}
|
||||
|
||||
/// Returns `true` if `num` has the value `-inf` (`-1/0`).
|
||||
/// Can fail on integer types.
|
||||
#[inline(always)]
|
||||
pub pure fn is_neg_infinity<T:One+Zero+Eq+Div<T,T>+Neg<T>>(num: &T)
|
||||
-> bool {
|
||||
(*num) == (neg_infinity::<T>())
|
||||
}
|
||||
|
||||
/// Returns `true` if `num` has the value `NaN` (is not equal to itself).
|
||||
#[inline(always)]
|
||||
pub pure fn is_NaN<T:Eq>(num: &T) -> bool {
|
||||
(*num) != (*num)
|
||||
}
|
||||
|
||||
/// Returns `true` if `num` has the value `-0` (`1/num == -1/0`).
|
||||
/// Can fail on integer types.
|
||||
#[inline(always)]
|
||||
pub pure fn is_neg_zero<T:One+Zero+Eq+Div<T,T>+Neg<T>>(num: &T) -> bool {
|
||||
let _1: T = One::one();
|
||||
let _0: T = Zero::zero();
|
||||
*num == _0 && is_neg_infinity(&(_1 / *num))
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a power to a given radix, optimized for uint `pow` and `radix`.
|
||||
*
|
||||
|
@ -186,540 +132,3 @@ pub pure fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(
|
|||
total
|
||||
}
|
||||
|
||||
pub enum ExponentFormat {
|
||||
ExpNone,
|
||||
ExpDec,
|
||||
ExpBin
|
||||
}
|
||||
|
||||
pub enum SignificantDigits {
|
||||
DigAll,
|
||||
DigMax(uint),
|
||||
DigExact(uint)
|
||||
}
|
||||
|
||||
pub enum SignFormat {
|
||||
SignNone,
|
||||
SignNeg,
|
||||
SignAll
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number to its string representation as a byte vector.
|
||||
* This is meant to be a common base implementation for all numeric string
|
||||
* conversion functions like `to_str()` or `to_str_radix()`.
|
||||
*
|
||||
* # Arguments
|
||||
* - `num` - The number to convert. Accepts any number that
|
||||
* implements the numeric traits.
|
||||
* - `radix` - Base to use. Accepts only the values 2-36.
|
||||
* - `special` - Whether to attempt to compare to special values like
|
||||
* `inf` or `NaN`. Also needed to detect negative 0.
|
||||
* Can fail if it doesn't match `num`s type
|
||||
* (see safety note).
|
||||
* - `negative_zero` - Whether to treat the special value `-0` as
|
||||
* `-0` or as `+0`.
|
||||
* - `sign` - How to emit the sign. Options are:
|
||||
* - `SignNone`: No sign at all. Basically emits `abs(num)`.
|
||||
* - `SignNeg`: Only `-` on negative values.
|
||||
* - `SignAll`: Both `+` on positive, and `-` on negative numbers.
|
||||
* - `digits` - The amount of digits to use for emitting the
|
||||
* fractional part, if any. Options are:
|
||||
* - `DigAll`: All calculatable digits. Beware of bignums or
|
||||
* fractions!
|
||||
* - `DigMax(uint)`: Maximum N digits, truncating any trailing zeros.
|
||||
* - `DigExact(uint)`: Exactly N digits.
|
||||
*
|
||||
* # Return value
|
||||
* A tuple containing the byte vector, and a boolean flag indicating
|
||||
* whether it represents a special value like `inf`, `-inf`, `NaN` or not.
|
||||
* It returns a tuple because there can be ambiguity between a special value
|
||||
* and a number representation at higher bases.
|
||||
*
|
||||
* # Failure
|
||||
* - Fails if `radix` < 2 or `radix` > 36.
|
||||
* - Fails on wrong value for `special` (see safety note).
|
||||
*
|
||||
* # Safety note
|
||||
* The function detects the special values `inf`, `-inf` and `NaN` by
|
||||
* dynamically comparing `num` to `1 / 0`, `-1 / 0` and `0 / 0`
|
||||
* (each of type T) if `special` is `true`. This will fail on integer types
|
||||
* with a 'divide by zero'. Likewise, it will fail if `num` **is** one of
|
||||
* those special values, and `special` is `false`, because then the
|
||||
* algorithm just does normal calculations on them.
|
||||
*/
|
||||
pub pure fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Round+Copy+Div<T,T>+
|
||||
Neg<T>+Modulo<T,T>+Mul<T,T>>(
|
||||
num: &T, radix: uint, special: bool, negative_zero: bool,
|
||||
sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
|
||||
if radix as int < 2 {
|
||||
fail!(fmt!("to_str_bytes_common: radix %? to low, \
|
||||
must lie in the range [2, 36]", radix));
|
||||
} else if radix as int > 36 {
|
||||
fail!(fmt!("to_str_bytes_common: radix %? to high, \
|
||||
must lie in the range [2, 36]", radix));
|
||||
}
|
||||
|
||||
let _0: T = Zero::zero();
|
||||
let _1: T = One::one();
|
||||
|
||||
if special {
|
||||
if is_NaN(num) {
|
||||
return (str::to_bytes("NaN"), true);
|
||||
} else if is_infinity(num){
|
||||
return match sign {
|
||||
SignAll => (str::to_bytes("+inf"), true),
|
||||
_ => (str::to_bytes("inf"), true)
|
||||
}
|
||||
} else if is_neg_infinity(num) {
|
||||
return match sign {
|
||||
SignNone => (str::to_bytes("inf"), true),
|
||||
_ => (str::to_bytes("-inf"), true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let neg = *num < _0 || (negative_zero && *num == _0
|
||||
&& special && is_neg_zero(num));
|
||||
let mut buf: ~[u8] = ~[];
|
||||
let radix_gen: T = cast(radix as int);
|
||||
|
||||
let mut deccum;
|
||||
|
||||
// First emit the non-fractional part, looping at least once to make
|
||||
// sure at least a `0` gets emitted.
|
||||
deccum = num.round(RoundToZero);
|
||||
loop {
|
||||
// Calculate the absolute value of each digit instead of only
|
||||
// doing it once for the whole number because a
|
||||
// representable negative number doesn't necessary have an
|
||||
// representable additive inverse of the same type
|
||||
// (See twos complement). But we assume that for the
|
||||
// numbers [-35 .. 0] we always have [0 .. 35].
|
||||
let current_digit_signed = deccum % radix_gen;
|
||||
let current_digit = if current_digit_signed < _0 {
|
||||
-current_digit_signed
|
||||
} else {
|
||||
current_digit_signed
|
||||
};
|
||||
|
||||
// Decrease the deccumulator one digit at a time
|
||||
deccum /= radix_gen;
|
||||
deccum = deccum.round(RoundToZero);
|
||||
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push(char::from_digit(current_digit.to_int() as uint, radix)
|
||||
.unwrap() as u8);
|
||||
}
|
||||
|
||||
// No more digits to calculate for the non-fractional part -> break
|
||||
if deccum == _0 { break; }
|
||||
}
|
||||
|
||||
// If limited digits, calculate one digit more for rounding.
|
||||
let (limit_digits, digit_count, exact) = match digits {
|
||||
DigAll => (false, 0u, false),
|
||||
DigMax(count) => (true, count+1, false),
|
||||
DigExact(count) => (true, count+1, true)
|
||||
};
|
||||
|
||||
// Decide what sign to put in front
|
||||
match sign {
|
||||
SignNeg | SignAll if neg => {
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push('-' as u8);
|
||||
}
|
||||
}
|
||||
SignAll => {
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push('+' as u8);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
vec::reverse(buf);
|
||||
}
|
||||
|
||||
// Remember start of the fractional digits.
|
||||
// Points one beyond end of buf if none get generated,
|
||||
// or at the '.' otherwise.
|
||||
let start_fractional_digits = buf.len();
|
||||
|
||||
// Now emit the fractional part, if any
|
||||
deccum = num.fract();
|
||||
if deccum != _0 || (limit_digits && exact && digit_count > 0) {
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push('.' as u8);
|
||||
}
|
||||
let mut dig = 0u;
|
||||
|
||||
// calculate new digits while
|
||||
// - there is no limit and there are digits left
|
||||
// - or there is a limit, it's not reached yet and
|
||||
// - it's exact
|
||||
// - or it's a maximum, and there are still digits left
|
||||
while (!limit_digits && deccum != _0)
|
||||
|| (limit_digits && dig < digit_count && (
|
||||
exact
|
||||
|| (!exact && deccum != _0)
|
||||
)
|
||||
) {
|
||||
// Shift first fractional digit into the integer part
|
||||
deccum *= radix_gen;
|
||||
|
||||
// Calculate the absolute value of each digit.
|
||||
// See note in first loop.
|
||||
let current_digit_signed = deccum.round(RoundToZero);
|
||||
let current_digit = if current_digit_signed < _0 {
|
||||
-current_digit_signed
|
||||
} else {
|
||||
current_digit_signed
|
||||
};
|
||||
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push(char::from_digit(
|
||||
current_digit.to_int() as uint, radix).unwrap() as u8);
|
||||
}
|
||||
|
||||
// Decrease the deccumulator one fractional digit at a time
|
||||
deccum = deccum.fract();
|
||||
dig += 1u;
|
||||
}
|
||||
|
||||
// If digits are limited, and that limit has been reached,
|
||||
// cut off the one extra digit, and depending on its value
|
||||
// round the remaining ones.
|
||||
if limit_digits && dig == digit_count {
|
||||
let ascii2value = |chr: u8| {
|
||||
char::to_digit(chr as char, radix).unwrap() as uint
|
||||
};
|
||||
let value2ascii = |val: uint| {
|
||||
char::from_digit(val, radix).unwrap() as u8
|
||||
};
|
||||
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
let extra_digit = ascii2value(buf.pop());
|
||||
if extra_digit >= radix / 2 { // -> need to round
|
||||
let mut i: int = buf.len() as int - 1;
|
||||
loop {
|
||||
// If reached left end of number, have to
|
||||
// insert additional digit:
|
||||
if i < 0
|
||||
|| buf[i] == '-' as u8
|
||||
|| buf[i] == '+' as u8 {
|
||||
buf.insert((i + 1) as uint, value2ascii(1));
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip the '.'
|
||||
if buf[i] == '.' as u8 { i -= 1; loop; }
|
||||
|
||||
// Either increment the digit,
|
||||
// or set to 0 if max and carry the 1.
|
||||
let current_digit = ascii2value(buf[i]);
|
||||
if current_digit < (radix - 1) {
|
||||
buf[i] = value2ascii(current_digit+1);
|
||||
break;
|
||||
} else {
|
||||
buf[i] = value2ascii(0);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if number of digits is not exact, remove all trailing '0's up to
|
||||
// and including the '.'
|
||||
if !exact {
|
||||
let buf_max_i = buf.len() - 1;
|
||||
|
||||
// index to truncate from
|
||||
let mut i = buf_max_i;
|
||||
|
||||
// discover trailing zeros of fractional part
|
||||
while i > start_fractional_digits && buf[i] == '0' as u8 {
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
// Only attempt to truncate digits if buf has fractional digits
|
||||
if i >= start_fractional_digits {
|
||||
// If buf ends with '.', cut that too.
|
||||
if buf[i] == '.' as u8 { i -= 1 }
|
||||
|
||||
// only resize buf if we actually remove digits
|
||||
if i < buf_max_i {
|
||||
buf = buf.slice(0, i + 1);
|
||||
}
|
||||
}
|
||||
} // If exact and trailing '.', just cut that
|
||||
else {
|
||||
let max_i = buf.len() - 1;
|
||||
if buf[max_i] == '.' as u8 {
|
||||
buf = buf.slice(0, max_i);
|
||||
}
|
||||
}
|
||||
|
||||
(buf, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number to its string representation. This is a wrapper for
|
||||
* `to_str_bytes_common()`, for details see there.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_common<T:NumCast+Zero+One+Eq+Ord+Round+Copy+Div<T,T>+Neg<T>
|
||||
+Modulo<T,T>+Mul<T,T>>(
|
||||
num: &T, radix: uint, special: bool, negative_zero: bool,
|
||||
sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
|
||||
let (bytes, special) = to_str_bytes_common(num, radix, special,
|
||||
negative_zero, sign, digits);
|
||||
(str::from_bytes(bytes), special)
|
||||
}
|
||||
|
||||
// Some constants for from_str_bytes_common's input validation,
|
||||
// they define minimum radix values for which the character is a valid digit.
|
||||
priv const DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
|
||||
priv const DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
|
||||
priv const DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
|
||||
|
||||
/**
|
||||
* Parses a byte slice as a number. This is meant to
|
||||
* be a common base implementation for all numeric string conversion
|
||||
* functions like `from_str()` or `from_str_radix()`.
|
||||
*
|
||||
* # Arguments
|
||||
* - `buf` - The byte slice to parse.
|
||||
* - `radix` - Which base to parse the number as. Accepts 2-36.
|
||||
* - `negative` - Whether to accept negative numbers.
|
||||
* - `fractional` - Whether to accept numbers with fractional parts.
|
||||
* - `special` - Whether to accept special values like `inf`
|
||||
* and `NaN`. Can conflict with `radix`, see Failure.
|
||||
* - `exponent` - Which exponent format to accept. Options are:
|
||||
* - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
|
||||
* `-8.2`.
|
||||
* - `ExpDec`: Accepts numbers with a decimal exponent like `42e5` or
|
||||
* `8.2E-2`. The exponent string itself is always base 10.
|
||||
* Can conflict with `radix`, see Failure.
|
||||
* - `ExpBin`: Accepts numbers with a binary exponent like `42P-8` or
|
||||
* `FFp128`. The exponent string itself is always base 10.
|
||||
* Can conflict with `radix`, see Failure.
|
||||
* - `empty_zero` - Whether to accept a empty `buf` as a 0 or not.
|
||||
*
|
||||
* # Return value
|
||||
* Returns `Some(n)` if `buf` parses to a number n without overflowing, and
|
||||
* `None` otherwise, depending on the constraints set by the remaining
|
||||
* arguments.
|
||||
*
|
||||
* # Failure
|
||||
* - Fails if `radix` < 2 or `radix` > 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'`.
|
||||
*
|
||||
* # Possible improvements
|
||||
* - Could accept option to allow ignoring underscores, allowing for numbers
|
||||
* formated like `FF_AE_FF_FF`.
|
||||
*/
|
||||
pub pure fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
|
||||
Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>>(
|
||||
buf: &[u8], radix: uint, negative: bool, fractional: bool,
|
||||
special: bool, exponent: ExponentFormat, empty_zero: bool
|
||||
) -> Option<T> {
|
||||
match exponent {
|
||||
ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
|
||||
=> fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
|
||||
use of 'e' as decimal exponent", radix)),
|
||||
ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
|
||||
=> fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
|
||||
use of 'p' as binary exponent", radix)),
|
||||
_ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
|
||||
=> fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
|
||||
special values 'inf' and 'NaN'", radix)),
|
||||
_ if radix as int < 2
|
||||
=> fail!(fmt!("from_str_bytes_common: radix %? to low, \
|
||||
must lie in the range [2, 36]", radix)),
|
||||
_ if radix as int > 36
|
||||
=> fail!(fmt!("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);
|
||||
|
||||
let len = buf.len();
|
||||
|
||||
if len == 0 {
|
||||
if empty_zero {
|
||||
return Some(_0);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
if special {
|
||||
if buf == str::to_bytes("inf") || buf == str::to_bytes("+inf") {
|
||||
return Some(infinity());
|
||||
} else if buf == str::to_bytes("-inf") {
|
||||
if negative {
|
||||
return Some(neg_infinity());
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} else if buf == str::to_bytes("NaN") {
|
||||
return Some(NaN());
|
||||
}
|
||||
}
|
||||
|
||||
let (start, accum_positive) = match buf[0] {
|
||||
'-' as u8 if !negative => return None,
|
||||
'-' as u8 => (1u, false),
|
||||
'+' as u8 => (1u, true),
|
||||
_ => (0u, true)
|
||||
};
|
||||
|
||||
// Initialize accumulator with signed zero for floating point parsing to
|
||||
// work
|
||||
let mut accum = if accum_positive { _0 } else { -_1 * _0};
|
||||
let mut last_accum = accum; // 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) {
|
||||
Some(digit) => {
|
||||
// shift accum one digit left
|
||||
accum *= radix_gen;
|
||||
|
||||
// add/subtract current digit depending on sign
|
||||
if accum_positive {
|
||||
accum += cast(digit as int);
|
||||
} else {
|
||||
accum -= cast(digit as int);
|
||||
}
|
||||
|
||||
// Detect overflow by comparing to last value
|
||||
if accum_positive && accum < last_accum { return None; }
|
||||
if !accum_positive && accum > last_accum { return None; }
|
||||
last_accum = accum;
|
||||
}
|
||||
None => match c {
|
||||
'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
|
||||
}
|
||||
}
|
||||
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
// Parse fractional part of number
|
||||
// Skip if already reached start of exponent
|
||||
if !exp_found {
|
||||
let mut power = _1;
|
||||
|
||||
while i < len {
|
||||
let c = buf[i] as char;
|
||||
|
||||
match char::to_digit(c, radix) {
|
||||
Some(digit) => {
|
||||
// Decrease power one order of magnitude
|
||||
power /= radix_gen;
|
||||
|
||||
let digit_t: T = cast(digit);
|
||||
|
||||
// add/subtract current digit depending on sign
|
||||
if accum_positive {
|
||||
accum += digit_t * power;
|
||||
} else {
|
||||
accum -= digit_t * power;
|
||||
}
|
||||
|
||||
// Detect overflow by comparing to last value
|
||||
if accum_positive && accum < last_accum { return None; }
|
||||
if !accum_positive && accum > last_accum { return None; }
|
||||
last_accum = accum;
|
||||
}
|
||||
None => match c {
|
||||
'e' | 'E' | 'p' | 'P' => {
|
||||
exp_found = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
let mut multiplier = _1;
|
||||
|
||||
if exp_found {
|
||||
let c = buf[i] as char;
|
||||
let base = match (c, exponent) {
|
||||
('e', ExpDec) | ('E', ExpDec) => 10u,
|
||||
('p', ExpBin) | ('P', ExpBin) => 2u,
|
||||
_ => return None // char doesn't fit given exponent format
|
||||
};
|
||||
|
||||
// parse remaining bytes as decimal integer,
|
||||
// skipping the exponent char
|
||||
let exp: Option<int> = from_str_bytes_common(
|
||||
buf.view(i+1, len), 10, true, false, false, ExpNone, false);
|
||||
|
||||
match exp {
|
||||
Some(exp_pow) => {
|
||||
multiplier = if exp_pow < 0 {
|
||||
_1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint)
|
||||
} else {
|
||||
pow_with_uint::<T>(base, exp_pow.to_int() as uint)
|
||||
}
|
||||
}
|
||||
None => return None // invalid exponent -> invalid number
|
||||
}
|
||||
}
|
||||
|
||||
Some(accum * multiplier)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string as a number. This is a wrapper for
|
||||
* `from_str_bytes_common()`, for details see there.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+Mul<T,T>+
|
||||
Sub<T,T>+Neg<T>+Add<T,T>>(
|
||||
buf: &str, radix: uint, negative: bool, fractional: bool,
|
||||
special: bool, exponent: ExponentFormat, empty_zero: bool
|
||||
) -> Option<T> {
|
||||
from_str_bytes_common(str::to_bytes(buf), radix, negative,
|
||||
fractional, special, exponent, empty_zero)
|
||||
}
|
||||
|
|
639
src/libcore/num/strconv.rs
Normal file
639
src/libcore/num/strconv.rs
Normal file
|
@ -0,0 +1,639 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
use core::cmp::{Ord, Eq};
|
||||
use ops::{Add, Div, Modulo, Mul, Neg, Sub};
|
||||
use option::{None, Option, Some};
|
||||
use char;
|
||||
use str;
|
||||
use kinds::Copy;
|
||||
use vec;
|
||||
use num::{NumCast, Zero, One, cast, pow_with_uint};
|
||||
use f64;
|
||||
|
||||
pub enum ExponentFormat {
|
||||
ExpNone,
|
||||
ExpDec,
|
||||
ExpBin
|
||||
}
|
||||
|
||||
pub enum SignificantDigits {
|
||||
DigAll,
|
||||
DigMax(uint),
|
||||
DigExact(uint)
|
||||
}
|
||||
|
||||
pub enum SignFormat {
|
||||
SignNone,
|
||||
SignNeg,
|
||||
SignAll
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pure fn is_NaN<T:Eq>(num: &T) -> bool {
|
||||
*num != *num
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pure fn is_inf<T:Eq+NumStrConv>(num: &T) -> bool {
|
||||
match NumStrConv::inf() {
|
||||
None => false,
|
||||
Some(n) => *num == n
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pure fn is_neg_inf<T:Eq+NumStrConv>(num: &T) -> bool {
|
||||
match NumStrConv::neg_inf() {
|
||||
None => false,
|
||||
Some(n) => *num == n
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pure fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Div<T,T>>(num: &T) -> bool {
|
||||
let _0: T = Zero::zero();
|
||||
let _1: T = One::one();
|
||||
|
||||
*num == _0 && is_neg_inf(&(_1 / *num))
|
||||
}
|
||||
|
||||
pub trait NumStrConv {
|
||||
static pure fn NaN() -> Option<Self>;
|
||||
static pure fn inf() -> Option<Self>;
|
||||
static pure fn neg_inf() -> Option<Self>;
|
||||
static pure fn neg_zero() -> Option<Self>;
|
||||
|
||||
pure fn round_to_zero(&self) -> Self;
|
||||
pure fn fractional_part(&self) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! impl_NumStrConv_Floating (($t:ty) => (
|
||||
impl NumStrConv for $t {
|
||||
#[inline(always)]
|
||||
static pure fn NaN() -> Option<$t> { Some( 0.0 / 0.0) }
|
||||
#[inline(always)]
|
||||
static pure fn inf() -> Option<$t> { Some( 1.0 / 0.0) }
|
||||
#[inline(always)]
|
||||
static pure fn neg_inf() -> Option<$t> { Some(-1.0 / 0.0) }
|
||||
#[inline(always)]
|
||||
static pure fn neg_zero() -> Option<$t> { Some(-0.0 ) }
|
||||
|
||||
#[inline(always)]
|
||||
pure fn round_to_zero(&self) -> $t {
|
||||
( if *self < 0.0 { f64::ceil(*self as f64) }
|
||||
else { f64::floor(*self as f64) }
|
||||
) as $t
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pure fn fractional_part(&self) -> $t {
|
||||
*self - self.round_to_zero()
|
||||
}
|
||||
}
|
||||
))
|
||||
|
||||
macro_rules! impl_NumStrConv_Integer (($t:ty) => (
|
||||
impl NumStrConv for $t {
|
||||
#[inline(always)] static pure fn NaN() -> Option<$t> { None }
|
||||
#[inline(always)] static pure fn inf() -> Option<$t> { None }
|
||||
#[inline(always)] static pure fn neg_inf() -> Option<$t> { None }
|
||||
#[inline(always)] static pure fn neg_zero() -> Option<$t> { None }
|
||||
|
||||
#[inline(always)] pure fn round_to_zero(&self) -> $t { *self }
|
||||
#[inline(always)] pure fn fractional_part(&self) -> $t { 0 }
|
||||
}
|
||||
))
|
||||
|
||||
// FIXME: #4955
|
||||
// Replace by two generic impls for traits 'Integral' and 'Floating'
|
||||
impl_NumStrConv_Floating!(float)
|
||||
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)
|
||||
|
||||
/**
|
||||
* Converts a number to its string representation as a byte vector.
|
||||
* This is meant to be a common base implementation for all numeric string
|
||||
* conversion functions like `to_str()` or `to_str_radix()`.
|
||||
*
|
||||
* # Arguments
|
||||
* - `num` - The number to convert. Accepts any number that
|
||||
* implements the numeric traits.
|
||||
* - `radix` - Base to use. Accepts only the values 2-36.
|
||||
* - `negative_zero` - Whether to treat the special value `-0` as
|
||||
* `-0` or as `+0`.
|
||||
* - `sign` - How to emit the sign. Options are:
|
||||
* - `SignNone`: No sign at all. Basically emits `abs(num)`.
|
||||
* - `SignNeg`: Only `-` on negative values.
|
||||
* - `SignAll`: Both `+` on positive, and `-` on negative numbers.
|
||||
* - `digits` - The amount of digits to use for emitting the
|
||||
* fractional part, if any. Options are:
|
||||
* - `DigAll`: All calculatable digits. Beware of bignums or
|
||||
* fractions!
|
||||
* - `DigMax(uint)`: Maximum N digits, truncating any trailing zeros.
|
||||
* - `DigExact(uint)`: Exactly N digits.
|
||||
*
|
||||
* # Return value
|
||||
* A tuple containing the byte vector, and a boolean flag indicating
|
||||
* whether it represents a special value like `inf`, `-inf`, `NaN` or not.
|
||||
* It returns a tuple because there can be ambiguity between a special value
|
||||
* and a number representation at higher bases.
|
||||
*
|
||||
* # Failure
|
||||
* - Fails if `radix` < 2 or `radix` > 36.
|
||||
*/
|
||||
pub pure fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
|
||||
Div<T,T>+Neg<T>+Modulo<T,T>+Mul<T,T>>(
|
||||
num: &T, radix: uint, negative_zero: bool,
|
||||
sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
|
||||
if radix as int < 2 {
|
||||
fail!(fmt!("to_str_bytes_common: radix %? to low, \
|
||||
must lie in the range [2, 36]", radix));
|
||||
} else if radix as int > 36 {
|
||||
fail!(fmt!("to_str_bytes_common: radix %? to high, \
|
||||
must lie in the range [2, 36]", radix));
|
||||
}
|
||||
|
||||
let _0: T = Zero::zero();
|
||||
let _1: T = One::one();
|
||||
|
||||
if is_NaN(num) {
|
||||
return (str::to_bytes("NaN"), true);
|
||||
}
|
||||
else if is_inf(num){
|
||||
return match sign {
|
||||
SignAll => (str::to_bytes("+inf"), true),
|
||||
_ => (str::to_bytes("inf"), true)
|
||||
}
|
||||
}
|
||||
else if is_neg_inf(num) {
|
||||
return match sign {
|
||||
SignNone => (str::to_bytes("inf"), true),
|
||||
_ => (str::to_bytes("-inf"), true),
|
||||
}
|
||||
}
|
||||
|
||||
let neg = *num < _0 || (negative_zero && is_neg_zero(num));
|
||||
let mut buf: ~[u8] = ~[];
|
||||
let radix_gen: T = cast(radix as int);
|
||||
|
||||
let mut deccum;
|
||||
|
||||
// First emit the non-fractional part, looping at least once to make
|
||||
// sure at least a `0` gets emitted.
|
||||
deccum = num.round_to_zero();
|
||||
loop {
|
||||
// Calculate the absolute value of each digit instead of only
|
||||
// doing it once for the whole number because a
|
||||
// representable negative number doesn't necessary have an
|
||||
// representable additive inverse of the same type
|
||||
// (See twos complement). But we assume that for the
|
||||
// numbers [-35 .. 0] we always have [0 .. 35].
|
||||
let current_digit_signed = deccum % radix_gen;
|
||||
let current_digit = if current_digit_signed < _0 {
|
||||
-current_digit_signed
|
||||
} else {
|
||||
current_digit_signed
|
||||
};
|
||||
|
||||
// Decrease the deccumulator one digit at a time
|
||||
deccum /= radix_gen;
|
||||
deccum = deccum.round_to_zero();
|
||||
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push(char::from_digit(current_digit.to_int() as uint, radix)
|
||||
.unwrap() as u8);
|
||||
}
|
||||
|
||||
// No more digits to calculate for the non-fractional part -> break
|
||||
if deccum == _0 { break; }
|
||||
}
|
||||
|
||||
// If limited digits, calculate one digit more for rounding.
|
||||
let (limit_digits, digit_count, exact) = match digits {
|
||||
DigAll => (false, 0u, false),
|
||||
DigMax(count) => (true, count+1, false),
|
||||
DigExact(count) => (true, count+1, true)
|
||||
};
|
||||
|
||||
// Decide what sign to put in front
|
||||
match sign {
|
||||
SignNeg | SignAll if neg => {
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push('-' as u8);
|
||||
}
|
||||
}
|
||||
SignAll => {
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push('+' as u8);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
vec::reverse(buf);
|
||||
}
|
||||
|
||||
// Remember start of the fractional digits.
|
||||
// Points one beyond end of buf if none get generated,
|
||||
// or at the '.' otherwise.
|
||||
let start_fractional_digits = buf.len();
|
||||
|
||||
// Now emit the fractional part, if any
|
||||
deccum = num.fractional_part();
|
||||
if deccum != _0 || (limit_digits && exact && digit_count > 0) {
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push('.' as u8);
|
||||
}
|
||||
let mut dig = 0u;
|
||||
|
||||
// calculate new digits while
|
||||
// - there is no limit and there are digits left
|
||||
// - or there is a limit, it's not reached yet and
|
||||
// - it's exact
|
||||
// - or it's a maximum, and there are still digits left
|
||||
while (!limit_digits && deccum != _0)
|
||||
|| (limit_digits && dig < digit_count && (
|
||||
exact
|
||||
|| (!exact && deccum != _0)
|
||||
)
|
||||
) {
|
||||
// Shift first fractional digit into the integer part
|
||||
deccum *= radix_gen;
|
||||
|
||||
// Calculate the absolute value of each digit.
|
||||
// See note in first loop.
|
||||
let current_digit_signed = deccum.round_to_zero();
|
||||
let current_digit = if current_digit_signed < _0 {
|
||||
-current_digit_signed
|
||||
} else {
|
||||
current_digit_signed
|
||||
};
|
||||
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
buf.push(char::from_digit(
|
||||
current_digit.to_int() as uint, radix).unwrap() as u8);
|
||||
}
|
||||
|
||||
// Decrease the deccumulator one fractional digit at a time
|
||||
deccum = deccum.fractional_part();
|
||||
dig += 1u;
|
||||
}
|
||||
|
||||
// If digits are limited, and that limit has been reached,
|
||||
// cut off the one extra digit, and depending on its value
|
||||
// round the remaining ones.
|
||||
if limit_digits && dig == digit_count {
|
||||
let ascii2value = |chr: u8| {
|
||||
char::to_digit(chr as char, radix).unwrap() as uint
|
||||
};
|
||||
let value2ascii = |val: uint| {
|
||||
char::from_digit(val, radix).unwrap() as u8
|
||||
};
|
||||
|
||||
unsafe { // FIXME: Pureness workaround (#4568)
|
||||
let extra_digit = ascii2value(buf.pop());
|
||||
if extra_digit >= radix / 2 { // -> need to round
|
||||
let mut i: int = buf.len() as int - 1;
|
||||
loop {
|
||||
// If reached left end of number, have to
|
||||
// insert additional digit:
|
||||
if i < 0
|
||||
|| buf[i] == '-' as u8
|
||||
|| buf[i] == '+' as u8 {
|
||||
buf.insert((i + 1) as uint, value2ascii(1));
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip the '.'
|
||||
if buf[i] == '.' as u8 { i -= 1; loop; }
|
||||
|
||||
// Either increment the digit,
|
||||
// or set to 0 if max and carry the 1.
|
||||
let current_digit = ascii2value(buf[i]);
|
||||
if current_digit < (radix - 1) {
|
||||
buf[i] = value2ascii(current_digit+1);
|
||||
break;
|
||||
} else {
|
||||
buf[i] = value2ascii(0);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if number of digits is not exact, remove all trailing '0's up to
|
||||
// and including the '.'
|
||||
if !exact {
|
||||
let buf_max_i = buf.len() - 1;
|
||||
|
||||
// index to truncate from
|
||||
let mut i = buf_max_i;
|
||||
|
||||
// discover trailing zeros of fractional part
|
||||
while i > start_fractional_digits && buf[i] == '0' as u8 {
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
// Only attempt to truncate digits if buf has fractional digits
|
||||
if i >= start_fractional_digits {
|
||||
// If buf ends with '.', cut that too.
|
||||
if buf[i] == '.' as u8 { i -= 1 }
|
||||
|
||||
// only resize buf if we actually remove digits
|
||||
if i < buf_max_i {
|
||||
buf = buf.slice(0, i + 1);
|
||||
}
|
||||
}
|
||||
} // If exact and trailing '.', just cut that
|
||||
else {
|
||||
let max_i = buf.len() - 1;
|
||||
if buf[max_i] == '.' as u8 {
|
||||
buf = buf.slice(0, max_i);
|
||||
}
|
||||
}
|
||||
|
||||
(buf, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number to its string representation. This is a wrapper for
|
||||
* `to_str_bytes_common()`, for details see there.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
|
||||
Div<T,T>+Neg<T>+Modulo<T,T>+Mul<T,T>>(
|
||||
num: &T, radix: uint, negative_zero: bool,
|
||||
sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
|
||||
let (bytes, special) = to_str_bytes_common(num, radix,
|
||||
negative_zero, sign, digits);
|
||||
(str::from_bytes(bytes), special)
|
||||
}
|
||||
|
||||
// Some constants for from_str_bytes_common's input validation,
|
||||
// they define minimum radix values for which the character is a valid digit.
|
||||
priv const DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
|
||||
priv const DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
|
||||
priv const DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
|
||||
|
||||
/**
|
||||
* Parses a byte slice as a number. This is meant to
|
||||
* be a common base implementation for all numeric string conversion
|
||||
* functions like `from_str()` or `from_str_radix()`.
|
||||
*
|
||||
* # Arguments
|
||||
* - `buf` - The byte slice to parse.
|
||||
* - `radix` - Which base to parse the number as. Accepts 2-36.
|
||||
* - `negative` - Whether to accept negative numbers.
|
||||
* - `fractional` - Whether to accept numbers with fractional parts.
|
||||
* - `special` - Whether to accept special values like `inf`
|
||||
* and `NaN`. Can conflict with `radix`, see Failure.
|
||||
* - `exponent` - Which exponent format to accept. Options are:
|
||||
* - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
|
||||
* `-8.2`.
|
||||
* - `ExpDec`: Accepts numbers with a decimal exponent like `42e5` or
|
||||
* `8.2E-2`. The exponent string itself is always base 10.
|
||||
* Can conflict with `radix`, see Failure.
|
||||
* - `ExpBin`: Accepts numbers with a binary exponent like `42P-8` or
|
||||
* `FFp128`. The exponent string itself is always base 10.
|
||||
* Can conflict with `radix`, see Failure.
|
||||
* - `empty_zero` - Whether to accept a empty `buf` as a 0 or not.
|
||||
*
|
||||
* # Return value
|
||||
* Returns `Some(n)` if `buf` parses to a number n without overflowing, and
|
||||
* `None` otherwise, depending on the constraints set by the remaining
|
||||
* arguments.
|
||||
*
|
||||
* # Failure
|
||||
* - Fails if `radix` < 2 or `radix` > 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'`.
|
||||
*
|
||||
* # Possible improvements
|
||||
* - Could accept option to allow ignoring underscores, allowing for numbers
|
||||
* formated like `FF_AE_FF_FF`.
|
||||
*/
|
||||
pub pure fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
|
||||
Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
|
||||
NumStrConv>(
|
||||
buf: &[u8], radix: uint, negative: bool, fractional: bool,
|
||||
special: bool, exponent: ExponentFormat, empty_zero: bool
|
||||
) -> Option<T> {
|
||||
match exponent {
|
||||
ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
|
||||
=> fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
|
||||
use of 'e' as decimal exponent", radix)),
|
||||
ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
|
||||
=> fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
|
||||
use of 'p' as binary exponent", radix)),
|
||||
_ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
|
||||
=> fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
|
||||
special values 'inf' and 'NaN'", radix)),
|
||||
_ if radix as int < 2
|
||||
=> fail!(fmt!("from_str_bytes_common: radix %? to low, \
|
||||
must lie in the range [2, 36]", radix)),
|
||||
_ if radix as int > 36
|
||||
=> fail!(fmt!("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);
|
||||
|
||||
let len = buf.len();
|
||||
|
||||
if len == 0 {
|
||||
if empty_zero {
|
||||
return Some(_0);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Bytevector constant from str
|
||||
if special {
|
||||
if buf == str::to_bytes("inf") || buf == str::to_bytes("+inf") {
|
||||
return NumStrConv::inf();
|
||||
} else if buf == str::to_bytes("-inf") {
|
||||
if negative {
|
||||
return NumStrConv::neg_inf();
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} else if buf == str::to_bytes("NaN") {
|
||||
return NumStrConv::NaN();
|
||||
}
|
||||
}
|
||||
|
||||
let (start, accum_positive) = match buf[0] {
|
||||
'-' as u8 if !negative => return None,
|
||||
'-' as u8 => (1u, false),
|
||||
'+' as u8 => (1u, true),
|
||||
_ => (0u, true)
|
||||
};
|
||||
|
||||
// Initialize accumulator with signed zero for floating point parsing to
|
||||
// work
|
||||
let mut accum = if accum_positive { _0 } else { -_1 * _0};
|
||||
let mut last_accum = accum; // 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) {
|
||||
Some(digit) => {
|
||||
// shift accum one digit left
|
||||
accum *= radix_gen;
|
||||
|
||||
// add/subtract current digit depending on sign
|
||||
if accum_positive {
|
||||
accum += cast(digit as int);
|
||||
} else {
|
||||
accum -= cast(digit as int);
|
||||
}
|
||||
|
||||
// Detect overflow by comparing to last value
|
||||
if accum_positive && accum < last_accum { return None; }
|
||||
if !accum_positive && accum > last_accum { return None; }
|
||||
last_accum = accum;
|
||||
}
|
||||
None => match c {
|
||||
'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
|
||||
}
|
||||
}
|
||||
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
// Parse fractional part of number
|
||||
// Skip if already reached start of exponent
|
||||
if !exp_found {
|
||||
let mut power = _1;
|
||||
|
||||
while i < len {
|
||||
let c = buf[i] as char;
|
||||
|
||||
match char::to_digit(c, radix) {
|
||||
Some(digit) => {
|
||||
// Decrease power one order of magnitude
|
||||
power /= radix_gen;
|
||||
|
||||
let digit_t: T = cast(digit);
|
||||
|
||||
// add/subtract current digit depending on sign
|
||||
if accum_positive {
|
||||
accum += digit_t * power;
|
||||
} else {
|
||||
accum -= digit_t * power;
|
||||
}
|
||||
|
||||
// Detect overflow by comparing to last value
|
||||
if accum_positive && accum < last_accum { return None; }
|
||||
if !accum_positive && accum > last_accum { return None; }
|
||||
last_accum = accum;
|
||||
}
|
||||
None => match c {
|
||||
'e' | 'E' | 'p' | 'P' => {
|
||||
exp_found = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
let mut multiplier = _1;
|
||||
|
||||
if exp_found {
|
||||
let c = buf[i] as char;
|
||||
let base = match (c, exponent) {
|
||||
('e', ExpDec) | ('E', ExpDec) => 10u,
|
||||
('p', ExpBin) | ('P', ExpBin) => 2u,
|
||||
_ => return None // char doesn't fit given exponent format
|
||||
};
|
||||
|
||||
// parse remaining bytes as decimal integer,
|
||||
// skipping the exponent char
|
||||
let exp: Option<int> = from_str_bytes_common(
|
||||
buf.view(i+1, len), 10, true, false, false, ExpNone, false);
|
||||
|
||||
match exp {
|
||||
Some(exp_pow) => {
|
||||
multiplier = if exp_pow < 0 {
|
||||
_1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint)
|
||||
} else {
|
||||
pow_with_uint::<T>(base, exp_pow.to_int() as uint)
|
||||
}
|
||||
}
|
||||
None => return None // invalid exponent -> invalid number
|
||||
}
|
||||
}
|
||||
|
||||
Some(accum * multiplier)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string as a number. This is a wrapper for
|
||||
* `from_str_bytes_common()`, for details see there.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+Mul<T,T>+
|
||||
Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>(
|
||||
buf: &str, radix: uint, negative: bool, fractional: bool,
|
||||
special: bool, exponent: ExponentFormat, empty_zero: bool
|
||||
) -> Option<T> {
|
||||
from_str_bytes_common(str::to_bytes(buf), radix, negative,
|
||||
fractional, special, exponent, empty_zero)
|
||||
}
|
|
@ -17,6 +17,7 @@ use cmp;
|
|||
use to_str::ToStr;
|
||||
use from_str::FromStr;
|
||||
use num::{ToStrRadix, FromStrRadix};
|
||||
use num::strconv;
|
||||
use num;
|
||||
use option::{None, Option, Some};
|
||||
use prelude::*;
|
||||
|
@ -140,18 +141,6 @@ impl num::One for T {
|
|||
static pure fn one() -> T { 1 }
|
||||
}
|
||||
|
||||
impl num::Round for T {
|
||||
#[inline(always)]
|
||||
pure fn round(&self, _: num::RoundMode) -> T { *self }
|
||||
|
||||
#[inline(always)]
|
||||
pure fn floor(&self) -> T { *self }
|
||||
#[inline(always)]
|
||||
pure fn ceil(&self) -> T { *self }
|
||||
#[inline(always)]
|
||||
pure fn fract(&self) -> T { 0 }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl ops::Add<T,T> for T {
|
||||
pure fn add(&self, other: &T) -> T { *self + *other }
|
||||
|
@ -182,22 +171,22 @@ impl ops::Neg<T> for T {
|
|||
/// Parse a string as a number in base 10.
|
||||
#[inline(always)]
|
||||
pub pure fn from_str(s: &str) -> Option<T> {
|
||||
num::from_str_common(s, 10u, false, false, false,
|
||||
num::ExpNone, false)
|
||||
strconv::from_str_common(s, 10u, false, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
/// Parse a string as a number in the given base.
|
||||
#[inline(always)]
|
||||
pub pure fn from_str_radix(s: &str, radix: uint) -> Option<T> {
|
||||
num::from_str_common(s, radix, false, false, false,
|
||||
num::ExpNone, false)
|
||||
strconv::from_str_common(s, radix, false, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
/// Parse a byte slice as a number in the given base.
|
||||
#[inline(always)]
|
||||
pub pure fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
|
||||
num::from_str_bytes_common(buf, radix, false, false, false,
|
||||
num::ExpNone, false)
|
||||
strconv::from_str_bytes_common(buf, radix, false, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl FromStr for T {
|
||||
|
@ -219,24 +208,24 @@ impl FromStrRadix for T {
|
|||
/// Convert to a string as a byte slice in a given base.
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
|
||||
let (buf, _) = num::to_str_bytes_common(&n, radix, false, false,
|
||||
num::SignNeg, num::DigAll);
|
||||
let (buf, _) = strconv::to_str_bytes_common(&n, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
f(buf)
|
||||
}
|
||||
|
||||
/// Convert to a string in base 10.
|
||||
#[inline(always)]
|
||||
pub pure fn to_str(num: T) -> ~str {
|
||||
let (buf, _) = num::to_str_common(&num, 10u, false, false,
|
||||
num::SignNeg, num::DigAll);
|
||||
let (buf, _) = strconv::to_str_common(&num, 10u, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
}
|
||||
|
||||
/// Convert to a string in a given base.
|
||||
#[inline(always)]
|
||||
pub pure fn to_str_radix(num: T, radix: uint) -> ~str {
|
||||
let (buf, _) = num::to_str_common(&num, radix, false, false,
|
||||
num::SignNeg, num::DigAll);
|
||||
let (buf, _) = strconv::to_str_common(&num, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue