Skip to content

Speed up fmt! by 20% #5463

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 22, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 209 additions & 0 deletions src/libcore/unstable/extfmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,215 @@ pub mod ct {
// decisions made a runtime. If it proves worthwhile then some of these
// conditions can be evaluated at compile-time. For now though it's cleaner to
// implement it this way, I think.
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
#[doc(hidden)]
pub mod rt {
use float;
use str;
use sys;
use int;
use uint;
use vec;
use option::{Some, None, Option};

pub const flag_none : u32 = 0u32;
pub const flag_left_justify : u32 = 0b00000000000001u32;
pub const flag_left_zero_pad : u32 = 0b00000000000010u32;
pub const flag_space_for_sign : u32 = 0b00000000000100u32;
pub const flag_sign_always : u32 = 0b00000000001000u32;
pub const flag_alternate : u32 = 0b00000000010000u32;

pub enum Count { CountIs(uint), CountImplied, }

pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, }

pub struct Conv {
flags: u32,
width: Count,
precision: Count,
ty: Ty,
}

pub pure fn conv_int(cv: Conv, i: int, buf: &mut ~str) {
let radix = 10;
let prec = get_int_precision(cv);
let mut s : ~str = uint_to_str_prec(int::abs(i) as uint, radix, prec);

let head = if i >= 0 {
if have_flag(cv.flags, flag_sign_always) {
Some('+')
} else if have_flag(cv.flags, flag_space_for_sign) {
Some(' ')
} else {
None
}
} else { Some('-') };
unsafe { pad(cv, s, head, PadSigned, buf) };
}
pub pure fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) {
let prec = get_int_precision(cv);
let mut rs =
match cv.ty {
TyDefault => uint_to_str_prec(u, 10, prec),
TyHexLower => uint_to_str_prec(u, 16, prec),
TyHexUpper => str::to_upper(uint_to_str_prec(u, 16, prec)),
TyBits => uint_to_str_prec(u, 2, prec),
TyOctal => uint_to_str_prec(u, 8, prec)
};
unsafe { pad(cv, rs, None, PadUnsigned, buf) };
}
pub pure fn conv_bool(cv: Conv, b: bool, buf: &mut ~str) {
let s = if b { "true" } else { "false" };
// run the boolean conversion through the string conversion logic,
// giving it the same rules for precision, etc.
conv_str(cv, s, buf);
}
pub pure fn conv_char(cv: Conv, c: char, buf: &mut ~str) {
unsafe { pad(cv, "", Some(c), PadNozero, buf) };
}
pub pure fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
// For strings, precision is the maximum characters
// displayed
let mut unpadded = match cv.precision {
CountImplied => s,
CountIs(max) => if (max as uint) < str::char_len(s) {
str::slice(s, 0, max as uint)
} else {
s
}
};
unsafe { pad(cv, unpadded, None, PadNozero, buf) };
}
pub pure fn conv_float(cv: Conv, f: float, buf: &mut ~str) {
let (to_str, digits) = match cv.precision {
CountIs(c) => (float::to_str_exact, c as uint),
CountImplied => (float::to_str_digits, 6u)
};
let mut s = unsafe { to_str(f, digits) };
let head = if 0.0 <= f {
if have_flag(cv.flags, flag_sign_always) {
Some('+')
} else if have_flag(cv.flags, flag_space_for_sign) {
Some(' ')
} else {
None
}
} else { None };
unsafe { pad(cv, s, head, PadFloat, buf) };
}
pub pure fn conv_poly<T>(cv: Conv, v: &T, buf: &mut ~str) {
let s = sys::log_str(v);
conv_str(cv, s, buf);
}

// Convert a uint to string with a minimum number of digits. If precision
// is 0 and num is 0 then the result is the empty string. Could move this
// to uint: but it doesn't seem all that useful.
pub pure fn uint_to_str_prec(num: uint, radix: uint,
prec: uint) -> ~str {
return if prec == 0u && num == 0u {
~""
} else {
let s = uint::to_str_radix(num, radix);
let len = str::char_len(s);
if len < prec {
let diff = prec - len;
let pad = str::from_chars(vec::from_elem(diff, '0'));
pad + s
} else { s }
};
}
pub pure fn get_int_precision(cv: Conv) -> uint {
return match cv.precision {
CountIs(c) => c as uint,
CountImplied => 1u
};
}

