]> git.lizzy.rs Git - rust.git/commitdiff
Specialize to_str_common for floats/integers in strconv
authorAlex Crichton <alex@alexcrichton.com>
Fri, 28 Jun 2013 21:05:10 +0000 (14:05 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Sun, 30 Jun 2013 16:19:25 +0000 (09:19 -0700)
This allows the integral paths to avoid allocations on the heap

Closes #4424, #4423

src/libextra/terminfo/parm.rs
src/libstd/char.rs
src/libstd/num/f32.rs
src/libstd/num/f64.rs
src/libstd/num/float.rs
src/libstd/num/int_macros.rs
src/libstd/num/strconv.rs
src/libstd/num/uint_macros.rs
src/libstd/repr.rs
src/libstd/str.rs

index f3edd81f9acd83d1ff62445cf90b76be70c66128..b7d21ea0ee3fd00726c0434d918b612c12224151 100644 (file)
@@ -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 @@ impl FormatOp {
                         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();
index 101ea67cf592fdb45e7822eb404edb205fad9111..6a9555f4efcdc1b5671f27bbf0414a53d6b8cc42 100644 (file)
@@ -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};
 
index 117a474ffd7d3b4bc12aaace61c80e1465161da3..0b6eb766b2990077b85cff5063642a415bda42b3 100644 (file)
@@ -754,8 +754,8 @@ fn next_after(&self, other: f32) -> 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
 }
 
index e13dff1e623573854df48db1cfa3aea991ccdd26..c39c7a3a57d213c15839127fe61a181cbb0e8828 100644 (file)
@@ -796,8 +796,8 @@ fn next_after(&self, other: f64) -> 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
 }
 
index c583aeacf162dd4a84fb12bb220f27f9752b19a1..7a6e3042e7b7523b83b15173db01bfc7c4e67ee3 100644 (file)
@@ -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
 }
 
index 845152f85525183753ffc53ebbedb351aa9b313b..f152d60cb7a355c94944af34cb220a00771908d2 100644 (file)
@@ -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 @@ fn from_str_radix(s: &str, radix: uint) -> Option<$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 {
index a062838aacf049889e6ee56535a7b746cfa9d68d..1b1b82190d55283d1ebc73aa1af47905beb27429 100644 (file)
 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 @@ fn neg_inf()  -> Option<$t> { Some(-1.0 / 0.0) }
         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 @@ impl NumStrConv for $t {
                                       '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 @@ impl NumStrConv for $t {
  * # 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)
 }
index 0dabe7fafa834e67fffb48b9bc77f6e892c8833c..25e338fcd0f64a80f20027283ea3b260260760c2 100644 (file)
@@ -18,6 +18,7 @@ macro_rules! uint_module (($T:ty, $T_SIGNED:ty, $bits:expr) => (mod generated {
 use num::{ToStrRadix, FromStrRadix};
 use num::{Zero, One, strconv};
 use prelude::*;
+use str;
 
 pub use cmp::{min, max};
 
@@ -356,25 +357,33 @@ fn from_str_radix(s: &str, radix: uint) -> Option<$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 {
index a96949d84c9855ed81cd8f9f47d99ac5cba7d555..fdda65d3e95b8c9acea2d491f1a3a6def0612275 100644 (file)
@@ -81,65 +81,35 @@ fn write_repr(&self, writer: @Writer) {
     }
 }
 
-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 {
-    fn write_repr(&self, writer: @Writer) {
-        writer.write_uint(*self as uint);
-    }
-}
-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.
+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 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
 
index 8e0b3b6ad3552534479ee878a6105124a0263a5c..4115cad65594067e91f914150d865d15801f23b5 100644 (file)
@@ -54,7 +54,6 @@
  *
  * 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 unsafe fn from_bytes(v: &[u8]) -> ~str {
         }
     }
 
+    /// 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 @@ fn escape_default(&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 @@ fn escape_unicode(&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
     }