1
0
mirror of https://github.com/golang/go synced 2024-11-19 10:04:56 -07:00

fmt: unify integer formatting

Deduplicate the verb switch for signed and unsigned integer formatting.

Make names of integer related functions consistent
with names of other fmt functions.

Consolidate basic integer tests.

Change-Id: I0c19c24f1c2c06a3b1a4d7d377dcdac3b36bb0f5
Reviewed-on: https://go-review.googlesource.com/20831
Run-TryBot: Rob Pike <r@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
Martin Möhrmann 2016-03-18 08:24:40 +01:00 committed by Rob Pike
parent 3eaa304629
commit 8d9ece9dde
3 changed files with 97 additions and 135 deletions

View File

@ -48,11 +48,6 @@ func TestFmtInterface(t *testing.T) {
} }
} }
const (
b32 uint32 = 1<<32 - 1
b64 uint64 = 1<<64 - 1
)
var ( var (
NaN = math.NaN() NaN = math.NaN()
posInf = math.Inf(1) posInf = math.Inf(1)
@ -319,23 +314,47 @@ var fmtTests = []struct {
{"%-10v", nil, "<nil> "}, {"%-10v", nil, "<nil> "},
// integers // integers
{"%d", 12345, "12345"}, {"%d", uint(12345), "12345"},
{"%d", -12345, "-12345"}, {"%d", int(-12345), "-12345"},
{"%d", ^uint8(0), "255"},
{"%d", ^uint16(0), "65535"},
{"%d", ^uint32(0), "4294967295"},
{"%d", ^uint64(0), "18446744073709551615"},
{"%d", int8(-1 << 7), "-128"},
{"%d", int16(-1 << 15), "-32768"},
{"%d", int32(-1 << 31), "-2147483648"},
{"%d", int64(-1 << 63), "-9223372036854775808"},
{"%.d", 0, ""},
{"%.0d", 0, ""},
{"% d", 12345, " 12345"},
{"%+d", 12345, "+12345"},
{"%+d", -12345, "-12345"},
{"%b", 7, "111"},
{"%b", -6, "-110"},
{"%b", ^uint32(0), "11111111111111111111111111111111"},
{"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"},
{"%o", 01234, "1234"},
{"%#o", 01234, "01234"},
{"%o", ^uint32(0), "37777777777"},
{"%o", ^uint64(0), "1777777777777777777777"},
{"%#X", 0, "0X0"},
{"%x", 0x12abcdef, "12abcdef"},
{"%X", 0x12abcdef, "12ABCDEF"},
{"%x", ^uint32(0), "ffffffff"},
{"%X", ^uint64(0), "FFFFFFFFFFFFFFFF"},
{"%.20b", 7, "00000000000000000111"},
{"%10d", 12345, " 12345"}, {"%10d", 12345, " 12345"},
{"%10d", -12345, " -12345"}, {"%10d", -12345, " -12345"},
{"%+10d", 12345, " +12345"}, {"%+10d", 12345, " +12345"},
{"%010d", 12345, "0000012345"}, {"%010d", 12345, "0000012345"},
{"%010d", -12345, "-000012345"}, {"%010d", -12345, "-000012345"},
{"%-10d", 12345, "12345 "}, {"%20.8d", 1234, " 00001234"},
{"%010.3d", 1, " 001"}, {"%20.8d", -1234, " -00001234"},
{"%010.3d", -1, " -001"}, {"%-20.8d", 1234, "00001234 "},
{"%+d", 12345, "+12345"}, {"%-20.8d", -1234, "-00001234 "},
{"%+d", -12345, "-12345"}, {"%-#20.8x", 0x1234abc, "0x01234abc "},
{"%+d", 0, "+0"}, {"%-#20.8X", 0x1234abc, "0X01234ABC "},
{"% d", 0, " 0"}, {"%-#20.8o", 01234, "00001234 "},
{"% d", 12345, " 12345"},
{"%.0d", 0, ""},
{"%.d", 0, ""},
// unicode format // unicode format
{"%U", 0, "U+0000"}, {"%U", 0, "U+0000"},
@ -453,25 +472,6 @@ var fmtTests = []struct {
{"%-08G", complex(NaN, NaN), "(NaN +NaN i)"}, {"%-08G", complex(NaN, NaN), "(NaN +NaN i)"},
// old test/fmt_test.go // old test/fmt_test.go
{"%d", 1234, "1234"},
{"%d", -1234, "-1234"},
{"%d", uint(1234), "1234"},
{"%d", uint32(b32), "4294967295"},
{"%d", uint64(b64), "18446744073709551615"},
{"%o", 01234, "1234"},
{"%#o", 01234, "01234"},
{"%o", uint32(b32), "37777777777"},
{"%o", uint64(b64), "1777777777777777777777"},
{"%x", 0x1234abcd, "1234abcd"},
{"%#x", 0x1234abcd, "0x1234abcd"},
{"%x", b32 - 0x1234567, "fedcba98"},
{"%X", 0x1234abcd, "1234ABCD"},
{"%X", b32 - 0x1234567, "FEDCBA98"},
{"%#X", 0, "0X0"},
{"%x", b64, "ffffffffffffffff"},
{"%b", 7, "111"},
{"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
{"%b", -6, "-110"},
{"%e", 1.0, "1.000000e+00"}, {"%e", 1.0, "1.000000e+00"},
{"%e", 1234.5678e3, "1.234568e+06"}, {"%e", 1234.5678e3, "1.234568e+06"},
{"%e", 1234.5678e-8, "1.234568e-05"}, {"%e", 1234.5678e-8, "1.234568e-05"},
@ -498,15 +498,6 @@ var fmtTests = []struct {
{"%G", -7.0, "-7"}, {"%G", -7.0, "-7"},
{"%G", -1e-9, "-1E-09"}, {"%G", -1e-9, "-1E-09"},
{"%G", float32(-1e-9), "-1E-09"}, {"%G", float32(-1e-9), "-1E-09"},
{"%20.8d", 1234, " 00001234"},
{"%20.8d", -1234, " -00001234"},
{"%20d", 1234, " 1234"},
{"%-20.8d", 1234, "00001234 "},
{"%-20.8d", -1234, "-00001234 "},
{"%-#20.8x", 0x1234abc, "0x01234abc "},
{"%-#20.8X", 0x1234abc, "0X01234ABC "},
{"%-#20.8o", 01234, "00001234 "},
{"%.20b", 7, "00000000000000000111"},
{"%20.5s", "qwertyuiop", " qwert"}, {"%20.5s", "qwertyuiop", " qwert"},
{"%.5s", "qwertyuiop", "qwert"}, {"%.5s", "qwertyuiop", "qwert"},
{"%-20.5s", "qwertyuiop", "qwert "}, {"%-20.5s", "qwertyuiop", "qwert "},
@ -822,11 +813,11 @@ var fmtTests = []struct {
{"%0.100f", -1.0, zeroFill("-1.", 100, "")}, {"%0.100f", -1.0, zeroFill("-1.", 100, "")},
// Used to panic: integer function didn't look at f.prec, f.unicode, f.width or sign. // Used to panic: integer function didn't look at f.prec, f.unicode, f.width or sign.
{"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"}, {"%#.65x", 42, zeroFill("0x", 65, "2a")},
{"%.65d", -44, "-00000000000000000000000000000000000000000000000000000000000000044"}, {"%.65d", -42, zeroFill("-", 65, "42")},
{"%+.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"}, {"%+.65d", 42, zeroFill("+", 65, "42")},
{"% .65d", 44, " 00000000000000000000000000000000000000000000000000000000000000044"}, {"% .65d", 42, zeroFill(" ", 65, "42")},
{"% +.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"}, {"% +.65d", 42, zeroFill("+", 65, "42")},
// Comparison of padding rules with C printf. // Comparison of padding rules with C printf.
/* /*

View File

@ -190,17 +190,16 @@ func (f *fmt) fmt_unicode(u uint64) {
f.zero = oldZero f.zero = oldZero
} }
// integer; interprets prec but not wid. Once formatted, result is sent to pad() // fmt_integer formats signed and unsigned integers.
// and then flags are cleared. func (f *fmt) fmt_integer(u uint64, base int, isSigned bool, digits string) {
func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
// precision of 0 and value of 0 means "print nothing" // precision of 0 and value of 0 means "print nothing"
if f.precPresent && f.prec == 0 && a == 0 { if f.precPresent && f.prec == 0 && u == 0 {
return return
} }
negative := signedness == signed && a < 0 negative := isSigned && int64(u) < 0
if negative { if negative {
a = -a u = -u
} }
var buf []byte = f.intbuf[0:] var buf []byte = f.intbuf[0:]
@ -233,45 +232,43 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
} }
} }
// format a into buf, ending at buf[i]. (printing is easier right-to-left.) // Because printing is easier right-to-left: format u into buf, ending at buf[i].
// a is made into unsigned ua. we could make things // We could make things marginally faster by splitting the 32-bit case out
// marginally faster by splitting the 32-bit case out into a separate // into a separate block but it's not worth the duplication, so u has 64 bits.
// block but it's not worth the duplication, so ua has 64 bits.
i := len(buf) i := len(buf)
ua := uint64(a) // Use constants for the division and modulo for more efficient code.
// use constants for the division and modulo for more efficient code. // Switch cases ordered by popularity.
// switch cases ordered by popularity.
switch base { switch base {
case 10: case 10:
for ua >= 10 { for u >= 10 {
i-- i--
next := ua / 10 next := u / 10
buf[i] = byte('0' + ua - next*10) buf[i] = byte('0' + u - next*10)
ua = next u = next
} }
case 16: case 16:
for ua >= 16 { for u >= 16 {
i-- i--
buf[i] = digits[ua&0xF] buf[i] = digits[u&0xF]
ua >>= 4 u >>= 4
} }
case 8: case 8:
for ua >= 8 { for u >= 8 {
i-- i--
buf[i] = byte('0' + ua&7) buf[i] = byte('0' + u&7)
ua >>= 3 u >>= 3
} }
case 2: case 2:
for ua >= 2 { for u >= 2 {
i-- i--
buf[i] = byte('0' + ua&1) buf[i] = byte('0' + u&1)
ua >>= 1 u >>= 1
} }
default: default:
panic("fmt: unknown base; can't happen") panic("fmt: unknown base; can't happen")
} }
i-- i--
buf[i] = digits[ua] buf[i] = digits[u]
for i > 0 && prec > len(buf)-i { for i > 0 && prec > len(buf)-i {
i-- i--
buf[i] = '0' buf[i] = '0'

View File

@ -338,68 +338,42 @@ func (p *pp) fmtBool(v bool, verb rune) {
} }
} }
func (p *pp) fmtInt64(v int64, verb rune) {
switch verb {
case 'b':
p.fmt.integer(v, 2, signed, ldigits)
case 'c':
p.fmt.fmt_c(uint64(v))
case 'd', 'v':
p.fmt.integer(v, 10, signed, ldigits)
case 'o':
p.fmt.integer(v, 8, signed, ldigits)
case 'q':
if 0 <= v && v <= utf8.MaxRune {
p.fmt.fmt_qc(uint64(v))
} else {
p.badVerb(verb)
}
case 'x':
p.fmt.integer(v, 16, signed, ldigits)
case 'U':
p.fmt.fmt_unicode(uint64(v))
case 'X':
p.fmt.integer(v, 16, signed, udigits)
default:
p.badVerb(verb)
}
}
// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or // fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
// not, as requested, by temporarily setting the sharp flag. // not, as requested, by temporarily setting the sharp flag.
func (p *pp) fmt0x64(v uint64, leading0x bool) { func (p *pp) fmt0x64(v uint64, leading0x bool) {
sharp := p.fmt.sharp sharp := p.fmt.sharp
p.fmt.sharp = leading0x p.fmt.sharp = leading0x
p.fmt.integer(int64(v), 16, unsigned, ldigits) p.fmt.fmt_integer(v, 16, unsigned, ldigits)
p.fmt.sharp = sharp p.fmt.sharp = sharp
} }
func (p *pp) fmtUint64(v uint64, verb rune) { // fmtInteger formats a signed or unsigned integer.
func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune) {
switch verb { switch verb {
case 'b':
p.fmt.integer(int64(v), 2, unsigned, ldigits)
case 'c':
p.fmt.fmt_c(v)
case 'd':
p.fmt.integer(int64(v), 10, unsigned, ldigits)
case 'v': case 'v':
if p.fmt.sharpV { if p.fmt.sharpV && !isSigned {
p.fmt0x64(v, true) p.fmt0x64(v, true)
} else { } else {
p.fmt.integer(int64(v), 10, unsigned, ldigits) p.fmt.fmt_integer(v, 10, isSigned, ldigits)
} }
case 'd':
p.fmt.fmt_integer(v, 10, isSigned, ldigits)
case 'b':
p.fmt.fmt_integer(v, 2, isSigned, ldigits)
case 'o': case 'o':
p.fmt.integer(int64(v), 8, unsigned, ldigits) p.fmt.fmt_integer(v, 8, isSigned, ldigits)
case 'x':
p.fmt.fmt_integer(v, 16, isSigned, ldigits)
case 'X':
p.fmt.fmt_integer(v, 16, isSigned, udigits)
case 'c':
p.fmt.fmt_c(v)
case 'q': case 'q':
if 0 <= v && v <= utf8.MaxRune { if v <= utf8.MaxRune {
p.fmt.fmt_qc(v) p.fmt.fmt_qc(v)
} else { } else {
p.badVerb(verb) p.badVerb(verb)
} }
case 'x':
p.fmt.integer(int64(v), 16, unsigned, ldigits)
case 'X':
p.fmt.integer(int64(v), 16, unsigned, udigits)
case 'U': case 'U':
p.fmt.fmt_unicode(v) p.fmt.fmt_unicode(v)
default: default:
@ -489,7 +463,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, typeString string) {
if i > 0 { if i > 0 {
p.buf.WriteByte(' ') p.buf.WriteByte(' ')
} }
p.fmt.integer(int64(c), 10, unsigned, ldigits) p.fmt.fmt_integer(uint64(c), 10, unsigned, ldigits)
} }
p.buf.WriteByte(']') p.buf.WriteByte(']')
} }
@ -538,7 +512,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune) {
case 'p': case 'p':
p.fmt0x64(uint64(u), !p.fmt.sharp) p.fmt0x64(uint64(u), !p.fmt.sharp)
case 'b', 'o', 'd', 'x', 'X': case 'b', 'o', 'd', 'x', 'X':
p.fmtUint64(uint64(u), verb) p.fmtInteger(uint64(u), unsigned, verb)
default: default:
p.badVerb(verb) p.badVerb(verb)
} }
@ -657,27 +631,27 @@ func (p *pp) printArg(arg interface{}, verb rune) {
case complex128: case complex128:
p.fmtComplex(f, 128, verb) p.fmtComplex(f, 128, verb)
case int: case int:
p.fmtInt64(int64(f), verb) p.fmtInteger(uint64(f), signed, verb)
case int8: case int8:
p.fmtInt64(int64(f), verb) p.fmtInteger(uint64(f), signed, verb)
case int16: case int16:
p.fmtInt64(int64(f), verb) p.fmtInteger(uint64(f), signed, verb)
case int32: case int32:
p.fmtInt64(int64(f), verb) p.fmtInteger(uint64(f), signed, verb)
case int64: case int64:
p.fmtInt64(f, verb) p.fmtInteger(uint64(f), signed, verb)
case uint: case uint:
p.fmtUint64(uint64(f), verb) p.fmtInteger(uint64(f), unsigned, verb)
case uint8: case uint8:
p.fmtUint64(uint64(f), verb) p.fmtInteger(uint64(f), unsigned, verb)
case uint16: case uint16:
p.fmtUint64(uint64(f), verb) p.fmtInteger(uint64(f), unsigned, verb)
case uint32: case uint32:
p.fmtUint64(uint64(f), verb) p.fmtInteger(uint64(f), unsigned, verb)
case uint64: case uint64:
p.fmtUint64(f, verb) p.fmtInteger(f, unsigned, verb)
case uintptr: case uintptr:
p.fmtUint64(uint64(f), verb) p.fmtInteger(uint64(f), unsigned, verb)
case string: case string:
p.fmtString(f, verb) p.fmtString(f, verb)
case []byte: case []byte:
@ -737,9 +711,9 @@ BigSwitch:
case reflect.Bool: case reflect.Bool:
p.fmtBool(f.Bool(), verb) p.fmtBool(f.Bool(), verb)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p.fmtInt64(f.Int(), verb) p.fmtInteger(uint64(f.Int()), signed, verb)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p.fmtUint64(f.Uint(), verb) p.fmtInteger(f.Uint(), unsigned, verb)
case reflect.Float32: case reflect.Float32:
p.fmtFloat(f.Float(), 32, verb) p.fmtFloat(f.Float(), 32, verb)
case reflect.Float64: case reflect.Float64: