diff --git a/doc/rust.md b/doc/rust.md index 7d4ec54aff5ce..34fd7cf25d60d 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -844,7 +844,7 @@ mod quux { pub fn bar() { } pub fn baz() { } } - + pub use quux::foo::*; } ~~~~ @@ -1242,7 +1242,7 @@ trait Num { impl float: Num { static pure fn from_int(n: int) -> float { n as float } } -let x: float = Num::from_int(42); +let x: float = Num::from_int(42); ~~~~ Traits may inherit from other traits. For example, in @@ -1615,7 +1615,7 @@ The following are examples of structure expressions: ~~~~ # struct Point { x: float, y: float } # struct TuplePoint(float, float); -# mod game { pub struct User { name: &str, age: uint, mut score: uint } } +# mod game { pub struct User { name: &str, age: uint, mut score: uint } } # use game; Point {x: 10f, y: 20f}; TuplePoint(10f, 20f); @@ -2812,7 +2812,7 @@ trait Printable { } impl int: Printable { - fn to_str() -> ~str { int::to_str(self, 10) } + fn to_str() -> ~str { int::to_str(self) } } fn print(a: @Printable) { diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 3434ef022da5e..f814970375a7d 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -473,7 +473,7 @@ fn stringifier(channel: &DuplexStream<~str, uint>) { let mut value: uint; loop { value = channel.recv(); - channel.send(uint::to_str(value, 10)); + channel.send(uint::to_str(value)); if value == 0 { break; } } } @@ -497,7 +497,7 @@ Here is the code for the parent task: # let mut value: uint; # loop { # value = channel.recv(); -# channel.send(uint::to_str(value, 10u)); +# channel.send(uint::to_str(value)); # if value == 0u { break; } # } # } diff --git a/src/libcore/char.rs b/src/libcore/char.rs index b656879e7a422..deecdc98ffa83 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -118,6 +118,26 @@ pub pure fn is_digit(c: char) -> bool { unicode::general_category::No(c); } +/** + * Checks if a character parses as a numeric digit in the given radix. + * Compared to `is_digit()`, this function only recognizes the ascii + * characters `0-9`, `a-z` and `A-Z`. + * + * Returns `true` if `c` is a valid digit under `radix`, and `false` + * otherwise. + * + * Fails if given a `radix` > 36. + * + * Note: This just wraps `to_digit()`. + */ +#[inline(always)] +pub pure fn is_digit_radix(c: char, radix: uint) -> bool { + match to_digit(c, radix) { + Some(_) => true, + None => false + } +} + /** * Convert a char to the corresponding digit. * @@ -127,9 +147,15 @@ pub pure fn is_digit(c: char) -> bool { * between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is * 'b' or 'B', 11, etc. Returns none if the char does not * refer to a digit in the given radix. + * + * # Failure + * Fails if given a `radix` outside the range `[0..36]`. */ #[inline] pub pure fn to_digit(c: char, radix: uint) -> Option { + if radix > 36 { + die!(fmt!("to_digit: radix %? is to high (maximum 36)", radix)); + } let val = match c { '0' .. '9' => c as uint - ('0' as uint), 'a' .. 'z' => c as uint + 10u - ('a' as uint), @@ -140,6 +166,30 @@ pub pure fn to_digit(c: char, radix: uint) -> Option { else { None } } +/** + * Converts a number to the ascii character representing it. + * + * Returns `Some(char)` if `num` represents one digit under `radix`, + * using one character of `0-9` or `a-z`, or `None` if it doesn't. + * + * Fails if given an `radix` > 36. + */ +#[inline] +pub pure fn from_digit(num: uint, radix: uint) -> Option { + if radix > 36 { + die!(fmt!("from_digit: radix %? is to high (maximum 36)", num)); + } + if num < radix { + if num < 10 { + Some(('0' as uint + num) as char) + } else { + Some(('a' as uint + num - 10u) as char) + } + } else { + None + } +} + /** * Return the hexadecimal unicode escape of a char. * @@ -150,7 +200,7 @@ pub pure fn to_digit(c: char, radix: uint) -> Option { * - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN` */ pub pure fn escape_unicode(c: char) -> ~str { - let s = u32::to_str(c as u32, 16u); + let s = u32::to_str_radix(c as u32, 16u); let (c, pad) = (if c <= '\xff' { ('x', 2u) } else if c <= '\uffff' { ('u', 4u) } else { ('U', 8u) }); diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 34804af70cae0..aece60652a21a 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -60,30 +60,33 @@ pub mod prelude; /* Primitive types */ -#[path = "int-template.rs"] #[merge = "int-template/int.rs"] +#[path = "num/int-template.rs"] #[merge = "num/int-template/int.rs"] pub mod int; -#[path = "int-template.rs"] #[merge = "int-template/i8.rs"] +#[path = "num/int-template.rs"] #[merge = "num/int-template/i8.rs"] pub mod i8; -#[path = "int-template.rs"] #[merge = "int-template/i16.rs"] +#[path = "num/int-template.rs"] #[merge = "num/int-template/i16.rs"] pub mod i16; -#[path = "int-template.rs"] #[merge = "int-template/i32.rs"] +#[path = "num/int-template.rs"] #[merge = "num/int-template/i32.rs"] pub mod i32; -#[path = "int-template.rs"] #[merge = "int-template/i64.rs"] +#[path = "num/int-template.rs"] #[merge = "num/int-template/i64.rs"] pub mod i64; -#[path = "uint-template.rs"] #[merge = "uint-template/uint.rs"] +#[path = "num/uint-template.rs"] #[merge = "num/uint-template/uint.rs"] pub mod uint; -#[path = "uint-template.rs"] #[merge = "uint-template/u8.rs"] +#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u8.rs"] pub mod u8; -#[path = "uint-template.rs"] #[merge = "uint-template/u16.rs"] +#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u16.rs"] pub mod u16; -#[path = "uint-template.rs"] #[merge = "uint-template/u32.rs"] +#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u32.rs"] pub mod u32; -#[path = "uint-template.rs"] #[merge = "uint-template/u64.rs"] +#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u64.rs"] pub mod u64; +#[path = "num/float.rs"] pub mod float; +#[path = "num/f32.rs"] pub mod f32; +#[path = "num/f64.rs"] pub mod f64; pub mod nil; @@ -116,6 +119,7 @@ pub mod managed; /* Common traits */ pub mod from_str; +#[path = "num/num.rs"] pub mod num; pub mod iter; pub mod to_str; @@ -232,6 +236,7 @@ pub mod private; /* For internal use, not exported */ mod unicode; +#[path = "num/cmath.rs"] mod cmath; mod stackwalk; diff --git a/src/libcore/extfmt.rs b/src/libcore/extfmt.rs index e452735777ece..ed0625624d80a 100644 --- a/src/libcore/extfmt.rs +++ b/src/libcore/extfmt.rs @@ -563,7 +563,7 @@ pub mod rt { pub pure fn conv_float(cv: Conv, f: float) -> ~str { let (to_str, digits) = match cv.precision { CountIs(c) => (float::to_str_exact, c as uint), - CountImplied => (float::to_str, 6u) + CountImplied => (float::to_str_digits, 6u) }; let mut s = unsafe { to_str(f, digits) }; if 0.0 <= f { @@ -596,7 +596,7 @@ pub mod rt { return if prec == 0u && num == 0u { ~"" } else { - let s = uint::to_str(num, radix); + let s = uint::to_str_radix(num, radix); let len = str::char_len(s); if len < prec { let diff = prec - len; diff --git a/src/libcore/hash.rs b/src/libcore/hash.rs index d9e53811b65c4..d676570e1e6cb 100644 --- a/src/libcore/hash.rs +++ b/src/libcore/hash.rs @@ -354,7 +354,7 @@ impl &SipState : Streaming { let r = self.result_bytes(); let mut s = ~""; for vec::each(r) |b| { - s += uint::to_str(*b as uint, 16u); + s += uint::to_str_radix(*b as uint, 16u); } move s } @@ -449,7 +449,7 @@ pub fn test_siphash() { fn to_hex_str(r: &[u8 * 8]) -> ~str { let mut s = ~""; for vec::each(*r) |b| { - s += uint::to_str(*b as uint, 16u); + s += uint::to_str_radix(*b as uint, 16u); } move s } diff --git a/src/libcore/io.rs b/src/libcore/io.rs index d2ddbc40885e3..b726cf62cfe52 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -910,7 +910,7 @@ impl T : WriterUtil { int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) } fn write_uint(&self, n: uint) { - uint::to_str_bytes(false, n, 10u, |bytes| self.write(bytes)) + uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) } fn write_le_uint(&self, n: uint) { u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v)) diff --git a/src/libcore/num.rs b/src/libcore/num.rs deleted file mode 100644 index 5680e3116bfb6..0000000000000 --- a/src/libcore/num.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! An interface for numeric types - -pub trait Num { - // FIXME: Trait composition. (#2616) - pure fn add(&self, other: &Self) -> Self; - pure fn sub(&self, other: &Self) -> Self; - pure fn mul(&self, other: &Self) -> Self; - pure fn div(&self, other: &Self) -> Self; - pure fn modulo(&self, other: &Self) -> Self; - pure fn neg(&self) -> Self; - - pure fn to_int(&self) -> int; - static pure fn from_int(n: int) -> Self; -} - -pub trait IntConvertible { - pure fn to_int(&self) -> int; - static pure fn from_int(n: int) -> Self; -} - -pub trait Zero { - static pure fn zero() -> Self; -} - -pub trait One { - static pure fn one() -> Self; -} diff --git a/src/libcore/cmath.rs b/src/libcore/num/cmath.rs similarity index 100% rename from src/libcore/cmath.rs rename to src/libcore/num/cmath.rs diff --git a/src/libcore/f32.rs b/src/libcore/num/f32.rs similarity index 62% rename from src/libcore/f32.rs rename to src/libcore/num/f32.rs index 795a9f9371c3c..68e7c3c9df26e 100644 --- a/src/libcore/f32.rs +++ b/src/libcore/num/f32.rs @@ -18,6 +18,9 @@ use cmath; use cmp; use libc::{c_float, c_int}; use num; +use option::Option; +use from_str; +use to_str; pub use cmath::c_float_targ_consts::*; @@ -306,6 +309,246 @@ pub extern { fn floorf32(val: f32) -> f32; } +impl f32: num::Round { + #[inline(always)] + pure fn round(&self, mode: num::RoundMode) -> f32 { + match mode { + num::RoundDown => floor(*self), + num::RoundUp => ceil(*self), + num::RoundToZero if is_negative(*self) => ceil(*self), + num::RoundToZero => floor(*self), + num::RoundFromZero if is_negative(*self) => floor(*self), + num::RoundFromZero => ceil(*self) + } + } + + #[inline(always)] + pure fn floor(&self) -> f32 { floor(*self) } + #[inline(always)] + pure fn ceil(&self) -> f32 { ceil(*self) } + #[inline(always)] + pure fn fract(&self) -> f32 { + if is_negative(*self) { + (*self) - ceil(*self) + } else { + (*self) - floor(*self) + } + } +} + +/** + * Section: String Conversions + */ + +/** + * Converts a float to a string + * + * # Arguments + * + * * num - The float value + */ +#[inline(always)] +pub pure fn to_str(num: f32) -> ~str { + let (r, _) = num::to_str_common( + &num, 10u, true, true, num::SignNeg, num::DigAll); + r +} + +/** + * Converts a float to a string in hexadecimal format + * + * # Arguments + * + * * num - The float value + */ +#[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); + r +} + +/** + * Converts a float to a string in a given radix + * + * # Arguments + * + * * num - The float value + * * radix - The base to use + * + * # Failure + * + * Fails if called on a special value like `inf`, `-inf` or `NaN` due to + * possible misinterpretation of the result at higher bases. If those values + * are expected, use `to_str_radix_special()` instead. + */ +#[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); + if special { die!(~"number has a special value, \ + try to_str_radix_special() if those are expected") } + r +} + +/** + * Converts a float to a string in a given radix, and a flag indicating + * whether it's a special value + * + * # Arguments + * + * * num - The float value + * * radix - The base to use + */ +#[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) +} + +/** + * Converts a float to a string with exactly the number of + * provided significant digits + * + * # Arguments + * + * * num - The float value + * * digits - The number of significant digits + */ +#[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)); + r +} + +/** + * Converts a float to a string with a maximum number of + * significant digits + * + * # Arguments + * + * * num - The float value + * * digits - The number of significant digits + */ +#[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)); + r +} + +impl f32: to_str::ToStr { + #[inline(always)] + pure fn to_str() -> ~str { to_str_digits(self, 8) } +} + +impl f32: num::ToStrRadix { + #[inline(always)] + pure fn to_str_radix(&self, rdx: uint) -> ~str { + to_str_radix(*self, rdx) + } +} + +/** + * Convert a string in base 10 to a float. + * Accepts a 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 + * + * * 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(always)] +pub pure fn from_str(num: &str) -> Option { + num::from_str_common(num, 10u, true, true, true, num::ExpDec, false) +} + +/** + * Convert a string in base 16 to a float. + * Accepts a 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(always)] +pub pure fn from_str_hex(num: &str) -> Option { + num::from_str_common(num, 16u, true, true, true, num::ExpBin, false) +} + +/** + * Convert a string in an 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 + * * 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`. + */ +#[inline(always)] +pub pure fn from_str_radix(num: &str, rdx: uint) -> Option { + num::from_str_common(num, rdx, true, true, false, num::ExpNone, false) +} + +impl f32: from_str::FromStr { + #[inline(always)] + static pure fn from_str(val: &str) -> Option { from_str(val) } +} + +impl f32: num::FromStrRadix { + #[inline(always)] + static pure fn from_str_radix(val: &str, rdx: uint) -> Option { + from_str_radix(val, rdx) + } +} + // // Local Variables: // mode: rust diff --git a/src/libcore/f64.rs b/src/libcore/num/f64.rs similarity index 64% rename from src/libcore/f64.rs rename to src/libcore/num/f64.rs index 8cd94c9357d61..85f44d1b94f8d 100644 --- a/src/libcore/f64.rs +++ b/src/libcore/num/f64.rs @@ -19,6 +19,9 @@ use cmp; use libc::{c_double, c_int}; use libc; use num; +use option::Option; +use to_str; +use from_str; pub use cmath::c_double_targ_consts::*; @@ -330,6 +333,246 @@ pub extern { fn floorf64(val: f64) -> f64; } +impl f64: num::Round { + #[inline(always)] + pure fn round(&self, mode: num::RoundMode) -> f64 { + match mode { + num::RoundDown => floor(*self), + num::RoundUp => ceil(*self), + num::RoundToZero if is_negative(*self) => ceil(*self), + num::RoundToZero => floor(*self), + num::RoundFromZero if is_negative(*self) => floor(*self), + num::RoundFromZero => ceil(*self) + } + } + + #[inline(always)] + pure fn floor(&self) -> f64 { floor(*self) } + #[inline(always)] + pure fn ceil(&self) -> f64 { ceil(*self) } + #[inline(always)] + pure fn fract(&self) -> f64 { + if is_negative(*self) { + (*self) - ceil(*self) + } else { + (*self) - floor(*self) + } + } +} + +/** + * Section: String Conversions + */ + +/** + * Converts a float to a string + * + * # Arguments + * + * * num - The float value + */ +#[inline(always)] +pub pure fn to_str(num: f64) -> ~str { + let (r, _) = num::to_str_common( + &num, 10u, true, true, num::SignNeg, num::DigAll); + r +} + +/** + * Converts a float to a string in hexadecimal format + * + * # Arguments + * + * * num - The float value + */ +#[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); + r +} + +/** + * Converts a float to a string in a given radix + * + * # Arguments + * + * * num - The float value + * * radix - The base to use + * + * # Failure + * + * Fails if called on a special value like `inf`, `-inf` or `NaN` due to + * possible misinterpretation of the result at higher bases. If those values + * are expected, use `to_str_radix_special()` instead. + */ +#[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); + if special { die!(~"number has a special value, \ + try to_str_radix_special() if those are expected") } + r +} + +/** + * Converts a float to a string in a given radix, and a flag indicating + * whether it's a special value + * + * # Arguments + * + * * num - The float value + * * radix - The base to use + */ +#[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) +} + +/** + * Converts a float to a string with exactly the number of + * provided significant digits + * + * # Arguments + * + * * num - The float value + * * digits - The number of significant digits + */ +#[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)); + r +} + +/** + * Converts a float to a string with a maximum number of + * significant digits + * + * # Arguments + * + * * num - The float value + * * digits - The number of significant digits + */ +#[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)); + r +} + +impl f64: to_str::ToStr { + #[inline(always)] + pure fn to_str() -> ~str { to_str_digits(self, 8) } +} + +impl f64: num::ToStrRadix { + #[inline(always)] + pure fn to_str_radix(&self, rdx: uint) -> ~str { + to_str_radix(*self, rdx) + } +} + +/** + * Convert a string in base 10 to a float. + * Accepts a 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 + * + * * 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(always)] +pub pure fn from_str(num: &str) -> Option { + num::from_str_common(num, 10u, true, true, true, num::ExpDec, false) +} + +/** + * Convert a string in base 16 to a float. + * Accepts a 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(always)] +pub pure fn from_str_hex(num: &str) -> Option { + num::from_str_common(num, 16u, true, true, true, num::ExpBin, false) +} + +/** + * Convert a string in an 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 + * * 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`. + */ +#[inline(always)] +pub pure fn from_str_radix(num: &str, rdx: uint) -> Option { + num::from_str_common(num, rdx, true, true, false, num::ExpNone, false) +} + +impl f64: from_str::FromStr { + #[inline(always)] + static pure fn from_str(val: &str) -> Option { from_str(val) } +} + +impl f64: num::FromStrRadix { + #[inline(always)] + static pure fn from_str_radix(val: &str, rdx: uint) -> Option { + from_str_radix(val, rdx) + } +} + // // Local Variables: // mode: rust diff --git a/src/libcore/float.rs b/src/libcore/num/float.rs similarity index 56% rename from src/libcore/float.rs rename to src/libcore/num/float.rs index b90edec4d9612..32c7717422135 100644 --- a/src/libcore/float.rs +++ b/src/libcore/num/float.rs @@ -34,6 +34,8 @@ use num::Num::from_int; use option::{None, Option, Some}; use str; use uint; +use to_str; +use from_str; pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt}; pub use f64::logarithm; @@ -95,7 +97,7 @@ pub mod consts { pub const ln_10: float = 2.30258509299404568401799145468436421; } -/** +/* * Section: String Conversions */ @@ -105,85 +107,63 @@ pub mod consts { * # Arguments * * * num - The float value - * * digits - The number of significant digits - * * exact - Whether to enforce the exact number of significant digits */ -pub pure fn to_str_common(num: float, digits: uint, exact: bool) -> ~str { - if is_NaN(num) { return ~"NaN"; } - if num == infinity { return ~"inf"; } - if num == neg_infinity { return ~"-inf"; } - - let mut (num, sign) = if num < 0.0 { (-num, ~"-") } else { (num, ~"") }; - - // truncated integer - let trunc = num as uint; - - // decimal remainder - let mut frac = num - (trunc as float); - - // stack of digits - let mut fractionalParts = ~[]; - - // FIXME: (#2608) - // This used to return right away without rounding, as "~[-]num", - // but given epsilon like in f64.rs, I don't see how the comparison - // to epsilon did much when only used there. - // if (frac < epsilon && !exact) || digits == 0u { return accum; } - // - // With something better, possibly weird results like this can be avoided: - // assert "3.14158999999999988262" == my_to_str_exact(3.14159, 20u); - - let mut ii = digits; - let mut epsilon_prime = 1.0 / pow_with_uint(10u, ii); - - // while we still need digits - // build stack of digits - while ii > 0 && (frac >= epsilon_prime || exact) { - // store the next digit - frac *= 10.0; - let digit = frac as uint; - // Bleh: not really unsafe. - unsafe { fractionalParts.push(digit); } - - // calculate the next frac - frac -= digit as float; - epsilon_prime *= 10.0; - ii -= 1u; - } - - let mut acc; - let mut racc = ~""; - let mut carry = if frac * 10.0 as uint >= 5 { 1 } else { 0 }; - - // turn digits into string - // using stack of digits - while !fractionalParts.is_empty() { - // Bleh; shouldn't need to be unsafe - let mut adjusted_digit = carry + unsafe { fractionalParts.pop() }; - - if adjusted_digit == 10 { - carry = 1; - adjusted_digit %= 10 - } else { - carry = 0; - }; +#[inline(always)] +pub pure fn to_str(num: float) -> ~str { + let (r, _) = num::to_str_common( + &num, 10u, true, true, num::SignNeg, num::DigAll); + r +} - racc = uint::str(adjusted_digit) + racc; - } +/** + * Converts a float to a string in hexadecimal format + * + * # Arguments + * + * * num - The float value + */ +#[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); + r +} - // pad decimals with trailing zeroes - while racc.len() < digits && exact { - racc += ~"0" - } +/** + * Converts a float to a string in a given radix + * + * # Arguments + * + * * num - The float value + * * radix - The base to use + * + * # Failure + * + * Fails if called on a special value like `inf`, `-inf` or `NaN` due to + * possible misinterpretation of the result at higher bases. If those values + * are expected, use `to_str_radix_special()` instead. + */ +#[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); + if special { die!(~"number has a special value, \ + try to_str_radix_special() if those are expected") } + r +} - // combine ints and decimals - let mut ones = uint::str(trunc + carry); - if racc == ~"" { - acc = sign + ones; - } else { - acc = sign + ones + ~"." + racc; - } - move acc +/** + * Converts a float to a string in a given radix, and a flag indicating + * whether it's a special value + * + * # Arguments + * + * * num - The float value + * * radix - The base to use + */ +#[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) } /** @@ -197,7 +177,9 @@ pub pure fn to_str_common(num: float, digits: uint, exact: bool) -> ~str { */ #[inline(always)] pub pure fn to_str_exact(num: float, digits: uint) -> ~str { - to_str_common(num, digits, true) + let (r, _) = num::to_str_common( + &num, 10u, true, true, num::SignNeg, num::DigExact(digits)); + r } #[test] @@ -206,7 +188,6 @@ pub fn test_to_str_exact_do_decimal() { assert s == ~"5.0000"; } - /** * Converts a float to a string with a maximum number of * significant digits @@ -217,12 +198,27 @@ pub fn test_to_str_exact_do_decimal() { * * digits - The number of significant digits */ #[inline(always)] -pub pure fn to_str(num: float, digits: uint) -> ~str { - to_str_common(num, digits, false) +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)); + r +} + +impl float: to_str::ToStr { + #[inline(always)] + pure fn to_str() -> ~str { to_str_digits(self, 8) } +} + +impl float: num::ToStrRadix { + #[inline(always)] + pure fn to_str_radix(&self, radix: uint) -> ~str { + to_str_radix(*self, radix) + } } /** - * Convert a string to a float + * Convert a string in base 10 to a float. + * Accepts a optional decimal exponent. * * This function accepts strings such as * @@ -231,12 +227,12 @@ pub pure fn to_str(num: float, digits: uint) -> ~str { * * '-3.14' * * '2.5E10', or equivalently, '2.5e10' * * '2.5E-10' - * * '', or, equivalently, '.' (understood as 0) + * * '.' (understood as 0) * * '5.' * * '.5', or, equivalently, '0.5' - * * 'inf', '-inf', 'NaN' + * * '+inf', 'inf', '-inf', 'NaN' * - * Leading and trailing whitespace are ignored. + * Leading and trailing whitespace represent an error. * * # Arguments * @@ -245,125 +241,79 @@ pub pure fn to_str(num: float, digits: uint) -> ~str { * # 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 `num`. */ +#[inline(always)] pub pure fn from_str(num: &str) -> Option { - if num == "inf" { - return Some(infinity as float); - } else if num == "-inf" { - return Some(neg_infinity as float); - } else if num == "NaN" { - return Some(NaN as float); - } - - let mut pos = 0u; //Current byte position in the string. - //Used to walk the string in O(n). - let len = str::len(num); //Length of the string, in bytes. - - if len == 0u { return None; } - let mut total = 0f; //Accumulated result - let mut c = 'z'; //Latest char. - - //The string must start with one of the following characters. - match str::char_at(num, 0u) { - '-' | '+' | '0' .. '9' | '.' => (), - _ => return None - } - - //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly. - let mut neg = false; //Sign of the result - match str::char_at(num, 0u) { - '-' => { - neg = true; - pos = 1u; - } - '+' => { - pos = 1u; - } - _ => () - } + num::from_str_common(num, 10u, true, true, true, num::ExpDec, false) +} - //Examine the following chars until '.', 'e', 'E' - while(pos < len) { - let char_range = str::char_range_at(num, pos); - c = char_range.ch; - pos = char_range.next; - match c { - '0' .. '9' => { - total = total * 10f; - total += ((c as int) - ('0' as int)) as float; - } - '.' | 'e' | 'E' => break, - _ => return None - } - } +/** + * Convert a string in base 16 to a float. + * Accepts a 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(always)] +pub pure fn from_str_hex(num: &str) -> Option { + num::from_str_common(num, 16u, true, true, true, num::ExpBin, false) +} - if c == '.' {//Examine decimal part - let mut decimal = 1f; - while(pos < len) { - let char_range = str::char_range_at(num, pos); - c = char_range.ch; - pos = char_range.next; - match c { - '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' => { - decimal /= 10f; - total += (((c as int) - ('0' as int)) as float)*decimal; - } - 'e' | 'E' => break, - _ => return None - } - } - } +/** + * Convert a string in an 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 + * * 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`. + */ +#[inline(always)] +pub pure fn from_str_radix(num: &str, radix: uint) -> Option { + num::from_str_common(num, radix, true, true, false, num::ExpNone, false) +} - if (c == 'e') || (c == 'E') { //Examine exponent - let mut exponent = 0u; - let mut neg_exponent = false; - if(pos < len) { - let char_range = str::char_range_at(num, pos); - c = char_range.ch; - match c { - '+' => { - pos = char_range.next; - } - '-' => { - pos = char_range.next; - neg_exponent = true; - } - _ => () - } - while(pos < len) { - let char_range = str::char_range_at(num, pos); - c = char_range.ch; - match c { - '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' => { - exponent *= 10u; - exponent += ((c as uint) - ('0' as uint)); - } - _ => break - } - pos = char_range.next; - } - let multiplier = pow_with_uint(10u, exponent); - //Note: not ~[int::pow], otherwise, we'll quickly - //end up with a nice overflow - if neg_exponent { - total = total / multiplier; - } else { - total = total * multiplier; - } - } else { - return None; - } - } +impl float: from_str::FromStr { + #[inline(always)] + static pure fn from_str(val: &str) -> Option { from_str(val) } +} - if(pos < len) { - return None; - } else { - if(neg) { - total *= -1f; - } - return Some(total); - } +impl float: num::FromStrRadix { + #[inline(always)] + static pure fn from_str_radix(val: &str, radix: uint) -> Option { + from_str_radix(val, radix) + } } /** @@ -488,9 +438,41 @@ impl float: num::One { static pure fn one() -> float { 1.0 } } +impl float: num::Round { + #[inline(always)] + pure fn round(&self, mode: num::RoundMode) -> float { + match mode { + num::RoundDown + => f64::floor(*self as f64) as float, + num::RoundUp + => f64::ceil(*self as f64) as float, + num::RoundToZero if is_negative(*self) + => f64::ceil(*self as f64) as float, + num::RoundToZero + => f64::floor(*self as f64) as float, + num::RoundFromZero if is_negative(*self) + => f64::floor(*self as f64) as float, + num::RoundFromZero + => f64::ceil(*self as f64) as float + } + } + + #[inline(always)] + pure fn floor(&self) -> float { f64::floor(*self as f64) as float} + #[inline(always)] + pure fn ceil(&self) -> float { f64::ceil(*self as f64) as float} + #[inline(always)] + pure fn fract(&self) -> float { + if is_negative(*self) { + (*self) - (f64::ceil(*self as f64) as float) + } else { + (*self) - (f64::floor(*self as f64) as float) + } + } +} + #[test] pub fn test_from_str() { - assert from_str(~"3") == Some(3.); assert from_str(~"3") == Some(3.); assert from_str(~"3.14") == Some(3.14); assert from_str(~"+3.14") == Some(3.14); @@ -504,20 +486,25 @@ pub fn test_from_str() { assert from_str(~"5.") == Some(5.); assert from_str(~".5") == Some(0.5); assert from_str(~"0.5") == Some(0.5); - assert from_str(~"0.5") == Some(0.5); - assert from_str(~"0.5") == Some(0.5); - assert from_str(~"-.5") == Some(-0.5); assert from_str(~"-.5") == Some(-0.5); assert from_str(~"-5") == Some(-5.); - assert from_str(~"-0") == Some(-0.); - assert from_str(~"0") == Some(0.); assert from_str(~"inf") == Some(infinity); + assert from_str(~"+inf") == Some(infinity); assert from_str(~"-inf") == Some(neg_infinity); // note: NaN != NaN, hence this slightly complex test match from_str(~"NaN") { Some(f) => assert is_NaN(f), None => die!() } + // note: -0 == 0, hence these slightly more complex tests + match from_str(~"-0") { + Some(v) if is_zero(v) => assert is_negative(v), + _ => die!() + } + match from_str(~"0") { + Some(v) if is_zero(v) => assert is_positive(v), + _ => die!() + } assert from_str(~"").is_none(); assert from_str(~"x").is_none(); @@ -531,6 +518,89 @@ pub fn test_from_str() { assert from_str(~"1e1-1").is_none(); } +#[test] +pub fn test_from_str_hex() { + assert from_str_hex(~"a4") == Some(164.); + assert from_str_hex(~"a4.fe") == Some(164.9921875); + assert from_str_hex(~"-a4.fe") == Some(-164.9921875); + assert from_str_hex(~"+a4.fe") == Some(164.9921875); + assert from_str_hex(~"ff0P4") == Some(0xff00 as float); + assert from_str_hex(~"ff0p4") == Some(0xff00 as float); + assert from_str_hex(~"ff0p-4") == Some(0xff as float); + assert from_str_hex(~".") == Some(0.); + assert from_str_hex(~".p1") == Some(0.); + assert from_str_hex(~".p-1") == Some(0.); + assert from_str_hex(~"f.") == Some(15.); + assert from_str_hex(~".f") == Some(0.9375); + assert from_str_hex(~"0.f") == Some(0.9375); + assert from_str_hex(~"-.f") == Some(-0.9375); + assert from_str_hex(~"-f") == Some(-15.); + assert from_str_hex(~"inf") == Some(infinity); + assert from_str_hex(~"+inf") == Some(infinity); + assert from_str_hex(~"-inf") == Some(neg_infinity); + // note: NaN != NaN, hence this slightly complex test + match from_str_hex(~"NaN") { + Some(f) => assert is_NaN(f), + None => die!() + } + // note: -0 == 0, hence these slightly more complex tests + match from_str_hex(~"-0") { + Some(v) if is_zero(v) => assert is_negative(v), + _ => die!() + } + match from_str_hex(~"0") { + Some(v) if is_zero(v) => assert is_positive(v), + _ => die!() + } + assert from_str_hex(~"e") == Some(14.); + assert from_str_hex(~"E") == Some(14.); + assert from_str_hex(~"E1") == Some(225.); + assert from_str_hex(~"1e1e1") == Some(123361.); + assert from_str_hex(~"1e1.1") == Some(481.0625); + + assert from_str_hex(~"").is_none(); + assert from_str_hex(~"x").is_none(); + assert from_str_hex(~" ").is_none(); + assert from_str_hex(~" ").is_none(); + assert from_str_hex(~"p").is_none(); + assert from_str_hex(~"P").is_none(); + assert from_str_hex(~"P1").is_none(); + assert from_str_hex(~"1p1p1").is_none(); + assert from_str_hex(~"1p1.1").is_none(); + assert from_str_hex(~"1p1-1").is_none(); +} + +#[test] +pub fn test_to_str_hex() { + assert to_str_hex(164.) == ~"a4"; + assert to_str_hex(164.9921875) == ~"a4.fe"; + assert to_str_hex(-164.9921875) == ~"-a4.fe"; + assert to_str_hex(0xff00 as float) == ~"ff00"; + assert to_str_hex(-(0xff00 as float)) == ~"-ff00"; + assert to_str_hex(0.) == ~"0"; + assert to_str_hex(15.) == ~"f"; + assert to_str_hex(-15.) == ~"-f"; + assert to_str_hex(0.9375) == ~"0.f"; + assert to_str_hex(-0.9375) == ~"-0.f"; + assert to_str_hex(infinity) == ~"inf"; + assert to_str_hex(neg_infinity) == ~"-inf"; + assert to_str_hex(NaN) == ~"NaN"; + assert to_str_hex(0.) == ~"0"; + assert to_str_hex(-0.) == ~"-0"; +} + +#[test] +pub fn test_to_str_radix() { + assert to_str_radix(36., 36u) == ~"10"; + assert to_str_radix(8.125, 2u) == ~"1000.001"; +} + +#[test] +pub fn test_from_str_radix() { + assert from_str_radix(~"10", 36u) == Some(36.); + assert from_str_radix(~"1000.001", 2u) == Some(8.125); +} + #[test] pub fn test_positive() { assert(is_positive(infinity)); @@ -577,8 +647,8 @@ pub fn test_nonnegative() { #[test] pub fn test_to_str_inf() { - assert to_str(infinity, 10u) == ~"inf"; - assert to_str(-infinity, 10u) == ~"-inf"; + assert to_str_digits(infinity, 10u) == ~"inf"; + assert to_str_digits(-infinity, 10u) == ~"-inf"; } #[test] diff --git a/src/libcore/int-template.rs b/src/libcore/num/int-template.rs similarity index 61% rename from src/libcore/int-template.rs rename to src/libcore/num/int-template.rs index 08508b09b70a7..06d11e23967e8 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -17,13 +17,18 @@ use T = self::inst::T; use char; use cmp::{Eq, Ord}; use cmp; +use to_str::ToStr; use from_str::FromStr; +use num::{ToStrRadix, FromStrRadix}; use num; use num::Num::from_int; use prelude::*; use str; use uint; use vec; +use i8; +use i16; +use i32; pub const bits : uint = inst::bits; pub const bytes : uint = (inst::bits / 8); @@ -200,83 +205,112 @@ impl T: num::One { static pure fn one() -> T { 1 } } -/** - * Parse a buffer of bytes - * - * # Arguments - * - * * buf - A byte buffer - * * radix - The base of the number - */ -pub pure fn parse_bytes(buf: &[u8], radix: uint) -> Option { - if vec::len(buf) == 0u { return None; } - let mut i = vec::len(buf) - 1u; - let mut start = 0u; - let mut power = 1 as T; - - if buf[0] == ('-' as u8) { - power = -1 as T; - start = 1u; - } - let mut n = 0 as T; - loop { - match char::to_digit(buf[i] as char, radix) { - Some(d) => n += (d as T) * power, - None => return None - } - power *= radix as T; - if i <= start { return Some(n); } - i -= 1u; - }; +impl T: num::Round { + #[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 } +} + +// String conversion functions and impl str -> num + +/// Parse a string as a number in base 10. +#[inline(always)] +pub pure fn from_str(s: &str) -> Option { + num::from_str_common(s, 10u, true, false, false, + num::ExpNone, false) } -/// Parse a string to an int +/// Parse a string as a number in the given base. #[inline(always)] -pub pure fn from_str(s: &str) -> Option -{ - parse_bytes(str::to_bytes(s), 10u) +pub pure fn from_str_radix(s: &str, radix: uint) -> Option { + num::from_str_common(s, radix, true, false, false, + num::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 { + num::from_str_bytes_common(buf, radix, true, false, false, + num::ExpNone, false) } impl T : FromStr { #[inline(always)] - static pure fn from_str(s: &str) -> Option { from_str(s) } + static pure fn from_str(s: &str) -> Option { + from_str(s) + } } -/// Convert to a string in a given base -#[inline(always)] -pub pure fn to_str(n: T, radix: uint) -> ~str { - do to_str_bytes(n, radix) |slice| { - do vec::as_imm_buf(slice) |p, len| { - unsafe { str::raw::from_buf_len(p, len) } - } +impl T : FromStrRadix { + #[inline(always)] + static pure fn from_str_radix(&self, s: &str, radix: uint) -> Option { + from_str_radix(s, radix) } } +// String conversion functions and impl num -> str + +/// Convert to a string as a byte slice in a given base. #[inline(always)] pub pure fn to_str_bytes(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U { - if n < 0 as T { - uint::to_str_bytes(true, -n as uint, radix, f) - } else { - uint::to_str_bytes(false, n as uint, radix, f) - } + let (buf, _) = num::to_str_bytes_common(&n, radix, false, false, + num::SignNeg, num::DigAll); + f(buf) } -/// Convert to a string +/// Convert to a string in base 10. #[inline(always)] -pub pure fn str(i: T) -> ~str { return to_str(i, 10u); } +pub pure fn to_str(num: T) -> ~str { + let (buf, _) = num::to_str_common(&num, 10u, false, false, + num::SignNeg, num::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); + buf +} + +/// Convert to a string. +/// *Deprecated*, use to_str() instead. +#[inline(always)] +pub pure fn str(i: T) -> ~str { to_str(i) } + +impl T : ToStr { + #[inline(always)] + pure fn to_str() -> ~str { + to_str(self) + } +} + +impl T : ToStrRadix { + #[inline(always)] + pure fn to_str_radix(&self, radix: uint) -> ~str { + to_str_radix(*self, radix) + } +} #[test] fn test_from_str() { assert from_str(~"0") == Some(0 as T); assert from_str(~"3") == Some(3 as T); assert from_str(~"10") == Some(10 as T); - assert from_str(~"123456789") == Some(123456789 as T); + assert i32::from_str(~"123456789") == Some(123456789 as i32); assert from_str(~"00100") == Some(100 as T); assert from_str(~"-1") == Some(-1 as T); assert from_str(~"-3") == Some(-3 as T); assert from_str(~"-10") == Some(-10 as T); - assert from_str(~"-123456789") == Some(-123456789 as T); + assert i32::from_str(~"-123456789") == Some(-123456789 as i32); assert from_str(~"-00100") == Some(-100 as T); assert from_str(~" ").is_none(); @@ -289,18 +323,18 @@ fn test_parse_bytes() { assert parse_bytes(to_bytes(~"123"), 10u) == Some(123 as T); assert parse_bytes(to_bytes(~"1001"), 2u) == Some(9 as T); assert parse_bytes(to_bytes(~"123"), 8u) == Some(83 as T); - assert parse_bytes(to_bytes(~"123"), 16u) == Some(291 as T); - assert parse_bytes(to_bytes(~"ffff"), 16u) == Some(65535 as T); - assert parse_bytes(to_bytes(~"FFFF"), 16u) == Some(65535 as T); + assert i32::parse_bytes(to_bytes(~"123"), 16u) == Some(291 as i32); + assert i32::parse_bytes(to_bytes(~"ffff"), 16u) == Some(65535 as i32); + assert i32::parse_bytes(to_bytes(~"FFFF"), 16u) == Some(65535 as i32); assert parse_bytes(to_bytes(~"z"), 36u) == Some(35 as T); assert parse_bytes(to_bytes(~"Z"), 36u) == Some(35 as T); assert parse_bytes(to_bytes(~"-123"), 10u) == Some(-123 as T); assert parse_bytes(to_bytes(~"-1001"), 2u) == Some(-9 as T); assert parse_bytes(to_bytes(~"-123"), 8u) == Some(-83 as T); - assert parse_bytes(to_bytes(~"-123"), 16u) == Some(-291 as T); - assert parse_bytes(to_bytes(~"-ffff"), 16u) == Some(-65535 as T); - assert parse_bytes(to_bytes(~"-FFFF"), 16u) == Some(-65535 as T); + assert i32::parse_bytes(to_bytes(~"-123"), 16u) == Some(-291 as i32); + assert i32::parse_bytes(to_bytes(~"-ffff"), 16u) == Some(-65535 as i32); + assert i32::parse_bytes(to_bytes(~"-FFFF"), 16u) == Some(-65535 as i32); assert parse_bytes(to_bytes(~"-z"), 36u) == Some(-35 as T); assert parse_bytes(to_bytes(~"-Z"), 36u) == Some(-35 as T); @@ -310,11 +344,74 @@ fn test_parse_bytes() { #[test] fn test_to_str() { - assert (to_str(0 as T, 10u) == ~"0"); - assert (to_str(1 as T, 10u) == ~"1"); - assert (to_str(-1 as T, 10u) == ~"-1"); - assert (to_str(127 as T, 16u) == ~"7f"); - assert (to_str(100 as T, 10u) == ~"100"); + assert (to_str_radix(0 as T, 10u) == ~"0"); + assert (to_str_radix(1 as T, 10u) == ~"1"); + assert (to_str_radix(-1 as T, 10u) == ~"-1"); + assert (to_str_radix(127 as T, 16u) == ~"7f"); + assert (to_str_radix(100 as T, 10u) == ~"100"); + +} + +#[test] +fn test_int_to_str_overflow() { + let mut i8_val: i8 = 127_i8; + assert (i8::to_str(i8_val) == ~"127"); + + i8_val += 1 as i8; + assert (i8::to_str(i8_val) == ~"-128"); + + let mut i16_val: i16 = 32_767_i16; + assert (i16::to_str(i16_val) == ~"32767"); + + i16_val += 1 as i16; + assert (i16::to_str(i16_val) == ~"-32768"); + + let mut i32_val: i32 = 2_147_483_647_i32; + assert (i32::to_str(i32_val) == ~"2147483647"); + + i32_val += 1 as i32; + assert (i32::to_str(i32_val) == ~"-2147483648"); + + let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; + assert (i64::to_str(i64_val) == ~"9223372036854775807"); + + i64_val += 1 as i64; + assert (i64::to_str(i64_val) == ~"-9223372036854775808"); +} + +#[test] +fn test_int_from_str_overflow() { + let mut i8_val: i8 = 127_i8; + assert (i8::from_str(~"127") == Some(i8_val)); + assert (i8::from_str(~"128").is_none()); + + i8_val += 1 as i8; + assert (i8::from_str(~"-128") == Some(i8_val)); + assert (i8::from_str(~"-129").is_none()); + + let mut i16_val: i16 = 32_767_i16; + assert (i16::from_str(~"32767") == Some(i16_val)); + assert (i16::from_str(~"32768").is_none()); + + i16_val += 1 as i16; + assert (i16::from_str(~"-32768") == Some(i16_val)); + assert (i16::from_str(~"-32769").is_none()); + + let mut i32_val: i32 = 2_147_483_647_i32; + assert (i32::from_str(~"2147483647") == Some(i32_val)); + assert (i32::from_str(~"2147483648").is_none()); + + i32_val += 1 as i32; + assert (i32::from_str(~"-2147483648") == Some(i32_val)); + assert (i32::from_str(~"-2147483649").is_none()); + + let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; + assert (i64::from_str(~"9223372036854775807") == Some(i64_val)); + assert (i64::from_str(~"9223372036854775808").is_none()); + + i64_val += 1 as i64; + assert (i64::from_str(~"-9223372036854775808") == Some(i64_val)); + assert (i64::from_str(~"-9223372036854775809").is_none()); } #[test] diff --git a/src/libcore/int-template/i16.rs b/src/libcore/num/int-template/i16.rs similarity index 100% rename from src/libcore/int-template/i16.rs rename to src/libcore/num/int-template/i16.rs diff --git a/src/libcore/int-template/i32.rs b/src/libcore/num/int-template/i32.rs similarity index 100% rename from src/libcore/int-template/i32.rs rename to src/libcore/num/int-template/i32.rs diff --git a/src/libcore/int-template/i64.rs b/src/libcore/num/int-template/i64.rs similarity index 100% rename from src/libcore/int-template/i64.rs rename to src/libcore/num/int-template/i64.rs diff --git a/src/libcore/int-template/i8.rs b/src/libcore/num/int-template/i8.rs similarity index 100% rename from src/libcore/int-template/i8.rs rename to src/libcore/num/int-template/i8.rs diff --git a/src/libcore/int-template/int.rs b/src/libcore/num/int-template/int.rs similarity index 100% rename from src/libcore/int-template/int.rs rename to src/libcore/num/int-template/int.rs diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs new file mode 100644 index 0000000000000..05b03a53dcdea --- /dev/null +++ b/src/libcore/num/num.rs @@ -0,0 +1,688 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An interface for numeric types +use core::cmp::{Ord, Eq}; +use option::{None, Option, Some}; +use char; +use str; +use kinds::Copy; +use vec; + +pub trait Num { + // FIXME: Trait composition. (#2616) + pure fn add(&self, other: &Self) -> Self; + pure fn sub(&self, other: &Self) -> Self; + pure fn mul(&self, other: &Self) -> Self; + pure fn div(&self, other: &Self) -> Self; + pure fn modulo(&self, other: &Self) -> Self; + pure fn neg(&self) -> Self; + + pure fn to_int(&self) -> int; + static pure fn from_int(n: int) -> Self; +} + +pub trait IntConvertible { + pure fn to_int(&self) -> int; + static pure fn from_int(n: int) -> Self; +} + +pub trait Zero { + static pure fn zero() -> Self; +} + +pub trait One { + static pure fn one() -> Self; +} + +pub trait Round { + pure fn round(&self, mode: RoundMode) -> Self; + + pure fn floor(&self) -> Self; + pure fn ceil(&self) -> Self; + pure fn fract(&self) -> Self; +} + +pub enum RoundMode { + RoundDown, + RoundUp, + RoundToZero, + RoundFromZero +} + +pub trait ToStrRadix { + pub pure fn to_str_radix(&self, radix: uint) -> ~str; +} + +pub trait FromStrRadix { + static pub pure fn from_str_radix(str: &str, radix: uint) -> Option; +} + +// Generic math functions: + +/// Dynamically calculates the value `inf` (`1/0`). +/// Can fail on integer types. +#[inline(always)] +pub pure fn infinity() -> 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 { + 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 { + 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(num: &T) -> bool { + (*num) == (infinity::()) +} + +/// Returns `true` if `num` has the value `-inf` (`-1/0`). +/// Can fail on integer types. +#[inline(always)] +pub pure fn is_neg_infinity(num: &T) -> bool { + (*num) == (neg_infinity::()) +} + +/// Returns `true` if `num` has the value `NaN` (is not equal to itself). +#[inline(always)] +pub pure fn is_NaN(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(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`. + * + * Returns `radix^pow` as `T`. + * + * Note: + * Also returns `1` for `0^0`, despite that technically being an + * undefined number. The reason for this is twofold: + * - If code written to use this function cares about that special case, it's + * probably going to catch it before making the call. + * - If code written to use this function doesn't care about it, it's + * probably assuming that `x^0` always equals `1`. + */ +pub pure fn pow_with_uint(radix: uint, + pow: uint) -> T { + let _0: T = Zero::zero(); + let _1: T = One::one(); + + if pow == 0u { return _1; } + if radix == 0u { return _0; } + let mut my_pow = pow; + let mut total = _1; + let mut multiplier = Num::from_int(radix as int); + while (my_pow > 0u) { + if my_pow % 2u == 1u { + total *= multiplier; + } + my_pow /= 2u; + multiplier *= multiplier; + } + 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( + num: &T, radix: uint, special: bool, negative_zero: bool, + sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) { + if radix as int < 2 { + die!(fmt!("to_str_bytes_common: radix %? to low, \ + must lie in the range [2, 36]", radix)); + } else if radix as int > 36 { + die!(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 = Num::from_int::(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( + 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( + buf: &[u8], radix: uint, negative: bool, fractional: bool, + special: bool, exponent: ExponentFormat, empty_zero: bool + ) -> Option { + match exponent { + ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' + => die!(fmt!("from_str_bytes_common: radix %? incompatible with \ + use of 'e' as decimal exponent", radix)), + ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p' + => die!(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' + => die!(fmt!("from_str_bytes_common: radix %? incompatible with \ + special values 'inf' and 'NaN'", radix)), + _ if radix as int < 2 + => die!(fmt!("from_str_bytes_common: radix %? to low, \ + must lie in the range [2, 36]", radix)), + _ if radix as int > 36 + => die!(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 = Num::from_int(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 += Num::from_int(digit as int); + } else { + accum -= Num::from_int(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; + + // add/subtract current digit depending on sign + if accum_positive { + accum += Num::from_int::(digit as int) * power; + } else { + accum -= Num::from_int::(digit as int) * 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 = 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::(base, (-exp_pow.to_int()) as uint) + } else { + pow_with_uint::(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( + buf: &str, radix: uint, negative: bool, fractional: bool, + special: bool, exponent: ExponentFormat, empty_zero: bool + ) -> Option { + from_str_bytes_common(str::to_bytes(buf), radix, negative, + fractional, special, exponent, empty_zero) +} diff --git a/src/libcore/uint-template.rs b/src/libcore/num/uint-template.rs similarity index 56% rename from src/libcore/uint-template.rs rename to src/libcore/num/uint-template.rs index 1cd447df00536..44ed9816cf94a 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -17,12 +17,19 @@ use T_SIGNED = self::inst::T_SIGNED; use char; use cmp::{Eq, Ord}; +use cmp; +use to_str::ToStr; use from_str::FromStr; +use num::{ToStrRadix, FromStrRadix}; use num; use option::{None, Option, Some}; +use prelude::*; use str; use uint; use vec; +use u8; +use u16; +use u32; pub const bits : uint = inst::bits; pub const bytes : uint = (inst::bits / 8); @@ -160,135 +167,109 @@ impl T: num::One { static pure fn one() -> T { 1 } } -/** - * Parse a buffer of bytes - * - * # Arguments - * - * * buf - A byte buffer - * * radix - The base of the number - * - * # Failure - * - * `buf` must not be empty - */ -pub pure fn parse_bytes(buf: &[const u8], radix: uint) -> Option { - if vec::len(buf) == 0u { return None; } - let mut i = vec::len(buf) - 1u; - let mut power = 1u as T; - let mut n = 0u as T; - loop { - match char::to_digit(buf[i] as char, radix) { - Some(d) => n += d as T * power, - None => return None - } - power *= radix as T; - if i == 0u { return Some(n); } - i -= 1u; - }; +impl T: num::Round { + #[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 } } -/// Parse a string to an int +// String conversion functions and impl str -> num + +/// Parse a string as a number in base 10. #[inline(always)] -pub pure fn from_str(s: &str) -> Option -{ - parse_bytes(str::to_bytes(s), 10u) +pub pure fn from_str(s: &str) -> Option { + num::from_str_common(s, 10u, false, false, false, + num::ExpNone, false) } -impl T : FromStr { - #[inline(always)] - static pure fn from_str(s: &str) -> Option { from_str(s) } +/// Parse a string as a number in the given base. +#[inline(always)] +pub pure fn from_str_radix(s: &str, radix: uint) -> Option { + num::from_str_common(s, radix, false, false, false, + num::ExpNone, false) } -/// Parse a string as an unsigned integer. -pub fn from_str_radix(buf: &str, radix: u64) -> Option { - if str::len(buf) == 0u { return None; } - let mut i = str::len(buf) - 1u; - let mut power = 1u64, n = 0u64; - loop { - match char::to_digit(buf[i] as char, radix as uint) { - Some(d) => n += d as u64 * power, - None => return None - } - power *= radix; - if i == 0u { return Some(n); } - i -= 1u; - }; +/// Parse a byte slice as a number in the given base. +#[inline(always)] +pub pure fn parse_bytes(buf: &[u8], radix: uint) -> Option { + num::from_str_bytes_common(buf, radix, false, false, false, + num::ExpNone, false) } -/** - * Convert to a string in a given base - * - * # Failure - * - * Fails if `radix` < 2 or `radix` > 16 - */ -#[inline(always)] -pub pure fn to_str(num: T, radix: uint) -> ~str { - do to_str_bytes(false, num, radix) |slice| { - do vec::as_imm_buf(slice) |p, len| { - unsafe { str::raw::from_buf_len(p, len) } - } +impl T : FromStr { + #[inline(always)] + static pure fn from_str(s: &str) -> Option { + from_str(s) } } -/// Low-level helper routine for string conversion. -pub pure fn to_str_bytes(neg: bool, num: T, radix: uint, - f: fn(v: &[u8]) -> U) -> U { - +impl T : FromStrRadix { #[inline(always)] - pure fn digit(n: T) -> u8 { - if n <= 9u as T { - n as u8 + '0' as u8 - } else if n <= 15u as T { - (n - 10 as T) as u8 + 'a' as u8 - } else { - die!(); - } + static pure fn from_str_radix(&self, s: &str, radix: uint) -> Option { + from_str_radix(s, radix) } +} - assert (1u < radix && radix <= 16u); - - // Enough room to hold any number in any radix. - // Worst case: 64-bit number, binary-radix, with - // a leading negative sign = 65 bytes. - let buf : [mut u8 * 65] = [mut 0u8, ..65]; - let len = buf.len(); - - let mut i = len; - let mut n = num; - let radix = radix as T; - loop { - i -= 1u; - assert 0u < i && i < len; - buf[i] = digit(n % radix); - n /= radix; - if n == 0 as T { break; } - } +// String conversion functions and impl num -> str - assert 0u < i && i < len; +/// Convert to a string as a byte slice in a given base. +#[inline(always)] +pub pure fn to_str_bytes(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); + f(buf) +} - if neg { - i -= 1u; - buf[i] = '-' as u8; - } +/// 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); + buf +} - f(vec::view(buf, i, len)) +/// 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); + buf } -/// Convert to a string +/// Convert to a string. +/// *Deprecated*, use to_str() instead. #[inline(always)] -pub pure fn str(i: T) -> ~str { return to_str(i, 10u); } +pub pure fn str(i: T) -> ~str { to_str(i) } + +impl T : ToStr { + #[inline(always)] + pure fn to_str() -> ~str { + to_str(self) + } +} + +impl T : ToStrRadix { + #[inline(always)] + pure fn to_str_radix(&self, radix: uint) -> ~str { + to_str_radix(*self, radix) + } +} #[test] pub fn test_to_str() { - assert to_str(0 as T, 10u) == ~"0"; - assert to_str(1 as T, 10u) == ~"1"; - assert to_str(2 as T, 10u) == ~"2"; - assert to_str(11 as T, 10u) == ~"11"; - assert to_str(11 as T, 16u) == ~"b"; - assert to_str(255 as T, 16u) == ~"ff"; - assert to_str(0xff as T, 10u) == ~"255"; + assert to_str_radix(0 as T, 10u) == ~"0"; + assert to_str_radix(1 as T, 10u) == ~"1"; + assert to_str_radix(2 as T, 10u) == ~"2"; + assert to_str_radix(11 as T, 10u) == ~"11"; + assert to_str_radix(11 as T, 16u) == ~"b"; + assert to_str_radix(255 as T, 16u) == ~"ff"; + assert to_str_radix(0xff as T, 10u) == ~"255"; } #[test] @@ -296,7 +277,7 @@ pub fn test_from_str() { assert from_str(~"0") == Some(0u as T); assert from_str(~"3") == Some(3u as T); assert from_str(~"10") == Some(10u as T); - assert from_str(~"123456789") == Some(123456789u as T); + assert u32::from_str(~"123456789") == Some(123456789 as u32); assert from_str(~"00100") == Some(100u as T); assert from_str(~"").is_none(); @@ -310,26 +291,88 @@ pub fn test_parse_bytes() { assert parse_bytes(to_bytes(~"123"), 10u) == Some(123u as T); assert parse_bytes(to_bytes(~"1001"), 2u) == Some(9u as T); assert parse_bytes(to_bytes(~"123"), 8u) == Some(83u as T); - assert parse_bytes(to_bytes(~"123"), 16u) == Some(291u as T); - assert parse_bytes(to_bytes(~"ffff"), 16u) == Some(65535u as T); + assert u16::parse_bytes(to_bytes(~"123"), 16u) == Some(291u as u16); + assert u16::parse_bytes(to_bytes(~"ffff"), 16u) == Some(65535u as u16); assert parse_bytes(to_bytes(~"z"), 36u) == Some(35u as T); assert parse_bytes(to_bytes(~"Z"), 10u).is_none(); assert parse_bytes(to_bytes(~"_"), 2u).is_none(); } +#[test] +fn test_uint_to_str_overflow() { + let mut u8_val: u8 = 255_u8; + assert (u8::to_str(u8_val) == ~"255"); + + u8_val += 1 as u8; + assert (u8::to_str(u8_val) == ~"0"); + + let mut u16_val: u16 = 65_535_u16; + assert (u16::to_str(u16_val) == ~"65535"); + + u16_val += 1 as u16; + assert (u16::to_str(u16_val) == ~"0"); + + let mut u32_val: u32 = 4_294_967_295_u32; + assert (u32::to_str(u32_val) == ~"4294967295"); + + u32_val += 1 as u32; + assert (u32::to_str(u32_val) == ~"0"); + + let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; + assert (u64::to_str(u64_val) == ~"18446744073709551615"); + + u64_val += 1 as u64; + assert (u64::to_str(u64_val) == ~"0"); +} + +#[test] +fn test_uint_from_str_overflow() { + let mut u8_val: u8 = 255_u8; + assert (u8::from_str(~"255") == Some(u8_val)); + assert (u8::from_str(~"256").is_none()); + + u8_val += 1 as u8; + assert (u8::from_str(~"0") == Some(u8_val)); + assert (u8::from_str(~"-1").is_none()); + + let mut u16_val: u16 = 65_535_u16; + assert (u16::from_str(~"65535") == Some(u16_val)); + assert (u16::from_str(~"65536").is_none()); + + u16_val += 1 as u16; + assert (u16::from_str(~"0") == Some(u16_val)); + assert (u16::from_str(~"-1").is_none()); + + let mut u32_val: u32 = 4_294_967_295_u32; + assert (u32::from_str(~"4294967295") == Some(u32_val)); + assert (u32::from_str(~"4294967296").is_none()); + + u32_val += 1 as u32; + assert (u32::from_str(~"0") == Some(u32_val)); + assert (u32::from_str(~"-1").is_none()); + + let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; + assert (u64::from_str(~"18446744073709551615") == Some(u64_val)); + assert (u64::from_str(~"18446744073709551616").is_none()); + + u64_val += 1 as u64; + assert (u64::from_str(~"0") == Some(u64_val)); + assert (u64::from_str(~"-1").is_none()); +} + #[test] #[should_fail] #[ignore(cfg(windows))] pub fn to_str_radix1() { - uint::to_str(100u, 1u); + uint::to_str_radix(100u, 1u); } #[test] #[should_fail] #[ignore(cfg(windows))] -pub fn to_str_radix17() { - uint::to_str(100u, 17u); +pub fn to_str_radix37() { + uint::to_str_radix(100u, 37u); } use io; diff --git a/src/libcore/uint-template/u16.rs b/src/libcore/num/uint-template/u16.rs similarity index 100% rename from src/libcore/uint-template/u16.rs rename to src/libcore/num/uint-template/u16.rs diff --git a/src/libcore/uint-template/u32.rs b/src/libcore/num/uint-template/u32.rs similarity index 100% rename from src/libcore/uint-template/u32.rs rename to src/libcore/num/uint-template/u32.rs diff --git a/src/libcore/uint-template/u64.rs b/src/libcore/num/uint-template/u64.rs similarity index 100% rename from src/libcore/uint-template/u64.rs rename to src/libcore/num/uint-template/u64.rs diff --git a/src/libcore/uint-template/u8.rs b/src/libcore/num/uint-template/u8.rs similarity index 100% rename from src/libcore/uint-template/u8.rs rename to src/libcore/num/uint-template/u8.rs diff --git a/src/libcore/uint-template/uint.rs b/src/libcore/num/uint-template/uint.rs similarity index 100% rename from src/libcore/uint-template/uint.rs rename to src/libcore/num/uint-template/uint.rs diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index a5c3afcc87f5e..2f77e71bef005 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -893,7 +893,7 @@ fn test_repr() { exact_test(&10, "10"); exact_test(&true, "true"); exact_test(&false, "false"); - exact_test(&1.234, "1.2340"); + exact_test(&1.234, "1.234"); exact_test(&(&"hello"), "\"hello\""); exact_test(&(@"hello"), "@\"hello\""); exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\""); @@ -918,11 +918,11 @@ fn test_repr() { exact_test(&(&["hi", "there"]), "&[\"hi\", \"there\"]"); exact_test(&(P{a:10, b:1.234}), - "{a: 10, b: 1.2340}"); + "{a: 10, b: 1.234}"); exact_test(&(@P{a:10, b:1.234}), - "@{a: 10, b: 1.2340}"); + "@{a: 10, b: 1.234}"); exact_test(&(~P{a:10, b:1.234}), - "~{a: 10, b: 1.2340}"); + "~{a: 10, b: 1.234}"); exact_test(&(10_u8, ~"hello"), "(10, ~\"hello\")"); exact_test(&(10_u16, ~"hello"), diff --git a/src/libcore/to_str.rs b/src/libcore/to_str.rs index b1fb1fdd483c4..51205b0c647fd 100644 --- a/src/libcore/to_str.rs +++ b/src/libcore/to_str.rs @@ -24,58 +24,6 @@ use vec; pub trait ToStr { pub pure fn to_str() -> ~str; } -impl int: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::int::str(self) } -} -impl i8: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::i8::str(self) } -} -impl i16: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::i16::str(self) } -} -impl i32: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::i32::str(self) } -} -impl i64: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::i64::str(self) } -} -impl uint: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::uint::str(self) } -} -impl u8: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::u8::str(self) } -} -impl u16: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::u16::str(self) } -} -impl u32: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::u32::str(self) } -} -impl u64: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::u64::str(self) } -} -impl float: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::float::to_str(self, 4u) } -} -impl f32: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::float::to_str(self as float, 4u) } -} -impl f64: ToStr { - #[inline(always)] - pure fn to_str() -> ~str { ::float::to_str(self as float, 4u) } -} impl bool: ToStr { #[inline(always)] pure fn to_str() -> ~str { ::bool::to_str(self) } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 7f7c01149888b..3dd49f661eefd 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -382,21 +382,21 @@ pub fn pretty_print_input(sess: Session, +cfg: ast::crate_cfg, input: input, match node { pprust::node_item(s, item) => { pp::space(s.s); - pprust::synth_comment(s, int::to_str(item.id, 10u)); + pprust::synth_comment(s, int::to_str(item.id)); } pprust::node_block(s, ref blk) => { pp::space(s.s); pprust::synth_comment( - s, ~"block " + int::to_str((*blk).node.id, 10u)); + s, ~"block " + int::to_str((*blk).node.id)); } pprust::node_expr(s, expr) => { pp::space(s.s); - pprust::synth_comment(s, int::to_str(expr.id, 10u)); + pprust::synth_comment(s, int::to_str(expr.id)); pprust::pclose(s); } pprust::node_pat(s, pat) => { pp::space(s.s); - pprust::synth_comment(s, ~"pat " + int::to_str(pat.id, 10u)); + pprust::synth_comment(s, ~"pat " + int::to_str(pat.id)); } } } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 33879237ffb49..b8a1b942453f0 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -245,7 +245,7 @@ fn encode_discriminant(ecx: @encode_ctxt, ebml_w: writer::Encoder, fn encode_disr_val(_ecx: @encode_ctxt, ebml_w: writer::Encoder, disr_val: int) { ebml_w.start_tag(tag_disr_val); - ebml_w.writer.write(str::to_bytes(int::to_str(disr_val,10u))); + ebml_w.writer.write(str::to_bytes(int::to_str(disr_val))); ebml_w.end_tag(); } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 69d69537f2ad9..f02f187c629a0 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -98,8 +98,8 @@ pub fn enc_ty(w: io::Writer, cx: @ctxt, t: ty::t) { let abbrev_len = 3u + estimate_sz(pos) + estimate_sz(len); if abbrev_len < len { // I.e. it's actually an abbreviation. - let s = ~"#" + uint::to_str(pos, 16u) + ~":" + - uint::to_str(len, 16u) + ~"#"; + let s = ~"#" + uint::to_str_radix(pos, 16u) + ~":" + + uint::to_str_radix(len, 16u) + ~"#"; let a = {pos: pos, len: len, s: @s}; abbrevs.insert(t, a); } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index f394c98ab6f4b..5a8fe94a4390a 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -679,7 +679,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, let variant_cx = sub_block(cx, ~"enum-iter-variant-" + - int::to_str(variant.disr_val, 10u)); + int::to_str(variant.disr_val)); AddCase(llswitch, C_int(ccx, variant.disr_val), variant_cx.llbb); let variant_cx = iter_variant(variant_cx, llunion_a_ptr, *variant, diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index e100392bba9ad..57e05926173d1 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -88,7 +88,7 @@ pub impl VarValue : InferStr { match *self { Redirect(ref vid) => fmt!("Redirect(%s)", vid.to_str()), Root(ref pt, rk) => fmt!("Root(%s, %s)", pt.inf_str(cx), - uint::to_str(rk, 10u)) + uint::to_str_radix(rk, 10u)) } } } diff --git a/src/libstd/bigint.rs b/src/libstd/bigint.rs index 0104e72764f69..64126ea918fc0 100644 --- a/src/libstd/bigint.rs +++ b/src/libstd/bigint.rs @@ -456,7 +456,7 @@ pub impl BigUint { pure fn fill_concat(v: &[BigDigit], radix: uint, l: uint) -> ~str { if v.is_empty() { return ~"0" } str::trim_left_chars(str::concat(vec::reversed(v).map(|n| { - let s = uint::to_str(*n as uint, radix); + let s = uint::to_str_radix(*n as uint, radix); str::from_chars(vec::from_elem(l - s.len(), '0')) + s })), ['0']) } diff --git a/src/libstd/json.rs b/src/libstd/json.rs index f0929c3dba047..b1cdeef4e6650 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -109,7 +109,7 @@ pub impl Encoder: serialize::Encoder { fn emit_f64(&self, v: f64) { self.emit_float(v as float); } fn emit_f32(&self, v: f32) { self.emit_float(v as float); } fn emit_float(&self, v: float) { - self.wr.write_str(float::to_str(v, 6u)); + self.wr.write_str(float::to_str_digits(v, 6u)); } fn emit_char(&self, v: char) { self.emit_borrowed_str(str::from_char(v)) } @@ -213,7 +213,7 @@ pub impl PrettyEncoder: serialize::Encoder { fn emit_f64(&self, v: f64) { self.emit_float(v as float); } fn emit_f32(&self, v: f32) { self.emit_float(v as float); } fn emit_float(&self, v: float) { - self.wr.write_str(float::to_str(v, 6u)); + self.wr.write_str(float::to_str_digits(v, 6u)); } fn emit_char(&self, v: char) { self.emit_borrowed_str(str::from_char(v)) } diff --git a/src/libstd/map.rs b/src/libstd/map.rs index 380e23b23a5e9..d557a5a06da1a 100644 --- a/src/libstd/map.rs +++ b/src/libstd/map.rs @@ -619,32 +619,35 @@ mod tests { map::HashMap::<~str, ~str>(); i = 0u; while i < num_to_insert { - assert hm_ss.insert(uint::to_str(i, 2u), uint::to_str(i * i, 2u)); + assert hm_ss.insert(uint::to_str_radix(i, 2u), + uint::to_str_radix(i * i, 2u)); debug!("inserting \"%s\" -> \"%s\"", - uint::to_str(i, 2u), - uint::to_str(i*i, 2u)); + uint::to_str_radix(i, 2u), + uint::to_str_radix(i*i, 2u)); i += 1u; } debug!("-----"); i = 0u; while i < num_to_insert { debug!("get(\"%s\") = \"%s\"", - uint::to_str(i, 2u), - hm_ss.get(uint::to_str(i, 2u))); - assert hm_ss.get(uint::to_str(i, 2u)) == uint::to_str(i * i, 2u); + uint::to_str_radix(i, 2u), + hm_ss.get(uint::to_str_radix(i, 2u))); + assert hm_ss.get(uint::to_str_radix(i, 2u)) == + uint::to_str_radix(i * i, 2u); i += 1u; } - assert (hm_ss.insert(uint::to_str(num_to_insert, 2u), - uint::to_str(17u, 2u))); - assert hm_ss.get(uint::to_str(num_to_insert, 2u)) == - uint::to_str(17u, 2u); + assert (hm_ss.insert(uint::to_str_radix(num_to_insert, 2u), + uint::to_str_radix(17u, 2u))); + assert hm_ss.get(uint::to_str_radix(num_to_insert, 2u)) == + uint::to_str_radix(17u, 2u); debug!("-----"); i = 0u; while i < num_to_insert { debug!("get(\"%s\") = \"%s\"", - uint::to_str(i, 2u), - hm_ss.get(uint::to_str(i, 2u))); - assert hm_ss.get(uint::to_str(i, 2u)) == uint::to_str(i * i, 2u); + uint::to_str_radix(i, 2u), + hm_ss.get(uint::to_str_radix(i, 2u))); + assert hm_ss.get(uint::to_str_radix(i, 2u)) == + uint::to_str_radix(i * i, 2u); i += 1u; } debug!("*** finished test_growth"); diff --git a/src/libstd/md4.rs b/src/libstd/md4.rs index 06b6aca6895d6..e1e2bb2697f8c 100644 --- a/src/libstd/md4.rs +++ b/src/libstd/md4.rs @@ -109,7 +109,7 @@ pub pure fn md4_str(msg: &[u8]) -> ~str { while i < 4u32 { let byte = (u >> (i * 8u32)) as u8; if byte <= 16u8 { result += ~"0"; } - result += uint::to_str(byte as uint, 16u); + result += uint::to_str_radix(byte as uint, 16u); i += 1u32; } } diff --git a/src/libstd/sha1.rs b/src/libstd/sha1.rs index 608d071d90e5c..a5c740c343cfc 100644 --- a/src/libstd/sha1.rs +++ b/src/libstd/sha1.rs @@ -253,7 +253,7 @@ pub fn sha1() -> Sha1 { let rr = mk_result(&self); let mut s = ~""; for vec::each(rr) |b| { - s += uint::to_str(*b as uint, 16u); + s += uint::to_str_radix(*b as uint, 16u); } return s; } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 165c2a3d9bcb9..dd25fc36d2ddf 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -926,7 +926,7 @@ mod tests { let s0 = precise_time_s(); let ns1 = precise_time_ns(); - log(debug, ~"s0=" + float::to_str(s0, 9u) + ~" sec"); + log(debug, ~"s0=" + float::to_str_digits(s0, 9u) + ~" sec"); assert s0 > 0.; let ns0 = (s0 * 1000000000.) as u64; log(debug, ~"ns0=" + u64::str(ns0) + ~" ns"); diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 71e96699c3d54..381183e736cf7 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -417,7 +417,7 @@ fn scan_number(c: char, rdr: string_reader) -> token::Token { if str::len(num_str) == 0u { rdr.fatal(~"no valid digits found for number"); } - let parsed = u64::from_str_radix(num_str, base as u64).get(); + let parsed = u64::from_str_radix(num_str, base as uint).get(); match tp { either::Left(t) => return token::LIT_INT(parsed as i64, t), either::Right(t) => return token::LIT_UINT(parsed, t) @@ -471,7 +471,7 @@ fn scan_number(c: char, rdr: string_reader) -> token::Token { if str::len(num_str) == 0u { rdr.fatal(~"no valid digits found for number"); } - let parsed = u64::from_str_radix(num_str, base as u64).get(); + let parsed = u64::from_str_radix(num_str, base as uint).get(); debug!("lexing %s as an unsuffixed integer literal", num_str); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 527b036a46c01..5079766239b00 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2006,24 +2006,24 @@ pub fn print_literal(s: ps, &&lit: @ast::lit) { ast::lit_int(i, t) => { if i < 0_i64 { word(s.s, - ~"-" + u64::to_str(-i as u64, 10u) + ~"-" + u64::to_str_radix(-i as u64, 10u) + ast_util::int_ty_to_str(t)); } else { word(s.s, - u64::to_str(i as u64, 10u) + u64::to_str_radix(i as u64, 10u) + ast_util::int_ty_to_str(t)); } } ast::lit_uint(u, t) => { word(s.s, - u64::to_str(u, 10u) + u64::to_str_radix(u, 10u) + ast_util::uint_ty_to_str(t)); } ast::lit_int_unsuffixed(i) => { if i < 0_i64 { - word(s.s, ~"-" + u64::to_str(-i as u64, 10u)); + word(s.s, ~"-" + u64::to_str_radix(-i as u64, 10u)); } else { - word(s.s, u64::to_str(i as u64, 10u)); + word(s.s, u64::to_str_radix(i as u64, 10u)); } } ast::lit_float(f, t) => { diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index d401b594c4c06..a61d8f01ab785 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -75,12 +75,12 @@ fn old_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) { let map = map::HashMap(); do timed(&mut results.sequential_strings) { for uint::range(0, num_keys) |i| { - let s = uint::to_str(i, 10); + let s = uint::to_str(i); map.insert(s, i); } for uint::range(0, num_keys) |i| { - let s = uint::to_str(i, 10); + let s = uint::to_str(i); assert map.get(s) == i; } } @@ -90,7 +90,7 @@ fn old_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) { let map = map::HashMap(); do timed(&mut results.random_strings) { for uint::range(0, num_keys) |i| { - let s = uint::to_str(rng.next() as uint, 10); + let s = uint::to_str(rng.next() as uint); map.insert(s, i); } } @@ -99,11 +99,11 @@ fn old_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) { { let map = map::HashMap(); for uint::range(0, num_keys) |i| { - map.insert(uint::to_str(i, 10), i); + map.insert(uint::to_str(i), i); } do timed(&mut results.delete_strings) { for uint::range(0, num_keys) |i| { - assert map.remove(uint::to_str(i, 10)); + assert map.remove(uint::to_str(i)); } } } @@ -151,12 +151,12 @@ fn linear_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) let mut map = LinearMap::new(); do timed(&mut results.sequential_strings) { for uint::range(0, num_keys) |i| { - let s = uint::to_str(i, 10); + let s = uint::to_str(i); map.insert(s, i); } for uint::range(0, num_keys) |i| { - let s = uint::to_str(i, 10); + let s = uint::to_str(i); assert map.find(&s).unwrap() == &i; } } @@ -166,7 +166,7 @@ fn linear_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) let mut map = LinearMap::new(); do timed(&mut results.random_strings) { for uint::range(0, num_keys) |i| { - let s = uint::to_str(rng.next() as uint, 10); + let s = uint::to_str(rng.next() as uint); map.insert(s, i); } } @@ -175,11 +175,11 @@ fn linear_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) { let mut map = LinearMap::new(); for uint::range(0, num_keys) |i| { - map.insert(uint::to_str(i, 10), i); + map.insert(uint::to_str(i), i); } do timed(&mut results.delete_strings) { for uint::range(0, num_keys) |i| { - assert map.remove(&uint::to_str(i, 10)); + assert map.remove(&uint::to_str(i)); } } } @@ -227,12 +227,12 @@ fn tree_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) { let mut map = TreeMap::new(); do timed(&mut results.sequential_strings) { for uint::range(0, num_keys) |i| { - let s = uint::to_str(i, 10); + let s = uint::to_str(i); map.insert(s, i); } for uint::range(0, num_keys) |i| { - let s = uint::to_str(i, 10); + let s = uint::to_str(i); assert map.find(&s).unwrap() == &i; } } @@ -242,7 +242,7 @@ fn tree_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) { let mut map = TreeMap::new(); do timed(&mut results.random_strings) { for uint::range(0, num_keys) |i| { - let s = uint::to_str(rng.next() as uint, 10); + let s = uint::to_str(rng.next() as uint); map.insert(s, i); } } @@ -251,11 +251,11 @@ fn tree_str_benchmarks(rng: @rand::Rng, num_keys: uint, results: &mut Results) { { let mut map = TreeMap::new(); for uint::range(0, num_keys) |i| { - map.insert(uint::to_str(i, 10), i); + map.insert(uint::to_str(i), i); } do timed(&mut results.delete_strings) { for uint::range(0, num_keys) |i| { - assert map.remove(&uint::to_str(i, 10)); + assert map.remove(&uint::to_str(i)); } } } diff --git a/src/test/bench/core-uint-to-str.rs b/src/test/bench/core-uint-to-str.rs index df4962fb44ccb..56f616c6f2815 100644 --- a/src/test/bench/core-uint-to-str.rs +++ b/src/test/bench/core-uint-to-str.rs @@ -21,7 +21,7 @@ fn main() { let n = uint::from_str(args[1]).get(); for uint::range(0u, n) |i| { - let x = uint::to_str(i, 10u); + let x = uint::to_str(i); log(debug, x); } } diff --git a/src/test/run-pass/core-export-f64-sqrt.rs b/src/test/run-pass/core-export-f64-sqrt.rs index 37f605d932002..d7ac91fe75c32 100644 --- a/src/test/run-pass/core-export-f64-sqrt.rs +++ b/src/test/run-pass/core-export-f64-sqrt.rs @@ -14,5 +14,5 @@ pub fn main() { let digits: uint = 10 as uint; - ::core::io::println(float::to_str(f64::sqrt(42.0f64) as float, digits)); + ::core::io::println(float::to_str_digits(f64::sqrt(42.0f64) as float, digits)); } diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index 3ea8ef23ea928..96bddf7099b8e 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -517,7 +517,7 @@ impl my_visitor: TyVisitor { } fn visit_int(&self) -> bool { do self.get::() |i| { - self.vals += ~[int::to_str(i, 10u)]; + self.vals += ~[int::to_str(i)]; }; true }