#[deriving(Eq)]
pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }

pub fn pad(cv: Conv, mut s: &str, head: Option<char>, mode: PadMode,
buf: &mut ~str) {
let headsize = match head { Some(_) => 1, _ => 0 };
let uwidth : uint = match cv.width {
CountImplied => {
for head.each |&c| {
buf.push_char(c);
}
return buf.push_str(s);
}
CountIs(width) => { width as uint }
};
let strlen = str::char_len(s) + headsize;
if uwidth <= strlen {
for head.each |&c| {
buf.push_char(c);
}
return buf.push_str(s);
}
let mut padchar = ' ';
let diff = uwidth - strlen;
if have_flag(cv.flags, flag_left_justify) {
for head.each |&c| {
buf.push_char(c);
}
buf.push_str(s);
for diff.times {
buf.push_char(padchar);
}
return;
}
let (might_zero_pad, signed) = match mode {
PadNozero => (false, true),
PadSigned => (true, true),
PadFloat => (true, true),
PadUnsigned => (true, false)
};
pure fn have_precision(cv: Conv) -> bool {
return match cv.precision { CountImplied => false, _ => true };
}
let zero_padding = {
if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
(!have_precision(cv) || mode == PadFloat) {
padchar = '0';
true
} else {
false
}
};
let padstr = str::from_chars(vec::from_elem(diff, padchar));
// This is completely heinous. If we have a signed value then
// potentially rip apart the intermediate result and insert some
// zeros. It may make sense to convert zero padding to a precision
// instead.

if signed && zero_padding {
for head.each |&head| {
if head == '+' || head == '-' || head == ' ' {
buf.push_char(head);
buf.push_str(padstr);
buf.push_str(s);
return;
}
}
}
buf.push_str(padstr);
for head.each |&c| {
buf.push_char(c);
}
buf.push_str(s);
}
#[inline(always)]
pub pure fn have_flag(flags: u32, f: u32) -> bool {
flags & f != 0
}
}

// XXX: remove after a snapshot of the above changes have gone in
#[cfg(stage0)]
#[doc(hidden)]
pub mod rt {
use float;
Expand Down
1 change: 0 additions & 1 deletion src/librustc/middle/typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ use core::prelude::*;
use middle::freevars::get_freevars;
use middle::pat_util::{pat_bindings, pat_is_binding};
use middle::ty::{encl_region, re_scope};
use middle::ty::{vstore_box, vstore_fixed, vstore_slice};
use middle::ty;
use middle::typeck::check::FnCtxt;
use middle::typeck::check::lookup_def;
Expand Down
2 changes: 0 additions & 2 deletions src/librustc/middle/typeck/check/regionmanip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ use util::ppaux::region_to_str;
use util::ppaux;

use std::list::Cons;
use syntax::ast;
use syntax::codemap;

// Helper functions related to manipulating region types.

Expand Down
1 change: 0 additions & 1 deletion src/librustc/middle/typeck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ independently:
use core::prelude::*;

use middle::resolve;
use middle::ty::{ty_param_substs_and_ty, vstore_uniq};
use middle::ty;
use util::common::time;
use util::ppaux;
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ pub fn mk_access(cx: @ext_ctxt, sp: span, +p: ~[ast::ident], m: ast::ident)
pub fn mk_addr_of(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
return mk_expr(cx, sp, ast::expr_addr_of(ast::m_imm, e));
}
pub fn mk_mut_addr_of(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
return mk_expr(cx, sp, ast::expr_addr_of(ast::m_mutbl, e));
}
pub fn mk_call_(cx: @ext_ctxt, sp: span, fn_expr: @ast::expr,
+args: ~[@ast::expr]) -> @ast::expr {
mk_expr(cx, sp, ast::expr_call(fn_expr, args, ast::NoSugar))
Expand Down
Loading