diff options
| -rw-r--r-- | src/libcore/fmt/float.rs | 289 | ||||
| -rw-r--r-- | src/libcore/fmt/mod.rs | 168 |
2 files changed, 125 insertions, 332 deletions
diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs deleted file mode 100644 index 4b75bd5f67e..00000000000 --- a/src/libcore/fmt/float.rs +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::ExponentFormat::*; -pub use self::SignificantDigits::*; - -use prelude::*; - -use char; -use fmt; -use num::Float; -use num::FpCategory as Fp; -use ops::{Div, Rem, Mul}; -use slice; -use str; - -/// A flag that specifies whether to use exponential (scientific) notation. -pub enum ExponentFormat { - /// Do not use exponential notation. - ExpNone, - /// Use exponential notation with the exponent having a base of 10 and the - /// exponent sign being `e` or `E`. For example, 1000 would be printed - /// 1e3. - ExpDec -} - -/// The number of digits used for emitting the fractional part of a number, if -/// any. -pub enum SignificantDigits { - /// At most the given number of digits will be printed, truncating any - /// trailing zeroes. - DigMax(usize), - - /// Precisely the given number of digits will be printed. - DigExact(usize) -} - -#[doc(hidden)] -pub trait MyFloat: Float + PartialEq + PartialOrd + Div<Output=Self> + - Mul<Output=Self> + Rem<Output=Self> + Copy { - fn from_u32(u: u32) -> Self; - fn to_i32(&self) -> i32; -} - -macro_rules! doit { - ($($t:ident)*) => ($(impl MyFloat for $t { - fn from_u32(u: u32) -> $t { u as $t } - fn to_i32(&self) -> i32 { *self as i32 } - })*) -} -doit! { f32 f64 } - -/// Converts a float number to its string representation. -/// This is meant to be a common base implementation for various formatting styles. -/// The number is assumed to be non-negative, callers use `Formatter::pad_integral` -/// to add the right sign, if any. -/// -/// # Arguments -/// -/// - `num` - The number to convert (non-negative). Accepts any number that -/// implements the numeric traits. -/// - `digits` - The amount of digits to use for emitting the fractional -/// part, if any. See `SignificantDigits`. -/// - `exp_format` - Whether or not to use the exponential (scientific) notation. -/// See `ExponentFormat`. -/// - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if -/// exponential notation is desired. -/// - `f` - A closure to invoke with the string representing the -/// float. -/// -/// # Panics -/// -/// - Panics if `num` is negative. -pub fn float_to_str_bytes_common<T: MyFloat, U, F>( - num: T, - digits: SignificantDigits, - exp_format: ExponentFormat, - exp_upper: bool, - f: F -) -> U where - F: FnOnce(&str) -> U, -{ - let _0: T = T::zero(); - let _1: T = T::one(); - let radix: u32 = 10; - let radix_f = T::from_u32(radix); - - assert!(num.is_nan() || num >= _0, "float_to_str_bytes_common: number is negative"); - - match num.classify() { - Fp::Nan => return f("NaN"), - Fp::Infinite if num > _0 => { - return f("inf"); - } - Fp::Infinite if num < _0 => { - return f("-inf"); - } - _ => {} - } - - // For an f64 the (decimal) exponent is roughly in the range of [-307, 308], so - // we may have up to that many digits. We err on the side of caution and - // add 50% extra wiggle room. - let mut buf = [0; 462]; - let mut end = 0; - - let (num, exp) = match exp_format { - ExpDec if num != _0 => { - let exp = num.log10().floor(); - (num / radix_f.powf(exp), exp.to_i32()) - } - _ => (num, 0) - }; - - // First emit the non-fractional part, looping at least once to make - // sure at least a `0` gets emitted. - let mut deccum = num.trunc(); - loop { - let current_digit = deccum % radix_f; - - // Decrease the deccumulator one digit at a time - deccum = deccum / radix_f; - deccum = deccum.trunc(); - - let c = char::from_digit(current_digit.to_i32() as u32, radix); - buf[end] = c.unwrap() as u8; - end += 1; - - // No more digits to calculate for the non-fractional part -> break - if deccum == _0 { break; } - } - - // If limited digits, calculate one digit more for rounding. - let (limit_digits, digit_count, exact) = match digits { - DigMax(count) => (true, count + 1, false), - DigExact(count) => (true, count + 1, true) - }; - - buf[..end].reverse(); - - // Remember start of the fractional digits. - // Points one beyond end of buf if none get generated, - // or at the '.' otherwise. - let start_fractional_digits = end; - - // Now emit the fractional part, if any - deccum = num.fract(); - if deccum != _0 || (limit_digits && exact && digit_count > 0) { - buf[end] = b'.'; - end += 1; - let mut dig = 0; - - // calculate new digits while - // - there is no limit and there are digits left - // - or there is a limit, it's not reached yet and - // - it's exact - // - or it's a maximum, and there are still digits left - while (!limit_digits && deccum != _0) - || (limit_digits && dig < digit_count && ( - exact - || (!exact && deccum != _0) - ) - ) { - // Shift first fractional digit into the integer part - deccum = deccum * radix_f; - - let current_digit = deccum.trunc(); - - let c = char::from_digit(current_digit.to_i32() as u32, radix); - buf[end] = c.unwrap() as u8; - end += 1; - - // Decrease the deccumulator one fractional digit at a time - deccum = deccum.fract(); - dig += 1; - } - - // If digits are limited, and that limit has been reached, - // cut off the one extra digit, and depending on its value - // round the remaining ones. - if limit_digits && dig == digit_count { - let ascii2value = |chr: u8| { - (chr as char).to_digit(radix).unwrap() - }; - let value2ascii = |val: u32| { - char::from_digit(val, radix).unwrap() as u8 - }; - - let extra_digit = ascii2value(buf[end - 1]); - end -= 1; - if extra_digit >= radix / 2 { // -> need to round - let mut i: isize = end as isize - 1; - loop { - // If reached left end of number, have to - // insert additional digit: - if i < 0 - || buf[i as usize] == b'-' - || buf[i as usize] == b'+' { - for j in ((i + 1) as usize..end).rev() { - buf[j + 1] = buf[j]; - } - buf[(i + 1) as usize] = value2ascii(1); - end += 1; - break; - } - - // Skip the '.' - if buf[i as usize] == b'.' { i -= 1; continue; } - - // Either increment the digit, - // or set to 0 if max and carry the 1. - let current_digit = ascii2value(buf[i as usize]); - if current_digit < (radix - 1) { - buf[i as usize] = value2ascii(current_digit+1); - break; - } else { - buf[i as usize] = value2ascii(0); - i -= 1; - } - } - } - } - } - - // if number of digits is not exact, remove all trailing '0's up to - // and including the '.' - if !exact { - let buf_max_i = end - 1; - - // index to truncate from - let mut i = buf_max_i; - - // discover trailing zeros of fractional part - while i > start_fractional_digits && buf[i] == b'0' { - i -= 1; - } - - // Only attempt to truncate digits if buf has fractional digits - if i >= start_fractional_digits { - // If buf ends with '.', cut that too. - if buf[i] == b'.' { i -= 1 } - - // only resize buf if we actually remove digits - if i < buf_max_i { - end = i + 1; - } - } - } // If exact and trailing '.', just cut that - else { - let max_i = end - 1; - if buf[max_i] == b'.' { - end = max_i; - } - } - - match exp_format { - ExpNone => {}, - ExpDec => { - buf[end] = if exp_upper { b'E' } else { b'e' }; - end += 1; - - struct Filler<'a> { - buf: &'a mut [u8], - end: &'a mut usize, - } - - impl<'a> fmt::Write for Filler<'a> { - fn write_str(&mut self, s: &str) -> fmt::Result { - slice::bytes::copy_memory(s.as_bytes(), - &mut self.buf[(*self.end)..]); - *self.end += s.len(); - Ok(()) - } - } - - let mut filler = Filler { buf: &mut buf, end: &mut end }; - let _ = fmt::write(&mut filler, format_args!("{:-}", exp)); - } - } - - f(unsafe { str::from_utf8_unchecked(&buf[..end]) }) -} diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index f8a1ef96bcc..a87f6619fe8 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -17,9 +17,9 @@ use prelude::*; use cell::{Cell, RefCell, Ref, RefMut, BorrowState}; use marker::PhantomData; use mem; +use num::flt2dec; use ops::Deref; use result; -use num::Float; use slice; use str; use self::rt::v1::Alignment; @@ -31,7 +31,6 @@ pub use self::num::RadixFmt; pub use self::builders::{DebugStruct, DebugTuple, DebugSet, DebugList, DebugMap}; mod num; -mod float; mod builders; #[unstable(feature = "core", reason = "internal to format_args!")] @@ -604,6 +603,83 @@ impl<'a> Formatter<'a> { Ok(()) } + /// Takes the formatted parts and applies the padding. + /// Assumes that the caller already has rendered the parts with required precision, + /// so that `self.precision` can be ignored. + fn pad_formatted_parts(&mut self, formatted: &flt2dec::Formatted) -> Result { + if let Some(mut width) = self.width { + // for the sign-aware zero padding, we render the sign first and + // behave as if we had no sign from the beginning. + let mut formatted = formatted.clone(); + let mut align = self.align; + let old_fill = self.fill; + if self.flags & (1 << (FlagV1::SignAwareZeroPad as u32)) != 0 { + // a sign always goes first + let sign = unsafe { str::from_utf8_unchecked(formatted.sign) }; + try!(self.buf.write_str(sign)); + + // remove the sign from the formatted parts + formatted.sign = b""; + width = if width < sign.len() { 0 } else { width - sign.len() }; + align = Alignment::Right; + self.fill = '0'; + } + + // remaining parts go through the ordinary padding process. + let len = formatted.len(); + let ret = if width <= len { // no padding + self.write_formatted_parts(&formatted) + } else { + self.with_padding(width - len, align, |f| { + f.write_formatted_parts(&formatted) + }) + }; + self.fill = old_fill; + ret + } else { + // this is the common case and we take a shortcut + self.write_formatted_parts(formatted) + } + } + + fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted) -> Result { + fn write_bytes(buf: &mut Write, s: &[u8]) -> Result { + buf.write_str(unsafe { str::from_utf8_unchecked(s) }) + } + + if !formatted.sign.is_empty() { + try!(write_bytes(self.buf, formatted.sign)); + } + for part in formatted.parts { + match *part { + flt2dec::Part::Zero(mut nzeroes) => { + const ZEROES: &'static str = // 64 zeroes + "0000000000000000000000000000000000000000000000000000000000000000"; + while nzeroes > ZEROES.len() { + try!(self.buf.write_str(ZEROES)); + nzeroes -= ZEROES.len(); + } + if nzeroes > 0 { + try!(self.buf.write_str(&ZEROES[..nzeroes])); + } + } + flt2dec::Part::Num(mut v) => { + let mut s = [0; 5]; + let len = part.len(); + for c in s[..len].iter_mut().rev() { + *c = b'0' + (v % 10) as u8; + v /= 10; + } + try!(write_bytes(self.buf, &s[..len])); + } + flt2dec::Part::Copy(buf) => { + try!(write_bytes(self.buf, buf)); + } + } + } + Ok(()) + } + /// Writes some data to the underlying buffer contained within this /// formatter. #[stable(feature = "rust1", since = "1.0.0")] @@ -918,18 +994,50 @@ impl<'a, T> Pointer for &'a mut T { } // Common code of floating point Debug and Display. -fn float_to_str_common<T: float::MyFloat, F>(num: &T, precision: Option<usize>, - post: F) -> Result - where F : FnOnce(&str) -> Result { - let digits = match precision { - Some(i) => float::DigExact(i), - None => float::DigMax(6), +fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result + where T: flt2dec::DecodableFloat +{ + let force_sign = fmt.flags & (1 << (FlagV1::SignPlus as u32)) != 0; + let sign = match (force_sign, negative_zero) { + (false, false) => flt2dec::Sign::Minus, + (false, true) => flt2dec::Sign::MinusRaw, + (true, false) => flt2dec::Sign::MinusPlus, + (true, true) => flt2dec::Sign::MinusPlusRaw, + }; + + let mut buf = [0; 1024]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = if let Some(precision) = fmt.precision { + flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign, + precision, false, &mut buf, &mut parts) + } else { + flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, + 0, false, &mut buf, &mut parts) + }; + fmt.pad_formatted_parts(&formatted) +} + +// Common code of floating point LowerExp and UpperExp. +fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) -> Result + where T: flt2dec::DecodableFloat +{ + let force_sign = fmt.flags & (1 << (FlagV1::SignPlus as u32)) != 0; + let sign = match force_sign { + false => flt2dec::Sign::Minus, + true => flt2dec::Sign::MinusPlus, }; - float::float_to_str_bytes_common(num.abs(), - digits, - float::ExpNone, - false, - post) + + let mut buf = [0; 1024]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = if let Some(precision) = fmt.precision { + // 1 integral digit + `precision` fractional digits = `precision + 1` total digits + flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, + precision + 1, upper, &mut buf, &mut parts) + } else { + flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, + (0, 0), upper, &mut buf, &mut parts) + }; + fmt.pad_formatted_parts(&formatted) } macro_rules! floating { ($ty:ident) => { @@ -937,54 +1045,28 @@ macro_rules! floating { ($ty:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - float_to_str_common(self, fmt.precision, |absolute| { - // is_positive() counts -0.0 as negative - fmt.pad_integral(self.is_nan() || self.is_positive(), "", absolute) - }) + float_to_decimal_common(fmt, self, true) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - float_to_str_common(self, fmt.precision, |absolute| { - // simple comparison counts -0.0 as positive - fmt.pad_integral(self.is_nan() || *self >= 0.0, "", absolute) - }) + float_to_decimal_common(fmt, self, false) } } #[stable(feature = "rust1", since = "1.0.0")] impl LowerExp for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - let digits = match fmt.precision { - Some(i) => float::DigExact(i), - None => float::DigMax(6), - }; - float::float_to_str_bytes_common(self.abs(), - digits, - float::ExpDec, - false, - |bytes| { - fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes) - }) + float_to_exponential_common(fmt, self, false) } } #[stable(feature = "rust1", since = "1.0.0")] impl UpperExp for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - let digits = match fmt.precision { - Some(i) => float::DigExact(i), - None => float::DigMax(6), - }; - float::float_to_str_bytes_common(self.abs(), - digits, - float::ExpDec, - true, - |bytes| { - fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes) - }) + float_to_exponential_common(fmt, self, true) } } } } |
