1
Fork 0

Correct the padding on integer types for formatting

This commit is contained in:
Alex Crichton 2013-08-10 16:50:42 -07:00
parent 6feb58ed84
commit 1f6afa887b
5 changed files with 133 additions and 113 deletions

View file

@ -32,7 +32,7 @@ pub struct Formatter<'self> {
/// Character used as 'fill' whenever there is alignment
fill: char,
/// Boolean indication of whether the output should be left-aligned
alignleft: bool,
align: parse::Alignment,
/// Optionally specified integer width that the output should be
width: Option<uint>,
/// Optionally specified precision for numeric types
@ -108,7 +108,7 @@ pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
precision: None,
// FIXME(#8248): shouldn't need a transmute
buf: cast::transmute(&output as &io::Writer),
alignleft: false,
align: parse::AlignUnknown,
fill: ' ',
args: args,
curarg: args.iter(),
@ -148,7 +148,7 @@ impl<'self> Formatter<'self> {
rt::Argument(ref arg) => {
// Fill in the format parameters into the formatter
self.fill = arg.format.fill;
self.alignleft = arg.format.alignleft;
self.align = arg.format.align;
self.flags = arg.format.flags;
setcount(&mut self.width, &arg.format.width);
setcount(&mut self.precision, &arg.format.precision);
@ -251,7 +251,7 @@ impl<'self> Formatter<'self> {
/// TODO: dox
pub fn pad_integral(&mut self, s: &[u8], alternate_prefix: &str,
positive: bool) {
use fmt::parse::{FlagAlternate, FlagSignPlus};
use fmt::parse::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
let mut actual_len = s.len();
if self.flags & 1 << (FlagAlternate as uint) != 0 {
@ -259,20 +259,27 @@ impl<'self> Formatter<'self> {
}
if self.flags & 1 << (FlagSignPlus as uint) != 0 {
actual_len += 1;
}
if !positive {
} else if !positive {
actual_len += 1;
}
let mut signprinted = false;
let sign = |this: &mut Formatter| {
if !signprinted {
if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive {
this.buf.write(['+' as u8]);
} else if !positive {
this.buf.write(['-' as u8]);
}
if this.flags & 1 << (FlagAlternate as uint) != 0 {
this.buf.write(alternate_prefix.as_bytes());
}
signprinted = true;
}
};
let emit = |this: &mut Formatter| {
if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive {
this.buf.write(['+' as u8]);
} else if !positive {
this.buf.write(['-' as u8]);
}
if this.flags & 1 << (FlagAlternate as uint) != 0 {
this.buf.write(alternate_prefix.as_bytes());
}
sign(this);
this.buf.write(s);
};
@ -280,7 +287,11 @@ impl<'self> Formatter<'self> {
None => { emit(self) }
Some(min) if actual_len >= min => { emit(self) }
Some(min) => {
do self.with_padding(min - actual_len) |me| {
if self.flags & 1 << (FlagSignAwareZeroPad as uint) != 0 {
self.fill = '0';
sign(self);
}
do self.with_padding(min - actual_len, parse::AlignRight) |me| {
emit(me);
}
}
@ -292,8 +303,8 @@ impl<'self> Formatter<'self> {
/// recognized for generic strings are:
///
/// * width - the minimum width of what to emit
/// * fill/alignleft - what to emit and where to emit it if the string
/// provided needs to be padded
/// * fill/align - what to emit and where to emit it if the string
/// provided needs to be padded
/// * precision - the maximum length to emit, the string is truncated if it
/// is longer than this length
///
@ -336,15 +347,20 @@ impl<'self> Formatter<'self> {
// 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) => {
do self.with_padding(width - s.len()) |me| {
do self.with_padding(width - s.len(), parse::AlignLeft) |me| {
me.buf.write(s.as_bytes());
}
}
}
}
fn with_padding(&mut self, padding: uint, f: &fn(&mut Formatter)) {
if self.alignleft {
fn with_padding(&mut self, padding: uint,
default: parse::Alignment, f: &fn(&mut Formatter)) {
let align = match self.align {
parse::AlignUnknown => default,
parse::AlignLeft | parse::AlignRight => self.align
};
if align == parse::AlignLeft {
f(self);
}
let mut fill = [0u8, ..4];
@ -352,7 +368,7 @@ impl<'self> Formatter<'self> {
for _ in range(0, padding) {
self.buf.write(fill.slice_to(len));
}
if !self.alignleft {
if align == parse::AlignRight {
f(self);
}
}
@ -427,7 +443,6 @@ macro_rules! upper_hex(($ty:ident, $into:ident) => {
}
}
})
// Not sure why, but this causes an "unresolved enum variant, struct or const"
// when inlined into the above macro...
#[doc(hidden)]
@ -500,9 +515,10 @@ impl<T> Poly for T {
// time.
impl<T> Pointer for *const T {
fn fmt(t: &*const T, f: &mut Formatter) {
// XXX: formatting args
f.buf.write("0x".as_bytes());
LowerHex::fmt(&(*t as uint), f);
f.flags |= 1 << (parse::FlagAlternate as uint);
do ::uint::to_str_bytes(*t as uint, 16) |buf| {
f.pad_integral(buf, "0x", true);
}
}
}

View file

@ -47,7 +47,7 @@ pub struct FormatSpec<'self> {
/// Optionally specified character to fill alignment with
fill: Option<char>,
/// Optionally specified alignment
align: Option<Alignment>,
align: Alignment,
/// Packed version of various flags provided
flags: uint,
/// The integer precision to use
@ -68,7 +68,7 @@ pub enum Position<'self> {
/// Enum of alignments which are supoprted.
#[deriving(Eq)]
pub enum Alignment { AlignLeft, AlignRight }
pub enum Alignment { AlignLeft, AlignRight, AlignUnknown }
/// Various flags which can be applied to format strings, the meaning of these
/// flags is defined by the formatters themselves.
@ -77,6 +77,7 @@ pub enum Flag {
FlagSignPlus,
FlagSignMinus,
FlagAlternate,
FlagSignAwareZeroPad,
}
/// A count is used for the precision and width parameters of an integer, and
@ -288,7 +289,7 @@ impl<'self> Parser<'self> {
fn format(&mut self) -> FormatSpec<'self> {
let mut spec = FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: 0,
precision: CountImplied,
width: CountImplied,
@ -311,9 +312,9 @@ impl<'self> Parser<'self> {
}
// Alignment
if self.consume('<') {
spec.align = Some(AlignLeft);
spec.align = AlignLeft;
} else if self.consume('>') {
spec.align = Some(AlignRight);
spec.align = AlignRight;
}
// Sign flags
if self.consume('+') {
@ -326,6 +327,9 @@ impl<'self> Parser<'self> {
spec.flags |= 1 << (FlagAlternate as uint);
}
// Width and precision
if self.consume('0') {
spec.flags |= 1 << (FlagSignAwareZeroPad as uint);
}
spec.width = self.count();
if self.consume('.') {
if self.consume('*') {
@ -597,7 +601,7 @@ mod tests {
fn fmtdflt() -> FormatSpec<'static> {
return FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: 0,
precision: CountImplied,
width: CountImplied,
@ -656,7 +660,7 @@ mod tests {
position: ArgumentIs(3),
format: FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: 0,
precision: CountImplied,
width: CountImplied,
@ -671,7 +675,7 @@ mod tests {
position: ArgumentIs(3),
format: FormatSpec {
fill: None,
align: Some(AlignRight),
align: AlignRight,
flags: 0,
precision: CountImplied,
width: CountImplied,
@ -683,7 +687,7 @@ mod tests {
position: ArgumentIs(3),
format: FormatSpec {
fill: Some('0'),
align: Some(AlignLeft),
align: AlignLeft,
flags: 0,
precision: CountImplied,
width: CountImplied,
@ -695,7 +699,7 @@ mod tests {
position: ArgumentIs(3),
format: FormatSpec {
fill: Some('*'),
align: Some(AlignLeft),
align: AlignLeft,
flags: 0,
precision: CountImplied,
width: CountImplied,
@ -710,7 +714,7 @@ mod tests {
position: ArgumentNext,
format: FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: 0,
precision: CountImplied,
width: CountIs(10),
@ -722,7 +726,7 @@ mod tests {
position: ArgumentNext,
format: FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: 0,
precision: CountIs(10),
width: CountIsParam(10),
@ -734,7 +738,7 @@ mod tests {
position: ArgumentNext,
format: FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: 0,
precision: CountIsNextParam,
width: CountImplied,
@ -746,7 +750,7 @@ mod tests {
position: ArgumentNext,
format: FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: 0,
precision: CountIsParam(10),
width: CountImplied,
@ -761,7 +765,7 @@ mod tests {
position: ArgumentNext,
format: FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: (1 << FlagSignMinus as uint),
precision: CountImplied,
width: CountImplied,
@ -773,7 +777,7 @@ mod tests {
position: ArgumentNext,
format: FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: (1 << FlagSignPlus as uint) | (1 << FlagAlternate as uint),
precision: CountImplied,
width: CountImplied,
@ -788,7 +792,7 @@ mod tests {
position: ArgumentIs(3),
format: FormatSpec {
fill: None,
align: None,
align: AlignUnknown,
flags: 0,
precision: CountImplied,
width: CountImplied,

View file

@ -36,7 +36,7 @@ pub struct Argument<'self> {
pub struct FormatSpec {
fill: char,
alignleft: bool,
align: parse::Alignment,
flags: uint,
precision: parse::Count,
width: parse::Count,

View file

@ -317,6 +317,10 @@ impl Context {
/// Translate a `parse::Piece` to a static `rt::Piece`
fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::expr {
let sp = self.fmtsp;
let parsepath = |s: &str| {
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
};
let rtpath = |s: &str| {
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
@ -482,20 +486,24 @@ impl Context {
let fill = self.ecx.expr_lit(sp, ast::lit_int(fill as i64,
ast::ty_char));
let align = match arg.format.align {
None | Some(parse::AlignLeft) => {
self.ecx.expr_bool(sp, true)
parse::AlignLeft => {
self.ecx.path_global(sp, parsepath("AlignLeft"))
}
Some(parse::AlignRight) => {
self.ecx.expr_bool(sp, false)
parse::AlignRight => {
self.ecx.path_global(sp, parsepath("AlignRight"))
}
parse::AlignUnknown => {
self.ecx.path_global(sp, parsepath("AlignUnknown"))
}
};
let align = self.ecx.expr_path(align);
let flags = self.ecx.expr_uint(sp, arg.format.flags);
let prec = trans_count(arg.format.precision);
let width = trans_count(arg.format.width);
let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
let fmt = self.ecx.expr_struct(sp, path, ~[
self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
self.ecx.field_imm(sp, self.ecx.ident_of("alignleft"), align),
self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),

View file

@ -95,36 +95,36 @@ pub fn main() {
// type of the argument. Also, hex/octal/binary should be defined for
// integers, but they shouldn't emit the negative sign.
t!(ifmt!("{:d}", -1i), "-1");
t!(ifmt!("{:d}", -1i8), "1");
t!(ifmt!("{:d}", -1i16), "1");
t!(ifmt!("{:d}", -1i32), "1");
t!(ifmt!("{:d}", -1i64), "1");
t!(ifmt!("{:t}", -1i), "1");
t!(ifmt!("{:t}", -1i8), "1");
t!(ifmt!("{:t}", -1i16), "1");
t!(ifmt!("{:t}", -1i32), "1");
t!(ifmt!("{:t}", -1i64), "1");
t!(ifmt!("{:x}", -1i), "1");
t!(ifmt!("{:x}", -1i8), "1");
t!(ifmt!("{:x}", -1i16), "1");
t!(ifmt!("{:x}", -1i32), "1");
t!(ifmt!("{:x}", -1i64), "1");
t!(ifmt!("{:X}", -1i), "1");
t!(ifmt!("{:X}", -1i8), "1");
t!(ifmt!("{:X}", -1i16), "1");
t!(ifmt!("{:X}", -1i32), "1");
t!(ifmt!("{:X}", -1i64), "1");
t!(ifmt!("{:o}", -1i), "1");
t!(ifmt!("{:o}", -1i8), "1");
t!(ifmt!("{:o}", -1i16), "1");
t!(ifmt!("{:o}", -1i32), "1");
t!(ifmt!("{:o}", -1i64), "1");
t!(ifmt!("{:d}", -1i8), "-1");
t!(ifmt!("{:d}", -1i16), "-1");
t!(ifmt!("{:d}", -1i32), "-1");
t!(ifmt!("{:d}", -1i64), "-1");
t!(ifmt!("{:t}", 1i), "1");
t!(ifmt!("{:t}", 1i8), "1");
t!(ifmt!("{:t}", 1i16), "1");
t!(ifmt!("{:t}", 1i32), "1");
t!(ifmt!("{:t}", 1i64), "1");
t!(ifmt!("{:x}", 1i), "1");
t!(ifmt!("{:x}", 1i8), "1");
t!(ifmt!("{:x}", 1i16), "1");
t!(ifmt!("{:x}", 1i32), "1");
t!(ifmt!("{:x}", 1i64), "1");
t!(ifmt!("{:X}", 1i), "1");
t!(ifmt!("{:X}", 1i8), "1");
t!(ifmt!("{:X}", 1i16), "1");
t!(ifmt!("{:X}", 1i32), "1");
t!(ifmt!("{:X}", 1i64), "1");
t!(ifmt!("{:o}", 1i), "1");
t!(ifmt!("{:o}", 1i8), "1");
t!(ifmt!("{:o}", 1i16), "1");
t!(ifmt!("{:o}", 1i32), "1");
t!(ifmt!("{:o}", 1i64), "1");
t!(ifmt!("{:d}", 1u), "1");
t!(ifmt!("{:d}", 1u8), "1");
t!(ifmt!("{:d}", 1u16), "1");
t!(ifmt!("{:d}", 1u32), "1");
t!(ifmt!("{:d}", 1u64), "1");
t!(ifmt!("{:u}", 1u), "1");
t!(ifmt!("{:u}", 1u8), "1");
t!(ifmt!("{:u}", 1u16), "1");
t!(ifmt!("{:u}", 1u32), "1");
t!(ifmt!("{:u}", 1u64), "1");
t!(ifmt!("{:t}", 1u), "1");
t!(ifmt!("{:t}", 1u8), "1");
t!(ifmt!("{:t}", 1u16), "1");
@ -147,44 +147,36 @@ pub fn main() {
t!(ifmt!("{:o}", 1u64), "1");
// Test the flags for formatting integers
t!(ifmt!("{:3d}", 1), "1 ");
t!(ifmt!("{:>3d}", 1), " 1");
t!(ifmt!("{:3d}", 1), " 1");
t!(ifmt!("{:>3d}", 1), " 1");
t!(ifmt!("{:>+3d}", 1), " +1");
t!(ifmt!("{:<3d}", 1), "1 ");
t!(ifmt!("{:#d}", 1), "1");
t!(ifmt!("{:#x}", 10u), "0xa");
t!(ifmt!("{:#X}", 10u), "0xA");
t!(ifmt!("{:#5x}", 10u), "0xa ");
t!(ifmt!("{:#o}", 10u), "0o12");
// Precision overrides 0-padding
// FIXME #2481: Recent gcc's report some of these as warnings
/*t!(ifmt!("{:0>6.5d}", 0), ~" 00000");*/
/*t!(ifmt!("{:0>6.5u}", 0u), ~" 00000");*/
/*t!(ifmt!("{:0>6.5x}", 0u), ~" 00000");*/
/*t!(ifmt!("{:0>6.5d}", 10), ~" 00010");*/
/*t!(ifmt!("{:0>6.5d}", -10), ~"-00010");*/
/*t!(ifmt!("{:0>6.5u}", 10u), ~" 00010");*/
/*t!(ifmt!("{:0>6.5s}", ~"t!"), ~" t!");*/
/*t!(ifmt!("{:0>6.5c}", 'A'), ~" A");*/
/*t!(ifmt!("{:0>6.5x}", 127u), ~" 0007f");*/
/*t!(ifmt!("{:0>6.5X}", 127u), ~" 0007F");*/
/*t!(ifmt!("{:0>6.5o}", 10u), ~" 00012");*/
t!(ifmt!("{:#x}", 10), "0xa");
t!(ifmt!("{:#X}", 10), "0xA");
t!(ifmt!("{:#5x}", 10), " 0xa");
t!(ifmt!("{:#o}", 10), "0o12");
t!(ifmt!("{:08x}", 10), "0000000a");
t!(ifmt!("{:8x}", 10), " a");
t!(ifmt!("{:<8x}", 10), "a ");
t!(ifmt!("{:>8x}", 10), " a");
t!(ifmt!("{:#08x}", 10), "0x00000a");
t!(ifmt!("{:08d}", -10), "-0000010");
t!(ifmt!("{:x}", -1u8), "ff");
t!(ifmt!("{:X}", -1u8), "FF");
t!(ifmt!("{:t}", -1u8), "11111111");
t!(ifmt!("{:o}", -1u8), "377");
t!(ifmt!("{:#x}", -1u8), "0xff");
t!(ifmt!("{:#X}", -1u8), "0xFF");
t!(ifmt!("{:#t}", -1u8), "0b11111111");
t!(ifmt!("{:#o}", -1u8), "0o377");
// Signed combinations
/*t!(ifmt!("{:5d}", 1), ~" 1");*/
/*t!(ifmt!("{: >5d}", -1), ~" -1");*/
/*t!(ifmt!("{:+5d}", 1), ~" +1");*/
/*t!(ifmt!("{:+5d}", -1), ~" -1");*/
/*t!(ifmt!("{:0>5d}", 1), ~" 0001");*/
/*t!(ifmt!("{:0>5d}", -1), ~"-0001");*/
/*t!(ifmt!("{:0>+5d}", 1), ~"+0001");*/
/*t!(ifmt!("{:0>+5d}", -1), ~"-0001");*/
/*t!(ifmt!("%- 5d", 1), ~" 1 ");*/
/*t!(ifmt!("%- 5d", -1), ~"-1 ");*/
/*t!(ifmt!("%-+5d", 1), ~"+1 ");*/
/*t!(ifmt!("%-+5d", -1), ~"-1 ");*/
/*t!(ifmt!("%- 05d", 1), ~" 1 ");*/
/*t!(ifmt!("%- 05d", -1), ~"-1 ");*/
/*t!(ifmt!("%-+05d", 1), ~"+1 ");*/
/*t!(ifmt!("%-+05d", -1), ~"-1 ");*/
t!(ifmt!("{:+5d}", 1), ~" +1");
t!(ifmt!("{:+5d}", -1), ~" -1");
t!(ifmt!("{:05d}", 1), ~"00001");
t!(ifmt!("{:05d}", -1), ~"-0001");
t!(ifmt!("{:+05d}", 1), ~"+0001");
t!(ifmt!("{:+05d}", -1), ~"-0001");
}