about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-09-09 23:55:43 +0000
committerbors <bors@rust-lang.org>2014-09-09 23:55:43 +0000
commita1f49730906ca27947cd99547f7295a1bcf83920 (patch)
tree4894feeb3041bedbce1a7febdf2916e142dcbede /src/libcore
parent651106462c357b71a4ca2c02ba2bfedfc38b0035 (diff)
parentfcf88b8f87597f97112f048eaa296b3127e51d0b (diff)
auto merge of #16662 : pczarn/rust/format-fmtstr-opt, r=brson
Based on an observation that strings and arguments are always interleaved, thanks to #15832. Additionally optimize invocations where formatting parameters are unspecified for all arguments, e.g. `"{} {:?} {:x}"`, by emptying the `__STATIC_FMTARGS` array. Next, `Arguments::new` replaces an empty slice with `None` so that passing empty `__STATIC_FMTARGS` generates slightly less machine code when `Arguments::new` is inlined. Furthermore, formatting itself treats these cases separately without making redundant copies of formatting parameters.

All in all, this adds a single mov instruction per `write!` in most cases. That's why code size has increased.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/fmt/mod.rs117
-rw-r--r--src/libcore/fmt/rt.rs2
2 files changed, 118 insertions, 1 deletions
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 7c4494358b1..be75bfec32c 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -113,6 +113,33 @@ impl<'a> Arguments<'a> {
     /// Arguments structure. The compiler inserts an `unsafe` block to call this,
     /// which is valid because the compiler performs all necessary validation to
     /// ensure that the resulting call to format/write would be safe.
+    #[cfg(not(stage0))]
+    #[doc(hidden)] #[inline]
+    pub unsafe fn new<'a>(pieces: &'static [&'static str],
+                          args: &'a [Argument<'a>]) -> Arguments<'a> {
+        Arguments {
+            pieces: mem::transmute(pieces),
+            fmt: None,
+            args: args
+        }
+    }
+
+    /// This function is used to specify nonstandard formatting parameters.
+    /// The `pieces` array must be at least as long as `fmt` to construct
+    /// a valid Arguments structure.
+    #[cfg(not(stage0))]
+    #[doc(hidden)] #[inline]
+    pub unsafe fn with_placeholders<'a>(pieces: &'static [&'static str],
+                                        fmt: &'static [rt::Argument<'static>],
+                                        args: &'a [Argument<'a>]) -> Arguments<'a> {
+        Arguments {
+            pieces: mem::transmute(pieces),
+            fmt: Some(mem::transmute(fmt)),
+            args: args
+        }
+    }
+
+    #[cfg(stage0)]
     #[doc(hidden)] #[inline]
     pub unsafe fn new<'a>(fmt: &'static [rt::Piece<'static>],
                           args: &'a [Argument<'a>]) -> Arguments<'a> {
@@ -129,6 +156,20 @@ impl<'a> Arguments<'a> {
 /// and pass it to a function or closure, passed as the first argument. The
 /// macro validates the format string at compile-time so usage of the `write`
 /// and `format` functions can be safely performed.
+#[cfg(not(stage0))]
+pub struct Arguments<'a> {
+    // Format string pieces to print.
+    pieces: &'a [&'a str],
+
+    // Placeholder specs, or `None` if all specs are default (as in "{}{}").
+    fmt: Option<&'a [rt::Argument<'a>]>,
+
+    // Dynamic arguments for interpolation, to be interleaved with string
+    // pieces. (Every argument is preceded by a string piece.)
+    args: &'a [Argument<'a>],
+}
+
+#[cfg(stage0)] #[doc(hidden)]
 pub struct Arguments<'a> {
     fmt: &'a [rt::Piece<'a>],
     args: &'a [Argument<'a>],
@@ -255,6 +296,18 @@ uniform_fn_call_workaround! {
     secret_upper_exp, UpperExp;
 }
 
+#[cfg(not(stage0))]
+static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument {
+    position: rt::ArgumentNext,
+    format: rt::FormatSpec {
+        fill: ' ',
+        align: rt::AlignUnknown,
+        flags: 0,
+        precision: rt::CountImplied,
+        width: rt::CountImplied,
+    }
+};
+
 /// The `write` function takes an output stream, a precompiled format string,
 /// and a list of arguments. The arguments will be formatted according to the
 /// specified format string into the output stream provided.
@@ -263,6 +316,51 @@ uniform_fn_call_workaround! {
 ///
 ///   * output - the buffer to write output to
 ///   * args - the precompiled arguments generated by `format_args!`
+#[cfg(not(stage0))]
+pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result {
+    let mut formatter = Formatter {
+        flags: 0,
+        width: None,
+        precision: None,
+        buf: output,
+        align: rt::AlignUnknown,
+        fill: ' ',
+        args: args.args,
+        curarg: args.args.iter(),
+    };
+
+    let mut pieces = args.pieces.iter();
+
+    match args.fmt {
+        None => {
+            // We can use default formatting parameters for all arguments.
+            for _ in range(0, args.args.len()) {
+                try!(formatter.buf.write(pieces.next().unwrap().as_bytes()));
+                try!(formatter.run(&DEFAULT_ARGUMENT));
+            }
+        }
+        Some(fmt) => {
+            // Every spec has a corresponding argument that is preceded by
+            // a string piece.
+            for (arg, piece) in fmt.iter().zip(pieces.by_ref()) {
+                try!(formatter.buf.write(piece.as_bytes()));
+                try!(formatter.run(arg));
+            }
+        }
+    }
+
+    // There can be only one trailing string piece left.
+    match pieces.next() {
+        Some(piece) => {
+            try!(formatter.buf.write(piece.as_bytes()));
+        }
+        None => {}
+    }
+
+    Ok(())
+}
+
+#[cfg(stage0)] #[doc(hidden)]
 pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result {
     let mut formatter = Formatter {
         flags: 0,
@@ -285,7 +383,26 @@ impl<'a> Formatter<'a> {
     // First up is the collection of functions used to execute a format string
     // at runtime. This consumes all of the compile-time statics generated by
     // the format! syntax extension.
+    #[cfg(not(stage0))]
+    fn run(&mut self, arg: &rt::Argument) -> Result {
+        // Fill in the format parameters into the formatter
+        self.fill = arg.format.fill;
+        self.align = arg.format.align;
+        self.flags = arg.format.flags;
+        self.width = self.getcount(&arg.format.width);
+        self.precision = self.getcount(&arg.format.precision);
+
+        // Extract the correct argument
+        let value = match arg.position {
+            rt::ArgumentNext => { *self.curarg.next().unwrap() }
+            rt::ArgumentIs(i) => self.args[i],
+        };
+
+        // Then actually do some printing
+        (value.formatter)(value.value, self)
+    }
 
+    #[cfg(stage0)] #[doc(hidden)]
     fn run(&mut self, piece: &rt::Piece) -> Result {
         match *piece {
             rt::String(s) => self.buf.write(s.as_bytes()),
diff --git a/src/libcore/fmt/rt.rs b/src/libcore/fmt/rt.rs
index 1f5449130ec..59fbde88d8b 100644
--- a/src/libcore/fmt/rt.rs
+++ b/src/libcore/fmt/rt.rs
@@ -14,7 +14,7 @@
 //! These definitions are similar to their `ct` equivalents, but differ in that
 //! these can be statically allocated and are slightly optimized for the runtime
 
-
+#[cfg(stage0)]
 #[doc(hidden)]
 pub enum Piece<'a> {
     String(&'a str),