about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/fmt/float.rs289
-rw-r--r--src/libcore/fmt/mod.rs168
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)
         }
     }
 } }