From 9abff54d61babab8050c108f7cb6b957b1636337 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 22 Feb 2014 03:51:56 +1100 Subject: [PATCH 1/3] Add Pod trait bound to std::num::Primitive --- src/libstd/num/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 8a417096c3e..767faa30f24 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -17,6 +17,7 @@ use clone::{Clone, DeepClone}; use cmp::{Eq, Ord}; +use kinds::Pod; use mem::size_of; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; @@ -262,7 +263,8 @@ pub trait Bitwise: Bounded /// Specifies the available operations common to all of Rust's core numeric primitives. /// These may not always make sense from a purely mathematical point of view, but /// may be useful for systems programming. -pub trait Primitive: Clone +pub trait Primitive: Pod + + Clone + DeepClone + Num + NumCast From e37327bfee6217e46921a294f1a321e2d71300ca Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 22 Feb 2014 03:52:32 +1100 Subject: [PATCH 2/3] Decouple integer formatting from std::num::strconv This works towards a complete rewrite and ultimate removal of the `std::num::strconv` module (see #6220), and the removal of the `ToStrRadix` trait in favour of using the `std::fmt` functionality directly. This should make for a cleaner API, encourage less allocation, and make the implementation far more comprehensible. The `Formatter::pad_integral` method has also been refactored make it easier to understand. The formatting tests for integers have been moved out of `run-pass/ifmt.rs` in order to provide more immediate feedback when building using `make check-stage2-std NO_REBUILD=1`. The benchmarks have been standardised between std::num::strconv and std::num::fmt to make it easier to compare the performance of the different implementations. Arbitrary radixes are now easier to use in format strings. For example: ~~~ assert_eq!(format!("{:04}", radix(3, 2)), ~"0011"); ~~~ --- src/libstd/fmt/mod.rs | 177 +++++---------- src/libstd/fmt/num.rs | 467 ++++++++++++++++++++++++++++++++++++++ src/libstd/num/mod.rs | 8 +- src/libstd/num/strconv.rs | 96 ++++++-- src/test/run-pass/ifmt.rs | 99 -------- 5 files changed, 609 insertions(+), 238 deletions(-) create mode 100644 src/libstd/fmt/num.rs diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index 9c70d34cc0f..38fae798d5d 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -215,7 +215,7 @@ impl fmt::Binary for Vector2D { // for details, and the function `pad` can be used to pad strings. let decimals = f.precision.unwrap_or(3); let string = f64::to_str_exact(magnitude, decimals); - f.pad_integral(string.as_bytes(), "", true) + f.pad_integral(true, "", string.as_bytes()) } } @@ -493,6 +493,11 @@ use str; use vec::ImmutableVector; use vec; +pub use self::num::radix; +pub use self::num::Radix; +pub use self::num::RadixFmt; + +mod num; pub mod parse; pub mod rt; @@ -891,58 +896,60 @@ impl<'a> Formatter<'a> { /// /// # Arguments /// - /// * s - the byte array that the number has been formatted into - /// * alternate_prefix - if the '#' character (FlagAlternate) is - /// provided, this is the prefix to put in front of the number. - /// Currently this is 0x/0o/0b/etc. - /// * positive - whether the original integer was positive or not. + /// * is_positive - whether the original integer was positive or not. + /// * prefix - if the '#' character (FlagAlternate) is provided, this + /// is the prefix to put in front of the number. + /// * buf - the byte array that the number has been formatted into /// /// This function will correctly account for the flags provided as well as /// the minimum width. It will not take precision into account. - pub fn pad_integral(&mut self, s: &[u8], alternate_prefix: &str, - positive: bool) -> Result { + pub fn pad_integral(&mut self, is_positive: bool, prefix: &str, buf: &[u8]) -> Result { use fmt::parse::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad}; - let mut actual_len = s.len(); - if self.flags & 1 << (FlagAlternate as uint) != 0 { - actual_len += alternate_prefix.len(); - } - if self.flags & 1 << (FlagSignPlus as uint) != 0 { - actual_len += 1; - } else if !positive { - actual_len += 1; + let mut width = buf.len(); + + let mut sign = None; + if !is_positive { + sign = Some('-'); width += 1; + } else if self.flags & (1 << (FlagSignPlus as uint)) != 0 { + sign = Some('+'); width += 1; } - let mut signprinted = false; - let sign = |this: &mut Formatter| { - if !signprinted { - if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive { - try!(this.buf.write(['+' as u8])); - } else if !positive { - try!(this.buf.write(['-' as u8])); - } - if this.flags & 1 << (FlagAlternate as uint) != 0 { - try!(this.buf.write(alternate_prefix.as_bytes())); - } - signprinted = true; - } - Ok(()) - }; - - let emit = |this: &mut Formatter| { - sign(this).and_then(|()| this.buf.write(s)) + let mut prefixed = false; + if self.flags & (1 << (FlagAlternate as uint)) != 0 { + prefixed = true; width += prefix.len(); + } + + // Writes the sign if it exists, and then the prefix if it was requested + let write_prefix = |f: &mut Formatter| { + for c in sign.move_iter() { try!(f.buf.write_char(c)); } + if prefixed { f.buf.write_str(prefix) } + else { Ok(()) } }; + // The `width` field is more of a `min-width` parameter at this point. match self.width { - None => emit(self), - Some(min) if actual_len >= min => emit(self), + // If there's no minimum length requirements then we can just + // write the bytes. + None => { + try!(write_prefix(self)); self.buf.write(buf) + } + // Check if we're over the minimum width, if so then we can also + // just write the bytes. + Some(min) if width >= min => { + try!(write_prefix(self)); self.buf.write(buf) + } + // The sign and prefix goes before the padding if the fill character + // is zero + Some(min) if self.flags & (1 << (FlagSignAwareZeroPad as uint)) != 0 => { + self.fill = '0'; + try!(write_prefix(self)); + self.with_padding(min - width, parse::AlignRight, |f| f.buf.write(buf)) + } + // Otherwise, the sign and prefix goes after the padding Some(min) => { - if self.flags & 1 << (FlagSignAwareZeroPad as uint) != 0 { - self.fill = '0'; - try!(sign(self)); - } - self.with_padding(min - actual_len, parse::AlignRight, |me| { - emit(me) + self.with_padding(min - width, parse::AlignRight, |f| { + try!(write_prefix(f)); f.buf.write(buf) }) } } @@ -979,19 +986,16 @@ impl<'a> Formatter<'a> { } None => {} } - // The `width` field is more of a `min-width` parameter at this point. match self.width { // If we're under the maximum length, and there's no minimum length // requirements, then we can just emit the string None => self.buf.write(s.as_bytes()), - // If we're under the maximum width, check if we're over the minimum // width, if so it's as easy as just emitting the string. Some(width) if s.char_len() >= width => { self.buf.write(s.as_bytes()) } - // If we're under both the maximum and the minimum width, then fill // up the minimum width with the specified string + some alignment. Some(width) => { @@ -1002,6 +1006,8 @@ impl<'a> Formatter<'a> { } } + /// Runs a callback, emitting the correct padding either before or + /// afterwards depending on whether right or left alingment is requested. fn with_padding(&mut self, padding: uint, default: parse::Alignment, @@ -1075,67 +1081,6 @@ impl Char for char { } } -macro_rules! int_base(($ty:ident, $into:ident, $base:expr, - $name:ident, $prefix:expr) => { - impl $name for $ty { - fn fmt(&self, f: &mut Formatter) -> Result { - ::$into::to_str_bytes(*self as $into, $base, |buf| { - f.pad_integral(buf, $prefix, true) - }) - } - } -}) -macro_rules! upper_hex(($ty:ident, $into:ident) => { - impl UpperHex for $ty { - fn fmt(&self, f: &mut Formatter) -> Result { - ::$into::to_str_bytes(*self as $into, 16, |buf| { - upperhex(buf, f) - }) - } - } -}) -// Not sure why, but this causes an "unresolved enum variant, struct or const" -// when inlined into the above macro... -#[doc(hidden)] -pub fn upperhex(buf: &[u8], f: &mut Formatter) -> Result { - let mut local = [0u8, ..16]; - for i in ::iter::range(0, buf.len()) { - local[i] = match buf[i] as char { - 'a' .. 'f' => (buf[i] - 'a' as u8) + 'A' as u8, - c => c as u8, - } - } - f.pad_integral(local.slice_to(buf.len()), "0x", true) -} - -macro_rules! integer(($signed:ident, $unsigned:ident) => { - // Signed is special because it actuall emits the negative sign, - // nothing else should do that, however. - impl Signed for $signed { - fn fmt(&self, f: &mut Formatter) -> Result { - ::$unsigned::to_str_bytes(self.abs() as $unsigned, 10, |buf| { - f.pad_integral(buf, "", *self >= 0) - }) - } - } - int_base!($signed, $unsigned, 2, Binary, "0b") - int_base!($signed, $unsigned, 8, Octal, "0o") - int_base!($signed, $unsigned, 16, LowerHex, "0x") - upper_hex!($signed, $unsigned) - - int_base!($unsigned, $unsigned, 2, Binary, "0b") - int_base!($unsigned, $unsigned, 8, Octal, "0o") - int_base!($unsigned, $unsigned, 10, Unsigned, "") - int_base!($unsigned, $unsigned, 16, LowerHex, "0x") - upper_hex!($unsigned, $unsigned) -}) - -integer!(int, uint) -integer!(i8, u8) -integer!(i16, u16) -integer!(i32, u32) -integer!(i64, u64) - macro_rules! floating(($ty:ident) => { impl Float for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { @@ -1144,7 +1089,7 @@ macro_rules! floating(($ty:ident) => { Some(i) => ::$ty::to_str_exact(self.abs(), i), None => ::$ty::to_str_digits(self.abs(), 6) }; - fmt.pad_integral(s.as_bytes(), "", *self >= 0.0) + fmt.pad_integral(*self >= 0.0, "", s.as_bytes()) } } @@ -1155,7 +1100,7 @@ macro_rules! floating(($ty:ident) => { Some(i) => ::$ty::to_str_exp_exact(self.abs(), i, false), None => ::$ty::to_str_exp_digits(self.abs(), 6, false) }; - fmt.pad_integral(s.as_bytes(), "", *self >= 0.0) + fmt.pad_integral(*self >= 0.0, "", s.as_bytes()) } } @@ -1166,7 +1111,7 @@ macro_rules! floating(($ty:ident) => { Some(i) => ::$ty::to_str_exp_exact(self.abs(), i, true), None => ::$ty::to_str_exp_digits(self.abs(), 6, true) }; - fmt.pad_integral(s.as_bytes(), "", *self >= 0.0) + fmt.pad_integral(*self >= 0.0, "", s.as_bytes()) } } }) @@ -1193,9 +1138,7 @@ impl Poly for T { impl Pointer for *T { fn fmt(&self, f: &mut Formatter) -> Result { f.flags |= 1 << (parse::FlagAlternate as uint); - ::uint::to_str_bytes(*self as uint, 16, |buf| { - f.pad_integral(buf, "0x", true) - }) + secret_lower_hex::(&(*self as uint), f) } } impl Pointer for *mut T { @@ -1223,16 +1166,6 @@ macro_rules! delegate(($ty:ty to $other:ident) => { } } }) -delegate!(int to signed) -delegate!( i8 to signed) -delegate!(i16 to signed) -delegate!(i32 to signed) -delegate!(i64 to signed) -delegate!(uint to unsigned) -delegate!( u8 to unsigned) -delegate!( u16 to unsigned) -delegate!( u32 to unsigned) -delegate!( u64 to unsigned) delegate!(~str to string) delegate!(&'a str to string) delegate!(bool to bool) diff --git a/src/libstd/fmt/num.rs b/src/libstd/fmt/num.rs new file mode 100644 index 00000000000..681d0678ed4 --- /dev/null +++ b/src/libstd/fmt/num.rs @@ -0,0 +1,467 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Integer and floating-point number formatting + +// FIXME: #6220 Implement floating point formatting + +use container::Container; +use fmt; +use iter::{Iterator, DoubleEndedIterator}; +use num::{Int, cast, zero}; +use option::{Some, None}; +use vec::{ImmutableVector, MutableVector}; + +/// A type that represents a specific radix +trait GenericRadix { + /// The number of digits. + fn base(&self) -> u8; + + /// A radix-specific prefix string. + fn prefix(&self) -> &'static str { "" } + + /// Converts an integer to corresponding radix digit. + fn digit(&self, x: u8) -> u8; + + /// Format an integer using the radix using a formatter. + fn fmt_int(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result { + // The radix can be as low as 2, so we need a buffer of at least 64 + // characters for a base 2 number. + let mut buf = [0u8, ..64]; + let base = cast(self.base()).unwrap(); + let mut curr = buf.len(); + let is_positive = x >= zero(); + if is_positive { + // Accumulate each digit of the number from the least significant + // to the most significant figure. + for byte in buf.mut_iter().rev() { + let n = x % base; // Get the current place value. + x = x / base; // Deaccumulate the number. + *byte = self.digit(cast(n).unwrap()); // Store the digit in the buffer. + curr -= 1; + if x == zero() { break; } // No more digits left to accumulate. + } + } else { + // Do the same as above, but accounting for two's complement. + for byte in buf.mut_iter().rev() { + let n = -(x % base); // Get the current place value. + x = x / base; // Deaccumulate the number. + *byte = self.digit(cast(n).unwrap()); // Store the digit in the buffer. + curr -= 1; + if x == zero() { break; } // No more digits left to accumulate. + } + } + f.pad_integral(is_positive, self.prefix(), buf.slice_from(curr)) + } +} + +/// A binary (base 2) radix +#[deriving(Clone, Eq)] +struct Binary; + +/// An octal (base 8) radix +#[deriving(Clone, Eq)] +struct Octal; + +/// A decimal (base 10) radix +#[deriving(Clone, Eq)] +struct Decimal; + +/// A hexidecimal (base 16) radix, formatted with lower-case characters +#[deriving(Clone, Eq)] +struct LowerHex; + +/// A hexidecimal (base 16) radix, formatted with upper-case characters +#[deriving(Clone, Eq)] +pub struct UpperHex; + +macro_rules! radix { + ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => { + impl GenericRadix for $T { + fn base(&self) -> u8 { $base } + fn prefix(&self) -> &'static str { $prefix } + fn digit(&self, x: u8) -> u8 { + match x { + $($x => $conv,)+ + x => fail!("number not in the range 0..{}: {}", self.base() - 1, x), + } + } + } + } +} + +radix!(Binary, 2, "0b", x @ 0 .. 2 => '0' as u8 + x) +radix!(Octal, 8, "0o", x @ 0 .. 7 => '0' as u8 + x) +radix!(Decimal, 10, "", x @ 0 .. 9 => '0' as u8 + x) +radix!(LowerHex, 16, "0x", x @ 0 .. 9 => '0' as u8 + x, + x @ 10 ..15 => 'a' as u8 + (x - 10)) +radix!(UpperHex, 16, "0x", x @ 0 .. 9 => '0' as u8 + x, + x @ 10 ..15 => 'A' as u8 + (x - 10)) + +/// A radix with in the range of `2..36`. +#[deriving(Clone, Eq)] +pub struct Radix { + priv base: u8, +} + +impl Radix { + fn new(base: u8) -> Radix { + assert!(2 <= base && base <= 36, "the base must be in the range of 0..36: {}", base); + Radix { base: base } + } +} + +impl GenericRadix for Radix { + fn base(&self) -> u8 { self.base } + fn digit(&self, x: u8) -> u8 { + match x { + x @ 0 ..9 => '0' as u8 + x, + x if x < self.base() => 'a' as u8 + (x - 10), + x => fail!("number not in the range 0..{}: {}", self.base() - 1, x), + } + } +} + +/// A helper type for formatting radixes. +pub struct RadixFmt(T, R); + +/// Constructs a radix formatter in the range of `2..36`. +/// +/// # Example +/// +/// ~~~ +/// use std::fmt::radix; +/// assert_eq!(format!("{}", radix(55, 36)), ~"1j"); +/// ~~~ +pub fn radix(x: T, base: u8) -> RadixFmt { + RadixFmt(x, Radix::new(base)) +} + +macro_rules! radix_fmt { + ($T:ty as $U:ty, $fmt:ident) => { + impl fmt::Show for RadixFmt<$T, Radix> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) } + } + } + } +} +macro_rules! int_base { + ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { + impl fmt::$Trait for $T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + $Radix.fmt_int(*self as $U, f) + } + } + } +} +macro_rules! integer { + ($Int:ident, $Uint:ident) => { + int_base!(Show for $Int as $Int -> Decimal) + int_base!(Signed for $Int as $Int -> Decimal) + int_base!(Binary for $Int as $Uint -> Binary) + int_base!(Octal for $Int as $Uint -> Octal) + int_base!(LowerHex for $Int as $Uint -> LowerHex) + int_base!(UpperHex for $Int as $Uint -> UpperHex) + radix_fmt!($Int as $Uint, fmt_int) + + int_base!(Show for $Uint as $Uint -> Decimal) + int_base!(Unsigned for $Uint as $Uint -> Decimal) + int_base!(Binary for $Uint as $Uint -> Binary) + int_base!(Octal for $Uint as $Uint -> Octal) + int_base!(LowerHex for $Uint as $Uint -> LowerHex) + int_base!(UpperHex for $Uint as $Uint -> UpperHex) + radix_fmt!($Uint as $Uint, fmt_int) + } +} +integer!(int, uint) +integer!(i8, u8) +integer!(i16, u16) +integer!(i32, u32) +integer!(i64, u64) + +#[cfg(test)] +mod tests { + use fmt::radix; + use super::{Binary, Octal, Decimal, LowerHex, UpperHex}; + use super::{GenericRadix, Radix}; + + #[test] + fn test_radix_base() { + assert_eq!(Binary.base(), 2); + assert_eq!(Octal.base(), 8); + assert_eq!(Decimal.base(), 10); + assert_eq!(LowerHex.base(), 16); + assert_eq!(UpperHex.base(), 16); + assert_eq!(Radix { base: 36 }.base(), 36); + } + + #[test] + fn test_radix_prefix() { + assert_eq!(Binary.prefix(), "0b"); + assert_eq!(Octal.prefix(), "0o"); + assert_eq!(Decimal.prefix(), ""); + assert_eq!(LowerHex.prefix(), "0x"); + assert_eq!(UpperHex.prefix(), "0x"); + assert_eq!(Radix { base: 36 }.prefix(), ""); + } + + #[test] + fn test_radix_digit() { + assert_eq!(Binary.digit(0), '0' as u8); + assert_eq!(Binary.digit(2), '2' as u8); + assert_eq!(Octal.digit(0), '0' as u8); + assert_eq!(Octal.digit(7), '7' as u8); + assert_eq!(Decimal.digit(0), '0' as u8); + assert_eq!(Decimal.digit(9), '9' as u8); + assert_eq!(LowerHex.digit(0), '0' as u8); + assert_eq!(LowerHex.digit(10), 'a' as u8); + assert_eq!(LowerHex.digit(15), 'f' as u8); + assert_eq!(UpperHex.digit(0), '0' as u8); + assert_eq!(UpperHex.digit(10), 'A' as u8); + assert_eq!(UpperHex.digit(15), 'F' as u8); + assert_eq!(Radix { base: 36 }.digit(0), '0' as u8); + assert_eq!(Radix { base: 36 }.digit(15), 'f' as u8); + assert_eq!(Radix { base: 36 }.digit(35), 'z' as u8); + } + + #[test] + #[should_fail] + fn test_hex_radix_digit_overflow() { + let _ = LowerHex.digit(16); + } + + #[test] + fn test_format_int() { + // Formatting integers should select the right implementation based off + // the type of the argument. Also, hex/octal/binary should be defined + // for integers, but they shouldn't emit the negative sign. + assert_eq!(format!("{}", 1i), ~"1"); + assert_eq!(format!("{}", 1i8), ~"1"); + assert_eq!(format!("{}", 1i16), ~"1"); + assert_eq!(format!("{}", 1i32), ~"1"); + assert_eq!(format!("{}", 1i64), ~"1"); + assert_eq!(format!("{:d}", -1i), ~"-1"); + assert_eq!(format!("{:d}", -1i8), ~"-1"); + assert_eq!(format!("{:d}", -1i16), ~"-1"); + assert_eq!(format!("{:d}", -1i32), ~"-1"); + assert_eq!(format!("{:d}", -1i64), ~"-1"); + assert_eq!(format!("{:t}", 1i), ~"1"); + assert_eq!(format!("{:t}", 1i8), ~"1"); + assert_eq!(format!("{:t}", 1i16), ~"1"); + assert_eq!(format!("{:t}", 1i32), ~"1"); + assert_eq!(format!("{:t}", 1i64), ~"1"); + assert_eq!(format!("{:x}", 1i), ~"1"); + assert_eq!(format!("{:x}", 1i8), ~"1"); + assert_eq!(format!("{:x}", 1i16), ~"1"); + assert_eq!(format!("{:x}", 1i32), ~"1"); + assert_eq!(format!("{:x}", 1i64), ~"1"); + assert_eq!(format!("{:X}", 1i), ~"1"); + assert_eq!(format!("{:X}", 1i8), ~"1"); + assert_eq!(format!("{:X}", 1i16), ~"1"); + assert_eq!(format!("{:X}", 1i32), ~"1"); + assert_eq!(format!("{:X}", 1i64), ~"1"); + assert_eq!(format!("{:o}", 1i), ~"1"); + assert_eq!(format!("{:o}", 1i8), ~"1"); + assert_eq!(format!("{:o}", 1i16), ~"1"); + assert_eq!(format!("{:o}", 1i32), ~"1"); + assert_eq!(format!("{:o}", 1i64), ~"1"); + + assert_eq!(format!("{}", 1u), ~"1"); + assert_eq!(format!("{}", 1u8), ~"1"); + assert_eq!(format!("{}", 1u16), ~"1"); + assert_eq!(format!("{}", 1u32), ~"1"); + assert_eq!(format!("{}", 1u64), ~"1"); + assert_eq!(format!("{:u}", 1u), ~"1"); + assert_eq!(format!("{:u}", 1u8), ~"1"); + assert_eq!(format!("{:u}", 1u16), ~"1"); + assert_eq!(format!("{:u}", 1u32), ~"1"); + assert_eq!(format!("{:u}", 1u64), ~"1"); + assert_eq!(format!("{:t}", 1u), ~"1"); + assert_eq!(format!("{:t}", 1u8), ~"1"); + assert_eq!(format!("{:t}", 1u16), ~"1"); + assert_eq!(format!("{:t}", 1u32), ~"1"); + assert_eq!(format!("{:t}", 1u64), ~"1"); + assert_eq!(format!("{:x}", 1u), ~"1"); + assert_eq!(format!("{:x}", 1u8), ~"1"); + assert_eq!(format!("{:x}", 1u16), ~"1"); + assert_eq!(format!("{:x}", 1u32), ~"1"); + assert_eq!(format!("{:x}", 1u64), ~"1"); + assert_eq!(format!("{:X}", 1u), ~"1"); + assert_eq!(format!("{:X}", 1u8), ~"1"); + assert_eq!(format!("{:X}", 1u16), ~"1"); + assert_eq!(format!("{:X}", 1u32), ~"1"); + assert_eq!(format!("{:X}", 1u64), ~"1"); + assert_eq!(format!("{:o}", 1u), ~"1"); + assert_eq!(format!("{:o}", 1u8), ~"1"); + assert_eq!(format!("{:o}", 1u16), ~"1"); + assert_eq!(format!("{:o}", 1u32), ~"1"); + assert_eq!(format!("{:o}", 1u64), ~"1"); + + // Test a larger number + assert_eq!(format!("{:t}", 55), ~"110111"); + assert_eq!(format!("{:o}", 55), ~"67"); + assert_eq!(format!("{:d}", 55), ~"55"); + assert_eq!(format!("{:x}", 55), ~"37"); + assert_eq!(format!("{:X}", 55), ~"37"); + } + + #[test] + fn test_format_int_zero() { + assert_eq!(format!("{}", 0i), ~"0"); + assert_eq!(format!("{:d}", 0i), ~"0"); + assert_eq!(format!("{:t}", 0i), ~"0"); + assert_eq!(format!("{:o}", 0i), ~"0"); + assert_eq!(format!("{:x}", 0i), ~"0"); + assert_eq!(format!("{:X}", 0i), ~"0"); + + assert_eq!(format!("{}", 0u), ~"0"); + assert_eq!(format!("{:u}", 0u), ~"0"); + assert_eq!(format!("{:t}", 0u), ~"0"); + assert_eq!(format!("{:o}", 0u), ~"0"); + assert_eq!(format!("{:x}", 0u), ~"0"); + assert_eq!(format!("{:X}", 0u), ~"0"); + } + + #[test] + fn test_format_int_flags() { + assert_eq!(format!("{:3d}", 1), ~" 1"); + assert_eq!(format!("{:>3d}", 1), ~" 1"); + assert_eq!(format!("{:>+3d}", 1), ~" +1"); + assert_eq!(format!("{:<3d}", 1), ~"1 "); + assert_eq!(format!("{:#d}", 1), ~"1"); + assert_eq!(format!("{:#x}", 10), ~"0xa"); + assert_eq!(format!("{:#X}", 10), ~"0xA"); + assert_eq!(format!("{:#5x}", 10), ~" 0xa"); + assert_eq!(format!("{:#o}", 10), ~"0o12"); + assert_eq!(format!("{:08x}", 10), ~"0000000a"); + assert_eq!(format!("{:8x}", 10), ~" a"); + assert_eq!(format!("{:<8x}", 10), ~"a "); + assert_eq!(format!("{:>8x}", 10), ~" a"); + assert_eq!(format!("{:#08x}", 10), ~"0x00000a"); + assert_eq!(format!("{:08d}", -10), ~"-0000010"); + assert_eq!(format!("{:x}", -1u8), ~"ff"); + assert_eq!(format!("{:X}", -1u8), ~"FF"); + assert_eq!(format!("{:t}", -1u8), ~"11111111"); + assert_eq!(format!("{:o}", -1u8), ~"377"); + assert_eq!(format!("{:#x}", -1u8), ~"0xff"); + assert_eq!(format!("{:#X}", -1u8), ~"0xFF"); + assert_eq!(format!("{:#t}", -1u8), ~"0b11111111"); + assert_eq!(format!("{:#o}", -1u8), ~"0o377"); + } + + #[test] + fn test_format_int_sign_padding() { + assert_eq!(format!("{:+5d}", 1), ~" +1"); + assert_eq!(format!("{:+5d}", -1), ~" -1"); + assert_eq!(format!("{:05d}", 1), ~"00001"); + assert_eq!(format!("{:05d}", -1), ~"-0001"); + assert_eq!(format!("{:+05d}", 1), ~"+0001"); + assert_eq!(format!("{:+05d}", -1), ~"-0001"); + } + + #[test] + fn test_format_int_twos_complement() { + use {i8, i16, i32, i64}; + assert_eq!(format!("{}", i8::MIN), ~"-128"); + assert_eq!(format!("{}", i16::MIN), ~"-32768"); + assert_eq!(format!("{}", i32::MIN), ~"-2147483648"); + assert_eq!(format!("{}", i64::MIN), ~"-9223372036854775808"); + } + + #[test] + fn test_format_radix() { + assert_eq!(format!("{:04}", radix(3, 2)), ~"0011"); + assert_eq!(format!("{}", radix(55, 36)), ~"1j"); + } + + #[test] + #[should_fail] + fn test_radix_base_too_large() { + let _ = radix(55, 37); + } +} + +#[cfg(test)] +mod bench { + extern crate test; + + mod uint { + use super::test::BenchHarness; + use fmt::radix; + use rand::{XorShiftRng, Rng}; + + #[bench] + fn format_bin(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{:t}", rng.gen::()); }) + } + + #[bench] + fn format_oct(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{:o}", rng.gen::()); }) + } + + #[bench] + fn format_dec(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{:u}", rng.gen::()); }) + } + + #[bench] + fn format_hex(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{:x}", rng.gen::()); }) + } + + #[bench] + fn format_base_36(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{}", radix(rng.gen::(), 36)); }) + } + } + + mod int { + use super::test::BenchHarness; + use fmt::radix; + use rand::{XorShiftRng, Rng}; + + #[bench] + fn format_bin(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{:t}", rng.gen::()); }) + } + + #[bench] + fn format_oct(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{:o}", rng.gen::()); }) + } + + #[bench] + fn format_dec(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{:d}", rng.gen::()); }) + } + + #[bench] + fn format_hex(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{:x}", rng.gen::()); }) + } + + #[bench] + fn format_base_36(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { format!("{}", radix(rng.gen::(), 36)); }) + } + } +} diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 767faa30f24..150c7bdab29 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -22,6 +22,7 @@ use mem::size_of; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::{Option, Some, None}; +use fmt::{Show, Binary, Octal, LowerHex, UpperHex}; pub mod strconv; @@ -278,7 +279,12 @@ pub trait Int: Integer + CheckedAdd + CheckedSub + CheckedMul - + CheckedDiv {} + + CheckedDiv + + Show + + Binary + + Octal + + LowerHex + + UpperHex {} /// Returns the smallest power of 2 greater than or equal to `n`. #[inline] diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 6be829f51d7..c0c3074be63 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -804,24 +804,88 @@ mod test { #[cfg(test)] mod bench { extern crate test; - use self::test::BenchHarness; - use rand::{XorShiftRng, Rng}; - use to_str::ToStr; - use f64; - #[bench] - fn uint_to_str_rand(bh: &mut BenchHarness) { - let mut rng = XorShiftRng::new(); - bh.iter(|| { - rng.gen::().to_str(); - }) + mod uint { + use super::test::BenchHarness; + use rand::{XorShiftRng, Rng}; + use num::ToStrRadix; + + #[bench] + fn to_str_bin(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(2); }) + } + + #[bench] + fn to_str_oct(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(8); }) + } + + #[bench] + fn to_str_dec(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(10); }) + } + + #[bench] + fn to_str_hex(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(16); }) + } + + #[bench] + fn to_str_base_36(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(36); }) + } } - #[bench] - fn float_to_str_rand(bh: &mut BenchHarness) { - let mut rng = XorShiftRng::new(); - bh.iter(|| { - f64::to_str(rng.gen()); - }) + mod int { + use super::test::BenchHarness; + use rand::{XorShiftRng, Rng}; + use num::ToStrRadix; + + #[bench] + fn to_str_bin(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(2); }) + } + + #[bench] + fn to_str_oct(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(8); }) + } + + #[bench] + fn to_str_dec(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(10); }) + } + + #[bench] + fn to_str_hex(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(16); }) + } + + #[bench] + fn to_str_base_36(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { rng.gen::().to_str_radix(36); }) + } + } + + mod f64 { + use super::test::BenchHarness; + use rand::{XorShiftRng, Rng}; + use f64; + + #[bench] + fn float_to_str(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + bh.iter(|| { f64::to_str(rng.gen()); }) + } } } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 09188b77ad8..ca798a77a4f 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -36,7 +36,6 @@ impl fmt::Signed for B { macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) }) pub fn main() { - // Make sure there's a poly formatter that takes anything t!(format!("{:?}", 1), "1"); t!(format!("{:?}", A), "A"); @@ -49,16 +48,6 @@ pub fn main() { t!(format!("hello \\{"), "hello {"); // default formatters should work - t!(format!("{}", 1i), "1"); - t!(format!("{}", 1i8), "1"); - t!(format!("{}", 1i16), "1"); - t!(format!("{}", 1i32), "1"); - t!(format!("{}", 1i64), "1"); - t!(format!("{}", 1u), "1"); - t!(format!("{}", 1u8), "1"); - t!(format!("{}", 1u16), "1"); - t!(format!("{}", 1u32), "1"); - t!(format!("{}", 1u64), "1"); t!(format!("{}", 1.0f32), "1"); t!(format!("{}", 1.0f64), "1"); t!(format!("{}", "a"), "a"); @@ -126,94 +115,6 @@ pub fn main() { t!(format!("{:-#s}", "a"), "a"); t!(format!("{:+#s}", "a"), "a"); - // Formatting integers should select the right implementation based off the - // type of the argument. Also, hex/octal/binary should be defined for - // integers, but they shouldn't emit the negative sign. - t!(format!("{:d}", -1i), "-1"); - t!(format!("{:d}", -1i8), "-1"); - t!(format!("{:d}", -1i16), "-1"); - t!(format!("{:d}", -1i32), "-1"); - t!(format!("{:d}", -1i64), "-1"); - t!(format!("{:t}", 1i), "1"); - t!(format!("{:t}", 1i8), "1"); - t!(format!("{:t}", 1i16), "1"); - t!(format!("{:t}", 1i32), "1"); - t!(format!("{:t}", 1i64), "1"); - t!(format!("{:x}", 1i), "1"); - t!(format!("{:x}", 1i8), "1"); - t!(format!("{:x}", 1i16), "1"); - t!(format!("{:x}", 1i32), "1"); - t!(format!("{:x}", 1i64), "1"); - t!(format!("{:X}", 1i), "1"); - t!(format!("{:X}", 1i8), "1"); - t!(format!("{:X}", 1i16), "1"); - t!(format!("{:X}", 1i32), "1"); - t!(format!("{:X}", 1i64), "1"); - t!(format!("{:o}", 1i), "1"); - t!(format!("{:o}", 1i8), "1"); - t!(format!("{:o}", 1i16), "1"); - t!(format!("{:o}", 1i32), "1"); - t!(format!("{:o}", 1i64), "1"); - - t!(format!("{:u}", 1u), "1"); - t!(format!("{:u}", 1u8), "1"); - t!(format!("{:u}", 1u16), "1"); - t!(format!("{:u}", 1u32), "1"); - t!(format!("{:u}", 1u64), "1"); - t!(format!("{:t}", 1u), "1"); - t!(format!("{:t}", 1u8), "1"); - t!(format!("{:t}", 1u16), "1"); - t!(format!("{:t}", 1u32), "1"); - t!(format!("{:t}", 1u64), "1"); - t!(format!("{:x}", 1u), "1"); - t!(format!("{:x}", 1u8), "1"); - t!(format!("{:x}", 1u16), "1"); - t!(format!("{:x}", 1u32), "1"); - t!(format!("{:x}", 1u64), "1"); - t!(format!("{:X}", 1u), "1"); - t!(format!("{:X}", 1u8), "1"); - t!(format!("{:X}", 1u16), "1"); - t!(format!("{:X}", 1u32), "1"); - t!(format!("{:X}", 1u64), "1"); - t!(format!("{:o}", 1u), "1"); - t!(format!("{:o}", 1u8), "1"); - t!(format!("{:o}", 1u16), "1"); - t!(format!("{:o}", 1u32), "1"); - t!(format!("{:o}", 1u64), "1"); - - // Test the flags for formatting integers - t!(format!("{:3d}", 1), " 1"); - t!(format!("{:>3d}", 1), " 1"); - t!(format!("{:>+3d}", 1), " +1"); - t!(format!("{:<3d}", 1), "1 "); - t!(format!("{:#d}", 1), "1"); - t!(format!("{:#x}", 10), "0xa"); - t!(format!("{:#X}", 10), "0xA"); - t!(format!("{:#5x}", 10), " 0xa"); - t!(format!("{:#o}", 10), "0o12"); - t!(format!("{:08x}", 10), "0000000a"); - t!(format!("{:8x}", 10), " a"); - t!(format!("{:<8x}", 10), "a "); - t!(format!("{:>8x}", 10), " a"); - t!(format!("{:#08x}", 10), "0x00000a"); - t!(format!("{:08d}", -10), "-0000010"); - t!(format!("{:x}", -1u8), "ff"); - t!(format!("{:X}", -1u8), "FF"); - t!(format!("{:t}", -1u8), "11111111"); - t!(format!("{:o}", -1u8), "377"); - t!(format!("{:#x}", -1u8), "0xff"); - t!(format!("{:#X}", -1u8), "0xFF"); - t!(format!("{:#t}", -1u8), "0b11111111"); - t!(format!("{:#o}", -1u8), "0o377"); - - // Signed combinations - t!(format!("{:+5d}", 1), " +1"); - t!(format!("{:+5d}", -1), " -1"); - t!(format!("{:05d}", 1), "00001"); - t!(format!("{:05d}", -1), "-0001"); - t!(format!("{:+05d}", 1), "+0001"); - t!(format!("{:+05d}", -1), "-0001"); - // Some float stuff t!(format!("{:f}", 1.0f32), "1"); t!(format!("{:f}", 1.0f64), "1"); From 6943acd1a50b0c4d0d95e298c151aa796ae05269 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 22 Feb 2014 03:53:18 +1100 Subject: [PATCH 3/3] Reduce reliance on `to_str_radix` This is in preparation to remove the implementations of ToStrRadix in integers, and to remove the associated logic from `std::num::strconv`. The parts that still need to be liberated are: - `std::fmt::Formatter::runplural` - `num::{bigint, complex, rational}` --- src/doc/complement-cheatsheet.md | 9 +- src/librustc/middle/ty.rs | 2 +- src/librustc/middle/typeck/infer/to_str.rs | 3 +- src/libstd/hash.rs | 5 +- src/libstd/io/mod.rs | 4 +- src/libstd/num/int_macros.rs | 2 +- src/libstd/num/uint_macros.rs | 2 +- src/libstd/repr.rs | 10 +- src/libsyntax/print/pprust.rs | 21 +---- src/libterm/terminfo/parm.rs | 104 +++++++++------------ 10 files changed, 60 insertions(+), 102 deletions(-) diff --git a/src/doc/complement-cheatsheet.md b/src/doc/complement-cheatsheet.md index a2d75fc95d1..79f33a88562 100644 --- a/src/doc/complement-cheatsheet.md +++ b/src/doc/complement-cheatsheet.md @@ -22,13 +22,14 @@ let y: int = x.unwrap(); **Int to string, in non-base-10** -Use [`ToStrRadix`](http://static.rust-lang.org/doc/master/std/num/trait.ToStrRadix.html). +Use the `format!` syntax extension. ~~~ -use std::num::ToStrRadix; - let x: int = 42; -let y: ~str = x.to_str_radix(16); +let y: ~str = format!("{:t}", x); // binary +let y: ~str = format!("{:o}", x); // octal +let y: ~str = format!("{:x}", x); // lowercase hexadecimal +let y: ~str = format!("{:X}", x); // uppercase hexidecimal ~~~ **String to int, in non-base-10** diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index f3016ff68a8..09c21d54c87 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2024,7 +2024,7 @@ impl ops::Sub for TypeContents { impl ToStr for TypeContents { fn to_str(&self) -> ~str { - format!("TypeContents({})", self.bits.to_str_radix(2)) + format!("TypeContents({:t})", self.bits) } } diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index d604d68dd54..aa3e3a23182 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -70,8 +70,7 @@ impl InferStr for VarValue { fn inf_str(&self, cx: &InferCtxt) -> ~str { match *self { Redirect(ref vid) => format!("Redirect({})", vid.to_str()), - Root(ref pt, rk) => format!("Root({}, {})", pt.inf_str(cx), - rk.to_str_radix(10u)) + Root(ref pt, rk) => format!("Root({}, {})", pt.inf_str(cx), rk) } } } diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index 4163d1e0c96..432e27257f3 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -29,7 +29,6 @@ use container::Container; use io::{Writer, IoResult}; use iter::Iterator; -use num::ToStrRadix; use option::{Some, None}; use result::Ok; use str::OwnedStr; @@ -281,7 +280,7 @@ impl Streaming for SipState { let r = self.result_bytes(); let mut s = ~""; for b in r.iter() { - s.push_str((*b as uint).to_str_radix(16u)); + s.push_str(format!("{:x}", *b)); } s } @@ -391,7 +390,7 @@ mod tests { fn to_hex_str(r: &[u8, ..8]) -> ~str { let mut s = ~""; for b in r.iter() { - s.push_str((*b as uint).to_str_radix(16u)); + s.push_str(format!("{:x}", *b)); } s } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index db5ee09fa14..f09dc3da9bf 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -857,12 +857,12 @@ pub trait Writer { /// Write the result of passing n through `int::to_str_bytes`. fn write_int(&mut self, n: int) -> IoResult<()> { - int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) + write!(self, "{:d}", n) } /// Write the result of passing n through `uint::to_str_bytes`. fn write_uint(&mut self, n: uint) -> IoResult<()> { - uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) + write!(self, "{:u}", n) } /// Write a little-endian uint (number of bytes depends on system). diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 3ecc6f32017..16af826eba8 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -401,7 +401,7 @@ impl ToStr for $T { /// Convert to a string in base 10. #[inline] fn to_str(&self) -> ~str { - self.to_str_radix(10) + format!("{:d}", *self) } } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 4fc30b43895..e4cac0960c0 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -245,7 +245,7 @@ impl ToStr for $T { /// Convert to a string in base 10. #[inline] fn to_str(&self) -> ~str { - self.to_str_radix(10u) + format!("{:u}", *self) } } diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index d367aaa6dc4..680ac112300 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -60,19 +60,13 @@ impl Repr for bool { impl Repr for int { fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> { - ::int::to_str_bytes(*self, 10u, |bits| { - writer.write(bits) - }) + write!(writer, "{}", *self) } } macro_rules! int_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty { fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> { - ::$ty::to_str_bytes(*self, 10u, |bits| { - writer.write(bits).and_then(|()| { - writer.write(bytes!($suffix)) - }) - }) + write!(writer, "{}{}", *self, $suffix) } })) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 21e1998208c..3b1386021d2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2267,29 +2267,14 @@ pub fn print_literal(s: &mut State, lit: &ast::Lit) -> io::IoResult<()> { word(&mut s.s, res) } ast::LitInt(i, t) => { - if i < 0_i64 { - word(&mut s.s, - ~"-" + (-i as u64).to_str_radix(10u) - + ast_util::int_ty_to_str(t)) - } else { - word(&mut s.s, - (i as u64).to_str_radix(10u) - + ast_util::int_ty_to_str(t)) - } + word(&mut s.s, format!("{}{}", i, ast_util::int_ty_to_str(t))) } ast::LitUint(u, t) => { - word(&mut s.s, - u.to_str_radix(10u) - + ast_util::uint_ty_to_str(t)) + word(&mut s.s, format!("{}{}", u, ast_util::uint_ty_to_str(t))) } ast::LitIntUnsuffixed(i) => { - if i < 0_i64 { - word(&mut s.s, ~"-" + (-i as u64).to_str_radix(10u)) - } else { - word(&mut s.s, (i as u64).to_str_radix(10u)) - } + word(&mut s.s, format!("{}", i)) } - ast::LitFloat(ref f, t) => { word(&mut s.s, f.get() + ast_util::float_ty_to_str(t)) } diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index 0491a567f15..948e79b4481 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -12,7 +12,6 @@ use std::{char, vec}; use std::mem::replace; -use std::num::strconv::{SignNone,SignNeg,SignAll,int_to_str_bytes_common}; #[deriving(Eq)] enum States { @@ -480,68 +479,49 @@ impl FormatOp { fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { let mut s = match val { Number(d) => { - match op { - FormatString => { - return Err(~"non-number on stack with %s") - } - _ => { - let radix = match op { - FormatDigit => 10, - FormatOctal => 8, - FormatHex|FormatHEX => 16, - FormatString => unreachable!() - }; - let mut s = ~[]; - match op { - FormatDigit => { - let sign = if flags.sign { SignAll } else { SignNeg }; - int_to_str_bytes_common(d, radix, sign, |c| { - s.push(c); - }) - } - _ => { - int_to_str_bytes_common(d as uint, radix, SignNone, |c| { - s.push(c); - }) - } - }; - if flags.precision > s.len() { - let mut s_ = vec::with_capacity(flags.precision); - let n = flags.precision - s.len(); - s_.grow(n, &('0' as u8)); - s_.push_all_move(s); - s = s_; - } - assert!(!s.is_empty(), "string conversion produced empty result"); - match op { - FormatDigit => { - if flags.space && !(s[0] == '-' as u8 || s[0] == '+' as u8) { - s.unshift(' ' as u8); - } - } - FormatOctal => { - if flags.alternate && s[0] != '0' as u8 { - s.unshift('0' as u8); - } - } - FormatHex => { - if flags.alternate { - let s_ = replace(&mut s, ~['0' as u8, 'x' as u8]); - s.push_all_move(s_); - } - } - FormatHEX => { - s = s.into_ascii().to_upper().into_bytes(); - if flags.alternate { - let s_ = replace(&mut s, ~['0' as u8, 'X' as u8]); - s.push_all_move(s_); - } - } - FormatString => unreachable!() - } - s - } + let mut s = match (op, flags.sign) { + (FormatDigit, true) => format!("{:+d}", d).into_bytes(), + (FormatDigit, false) => format!("{:d}", d).into_bytes(), + (FormatOctal, _) => format!("{:o}", d).into_bytes(), + (FormatHex, _) => format!("{:x}", d).into_bytes(), + (FormatHEX, _) => format!("{:X}", d).into_bytes(), + (FormatString, _) => return Err(~"non-number on stack with %s"), + }; + if flags.precision > s.len() { + let mut s_ = vec::with_capacity(flags.precision); + let n = flags.precision - s.len(); + s_.grow(n, &('0' as u8)); + s_.push_all_move(s); + s = s_; } + assert!(!s.is_empty(), "string conversion produced empty result"); + match op { + FormatDigit => { + if flags.space && !(s[0] == '-' as u8 || s[0] == '+' as u8) { + s.unshift(' ' as u8); + } + } + FormatOctal => { + if flags.alternate && s[0] != '0' as u8 { + s.unshift('0' as u8); + } + } + FormatHex => { + if flags.alternate { + let s_ = replace(&mut s, ~['0' as u8, 'x' as u8]); + s.push_all_move(s_); + } + } + FormatHEX => { + s = s.into_ascii().to_upper().into_bytes(); + if flags.alternate { + let s_ = replace(&mut s, ~['0' as u8, 'X' as u8]); + s.push_all_move(s_); + } + } + FormatString => unreachable!() + } + s } String(s) => { match op {