Specialize to_str_common for floats/integers in strconv
This allows the integral paths to avoid allocations on the heap Closes #4424, #4423
This commit is contained in:
parent
8fe6fc11de
commit
d3155faede
@ -11,7 +11,7 @@
|
||||
//! Parameterized string expansion
|
||||
|
||||
use std::{char, vec, util};
|
||||
use std::num::strconv::{SignNone,SignNeg,SignAll,DigAll,to_str_bytes_common};
|
||||
use std::num::strconv::{SignNone,SignNeg,SignAll,int_to_str_bytes_common};
|
||||
use std::iterator::IteratorUtil;
|
||||
|
||||
#[deriving(Eq)]
|
||||
@ -469,14 +469,20 @@ priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> {
|
||||
FormatHex|FormatHEX => 16,
|
||||
FormatString => util::unreachable()
|
||||
};
|
||||
let (s,_) = match op {
|
||||
let mut s = ~[];
|
||||
match op {
|
||||
FormatDigit => {
|
||||
let sign = if flags.sign { SignAll } else { SignNeg };
|
||||
to_str_bytes_common(&d, radix, false, sign, DigAll)
|
||||
do int_to_str_bytes_common(d, radix, sign) |c| {
|
||||
s.push(c);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
do int_to_str_bytes_common(d as uint, radix, SignNone) |c| {
|
||||
s.push(c);
|
||||
}
|
||||
}
|
||||
_ => to_str_bytes_common(&(d as uint), radix, false, SignNone, DigAll)
|
||||
};
|
||||
let mut s = s;
|
||||
if flags.precision > s.len() {
|
||||
let mut s_ = vec::with_capacity(flags.precision);
|
||||
let n = flags.precision - s.len();
|
||||
|
@ -10,8 +10,8 @@
|
||||
|
||||
//! Utilities for manipulating the char type
|
||||
|
||||
use container::Container;
|
||||
use option::{None, Option, Some};
|
||||
use int;
|
||||
use str::StrSlice;
|
||||
use unicode::{derived_property, general_category};
|
||||
|
||||
|
@ -754,8 +754,8 @@ impl Float for f32 {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str(num: f32) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
@ -768,8 +768,8 @@ pub fn to_str(num: f32) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_hex(num: f32) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
@ -789,8 +789,8 @@ pub fn to_str_hex(num: f32) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_radix(num: f32, rdx: uint) -> ~str {
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, special) = strconv::float_to_str_common(
|
||||
num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!("number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
@ -807,7 +807,7 @@ pub fn to_str_radix(num: f32, rdx: uint) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
|
||||
strconv::to_str_common(&num, rdx, true,
|
||||
strconv::float_to_str_common(num, rdx, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
@ -822,8 +822,8 @@ pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_exact(num: f32, dig: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
||||
r
|
||||
}
|
||||
|
||||
@ -838,8 +838,8 @@ pub fn to_str_exact(num: f32, dig: uint) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_digits(num: f32, dig: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -796,8 +796,8 @@ impl Float for f64 {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str(num: f64) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
@ -810,8 +810,8 @@ pub fn to_str(num: f64) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_hex(num: f64) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
@ -831,8 +831,8 @@ pub fn to_str_hex(num: f64) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_radix(num: f64, rdx: uint) -> ~str {
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, special) = strconv::float_to_str_common(
|
||||
num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!("number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
@ -849,7 +849,7 @@ pub fn to_str_radix(num: f64, rdx: uint) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
|
||||
strconv::to_str_common(&num, rdx, true,
|
||||
strconv::float_to_str_common(num, rdx, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
@ -864,8 +864,8 @@ pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_exact(num: f64, dig: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
||||
r
|
||||
}
|
||||
|
||||
@ -880,8 +880,8 @@ pub fn to_str_exact(num: f64, dig: uint) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_digits(num: f64, dig: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -101,8 +101,8 @@ pub mod consts {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str(num: float) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
@ -115,8 +115,8 @@ pub fn to_str(num: float) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_hex(num: float) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
@ -136,8 +136,8 @@ pub fn to_str_hex(num: float) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_radix(num: float, radix: uint) -> ~str {
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, radix, true, strconv::SignNeg, strconv::DigAll);
|
||||
let (r, special) = strconv::float_to_str_common(
|
||||
num, radix, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!("number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
@ -154,7 +154,7 @@ pub fn to_str_radix(num: float, radix: uint) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) {
|
||||
strconv::to_str_common(&num, radix, true,
|
||||
strconv::float_to_str_common(num, radix, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
@ -169,8 +169,8 @@ pub fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_exact(num: float, digits: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(digits));
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigExact(digits));
|
||||
r
|
||||
}
|
||||
|
||||
@ -185,8 +185,8 @@ pub fn to_str_exact(num: float, digits: uint) -> ~str {
|
||||
///
|
||||
#[inline]
|
||||
pub fn to_str_digits(num: float, digits: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(digits));
|
||||
let (r, _) = strconv::float_to_str_common(
|
||||
num, 10u, true, strconv::SignNeg, strconv::DigMax(digits));
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ macro_rules! int_module (($T:ty, $bits:expr) => (mod generated {
|
||||
use num::{ToStrRadix, FromStrRadix};
|
||||
use num::{Zero, One, strconv};
|
||||
use prelude::*;
|
||||
use str;
|
||||
|
||||
pub use cmp::{min, max};
|
||||
|
||||
@ -529,25 +530,33 @@ impl FromStrRadix for $T {
|
||||
/// Convert to a string as a byte slice in a given base.
|
||||
#[inline]
|
||||
pub fn to_str_bytes<U>(n: $T, radix: uint, f: &fn(v: &[u8]) -> U) -> U {
|
||||
let (buf, _) = strconv::to_str_bytes_common(&n, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
f(buf)
|
||||
// The radix can be as low as 2, so we need at least 64 characters for a
|
||||
// base 2 number, and then we need another for a possible '-' character.
|
||||
let mut buf = [0u8, ..65];
|
||||
let mut cur = 0;
|
||||
do strconv::int_to_str_bytes_common(n, radix, strconv::SignNeg) |i| {
|
||||
buf[cur] = i;
|
||||
cur += 1;
|
||||
}
|
||||
f(buf.slice(0, cur))
|
||||
}
|
||||
|
||||
/// Convert to a string in base 10.
|
||||
#[inline]
|
||||
pub fn to_str(num: $T) -> ~str {
|
||||
let (buf, _) = strconv::to_str_common(&num, 10u, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
to_str_radix(num, 10u)
|
||||
}
|
||||
|
||||
/// Convert to a string in a given base.
|
||||
#[inline]
|
||||
pub fn to_str_radix(num: $T, radix: uint) -> ~str {
|
||||
let (buf, _) = strconv::to_str_common(&num, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
let mut buf: ~[u8] = ~[];
|
||||
do strconv::int_to_str_bytes_common(num, radix, strconv::SignNeg) |i| {
|
||||
buf.push(i);
|
||||
}
|
||||
// We know we generated valid utf-8, so we don't need to go through that
|
||||
// check.
|
||||
unsafe { str::raw::from_bytes_owned(buf) }
|
||||
}
|
||||
|
||||
impl ToStr for $T {
|
||||
|
@ -16,13 +16,13 @@ use ops::{Add, Sub, Mul, Div, Rem, Neg};
|
||||
use option::{None, Option, Some};
|
||||
use char;
|
||||
use str;
|
||||
use str::{StrSlice};
|
||||
use str::StrSlice;
|
||||
use kinds::Copy;
|
||||
use vec;
|
||||
use vec::{CopyableVector, ImmutableVector};
|
||||
use vec::OwnedVector;
|
||||
use num::{NumCast, Zero, One, cast, pow_with_uint};
|
||||
use f64;
|
||||
use num::{NumCast, Zero, One, cast, pow_with_uint, Integer};
|
||||
use num::{Round, Float, FPNaN, FPInfinite};
|
||||
|
||||
pub enum ExponentFormat {
|
||||
ExpNone,
|
||||
@ -42,35 +42,6 @@ pub enum SignFormat {
|
||||
SignAll
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_NaN<T:Eq>(num: &T) -> bool {
|
||||
*num != *num
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_inf<T:Eq+NumStrConv>(num: &T) -> bool {
|
||||
match NumStrConv::inf() {
|
||||
None => false,
|
||||
Some(n) => *num == n
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_neg_inf<T:Eq+NumStrConv>(num: &T) -> bool {
|
||||
match NumStrConv::neg_inf() {
|
||||
None => false,
|
||||
Some(n) => *num == n
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Div<T,T>>(num: &T) -> bool {
|
||||
let _0: T = Zero::zero();
|
||||
let _1: T = One::one();
|
||||
|
||||
*num == _0 && is_neg_inf(&(_1 / *num))
|
||||
}
|
||||
|
||||
pub trait NumStrConv {
|
||||
fn NaN() -> Option<Self>;
|
||||
fn inf() -> Option<Self>;
|
||||
@ -93,16 +64,9 @@ macro_rules! impl_NumStrConv_Floating (($t:ty) => (
|
||||
fn neg_zero() -> Option<$t> { Some(-0.0 ) }
|
||||
|
||||
#[inline]
|
||||
fn round_to_zero(&self) -> $t {
|
||||
( if *self < 0.0 { f64::ceil(*self as f64) }
|
||||
else { f64::floor(*self as f64) }
|
||||
) as $t
|
||||
}
|
||||
|
||||
fn round_to_zero(&self) -> $t { self.trunc() }
|
||||
#[inline]
|
||||
fn fractional_part(&self) -> $t {
|
||||
*self - self.round_to_zero()
|
||||
}
|
||||
fn fractional_part(&self) -> $t { self.fract() }
|
||||
}
|
||||
))
|
||||
|
||||
@ -145,6 +109,87 @@ static negative_inf_buf: [u8, ..4] = ['-' as u8, 'i' as u8, 'n' as u8,
|
||||
'f' as u8];
|
||||
static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8];
|
||||
|
||||
/**
|
||||
* Converts an integral number to its string representation as a byte vector.
|
||||
* This is meant to be a common base implementation for all integral string
|
||||
* 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.
|
||||
* - `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.
|
||||
* - `f` - a callback which will be invoked for each ascii character
|
||||
* which composes the string representation of this integer
|
||||
*
|
||||
* # Return value
|
||||
* A tuple containing the byte vector, and a boolean flag indicating
|
||||
* whether it represents a special value like `inf`, `-inf`, `NaN` or not.
|
||||
* It returns a tuple because there can be ambiguity between a special value
|
||||
* and a number representation at higher bases.
|
||||
*
|
||||
* # Failure
|
||||
* - Fails if `radix` < 2 or `radix` > 36.
|
||||
*/
|
||||
pub fn int_to_str_bytes_common<T:NumCast+Zero+Eq+Ord+Integer+
|
||||
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
|
||||
num: T, radix: uint, sign: SignFormat, f: &fn(u8)) {
|
||||
assert!(2 <= radix && radix <= 36);
|
||||
|
||||
let _0: T = Zero::zero();
|
||||
|
||||
let neg = num < _0;
|
||||
let radix_gen: T = cast(radix);
|
||||
|
||||
let mut deccum = num;
|
||||
// This is just for integral types, the largest of which is a u64. The
|
||||
// smallest base that we can have is 2, so the most number of digits we're
|
||||
// ever going to have is 64
|
||||
let mut buf = [0u8, ..64];
|
||||
let mut cur = 0;
|
||||
|
||||
// Loop at least once to make sure at least a `0` gets emitted.
|
||||
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
|
||||
};
|
||||
buf[cur] = match current_digit.to_u8() {
|
||||
i @ 0..9 => '0' as u8 + i,
|
||||
i => 'a' as u8 + (i - 10),
|
||||
};
|
||||
cur += 1;
|
||||
|
||||
deccum = deccum / radix_gen;
|
||||
// No more digits to calculate for the non-fractional part -> break
|
||||
if deccum == _0 { break; }
|
||||
}
|
||||
|
||||
// Decide what sign to put in front
|
||||
match sign {
|
||||
SignNeg | SignAll if neg => { f('-' as u8); }
|
||||
SignAll => { f('+' as u8); }
|
||||
_ => ()
|
||||
}
|
||||
|
||||
// We built the number in reverse order, so un-reverse it here
|
||||
while cur > 0 {
|
||||
cur -= 1;
|
||||
f(buf[cur]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number to its string representation as a byte vector.
|
||||
* This is meant to be a common base implementation for all numeric string
|
||||
@ -176,44 +221,39 @@ static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8];
|
||||
* # Failure
|
||||
* - Fails if `radix` < 2 or `radix` > 36.
|
||||
*/
|
||||
pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
|
||||
pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
|
||||
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
|
||||
num: &T, radix: uint, negative_zero: bool,
|
||||
num: T, radix: uint, negative_zero: bool,
|
||||
sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
|
||||
if (radix as int) < 2 {
|
||||
fail!("to_str_bytes_common: radix %? to low, must lie in the range [2, 36]", radix);
|
||||
} else if radix as int > 36 {
|
||||
fail!("to_str_bytes_common: radix %? to high, must lie in the range [2, 36]", radix);
|
||||
}
|
||||
assert!(2 <= radix && radix <= 36);
|
||||
|
||||
let _0: T = Zero::zero();
|
||||
let _1: T = One::one();
|
||||
|
||||
if is_NaN(num) {
|
||||
return ("NaN".as_bytes().to_owned(), true);
|
||||
}
|
||||
else if is_inf(num){
|
||||
return match sign {
|
||||
SignAll => ("+inf".as_bytes().to_owned(), true),
|
||||
_ => ("inf".as_bytes().to_owned(), true)
|
||||
match num.classify() {
|
||||
FPNaN => { return ("NaN".as_bytes().to_owned(), true); }
|
||||
FPInfinite if num > _0 => {
|
||||
return match sign {
|
||||
SignAll => ("+inf".as_bytes().to_owned(), true),
|
||||
_ => ("inf".as_bytes().to_owned(), true)
|
||||
};
|
||||
}
|
||||
}
|
||||
else if is_neg_inf(num) {
|
||||
return match sign {
|
||||
SignNone => ("inf".as_bytes().to_owned(), true),
|
||||
_ => ("-inf".as_bytes().to_owned(), true),
|
||||
FPInfinite if num < _0 => {
|
||||
return match sign {
|
||||
SignNone => ("inf".as_bytes().to_owned(), true),
|
||||
_ => ("-inf".as_bytes().to_owned(), true),
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let neg = *num < _0 || (negative_zero && is_neg_zero(num));
|
||||
let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
|
||||
let mut buf: ~[u8] = ~[];
|
||||
let radix_gen: T = cast(radix as int);
|
||||
|
||||
let mut deccum;
|
||||
|
||||
// First emit the non-fractional part, looping at least once to make
|
||||
// sure at least a `0` gets emitted.
|
||||
deccum = num.round_to_zero();
|
||||
let mut deccum = num.trunc();
|
||||
loop {
|
||||
// Calculate the absolute value of each digit instead of only
|
||||
// doing it once for the whole number because a
|
||||
@ -221,16 +261,11 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
|
||||
// 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
|
||||
};
|
||||
let current_digit = (deccum % radix_gen).abs();
|
||||
|
||||
// Decrease the deccumulator one digit at a time
|
||||
deccum = deccum / radix_gen;
|
||||
deccum = deccum.round_to_zero();
|
||||
deccum = deccum.trunc();
|
||||
|
||||
buf.push(char::from_digit(current_digit.to_int() as uint, radix)
|
||||
.unwrap() as u8);
|
||||
@ -265,7 +300,7 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
|
||||
let start_fractional_digits = buf.len();
|
||||
|
||||
// Now emit the fractional part, if any
|
||||
deccum = num.fractional_part();
|
||||
deccum = num.fract();
|
||||
if deccum != _0 || (limit_digits && exact && digit_count > 0) {
|
||||
buf.push('.' as u8);
|
||||
let mut dig = 0u;
|
||||
@ -286,18 +321,13 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
|
||||
|
||||
// Calculate the absolute value of each digit.
|
||||
// See note in first loop.
|
||||
let current_digit_signed = deccum.round_to_zero();
|
||||
let current_digit = if current_digit_signed < _0 {
|
||||
-current_digit_signed
|
||||
} else {
|
||||
current_digit_signed
|
||||
};
|
||||
let current_digit = deccum.trunc().abs();
|
||||
|
||||
buf.push(char::from_digit(
|
||||
current_digit.to_int() as uint, radix).unwrap() as u8);
|
||||
|
||||
// Decrease the deccumulator one fractional digit at a time
|
||||
deccum = deccum.fractional_part();
|
||||
deccum = deccum.fract();
|
||||
dig += 1u;
|
||||
}
|
||||
|
||||
@ -382,11 +412,11 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
|
||||
* `to_str_bytes_common()`, for details see there.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
|
||||
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
|
||||
num: &T, radix: uint, negative_zero: bool,
|
||||
pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+Round+
|
||||
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
|
||||
num: T, radix: uint, negative_zero: bool,
|
||||
sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
|
||||
let (bytes, special) = to_str_bytes_common(num, radix,
|
||||
let (bytes, special) = float_to_str_bytes_common(num, radix,
|
||||
negative_zero, sign, digits);
|
||||
(str::from_bytes(bytes), special)
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ use num::BitCount;
|
||||
use num::{ToStrRadix, FromStrRadix};
|
||||
use num::{Zero, One, strconv};
|
||||
use prelude::*;
|
||||
use str;
|
||||
|
||||
pub use cmp::{min, max};
|
||||
|
||||
@ -356,25 +357,33 @@ impl FromStrRadix for $T {
|
||||
/// Convert to a string as a byte slice in a given base.
|
||||
#[inline]
|
||||
pub fn to_str_bytes<U>(n: $T, radix: uint, f: &fn(v: &[u8]) -> U) -> U {
|
||||
let (buf, _) = strconv::to_str_bytes_common(&n, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
f(buf)
|
||||
// The radix can be as low as 2, so we need at least 64 characters for a
|
||||
// base 2 number.
|
||||
let mut buf = [0u8, ..64];
|
||||
let mut cur = 0;
|
||||
do strconv::int_to_str_bytes_common(n, radix, strconv::SignNone) |i| {
|
||||
buf[cur] = i;
|
||||
cur += 1;
|
||||
}
|
||||
f(buf.slice(0, cur))
|
||||
}
|
||||
|
||||
/// Convert to a string in base 10.
|
||||
#[inline]
|
||||
pub fn to_str(num: $T) -> ~str {
|
||||
let (buf, _) = strconv::to_str_common(&num, 10u, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
to_str_radix(num, 10u)
|
||||
}
|
||||
|
||||
/// Convert to a string in a given base.
|
||||
#[inline]
|
||||
pub fn to_str_radix(num: $T, radix: uint) -> ~str {
|
||||
let (buf, _) = strconv::to_str_common(&num, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
let mut buf = ~[];
|
||||
do strconv::int_to_str_bytes_common(num, radix, strconv::SignNone) |i| {
|
||||
buf.push(i);
|
||||
}
|
||||
// We know we generated valid utf-8, so we don't need to go through that
|
||||
// check.
|
||||
unsafe { str::raw::from_bytes_owned(buf) }
|
||||
}
|
||||
|
||||
impl ToStr for $T {
|
||||
|
@ -81,65 +81,35 @@ impl Repr for bool {
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for int {
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_int(*self); }
|
||||
}
|
||||
impl Repr for i8 {
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
|
||||
}
|
||||
impl Repr for i16 {
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
|
||||
}
|
||||
impl Repr for i32 {
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
|
||||
}
|
||||
impl Repr for i64 {
|
||||
// FIXME #4424: This can lose precision.
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
|
||||
}
|
||||
|
||||
impl Repr for uint {
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_uint(*self); }
|
||||
}
|
||||
impl Repr for u8 {
|
||||
macro_rules! int_repr(($ty:ident) => (impl Repr for $ty {
|
||||
fn write_repr(&self, writer: @Writer) {
|
||||
writer.write_uint(*self as uint);
|
||||
do ::$ty::to_str_bytes(*self, 10u) |bits| {
|
||||
writer.write(bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Repr for u16 {
|
||||
fn write_repr(&self, writer: @Writer) {
|
||||
writer.write_uint(*self as uint);
|
||||
}
|
||||
}
|
||||
impl Repr for u32 {
|
||||
fn write_repr(&self, writer: @Writer) {
|
||||
writer.write_uint(*self as uint);
|
||||
}
|
||||
}
|
||||
impl Repr for u64 {
|
||||
// FIXME #4424: This can lose precision.
|
||||
fn write_repr(&self, writer: @Writer) {
|
||||
writer.write_uint(*self as uint);
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
impl Repr for float {
|
||||
// FIXME #4423: This mallocs.
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
|
||||
}
|
||||
impl Repr for f32 {
|
||||
// FIXME #4423 This mallocs.
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
|
||||
}
|
||||
impl Repr for f64 {
|
||||
// FIXME #4423: This mallocs.
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
|
||||
}
|
||||
int_repr!(int)
|
||||
int_repr!(i8)
|
||||
int_repr!(i16)
|
||||
int_repr!(i32)
|
||||
int_repr!(i64)
|
||||
int_repr!(uint)
|
||||
int_repr!(u8)
|
||||
int_repr!(u16)
|
||||
int_repr!(u32)
|
||||
int_repr!(u64)
|
||||
|
||||
impl Repr for char {
|
||||
fn write_repr(&self, writer: @Writer) { writer.write_char(*self); }
|
||||
}
|
||||
macro_rules! num_repr(($ty:ident) => (impl Repr for $ty {
|
||||
fn write_repr(&self, writer: @Writer) {
|
||||
let s = self.to_str();
|
||||
writer.write(s.as_bytes());
|
||||
}
|
||||
}))
|
||||
|
||||
num_repr!(float)
|
||||
num_repr!(f32)
|
||||
num_repr!(f64)
|
||||
|
||||
// New implementation using reflect::MovePtr
|
||||
|
||||
|
@ -54,7 +54,6 @@ Section: Creating a string
|
||||
*
|
||||
* Raises the `not_utf8` condition if invalid UTF-8
|
||||
*/
|
||||
|
||||
pub fn from_bytes(vv: &[u8]) -> ~str {
|
||||
use str::not_utf8::cond;
|
||||
|
||||
@ -68,6 +67,25 @@ pub fn from_bytes(vv: &[u8]) -> ~str {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes a vector of bytes to create a new utf-8 string
|
||||
*
|
||||
* # Failure
|
||||
*
|
||||
* Raises the `not_utf8` condition if invalid UTF-8
|
||||
*/
|
||||
pub fn from_bytes_owned(vv: ~[u8]) -> ~str {
|
||||
use str::not_utf8::cond;
|
||||
|
||||
if !is_utf8(vv) {
|
||||
let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).get();
|
||||
cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u",
|
||||
first_bad_byte as uint))
|
||||
} else {
|
||||
return unsafe { raw::from_bytes_owned(vv) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a vector of bytes to a UTF-8 string.
|
||||
* The vector needs to be one byte longer than the string, and end with a 0 byte.
|
||||
@ -850,6 +868,13 @@ pub mod raw {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an owned vector of bytes to a new owned string. This assumes
|
||||
/// that the utf-8-ness of the vector has already been validated
|
||||
pub unsafe fn from_bytes_owned(mut v: ~[u8]) -> ~str {
|
||||
v.push(0u8);
|
||||
cast::transmute(v)
|
||||
}
|
||||
|
||||
/// Converts a vector of bytes to a string.
|
||||
/// The byte slice needs to contain valid utf8 and needs to be one byte longer than
|
||||
/// the string, if possible ending in a 0 byte.
|
||||
@ -1472,7 +1497,9 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
let mut out: ~str = ~"";
|
||||
out.reserve_at_least(self.len());
|
||||
for self.iter().advance |c| {
|
||||
out.push_str(char::escape_default(c));
|
||||
do c.escape_default |c| {
|
||||
out.push_char(c);
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
@ -1482,7 +1509,9 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
let mut out: ~str = ~"";
|
||||
out.reserve_at_least(self.len());
|
||||
for self.iter().advance |c| {
|
||||
out.push_str(char::escape_unicode(c));
|
||||
do c.escape_unicode |c| {
|
||||
out.push_char(c);
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user