aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/fmt
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2016-07-22 18:15:38 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2016-07-22 18:15:38 +0000
commit22b955cca564a9a3a5b8c9d9dd1e295b7943c128 (patch)
treeabdbd898676e1f853fca2d7e031d105d7ebcf676 /libgo/go/fmt
parent9d04a3af4c6491536badf6bde9707c907e4d196b (diff)
downloadgcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.zip
gcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.tar.gz
gcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.tar.bz2
libgo: update to go1.7rc3
Reviewed-on: https://go-review.googlesource.com/25150 From-SVN: r238662
Diffstat (limited to 'libgo/go/fmt')
-rw-r--r--libgo/go/fmt/doc.go12
-rw-r--r--libgo/go/fmt/export_test.go2
-rw-r--r--libgo/go/fmt/fmt_test.go781
-rw-r--r--libgo/go/fmt/format.go593
-rw-r--r--libgo/go/fmt/print.go852
-rw-r--r--libgo/go/fmt/scan.go152
-rw-r--r--libgo/go/fmt/scan_test.go127
7 files changed, 1330 insertions, 1189 deletions
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go
index 4eea48e..c312914 100644
--- a/libgo/go/fmt/doc.go
+++ b/libgo/go/fmt/doc.go
@@ -62,7 +62,7 @@
For compound objects, the elements are printed using these rules, recursively,
laid out like this:
struct: {field0 field1 ...}
- array, slice: [elem0 elem1 ...]
+ array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2]
pointer to above: &{}, &[], &map[]
@@ -95,10 +95,10 @@
For floating-point values, width sets the minimum width of the field and
precision sets the number of places after the decimal, if appropriate,
- except that for %g/%G it sets the total number of digits. For example,
- given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
- The default precision for %e and %f is 6; for %g it is the smallest
- number of digits necessary to identify the value uniquely.
+ except that for %g/%G precision sets the total number of significant
+ digits. For example, given 12.345 the format %6.3f prints 12.345 while
+ %.3g prints 12.3. The default precision for %e and %f is 6; for %g it
+ is the smallest number of digits necessary to identify the value uniquely.
For complex numbers, the width and precision apply to the two
components independently and the result is parenthesized, so %f applied
@@ -210,7 +210,7 @@
Too many arguments: %!(EXTRA type=value)
Printf("hi", "guys"): hi%!(EXTRA string=guys)
Too few arguments: %!verb(MISSING)
- Printf("hi%d"): hi %!d(MISSING)
+ Printf("hi%d"): hi%!d(MISSING)
Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi
Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
diff --git a/libgo/go/fmt/export_test.go b/libgo/go/fmt/export_test.go
index 89d57ee..12d5a11 100644
--- a/libgo/go/fmt/export_test.go
+++ b/libgo/go/fmt/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index ea6392f..b658236 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -48,13 +48,18 @@ func TestFmtInterface(t *testing.T) {
}
}
-const b32 uint32 = 1<<32 - 1
-const b64 uint64 = 1<<64 - 1
+var (
+ NaN = math.NaN()
+ posInf = math.Inf(1)
+ negInf = math.Inf(-1)
-var array = [5]int{1, 2, 3, 4, 5}
-var iarray = [4]interface{}{1, "hello", 2.5, nil}
-var slice = array[:]
-var islice = iarray[:]
+ intVar = 0
+
+ array = [5]int{1, 2, 3, 4, 5}
+ iarray = [4]interface{}{1, "hello", 2.5, nil}
+ slice = array[:]
+ islice = iarray[:]
+)
type A struct {
i int
@@ -112,9 +117,11 @@ var bslice = barray[:]
type byteStringer byte
-func (byteStringer) String() string { return "X" }
+func (byteStringer) String() string {
+ return "X"
+}
-var byteStringerSlice = []byteStringer{97, 98, 99, 100}
+var byteStringerSlice = []byteStringer{'h', 'e', 'l', 'l', 'o'}
type byteFormatter byte
@@ -122,9 +129,7 @@ func (byteFormatter) Format(f State, _ rune) {
Fprint(f, "X")
}
-var byteFormatterSlice = []byteFormatter{97, 98, 99, 100}
-
-var b byte
+var byteFormatterSlice = []byteFormatter{'h', 'e', 'l', 'l', 'o'}
var fmtTests = []struct {
fmt string
@@ -141,6 +146,10 @@ var fmtTests = []struct {
{"%x", "abc", "616263"},
{"%x", "\xff\xf0\x0f\xff", "fff00fff"},
{"%X", "\xff\xf0\x0f\xff", "FFF00FFF"},
+ {"%x", "", ""},
+ {"% x", "", ""},
+ {"%#x", "", ""},
+ {"%# x", "", ""},
{"%x", "xyz", "78797a"},
{"%X", "xyz", "78797A"},
{"% x", "xyz", "78 79 7a"},
@@ -152,10 +161,16 @@ var fmtTests = []struct {
// basic bytes
{"%s", []byte("abc"), "abc"},
+ {"%s", [3]byte{'a', 'b', 'c'}, "abc"},
+ {"%s", &[3]byte{'a', 'b', 'c'}, "&abc"},
{"%q", []byte("abc"), `"abc"`},
{"%x", []byte("abc"), "616263"},
{"%x", []byte("\xff\xf0\x0f\xff"), "fff00fff"},
{"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"},
+ {"%x", []byte(""), ""},
+ {"% x", []byte(""), ""},
+ {"%#x", []byte(""), ""},
+ {"%# x", []byte(""), ""},
{"%x", []byte("xyz"), "78797a"},
{"%X", []byte("xyz"), "78797A"},
{"% x", []byte("xyz"), "78 79 7a"},
@@ -166,29 +181,112 @@ var fmtTests = []struct {
{"%# X", []byte("xyz"), "0X78 0X79 0X7A"},
// escaped strings
- {"%#q", `abc`, "`abc`"},
- {"%#q", `"`, "`\"`"},
- {"1 %#q", `\n`, "1 `\\n`"},
- {"2 %#q", "\n", `2 "\n"`},
- {"%q", `"`, `"\""`},
- {"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+ {"%q", "", `""`},
+ {"%#q", "", "``"},
+ {"%q", "\"", `"\""`},
+ {"%#q", "\"", "`\"`"},
+ {"%q", "`", `"` + "`" + `"`},
+ {"%#q", "`", `"` + "`" + `"`},
+ {"%q", "\n", `"\n"`},
+ {"%#q", "\n", `"\n"`},
+ {"%q", `\n`, `"\\n"`},
+ {"%#q", `\n`, "`\\n`"},
+ {"%q", "abc", `"abc"`},
+ {"%#q", "abc", "`abc`"},
+ {"%q", "日本語", `"日本語"`},
+ {"%+q", "日本語", `"\u65e5\u672c\u8a9e"`},
+ {"%#q", "日本語", "`日本語`"},
+ {"%#+q", "日本語", "`日本語`"},
+ {"%q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+ {"%+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+ {"%#q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+ {"%#+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+ {"%q", "☺", `"☺"`},
+ {"% q", "☺", `"☺"`}, // The space modifier should have no effect.
+ {"%+q", "☺", `"\u263a"`},
+ {"%#q", "☺", "`☺`"},
+ {"%#+q", "☺", "`☺`"},
+ {"%10q", "⌘", ` "⌘"`},
+ {"%+10q", "⌘", ` "\u2318"`},
+ {"%-10q", "⌘", `"⌘" `},
+ {"%+-10q", "⌘", `"\u2318" `},
+ {"%010q", "⌘", `0000000"⌘"`},
+ {"%+010q", "⌘", `00"\u2318"`},
+ {"%-010q", "⌘", `"⌘" `}, // 0 has no effect when - is present.
+ {"%+-010q", "⌘", `"\u2318" `},
+ {"%#8q", "\n", ` "\n"`},
+ {"%#+8q", "\r", ` "\r"`},
+ {"%#-8q", "\t", "` ` "},
+ {"%#+-8q", "\b", `"\b" `},
{"%q", "abc\xffdef", `"abc\xffdef"`},
- {"%q", "\u263a", `"☺"`},
- {"%+q", "\u263a", `"\u263a"`},
+ {"%+q", "abc\xffdef", `"abc\xffdef"`},
+ {"%#q", "abc\xffdef", `"abc\xffdef"`},
+ {"%#+q", "abc\xffdef", `"abc\xffdef"`},
+ // Runes that are not printable.
{"%q", "\U0010ffff", `"\U0010ffff"`},
+ {"%+q", "\U0010ffff", `"\U0010ffff"`},
+ {"%#q", "\U0010ffff", "`􏿿`"},
+ {"%#+q", "\U0010ffff", "`􏿿`"},
+ // Runes that are not valid.
+ {"%q", string(0x110000), `"�"`},
+ {"%+q", string(0x110000), `"\ufffd"`},
+ {"%#q", string(0x110000), "`�`"},
+ {"%#+q", string(0x110000), "`�`"},
+
+ // characters
+ {"%c", uint('x'), "x"},
+ {"%c", 0xe4, "ä"},
+ {"%c", 0x672c, "本"},
+ {"%c", '日', "日"},
+ {"%.0c", '⌘', "⌘"}, // Specifying precision should have no effect.
+ {"%3c", '⌘', " ⌘"},
+ {"%-3c", '⌘', "⌘ "},
+ // Runes that are not printable.
+ {"%c", '\U00000e00', "\u0e00"},
+ {"%c", '\U0010ffff', "\U0010ffff"},
+ // Runes that are not valid.
+ {"%c", -1, "�"},
+ {"%c", 0xDC80, "�"},
+ {"%c", rune(0x110000), "�"},
+ {"%c", int64(0xFFFFFFFFF), "�"},
+ {"%c", uint64(0xFFFFFFFFF), "�"},
// escaped characters
- {"%q", 'x', `'x'`},
- {"%q", 0, `'\x00'`},
- {"%q", '\n', `'\n'`},
- {"%q", '\u0e00', `'\u0e00'`}, // not a printable rune.
- {"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune.
- {"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`},
- {"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
+ {"%q", uint(0), `'\x00'`},
+ {"%+q", uint(0), `'\x00'`},
{"%q", '"', `'"'`},
+ {"%+q", '"', `'"'`},
{"%q", '\'', `'\''`},
- {"%q", "\u263a", `"☺"`},
- {"%+q", "\u263a", `"\u263a"`},
+ {"%+q", '\'', `'\''`},
+ {"%q", '`', "'`'"},
+ {"%+q", '`', "'`'"},
+ {"%q", 'x', `'x'`},
+ {"%+q", 'x', `'x'`},
+ {"%q", 'ÿ', `'ÿ'`},
+ {"%+q", 'ÿ', `'\u00ff'`},
+ {"%q", '\n', `'\n'`},
+ {"%+q", '\n', `'\n'`},
+ {"%q", '☺', `'☺'`},
+ {"%+q", '☺', `'\u263a'`},
+ {"% q", '☺', `'☺'`}, // The space modifier should have no effect.
+ {"%.0q", '☺', `'☺'`}, // Specifying precision should have no effect.
+ {"%10q", '⌘', ` '⌘'`},
+ {"%+10q", '⌘', ` '\u2318'`},
+ {"%-10q", '⌘', `'⌘' `},
+ {"%+-10q", '⌘', `'\u2318' `},
+ {"%010q", '⌘', `0000000'⌘'`},
+ {"%+010q", '⌘', `00'\u2318'`},
+ {"%-010q", '⌘', `'⌘' `}, // 0 has no effect when - is present.
+ {"%+-010q", '⌘', `'\u2318' `},
+ // Runes that are not printable.
+ {"%q", '\U00000e00', `'\u0e00'`},
+ {"%q", '\U0010ffff', `'\U0010ffff'`},
+ // Runes that are not valid.
+ {"%q", int32(-1), "%!q(int32=-1)"},
+ {"%q", 0xDC80, `'�'`},
+ {"%q", rune(0x110000), "%!q(int32=1114112)"},
+ {"%q", int64(0xFFFFFFFFF), "%!q(int64=68719476735)"},
+ {"%q", uint64(0xFFFFFFFFF), "%!q(uint64=68719476735)"},
// width
{"%5s", "abc", " abc"},
@@ -199,57 +297,99 @@ var fmtTests = []struct {
{"%08q", "abc", `000"abc"`},
{"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"},
{"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"},
+ {"%.0s", "日本語日本語", ""},
{"%.5s", "日本語日本語", "日本語日本"},
+ {"%.10s", "日本語日本語", "日本語日本語"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
- {"%.5x", "abcdefghijklmnopqrstuvwxyz", `6162636465`},
+ {"%.5x", "abcdefghijklmnopqrstuvwxyz", "6162636465"},
{"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`},
- {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), `6162636465`},
+ {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), "6162636465"},
{"%.3q", "日本語日本語", `"日本語"`},
{"%.3q", []byte("日本語日本語"), `"日本語"`},
{"%.1q", "日本語", `"日"`},
{"%.1q", []byte("日本語"), `"日"`},
- {"%.1x", "日本語", `e6`},
- {"%.1X", []byte("日本語"), `E6`},
+ {"%.1x", "日本語", "e6"},
+ {"%.1X", []byte("日本語"), "E6"},
{"%10.1q", "日本語日本語", ` "日"`},
- {"%3c", '⌘', " ⌘"},
- {"%5q", '\u2026', ` '…'`},
{"%10v", nil, " <nil>"},
{"%-10v", nil, "<nil> "},
// integers
- {"%d", 12345, "12345"},
- {"%d", -12345, "-12345"},
+ {"%d", uint(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, ""},
+ {"%6.0d", 0, " "},
+ {"%06.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"},
+ {"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
+ {"%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"},
{"%010d", 12345, "0000012345"},
{"%010d", -12345, "-000012345"},
- {"%-10d", 12345, "12345 "},
- {"%010.3d", 1, " 001"},
- {"%010.3d", -1, " -001"},
- {"%+d", 12345, "+12345"},
- {"%+d", -12345, "-12345"},
- {"%+d", 0, "+0"},
- {"% d", 0, " 0"},
- {"% d", 12345, " 12345"},
- {"%.0d", 0, ""},
- {"%.d", 0, ""},
+ {"%20.8d", 1234, " 00001234"},
+ {"%20.8d", -1234, " -00001234"},
+ {"%020.8d", 1234, " 00001234"},
+ {"%020.8d", -1234, " -00001234"},
+ {"%-20.8d", 1234, "00001234 "},
+ {"%-20.8d", -1234, "-00001234 "},
+ {"%-#20.8x", 0x1234abc, "0x01234abc "},
+ {"%-#20.8X", 0x1234abc, "0X01234ABC "},
+ {"%-#20.8o", 01234, "00001234 "},
+
+ // Test correct f.intbuf overflow checks.
+ {"%068d", 1, zeroFill("", 68, "1")},
+ {"%068d", -1, zeroFill("-", 67, "1")},
+ {"%#.68x", 42, zeroFill("0x", 68, "2a")},
+ {"%.68d", -42, zeroFill("-", 68, "42")},
+ {"%+.68d", 42, zeroFill("+", 68, "42")},
+ {"% .68d", 42, zeroFill(" ", 68, "42")},
+ {"% +.68d", 42, zeroFill("+", 68, "42")},
// unicode format
- {"%U", 0x1, "U+0001"},
- {"%U", uint(0x1), "U+0001"},
- {"%.8U", 0x2, "U+00000002"},
- {"%U", 0x1234, "U+1234"},
- {"%U", 0x12345, "U+12345"},
- {"%10.6U", 0xABC, " U+000ABC"},
- {"%-10.6U", 0xABC, "U+000ABC "},
+ {"%U", 0, "U+0000"},
+ {"%U", -1, "U+FFFFFFFFFFFFFFFF"},
{"%U", '\n', `U+000A`},
{"%#U", '\n', `U+000A`},
- {"%U", 'x', `U+0078`},
- {"%#U", 'x', `U+0078 'x'`},
+ {"%+U", 'x', `U+0078`}, // Plus flag should have no effect.
+ {"%# U", 'x', `U+0078 'x'`}, // Space flag should have no effect.
+ {"%#.2U", 'x', `U+0078 'x'`}, // Precisions below 4 should print 4 digits.
{"%U", '\u263a', `U+263A`},
{"%#U", '\u263a', `U+263A '☺'`},
+ {"%U", '\U0001D6C2', `U+1D6C2`},
+ {"%#U", '\U0001D6C2', `U+1D6C2 '𝛂'`},
+ {"%#14.6U", '⌘', " U+002318 '⌘'"},
+ {"%#-14.6U", '⌘', "U+002318 '⌘' "},
+ {"%#014.6U", '⌘', " U+002318 '⌘'"},
+ {"%#-014.6U", '⌘', "U+002318 '⌘' "},
+ {"%.68U", uint(42), zeroFill("U+", 68, "2A")},
+ {"%#.68U", '日', zeroFill("U+", 68, "65E5") + " '日'"},
// floats
{"%+.3e", 0.0, "+0.000e+00"},
@@ -259,6 +399,12 @@ var fmtTests = []struct {
{"%+.3F", float32(-1.0), "-1.000"},
{"%+07.2f", 1.0, "+001.00"},
{"%+07.2f", -1.0, "-001.00"},
+ {"%-07.2f", 1.0, "1.00 "},
+ {"%-07.2f", -1.0, "-1.00 "},
+ {"%+-07.2f", 1.0, "+1.00 "},
+ {"%+-07.2f", -1.0, "-1.00 "},
+ {"%-+07.2f", 1.0, "+1.00 "},
+ {"%-+07.2f", -1.0, "-1.00 "},
{"%+10.2f", +1.0, " +1.00"},
{"%+10.2f", -1.0, " -1.00"},
{"% .3E", -1.0, "-1.000E+00"},
@@ -270,8 +416,36 @@ var fmtTests = []struct {
{"% .3g", 1.0, " 1"},
{"%b", float32(1.0), "8388608p-23"},
{"%b", 1.0, "4503599627370496p-52"},
+ // Precision has no effect for binary float format.
+ {"%.4b", float32(1.0), "8388608p-23"},
+ {"%.4b", -1.0, "-4503599627370496p-52"},
+ // Test correct f.intbuf boundary checks.
+ {"%.68f", 1.0, zeroFill("1.", 68, "")},
+ {"%.68f", -1.0, zeroFill("-1.", 68, "")},
+ // float infinites and NaNs
+ {"%f", posInf, "+Inf"},
+ {"%.1f", negInf, "-Inf"},
+ {"% f", NaN, " NaN"},
+ {"%20f", posInf, " +Inf"},
+ {"% 20F", posInf, " Inf"},
+ {"% 20e", negInf, " -Inf"},
+ {"%+20E", negInf, " -Inf"},
+ {"% +20g", negInf, " -Inf"},
+ {"%+-20G", posInf, "+Inf "},
+ {"%20e", NaN, " NaN"},
+ {"% +20E", NaN, " +NaN"},
+ {"% -20g", NaN, " NaN "},
+ {"%+-20G", NaN, "+NaN "},
+ // Zero padding does not apply to infinities and NaN.
+ {"%+020e", posInf, " +Inf"},
+ {"%-020f", negInf, "-Inf "},
+ {"%-020E", NaN, "NaN "},
// complex values
+ {"%.f", 0i, "(0+0i)"},
+ {"% .f", 0i, "( 0+0i)"},
+ {"%+.f", 0i, "(+0+0i)"},
+ {"% +.f", 0i, "(+0+0i)"},
{"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
{"%+.3f", 0i, "(+0.000+0.000i)"},
{"%+.3g", 0i, "(+0+0i)"},
@@ -290,35 +464,33 @@ var fmtTests = []struct {
{"%.3f", -1 - 2i, "(-1.000-2.000i)"},
{"%.3g", -1 - 2i, "(-1-2i)"},
{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
+ {"%+.3g", 1 + 2i, "(+1+2i)"},
{"%+.3g", complex64(1 + 2i), "(+1+2i)"},
- {"%+.3g", complex128(1 + 2i), "(+1+2i)"},
- {"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
{"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
-
- // erroneous formats
- {"", 2, "%!(EXTRA int=2)"},
- {"%d", "hello", "%!d(string=hello)"},
+ {"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
+ // Precision has no effect for binary complex format.
+ {"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
+ {"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
+ // complex infinites and NaNs
+ {"%f", complex(posInf, posInf), "(+Inf+Infi)"},
+ {"%f", complex(negInf, negInf), "(-Inf-Infi)"},
+ {"%f", complex(NaN, NaN), "(NaN+NaNi)"},
+ {"%.1f", complex(posInf, posInf), "(+Inf+Infi)"},
+ {"% f", complex(posInf, posInf), "( Inf+Infi)"},
+ {"% f", complex(negInf, negInf), "(-Inf-Infi)"},
+ {"% f", complex(NaN, NaN), "( NaN+NaNi)"},
+ {"%8e", complex(posInf, posInf), "( +Inf +Infi)"},
+ {"% 8E", complex(posInf, posInf), "( Inf +Infi)"},
+ {"%+8f", complex(negInf, negInf), "( -Inf -Infi)"},
+ {"% +8g", complex(negInf, negInf), "( -Inf -Infi)"},
+ {"% -8G", complex(NaN, NaN), "( NaN +NaN i)"},
+ {"%+-8b", complex(NaN, NaN), "(+NaN +NaN i)"},
+ // Zero padding does not apply to infinities and NaN.
+ {"%08f", complex(posInf, posInf), "( +Inf +Infi)"},
+ {"%-08g", complex(negInf, negInf), "(-Inf -Inf i)"},
+ {"%-08G", complex(NaN, NaN), "(NaN +NaN i)"},
// 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", 1234.5678e3, "1.234568e+06"},
{"%e", 1234.5678e-8, "1.234568e-05"},
@@ -345,19 +517,6 @@ var fmtTests = []struct {
{"%G", -7.0, "-7"},
{"%G", -1e-9, "-1E-09"},
{"%G", float32(-1e-9), "-1E-09"},
- {"%c", 'x', "x"},
- {"%c", 0xe4, "ä"},
- {"%c", 0x672c, "本"},
- {"%c", '日', "日"},
- {"%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"},
{"%.5s", "qwertyuiop", "qwert"},
{"%-20.5s", "qwertyuiop", "qwert "},
@@ -377,9 +536,6 @@ var fmtTests = []struct {
{"%g", 1.23456789e3, "1234.56789"},
{"%g", 1.23456789e-3, "0.00123456789"},
{"%g", 1.23456789e20, "1.23456789e+20"},
- {"%20e", math.Inf(1), " +Inf"},
- {"%-20f", math.Inf(-1), "-Inf "},
- {"%20g", math.NaN(), " NaN"},
// arrays
{"%v", array, "[1 2 3 4 5]"},
@@ -396,13 +552,44 @@ var fmtTests = []struct {
{"%v", &slice, "&[1 2 3 4 5]"},
{"%v", &islice, "&[1 hello 2.5 <nil>]"},
{"%v", &bslice, "&[1 2 3 4 5]"},
- {"%v", []byte{1}, "[1]"},
- {"%v", []byte{}, "[]"},
+
+ // byte arrays and slices with %b,%c,%d,%o,%U and %v
+ {"%b", [3]byte{65, 66, 67}, "[1000001 1000010 1000011]"},
+ {"%c", [3]byte{65, 66, 67}, "[A B C]"},
+ {"%d", [3]byte{65, 66, 67}, "[65 66 67]"},
+ {"%o", [3]byte{65, 66, 67}, "[101 102 103]"},
+ {"%U", [3]byte{65, 66, 67}, "[U+0041 U+0042 U+0043]"},
+ {"%v", [3]byte{65, 66, 67}, "[65 66 67]"},
+ {"%v", [1]byte{123}, "[123]"},
+ {"%012v", []byte{}, "[]"},
+ {"%#012v", []byte{}, "[]byte{}"},
+ {"%6v", []byte{1, 11, 111}, "[ 1 11 111]"},
+ {"%06v", []byte{1, 11, 111}, "[000001 000011 000111]"},
+ {"%-6v", []byte{1, 11, 111}, "[1 11 111 ]"},
+ {"%-06v", []byte{1, 11, 111}, "[1 11 111 ]"},
+ {"%#v", []byte{1, 11, 111}, "[]byte{0x1, 0xb, 0x6f}"},
+ {"%#6v", []byte{1, 11, 111}, "[]byte{ 0x1, 0xb, 0x6f}"},
+ {"%#06v", []byte{1, 11, 111}, "[]byte{0x000001, 0x00000b, 0x00006f}"},
+ {"%#-6v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"},
+ {"%#-06v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"},
+ // f.space should and f.plus should not have an effect with %v.
+ {"% v", []byte{1, 11, 111}, "[ 1 11 111]"},
+ {"%+v", [3]byte{1, 11, 111}, "[1 11 111]"},
+ {"%# -6v", []byte{1, 11, 111}, "[]byte{ 0x1 , 0xb , 0x6f }"},
+ {"%#+-6v", [3]byte{1, 11, 111}, "[3]uint8{0x1 , 0xb , 0x6f }"},
+ // f.space and f.plus should have an effect with %d.
+ {"% d", []byte{1, 11, 111}, "[ 1 11 111]"},
+ {"%+d", [3]byte{1, 11, 111}, "[+1 +11 +111]"},
+ {"%# -6d", []byte{1, 11, 111}, "[ 1 11 111 ]"},
+ {"%#+-6d", [3]byte{1, 11, 111}, "[+1 +11 +111 ]"},
+
+ // floates with %v
+ {"%v", 1.2345678, "1.2345678"},
+ {"%v", float32(1.2345678), "1.2345678"},
// complexes with %v
{"%v", 1 + 2i, "(1+2i)"},
{"%v", complex64(1 + 2i), "(1+2i)"},
- {"%v", complex128(1 + 2i), "(1+2i)"},
// structs
{"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
@@ -422,7 +609,7 @@ var fmtTests = []struct {
// go syntax
{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
- {"%#v", &b, "(*uint8)(0xPTR)"},
+ {"%#v", new(byte), "(*uint8)(0xPTR)"},
{"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"},
{"%#v", make(chan int), "(chan int)(0xPTR)"},
{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
@@ -442,8 +629,20 @@ var fmtTests = []struct {
{"%#v", "foo", `"foo"`},
{"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
{"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
- {"%#v", []byte(nil), "[]byte(nil)"},
{"%#v", []int32(nil), "[]int32(nil)"},
+ {"%#v", 1.2345678, "1.2345678"},
+ {"%#v", float32(1.2345678), "1.2345678"},
+ // Only print []byte and []uint8 as type []byte if they appear at the top level.
+ {"%#v", []byte(nil), "[]byte(nil)"},
+ {"%#v", []uint8(nil), "[]byte(nil)"},
+ {"%#v", []byte{}, "[]byte{}"},
+ {"%#v", []uint8{}, "[]byte{}"},
+ {"%#v", reflect.ValueOf([]byte{}), "[]uint8{}"},
+ {"%#v", reflect.ValueOf([]uint8{}), "[]uint8{}"},
+ {"%#v", &[]byte{}, "&[]uint8{}"},
+ {"%#v", &[]byte{}, "&[]uint8{}"},
+ {"%#v", [3]byte{}, "[3]uint8{0x0, 0x0, 0x0}"},
+ {"%#v", [3]uint8{}, "[3]uint8{0x0, 0x0, 0x0}"},
// slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -453,30 +652,61 @@ var fmtTests = []struct {
{"%q", []string{"a", "b"}, `["a" "b"]`},
{"% 02x", []byte{1}, "01"},
{"% 02x", []byte{1, 2, 3}, "01 02 03"},
+
// Padding with byte slices.
- {"%x", []byte{}, ""},
- {"%02x", []byte{}, "00"},
+ {"%2x", []byte{}, " "},
+ {"%#2x", []byte{}, " "},
{"% 02x", []byte{}, "00"},
- {"%08x", []byte{0xab}, "000000ab"},
- {"% 08x", []byte{0xab}, "000000ab"},
- {"%08x", []byte{0xab, 0xcd}, "0000abcd"},
- {"% 08x", []byte{0xab, 0xcd}, "000ab cd"},
+ {"%# 02x", []byte{}, "00"},
+ {"%-2x", []byte{}, " "},
+ {"%-02x", []byte{}, " "},
{"%8x", []byte{0xab}, " ab"},
{"% 8x", []byte{0xab}, " ab"},
- {"%8x", []byte{0xab, 0xcd}, " abcd"},
- {"% 8x", []byte{0xab, 0xcd}, " ab cd"},
+ {"%#8x", []byte{0xab}, " 0xab"},
+ {"%# 8x", []byte{0xab}, " 0xab"},
+ {"%08x", []byte{0xab}, "000000ab"},
+ {"% 08x", []byte{0xab}, "000000ab"},
+ {"%#08x", []byte{0xab}, "00000xab"},
+ {"%# 08x", []byte{0xab}, "00000xab"},
+ {"%10x", []byte{0xab, 0xcd}, " abcd"},
+ {"% 10x", []byte{0xab, 0xcd}, " ab cd"},
+ {"%#10x", []byte{0xab, 0xcd}, " 0xabcd"},
+ {"%# 10x", []byte{0xab, 0xcd}, " 0xab 0xcd"},
+ {"%010x", []byte{0xab, 0xcd}, "000000abcd"},
+ {"% 010x", []byte{0xab, 0xcd}, "00000ab cd"},
+ {"%#010x", []byte{0xab, 0xcd}, "00000xabcd"},
+ {"%# 010x", []byte{0xab, 0xcd}, "00xab 0xcd"},
+ {"%-10X", []byte{0xab}, "AB "},
+ {"% -010X", []byte{0xab}, "AB "},
+ {"%#-10X", []byte{0xab, 0xcd}, "0XABCD "},
+ {"%# -010X", []byte{0xab, 0xcd}, "0XAB 0XCD "},
// Same for strings
- {"%x", "", ""},
- {"%02x", "", "00"},
+ {"%2x", "", " "},
+ {"%#2x", "", " "},
{"% 02x", "", "00"},
- {"%08x", "\xab", "000000ab"},
- {"% 08x", "\xab", "000000ab"},
- {"%08x", "\xab\xcd", "0000abcd"},
- {"% 08x", "\xab\xcd", "000ab cd"},
+ {"%# 02x", "", "00"},
+ {"%-2x", "", " "},
+ {"%-02x", "", " "},
{"%8x", "\xab", " ab"},
{"% 8x", "\xab", " ab"},
- {"%8x", "\xab\xcd", " abcd"},
- {"% 8x", "\xab\xcd", " ab cd"},
+ {"%#8x", "\xab", " 0xab"},
+ {"%# 8x", "\xab", " 0xab"},
+ {"%08x", "\xab", "000000ab"},
+ {"% 08x", "\xab", "000000ab"},
+ {"%#08x", "\xab", "00000xab"},
+ {"%# 08x", "\xab", "00000xab"},
+ {"%10x", "\xab\xcd", " abcd"},
+ {"% 10x", "\xab\xcd", " ab cd"},
+ {"%#10x", "\xab\xcd", " 0xabcd"},
+ {"%# 10x", "\xab\xcd", " 0xab 0xcd"},
+ {"%010x", "\xab\xcd", "000000abcd"},
+ {"% 010x", "\xab\xcd", "00000ab cd"},
+ {"%#010x", "\xab\xcd", "00000xabcd"},
+ {"%# 010x", "\xab\xcd", "00xab 0xcd"},
+ {"%-10X", "\xab", "AB "},
+ {"% -010X", "\xab", "AB "},
+ {"%#-10X", "\xab\xcd", "0XABCD "},
+ {"%# -010X", "\xab\xcd", "0XAB 0XCD "},
// renamings
{"%v", renamedBool(true), "true"},
@@ -495,7 +725,8 @@ var fmtTests = []struct {
{"%x", renamedString("thing"), "7468696e67"},
{"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
{"%q", renamedBytes([]byte("hello")), `"hello"`},
- {"%x", []renamedUint8{'a', 'b', 'c'}, "616263"},
+ {"%x", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656c6c6f"},
+ {"%X", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656C6C6F"},
{"%s", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "hello"},
{"%q", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, `"hello"`},
{"%v", renamedFloat32(22), "22"},
@@ -513,79 +744,72 @@ var fmtTests = []struct {
{"%#v", S{F(7), G(8)}, "fmt_test.S{F:<v=F(7)>, G:GoString(8)}"},
// %T
+ {"%T", byte(0), "uint8"},
+ {"%T", reflect.ValueOf(nil), "reflect.Value"},
{"%T", (4 - 3i), "complex128"},
{"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
- {"%T", intVal, "int"},
- {"%6T", &intVal, " *int"},
+ {"%T", intVar, "int"},
+ {"%6T", &intVar, " *int"},
{"%10T", nil, " <nil>"},
{"%-10T", nil, "<nil> "},
- // %p
- {"p0=%p", new(int), "p0=0xPTR"},
- {"p1=%s", &pValue, "p1=String(p)"}, // String method...
- {"p2=%p", &pValue, "p2=0xPTR"}, // ... not called with %p
- {"p3=%p", (*int)(nil), "p3=0x0"},
- {"p4=%#p", new(int), "p4=PTR"},
-
+ // %p with pointers
+ {"%p", (*int)(nil), "0x0"},
+ {"%#p", (*int)(nil), "0"},
+ {"%p", &intVar, "0xPTR"},
+ {"%#p", &intVar, "PTR"},
+ {"%p", &array, "0xPTR"},
+ {"%p", &slice, "0xPTR"},
+ {"%8.2p", (*int)(nil), " 0x00"},
+ {"%-20.16p", &intVar, "0xPTR "},
// %p on non-pointers
{"%p", make(chan int), "0xPTR"},
{"%p", make(map[int]int), "0xPTR"},
- {"%p", make([]int, 1), "0xPTR"},
- {"%p", 27, "%!p(int=27)"}, // not a pointer at all
-
- // %q on pointers
- {"%q", (*int)(nil), "%!q(*int=<nil>)"},
- {"%q", new(int), "%!q(*int=0xPTR)"},
-
- // %v on pointers formats 0 as <nil>
+ {"%p", func() {}, "0xPTR"},
+ {"%p", 27, "%!p(int=27)"}, // not a pointer at all
+ {"%p", nil, "%!p(<nil>)"}, // nil on its own has no type ...
+ {"%#p", nil, "%!p(<nil>)"}, // ... and hence is not a pointer type.
+ // pointers with specified base
+ {"%b", &intVar, "PTR_b"},
+ {"%d", &intVar, "PTR_d"},
+ {"%o", &intVar, "PTR_o"},
+ {"%x", &intVar, "PTR_x"},
+ {"%X", &intVar, "PTR_X"},
+ // %v on pointers
+ {"%v", nil, "<nil>"},
+ {"%#v", nil, "<nil>"},
{"%v", (*int)(nil), "<nil>"},
- {"%v", new(int), "0xPTR"},
-
- // %d etc. pointers use specified base.
- {"%d", new(int), "PTR_d"},
- {"%o", new(int), "PTR_o"},
- {"%x", new(int), "PTR_x"},
+ {"%#v", (*int)(nil), "(*int)(nil)"},
+ {"%v", &intVar, "0xPTR"},
+ {"%#v", &intVar, "(*int)(0xPTR)"},
+ {"%8.2v", (*int)(nil), " <nil>"},
+ {"%-20.16v", &intVar, "0xPTR "},
+ // string method on pointer
+ {"%s", &pValue, "String(p)"}, // String method...
+ {"%p", &pValue, "0xPTR"}, // ... is not called with %p.
// %d on Stringer should give integer if possible
{"%s", time.Time{}.Month(), "January"},
{"%d", time.Time{}.Month(), "1"},
// erroneous things
+ {"", nil, "%!(EXTRA <nil>)"},
+ {"", 2, "%!(EXTRA int=2)"},
+ {"no args", "hello", "no args%!(EXTRA string=hello)"},
{"%s %", "hello", "hello %!(NOVERB)"},
{"%s %.2", "hello", "hello %!(NOVERB)"},
- {"%d", "hello", "%!d(string=hello)"},
- {"no args", "hello", "no args%!(EXTRA string=hello)"},
- {"%s", nil, "%!s(<nil>)"},
- {"%T", nil, "<nil>"},
- {"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
{"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)%!(EXTRA int=0)"},
{"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"},
+ // Extra argument errors should format without flags set.
+ {"%010.2", "12345", "%!(NOVERB)%!(EXTRA string=12345)"},
// The "<nil>" show up because maps are printed by
// first obtaining a list of keys and then looking up
- // each key. Since NaNs can be map keys but cannot
+ // each key. Since NaNs can be map keys but cannot
// be fetched directly, the lookup fails and returns a
// zero reflect.Value, which formats as <nil>.
// This test is just to check that it shows the two NaNs at all.
- {"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
-
- // Used to crash because nByte didn't allow for a sign.
- {"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
-
- // Used to panic.
- {"%0100d", 1, zeroFill("", 100, "1")},
- {"%0100d", -1, zeroFill("-", 99, "1")},
- {"%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.
- {"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"},
- {"%.80U", 42, "U+0000000000000000000000000000000000000000000000000000000000000000000000000000002A"},
- {"%#.80U", '日', "U+000000000000000000000000000000000000000000000000000000000000000000000000000065E5 '日'"},
- {"%.65d", -44, "-00000000000000000000000000000000000000000000000000000000000000044"},
- {"%+.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
- {"% .65d", 44, " 00000000000000000000000000000000000000000000000000000000000000044"},
- {"% +.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
+ {"%v", map[float64]int{NaN: 1, NaN: 2}, "map[NaN:<nil> NaN:<nil>]"},
// Comparison of padding rules with C printf.
/*
@@ -599,14 +823,16 @@ var fmtTests = []struct {
"[%7.2f]",
"[% 7.2f]",
"[%+7.2f]",
+ "[% +7.2f]",
"[%07.2f]",
"[% 07.2f]",
"[%+07.2f]",
+ "[% +07.2f]"
};
int main(void) {
int i;
- for(i = 0; i < 9; i++) {
+ for(i = 0; i < 11; i++) {
printf("%s: ", format[i]);
printf(format[i], 1.0);
printf(" ");
@@ -622,9 +848,12 @@ var fmtTests = []struct {
[%7.2f]: [ 1.00] [ -1.00]
[% 7.2f]: [ 1.00] [ -1.00]
[%+7.2f]: [ +1.00] [ -1.00]
+ [% +7.2f]: [ +1.00] [ -1.00]
[%07.2f]: [0001.00] [-001.00]
[% 07.2f]: [ 001.00] [-001.00]
[%+07.2f]: [+001.00] [-001.00]
+ [% +07.2f]: [+001.00] [-001.00]
+
*/
{"%.2f", 1.0, "1.00"},
{"%.2f", -1.0, "-1.00"},
@@ -638,26 +867,35 @@ var fmtTests = []struct {
{"% 7.2f", -1.0, " -1.00"},
{"%+7.2f", 1.0, " +1.00"},
{"%+7.2f", -1.0, " -1.00"},
+ {"% +7.2f", 1.0, " +1.00"},
+ {"% +7.2f", -1.0, " -1.00"},
{"%07.2f", 1.0, "0001.00"},
{"%07.2f", -1.0, "-001.00"},
{"% 07.2f", 1.0, " 001.00"},
{"% 07.2f", -1.0, "-001.00"},
{"%+07.2f", 1.0, "+001.00"},
{"%+07.2f", -1.0, "-001.00"},
+ {"% +07.2f", 1.0, "+001.00"},
+ {"% +07.2f", -1.0, "-001.00"},
// Complex numbers: exhaustively tested in TestComplexFormatting.
{"%7.2f", 1 + 2i, "( 1.00 +2.00i)"},
{"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
- // Zero padding does not apply to infinities.
- {"%020f", math.Inf(-1), " -Inf"},
- {"%020f", math.Inf(+1), " +Inf"},
- {"% 020f", math.Inf(-1), " -Inf"},
- {"% 020f", math.Inf(+1), " Inf"},
- {"%+020f", math.Inf(-1), " -Inf"},
- {"%+020f", math.Inf(+1), " +Inf"},
- {"%20f", -1.0, " -1.000000"},
- // Make sure we can handle very large widths.
- {"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
+
+ // Use spaces instead of zero if padding to the right.
+ {"%0-5s", "abc", "abc "},
+ {"%-05.1f", 1.0, "1.0 "},
+
+ // float and complex formatting should not change the padding width
+ // for other elements. See issue 14642.
+ {"%06v", []interface{}{+10.0, 10}, "[000010 000010]"},
+ {"%06v", []interface{}{-10.0, 10}, "[-00010 000010]"},
+ {"%06v", []interface{}{+10.0 + 10i, 10}, "[(000010+00010i) 000010]"},
+ {"%06v", []interface{}{-10.0 + 10i, 10}, "[(-00010+00010i) 000010]"},
+
+ // integer formatting should not alter padding for other elements.
+ {"%03.6v", []interface{}{1, 2.0, "x"}, "[000001 002 00x]"},
+ {"%03.0v", []interface{}{0, 2.0, "x"}, "[ 002 000]"},
// Complex fmt used to leave the plus flag set for future entries in the array
// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
@@ -667,27 +905,6 @@ var fmtTests = []struct {
// Incomplete format specification caused crash.
{"%.", 3, "%!.(int=3)"},
- // Used to panic with out-of-bounds for very large numeric representations.
- // nByte is set to handle one bit per uint64 in %b format, with a negative number.
- // See issue 6777.
- {"%#064x", 1, zeroFill("0x", 64, "1")},
- {"%#064x", -1, zeroFill("-0x", 63, "1")},
- {"%#064b", 1, zeroFill("", 64, "1")},
- {"%#064b", -1, zeroFill("-", 63, "1")},
- {"%#064o", 1, zeroFill("", 64, "1")},
- {"%#064o", -1, zeroFill("-", 63, "1")},
- {"%#064d", 1, zeroFill("", 64, "1")},
- {"%#064d", -1, zeroFill("-", 63, "1")},
- // Test that we handle the crossover above the size of uint64
- {"%#072x", 1, zeroFill("0x", 72, "1")},
- {"%#072x", -1, zeroFill("-0x", 71, "1")},
- {"%#072b", 1, zeroFill("", 72, "1")},
- {"%#072b", -1, zeroFill("-", 71, "1")},
- {"%#072o", 1, zeroFill("", 72, "1")},
- {"%#072o", -1, zeroFill("-", 71, "1")},
- {"%#072d", 1, zeroFill("", 72, "1")},
- {"%#072d", -1, zeroFill("-", 71, "1")},
-
// Padding for complex numbers. Has been bad, then fixed, then bad again.
{"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"},
{"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"},
@@ -699,19 +916,21 @@ var fmtTests = []struct {
{"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
// []T where type T is a byte with a Stringer method.
- {"%v", byteStringerSlice, "[X X X X]"},
- {"%s", byteStringerSlice, "abcd"},
- {"%q", byteStringerSlice, "\"abcd\""},
- {"%x", byteStringerSlice, "61626364"},
- {"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x61, 0x62, 0x63, 0x64}"},
+ {"%v", byteStringerSlice, "[X X X X X]"},
+ {"%s", byteStringerSlice, "hello"},
+ {"%q", byteStringerSlice, "\"hello\""},
+ {"%x", byteStringerSlice, "68656c6c6f"},
+ {"%X", byteStringerSlice, "68656C6C6F"},
+ {"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x68, 0x65, 0x6c, 0x6c, 0x6f}"},
// And the same for Formatter.
- {"%v", byteFormatterSlice, "[X X X X]"},
- {"%s", byteFormatterSlice, "abcd"},
- {"%q", byteFormatterSlice, "\"abcd\""},
- {"%x", byteFormatterSlice, "61626364"},
+ {"%v", byteFormatterSlice, "[X X X X X]"},
+ {"%s", byteFormatterSlice, "hello"},
+ {"%q", byteFormatterSlice, "\"hello\""},
+ {"%x", byteFormatterSlice, "68656c6c6f"},
+ {"%X", byteFormatterSlice, "68656C6C6F"},
// This next case seems wrong, but the docs say the Formatter wins here.
- {"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"},
+ {"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X, X}"},
// reflect.Value handled specially in Go 1.5, making it possible to
// see inside non-exported fields (which cannot be accessed with Interface()).
@@ -726,6 +945,32 @@ var fmtTests = []struct {
// invalid reflect.Value doesn't crash.
{"%v", reflect.Value{}, "<invalid reflect.Value>"},
+ {"%v", &reflect.Value{}, "<invalid Value>"},
+ {"%v", SI{reflect.Value{}}, "{<invalid Value>}"},
+
+ // Tests to check that not supported verbs generate an error string.
+ {"%☠", nil, "%!☠(<nil>)"},
+ {"%☠", interface{}(nil), "%!☠(<nil>)"},
+ {"%☠", int(0), "%!☠(int=0)"},
+ {"%☠", uint(0), "%!☠(uint=0)"},
+ {"%☠", []byte{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"},
+ {"%☠", []uint8{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"},
+ {"%☠", [1]byte{0}, "[%!☠(uint8=0)]"},
+ {"%☠", [1]uint8{0}, "[%!☠(uint8=0)]"},
+ {"%☠", "hello", "%!☠(string=hello)"},
+ {"%☠", 1.2345678, "%!☠(float64=1.2345678)"},
+ {"%☠", float32(1.2345678), "%!☠(float32=1.2345678)"},
+ {"%☠", 1.2345678 + 1.2345678i, "%!☠(complex128=(1.2345678+1.2345678i))"},
+ {"%☠", complex64(1.2345678 + 1.2345678i), "%!☠(complex64=(1.2345678+1.2345678i))"},
+ {"%☠", &intVar, "%!☠(*int=0xPTR)"},
+ {"%☠", make(chan int), "%!☠(chan int=0xPTR)"},
+ {"%☠", func() {}, "%!☠(func()=0xPTR)"},
+ {"%☠", reflect.ValueOf(renamedInt(0)), "%!☠(fmt_test.renamedInt=0)"},
+ {"%☠", SI{renamedInt(0)}, "{%!☠(fmt_test.renamedInt=0)}"},
+ {"%☠", &[]interface{}{I(1), G(2)}, "&[%!☠(fmt_test.I=1) %!☠(fmt_test.G=2)]"},
+ {"%☠", SI{&[]interface{}{I(1), G(2)}}, "{%!☠(*[]interface {}=&[1 2])}"},
+ {"%☠", reflect.Value{}, "<invalid reflect.Value>"},
+ {"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠(<nil>)]"},
}
// zeroFill generates zero-filled strings of the specified width. The length
@@ -737,27 +982,37 @@ func zeroFill(prefix string, width int, suffix string) string {
func TestSprintf(t *testing.T) {
for _, tt := range fmtTests {
s := Sprintf(tt.fmt, tt.val)
- if i := strings.Index(tt.out, "PTR"); i >= 0 {
- pattern := "PTR"
- chars := "0123456789abcdefABCDEF"
+ i := strings.Index(tt.out, "PTR")
+ if i >= 0 && i < len(s) {
+ var pattern, chars string
switch {
- case strings.HasPrefix(tt.out[i:], "PTR_d"):
- pattern = "PTR_d"
- chars = chars[:10]
+ case strings.HasPrefix(tt.out[i:], "PTR_b"):
+ pattern = "PTR_b"
+ chars = "01"
case strings.HasPrefix(tt.out[i:], "PTR_o"):
pattern = "PTR_o"
- chars = chars[:8]
+ chars = "01234567"
+ case strings.HasPrefix(tt.out[i:], "PTR_d"):
+ pattern = "PTR_d"
+ chars = "0123456789"
case strings.HasPrefix(tt.out[i:], "PTR_x"):
pattern = "PTR_x"
+ chars = "0123456789abcdef"
+ case strings.HasPrefix(tt.out[i:], "PTR_X"):
+ pattern = "PTR_X"
+ chars = "0123456789ABCDEF"
+ default:
+ pattern = "PTR"
+ chars = "0123456789abcdefABCDEF"
}
- j := i
- for ; j < len(s); j++ {
- c := s[j]
- if !strings.ContainsRune(chars, rune(c)) {
+ p := s[:i] + pattern
+ for j := i; j < len(s); j++ {
+ if !strings.ContainsRune(chars, rune(s[j])) {
+ p += s[j:]
break
}
}
- s = s[0:i] + pattern + s[j:]
+ s = p
}
if s != tt.out {
if _, ok := tt.val.(string); ok {
@@ -775,7 +1030,7 @@ func TestSprintf(t *testing.T) {
// thing as if done by hand with two singleton prints.
func TestComplexFormatting(t *testing.T) {
var yesNo = []bool{true, false}
- var values = []float64{1, 0, -1, math.Inf(1), math.Inf(-1), math.NaN()}
+ var values = []float64{1, 0, -1, posInf, negInf, NaN}
for _, plus := range yesNo {
for _, zero := range yesNo {
for _, space := range yesNo {
@@ -869,6 +1124,14 @@ func TestReorder(t *testing.T) {
}
}
+func BenchmarkSprintfPadding(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%16f", 1.0)
+ }
+ })
+}
+
func BenchmarkSprintfEmpty(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
@@ -885,6 +1148,22 @@ func BenchmarkSprintfString(b *testing.B) {
})
}
+func BenchmarkSprintfTruncateString(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%.3s", "日本語日本語日本語")
+ }
+ })
+}
+
+func BenchmarkSprintfQuoteString(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%q", "日本語日本語日本語")
+ }
+ })
+}
+
func BenchmarkSprintfInt(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
@@ -917,6 +1196,66 @@ func BenchmarkSprintfFloat(b *testing.B) {
})
}
+func BenchmarkSprintfComplex(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%f", 5.23184+5.23184i)
+ }
+ })
+}
+
+func BenchmarkSprintfBoolean(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%t", true)
+ }
+ })
+}
+
+func BenchmarkSprintfHexString(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("% #x", "0123456789abcdef")
+ }
+ })
+}
+
+func BenchmarkSprintfHexBytes(b *testing.B) {
+ data := []byte("0123456789abcdef")
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("% #x", data)
+ }
+ })
+}
+
+func BenchmarkSprintfBytes(b *testing.B) {
+ data := []byte("0123456789abcdef")
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%v", data)
+ }
+ })
+}
+
+func BenchmarkSprintfStringer(b *testing.B) {
+ stringer := I(12345)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%v", stringer)
+ }
+ })
+}
+
+func BenchmarkSprintfStructure(b *testing.B) {
+ s := &[]interface{}{SI{12345}, map[int]string{0: "hello"}}
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%#v", s)
+ }
+ })
+}
+
func BenchmarkManyArgs(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var buf bytes.Buffer
diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
index 517b18f..0236475 100644
--- a/libgo/go/fmt/format.go
+++ b/libgo/go/fmt/format.go
@@ -5,18 +5,13 @@
package fmt
import (
- "math"
"strconv"
"unicode/utf8"
)
const (
- // %b of an int64, plus a sign.
- // Hex can add 0x and we handle it specially.
- nByte = 65
-
- ldigits = "0123456789abcdef"
- udigits = "0123456789ABCDEF"
+ ldigits = "0123456789abcdefx"
+ udigits = "0123456789ABCDEFX"
)
const (
@@ -24,16 +19,6 @@ const (
unsigned = false
)
-var padZeroBytes = make([]byte, nByte)
-var padSpaceBytes = make([]byte, nByte)
-
-func init() {
- for i := 0; i < nByte; i++ {
- padZeroBytes[i] = '0'
- padSpaceBytes[i] = ' '
- }
-}
-
// flags placed in a separate struct for easy clearing.
type fmtFlags struct {
widPresent bool
@@ -42,8 +27,6 @@ type fmtFlags struct {
plus bool
sharp bool
space bool
- unicode bool
- uniQuote bool // Use 'x'= prefix for %U if printable.
zero bool
// For the formats %+v %#v, we set the plusV/sharpV flags
@@ -56,12 +39,16 @@ type fmtFlags struct {
// A fmt is the raw formatter used by Printf etc.
// It prints into a buffer that must be set up separately.
type fmt struct {
- intbuf [nByte]byte
- buf *buffer
- // width, precision
- wid int
- prec int
+ buf *buffer
+
fmtFlags
+
+ wid int // width
+ prec int // precision
+
+ // intbuf is large enought to store %b of an int64 with a sign and
+ // avoids padding at the end of the struct on 32 bit architectures.
+ intbuf [68]byte
}
func (f *fmt) clearflags() {
@@ -73,176 +60,213 @@ func (f *fmt) init(buf *buffer) {
f.clearflags()
}
-// computePadding computes left and right padding widths (only one will be non-zero).
-func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
- left := !f.minus
- w := f.wid
- if w < 0 {
- left = false
- w = -w
- }
- w -= width
- if w > 0 {
- if left && f.zero {
- return padZeroBytes, w, 0
- }
- if left {
- return padSpaceBytes, w, 0
- } else {
- // can't be zero padding on the right
- return padSpaceBytes, 0, w
- }
- }
- return
-}
-
// writePadding generates n bytes of padding.
-func (f *fmt) writePadding(n int, padding []byte) {
- for n > 0 {
- m := n
- if m > nByte {
- m = nByte
- }
- f.buf.Write(padding[0:m])
- n -= m
+func (f *fmt) writePadding(n int) {
+ if n <= 0 { // No padding bytes needed.
+ return
}
+ buf := *f.buf
+ oldLen := len(buf)
+ newLen := oldLen + n
+ // Make enough room for padding.
+ if newLen > cap(buf) {
+ buf = make(buffer, cap(buf)*2+n)
+ copy(buf, *f.buf)
+ }
+ // Decide which byte the padding should be filled with.
+ padByte := byte(' ')
+ if f.zero {
+ padByte = byte('0')
+ }
+ // Fill padding with padByte.
+ padding := buf[oldLen:newLen]
+ for i := range padding {
+ padding[i] = padByte
+ }
+ *f.buf = buf[:newLen]
}
-// pad appends b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) pad(b []byte) {
if !f.widPresent || f.wid == 0 {
f.buf.Write(b)
return
}
- padding, left, right := f.computePadding(utf8.RuneCount(b))
- if left > 0 {
- f.writePadding(left, padding)
- }
- f.buf.Write(b)
- if right > 0 {
- f.writePadding(right, padding)
+ width := f.wid - utf8.RuneCount(b)
+ if !f.minus {
+ // left padding
+ f.writePadding(width)
+ f.buf.Write(b)
+ } else {
+ // right padding
+ f.buf.Write(b)
+ f.writePadding(width)
}
}
-// padString appends s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) padString(s string) {
if !f.widPresent || f.wid == 0 {
f.buf.WriteString(s)
return
}
- padding, left, right := f.computePadding(utf8.RuneCountInString(s))
- if left > 0 {
- f.writePadding(left, padding)
- }
- f.buf.WriteString(s)
- if right > 0 {
- f.writePadding(right, padding)
+ width := f.wid - utf8.RuneCountInString(s)
+ if !f.minus {
+ // left padding
+ f.writePadding(width)
+ f.buf.WriteString(s)
+ } else {
+ // right padding
+ f.buf.WriteString(s)
+ f.writePadding(width)
}
}
-var (
- trueBytes = []byte("true")
- falseBytes = []byte("false")
-)
-
// fmt_boolean formats a boolean.
func (f *fmt) fmt_boolean(v bool) {
if v {
- f.pad(trueBytes)
+ f.padString("true")
} else {
- f.pad(falseBytes)
+ f.padString("false")
}
}
-// integer; interprets prec but not wid. Once formatted, result is sent to pad()
-// and then flags are cleared.
-func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
- // precision of 0 and value of 0 means "print nothing"
- if f.precPresent && f.prec == 0 && a == 0 {
- return
+// fmt_unicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
+func (f *fmt) fmt_unicode(u uint64) {
+ buf := f.intbuf[0:]
+
+ // With default precision set the maximum needed buf length is 18
+ // for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits
+ // into the already allocated intbuf with a capacity of 68 bytes.
+ prec := 4
+ if f.precPresent && f.prec > 4 {
+ prec = f.prec
+ // Compute space needed for "U+" , number, " '", character, "'".
+ width := 2 + prec + 2 + utf8.UTFMax + 1
+ if width > len(buf) {
+ buf = make([]byte, width)
+ }
}
- negative := signedness == signed && a < 0
+ // Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left.
+ i := len(buf)
+
+ // For %#U we want to add a space and a quoted character at the end of the buffer.
+ if f.sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) {
+ i--
+ buf[i] = '\''
+ i -= utf8.RuneLen(rune(u))
+ utf8.EncodeRune(buf[i:], rune(u))
+ i--
+ buf[i] = '\''
+ i--
+ buf[i] = ' '
+ }
+ // Format the Unicode code point u as a hexadecimal number.
+ for u >= 16 {
+ i--
+ buf[i] = udigits[u&0xF]
+ prec--
+ u >>= 4
+ }
+ i--
+ buf[i] = udigits[u]
+ prec--
+ // Add zeros in front of the number until requested precision is reached.
+ for prec > 0 {
+ i--
+ buf[i] = '0'
+ prec--
+ }
+ // Add a leading "U+".
+ i--
+ buf[i] = '+'
+ i--
+ buf[i] = 'U'
+
+ oldZero := f.zero
+ f.zero = false
+ f.pad(buf[i:])
+ f.zero = oldZero
+}
+
+// fmt_integer formats signed and unsigned integers.
+func (f *fmt) fmt_integer(u uint64, base int, isSigned bool, digits string) {
+ negative := isSigned && int64(u) < 0
if negative {
- a = -a
+ u = -u
}
- var buf []byte = f.intbuf[0:]
- if f.widPresent || f.precPresent || f.plus || f.space {
- width := f.wid + f.prec // Only one will be set, both are positive; this provides the maximum.
- if base == 16 && f.sharp {
- // Also adds "0x".
- width += 2
- }
- if f.unicode {
- // Also adds "U+".
- width += 2
- if f.uniQuote {
- // Also adds " 'x'".
- width += 1 + 1 + utf8.UTFMax + 1
- }
- }
- if negative || f.plus || f.space {
- width++
- }
- if width > nByte {
+ buf := f.intbuf[0:]
+ // The already allocated f.intbuf with a capacity of 68 bytes
+ // is large enough for integer formatting when no precision or width is set.
+ if f.widPresent || f.precPresent {
+ // Account 3 extra bytes for possible addition of a sign and "0x".
+ width := 3 + f.wid + f.prec // wid and prec are always positive.
+ if width > len(buf) {
// We're going to need a bigger boat.
buf = make([]byte, width)
}
}
- // two ways to ask for extra leading zero digits: %.3d or %03d.
- // apparently the first cancels the second.
+ // Two ways to ask for extra leading zero digits: %.3d or %03d.
+ // If both are specified the f.zero flag is ignored and
+ // padding with spaces is used instead.
prec := 0
if f.precPresent {
prec = f.prec
- f.zero = false
- } else if f.zero && f.widPresent && !f.minus && f.wid > 0 {
+ // Precision of 0 and value of 0 means "print nothing" but padding.
+ if prec == 0 && u == 0 {
+ oldZero := f.zero
+ f.zero = false
+ f.writePadding(f.wid)
+ f.zero = oldZero
+ return
+ }
+ } else if f.zero && f.widPresent {
prec = f.wid
if negative || f.plus || f.space {
prec-- // leave room for sign
}
}
- // format a into buf, ending at buf[i]. (printing is easier right-to-left.)
- // a is made into unsigned ua. we could make things
- // marginally faster by splitting the 32-bit case out into a separate
- // block but it's not worth the duplication, so ua has 64 bits.
+ // Because printing is easier right-to-left: format u into buf, ending at buf[i].
+ // We could make things marginally faster by splitting the 32-bit case out
+ // into a separate block but it's not worth the duplication, so u has 64 bits.
i := len(buf)
- ua := uint64(a)
- // use constants for the division and modulo for more efficient code.
- // switch cases ordered by popularity.
+ // Use constants for the division and modulo for more efficient code.
+ // Switch cases ordered by popularity.
switch base {
case 10:
- for ua >= 10 {
+ for u >= 10 {
i--
- next := ua / 10
- buf[i] = byte('0' + ua - next*10)
- ua = next
+ next := u / 10
+ buf[i] = byte('0' + u - next*10)
+ u = next
}
case 16:
- for ua >= 16 {
+ for u >= 16 {
i--
- buf[i] = digits[ua&0xF]
- ua >>= 4
+ buf[i] = digits[u&0xF]
+ u >>= 4
}
case 8:
- for ua >= 8 {
+ for u >= 8 {
i--
- buf[i] = byte('0' + ua&7)
- ua >>= 3
+ buf[i] = byte('0' + u&7)
+ u >>= 3
}
case 2:
- for ua >= 2 {
+ for u >= 2 {
i--
- buf[i] = byte('0' + ua&1)
- ua >>= 1
+ buf[i] = byte('0' + u&1)
+ u >>= 1
}
default:
panic("fmt: unknown base; can't happen")
}
i--
- buf[i] = digits[ua]
+ buf[i] = digits[u]
for i > 0 && prec > len(buf)-i {
i--
buf[i] = '0'
@@ -257,18 +281,13 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
buf[i] = '0'
}
case 16:
+ // Add a leading 0x or 0X.
i--
- buf[i] = 'x' + digits[10] - 'a'
+ buf[i] = digits[16]
i--
buf[i] = '0'
}
}
- if f.unicode {
- i--
- buf[i] = '+'
- i--
- buf[i] = 'U'
- }
if negative {
i--
@@ -281,36 +300,23 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
buf[i] = ' '
}
- // If we want a quoted char for %#U, move the data up to make room.
- if f.unicode && f.uniQuote && a >= 0 && a <= utf8.MaxRune && strconv.IsPrint(rune(a)) {
- runeWidth := utf8.RuneLen(rune(a))
- width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
- copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
- i -= width
- // Now put " 'x'" at the end.
- j := len(buf) - width
- buf[j] = ' '
- j++
- buf[j] = '\''
- j++
- utf8.EncodeRune(buf[j:], rune(a))
- j += runeWidth
- buf[j] = '\''
- }
-
+ // Left padding with zeros has already been handled like precision earlier
+ // or the f.zero flag is ignored due to an explicitly set precision.
+ oldZero := f.zero
+ f.zero = false
f.pad(buf[i:])
+ f.zero = oldZero
}
// truncate truncates the string to the specified precision, if present.
func (f *fmt) truncate(s string) string {
- if f.precPresent && f.prec < utf8.RuneCountInString(s) {
+ if f.precPresent {
n := f.prec
for i := range s {
- if n == 0 {
- s = s[:i]
- break
- }
n--
+ if n < 0 {
+ return s[:i]
+ }
}
}
return s
@@ -324,212 +330,169 @@ func (f *fmt) fmt_s(s string) {
// fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sbx(s string, b []byte, digits string) {
- n := len(b)
+ length := len(b)
if b == nil {
- n = len(s)
+ // No byte slice present. Assume string s should be encoded.
+ length = len(s)
+ }
+ // Set length to not process more bytes than the precision demands.
+ if f.precPresent && f.prec < length {
+ length = f.prec
+ }
+ // Compute width of the encoding taking into account the f.sharp and f.space flag.
+ width := 2 * length
+ if width > 0 {
+ if f.space {
+ // Each element encoded by two hexadecimals will get a leading 0x or 0X.
+ if f.sharp {
+ width *= 2
+ }
+ // Elements will be separated by a space.
+ width += length - 1
+ } else if f.sharp {
+ // Only a leading 0x or 0X will be added for the whole string.
+ width += 2
+ }
+ } else { // The byte slice or string that should be encoded is empty.
+ if f.widPresent {
+ f.writePadding(f.wid)
+ }
+ return
+ }
+ // Handle padding to the left.
+ if f.widPresent && f.wid > width && !f.minus {
+ f.writePadding(f.wid - width)
}
- x := digits[10] - 'a' + 'x'
- // TODO: Avoid buffer by pre-padding.
- var buf []byte
- for i := 0; i < n; i++ {
- if i > 0 && f.space {
+ // Write the encoding directly into the output buffer.
+ buf := *f.buf
+ if f.sharp {
+ // Add leading 0x or 0X.
+ buf = append(buf, '0', digits[16])
+ }
+ var c byte
+ for i := 0; i < length; i++ {
+ if f.space && i > 0 {
+ // Separate elements with a space.
buf = append(buf, ' ')
+ if f.sharp {
+ // Add leading 0x or 0X for each element.
+ buf = append(buf, '0', digits[16])
+ }
}
- if f.sharp && (f.space || i == 0) {
- buf = append(buf, '0', x)
- }
- var c byte
- if b == nil {
- c = s[i]
+ if b != nil {
+ c = b[i] // Take a byte from the input byte slice.
} else {
- c = b[i]
+ c = s[i] // Take a byte from the input string.
}
+ // Encode each byte as two hexadecimal digits.
buf = append(buf, digits[c>>4], digits[c&0xF])
}
- f.pad(buf)
+ *f.buf = buf
+ // Handle padding to the right.
+ if f.widPresent && f.wid > width && f.minus {
+ f.writePadding(f.wid - width)
+ }
}
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sx(s, digits string) {
- if f.precPresent && f.prec < len(s) {
- s = s[:f.prec]
- }
f.fmt_sbx(s, nil, digits)
}
// fmt_bx formats a byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_bx(b []byte, digits string) {
- if f.precPresent && f.prec < len(b) {
- b = b[:f.prec]
- }
f.fmt_sbx("", b, digits)
}
// fmt_q formats a string as a double-quoted, escaped Go string constant.
+// If f.sharp is set a raw (backquoted) string may be returned instead
+// if the string does not contain any control characters other than tab.
func (f *fmt) fmt_q(s string) {
s = f.truncate(s)
- var quoted string
if f.sharp && strconv.CanBackquote(s) {
- quoted = "`" + s + "`"
+ f.padString("`" + s + "`")
+ return
+ }
+ buf := f.intbuf[:0]
+ if f.plus {
+ f.pad(strconv.AppendQuoteToASCII(buf, s))
} else {
- if f.plus {
- quoted = strconv.QuoteToASCII(s)
- } else {
- quoted = strconv.Quote(s)
- }
+ f.pad(strconv.AppendQuote(buf, s))
}
- f.padString(quoted)
}
-// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
+// fmt_c formats an integer as a Unicode character.
// If the character is not valid Unicode, it will print '\ufffd'.
-func (f *fmt) fmt_qc(c int64) {
- var quoted []byte
+func (f *fmt) fmt_c(c uint64) {
+ r := rune(c)
+ if c > utf8.MaxRune {
+ r = utf8.RuneError
+ }
+ buf := f.intbuf[:0]
+ w := utf8.EncodeRune(buf[:utf8.UTFMax], r)
+ f.pad(buf[:w])
+}
+
+// fmt_qc formats an integer as a single-quoted, escaped Go character constant.
+// If the character is not valid Unicode, it will print '\ufffd'.
+func (f *fmt) fmt_qc(c uint64) {
+ r := rune(c)
+ if c > utf8.MaxRune {
+ r = utf8.RuneError
+ }
+ buf := f.intbuf[:0]
if f.plus {
- quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
+ f.pad(strconv.AppendQuoteRuneToASCII(buf, r))
} else {
- quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
+ f.pad(strconv.AppendQuoteRune(buf, r))
}
- f.pad(quoted)
}
-// floating-point
-
-func doPrec(f *fmt, def int) int {
+// fmt_float formats a float64. It assumes that verb is a valid format specifier
+// for strconv.AppendFloat and therefore fits into a byte.
+func (f *fmt) fmt_float(v float64, size int, verb rune, prec int) {
+ // Explicit precision in format specifier overrules default precision.
if f.precPresent {
- return f.prec
+ prec = f.prec
}
- return def
-}
-
-// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
-func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
// Format number, reserving space for leading + sign if needed.
- num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+ num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
if num[1] == '-' || num[1] == '+' {
num = num[1:]
} else {
num[0] = '+'
}
- // Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros.
- if math.IsInf(v, 0) {
- if f.zero {
- defer func() { f.zero = true }()
- f.zero = false
- }
+ // f.space means to add a leading space instead of a "+" sign unless
+ // the sign is explicitly asked for by f.plus.
+ if f.space && num[0] == '+' && !f.plus {
+ num[0] = ' '
}
- // num is now a signed version of the number.
- // If we're zero padding, want the sign before the leading zeros.
- // Achieve this by writing the sign out and then padding the unsigned number.
- if f.zero && f.widPresent && f.wid > len(num) {
- if f.space && v >= 0 {
- f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space.
- f.wid--
- } else if f.plus || v < 0 {
- f.buf.WriteByte(num[0])
- f.wid--
+ // Special handling for infinities and NaN,
+ // which don't look like a number so shouldn't be padded with zeros.
+ if num[1] == 'I' || num[1] == 'N' {
+ oldZero := f.zero
+ f.zero = false
+ // Remove sign before NaN if not asked for.
+ if num[1] == 'N' && !f.space && !f.plus {
+ num = num[1:]
}
- f.pad(num[1:])
- return
- }
- // f.space says to replace a leading + with a space.
- if f.space && num[0] == '+' {
- num[0] = ' '
f.pad(num)
+ f.zero = oldZero
return
}
- // Now we know the sign is attached directly to the number, if present at all.
- // We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf).
- if f.plus || num[0] == '-' || math.IsInf(v, 0) {
+ // We want a sign if asked for and if the sign is not positive.
+ if f.plus || num[0] != '+' {
+ // If we're zero padding to the left we want the sign before the leading zeros.
+ // Achieve this by writing the sign out and then padding the unsigned number.
+ if f.zero && f.widPresent && f.wid > len(num) {
+ f.buf.WriteByte(num[0])
+ f.writePadding(f.wid - len(num))
+ f.buf.Write(num[1:])
+ return
+ }
f.pad(num)
return
}
// No sign to show and the number is positive; just print the unsigned number.
f.pad(num[1:])
}
-
-// fmt_e64 formats a float64 in the form -1.23e+12.
-func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
-
-// fmt_E64 formats a float64 in the form -1.23E+12.
-func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
-
-// fmt_f64 formats a float64 in the form -1.23.
-func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
-
-// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
-
-// fmt_G64 formats a float64 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
-
-// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
-
-// float32
-// cannot defer to float64 versions
-// because it will get rounding wrong in corner cases.
-
-// fmt_e32 formats a float32 in the form -1.23e+12.
-func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
-
-// fmt_E32 formats a float32 in the form -1.23E+12.
-func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
-
-// fmt_f32 formats a float32 in the form -1.23.
-func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
-
-// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
-
-// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
-
-// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
-
-// fmt_c64 formats a complex64 according to the verb.
-func (f *fmt) fmt_c64(v complex64, verb rune) {
- f.fmt_complex(float64(real(v)), float64(imag(v)), 32, verb)
-}
-
-// fmt_c128 formats a complex128 according to the verb.
-func (f *fmt) fmt_c128(v complex128, verb rune) {
- f.fmt_complex(real(v), imag(v), 64, verb)
-}
-
-// fmt_complex formats a complex number as (r+ji).
-func (f *fmt) fmt_complex(r, j float64, size int, verb rune) {
- f.buf.WriteByte('(')
- oldPlus := f.plus
- oldSpace := f.space
- oldWid := f.wid
- for i := 0; ; i++ {
- switch verb {
- case 'b':
- f.formatFloat(r, 'b', 0, size)
- case 'e':
- f.formatFloat(r, 'e', doPrec(f, 6), size)
- case 'E':
- f.formatFloat(r, 'E', doPrec(f, 6), size)
- case 'f', 'F':
- f.formatFloat(r, 'f', doPrec(f, 6), size)
- case 'g':
- f.formatFloat(r, 'g', doPrec(f, -1), size)
- case 'G':
- f.formatFloat(r, 'G', doPrec(f, -1), size)
- }
- if i != 0 {
- break
- }
- // Imaginary part always has a sign.
- f.plus = true
- f.space = false
- f.wid = oldWid
- r = j
- }
- f.space = oldSpace
- f.plus = oldPlus
- f.wid = oldWid
- f.buf.Write(irparenBytes)
-}
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index ebfa13e..f8c7316 100644
--- a/libgo/go/fmt/print.go
+++ b/libgo/go/fmt/print.go
@@ -13,24 +13,23 @@ import (
"unicode/utf8"
)
-// Some constants in the form of bytes, to avoid string overhead.
-// Needlessly fastidious, I suppose.
-var (
- commaSpaceBytes = []byte(", ")
- nilAngleBytes = []byte("<nil>")
- nilParenBytes = []byte("(nil)")
- nilBytes = []byte("nil")
- mapBytes = []byte("map[")
- percentBangBytes = []byte("%!")
- missingBytes = []byte("(MISSING)")
- badIndexBytes = []byte("(BADINDEX)")
- panicBytes = []byte("(PANIC=")
- extraBytes = []byte("%!(EXTRA ")
- irparenBytes = []byte("i)")
- bytesBytes = []byte("[]byte{")
- badWidthBytes = []byte("%!(BADWIDTH)")
- badPrecBytes = []byte("%!(BADPREC)")
- noVerbBytes = []byte("%!(NOVERB)")
+// Strings for use with buffer.WriteString.
+// This is less overhead than using buffer.Write with byte arrays.
+const (
+ commaSpaceString = ", "
+ nilAngleString = "<nil>"
+ nilParenString = "(nil)"
+ nilString = "nil"
+ mapString = "map["
+ percentBangString = "%!"
+ missingString = "(MISSING)"
+ badIndexString = "(BADINDEX)"
+ panicString = "(PANIC="
+ extraString = "%!(EXTRA "
+ badWidthString = "%!(BADWIDTH)"
+ badPrecString = "%!(BADPREC)"
+ noVerbString = "%!(NOVERB)"
+ invReflectString = "<invalid reflect.Value>"
)
// State represents the printer state passed to custom formatters.
@@ -38,7 +37,7 @@ var (
// the flags and options for the operand's format specifier.
type State interface {
// Write is the function to call to emit formatted output to be printed.
- Write(b []byte) (ret int, err error)
+ Write(b []byte) (n int, err error)
// Width returns the value of the width option and whether it has been set.
Width() (wid int, ok bool)
// Precision returns the value of the precision option and whether it has been set.
@@ -75,25 +74,22 @@ type GoStringer interface {
// Use simple []byte instead of bytes.Buffer to avoid large dependency.
type buffer []byte
-func (b *buffer) Write(p []byte) (n int, err error) {
+func (b *buffer) Write(p []byte) {
*b = append(*b, p...)
- return len(p), nil
}
-func (b *buffer) WriteString(s string) (n int, err error) {
+func (b *buffer) WriteString(s string) {
*b = append(*b, s...)
- return len(s), nil
}
-func (b *buffer) WriteByte(c byte) error {
+func (b *buffer) WriteByte(c byte) {
*b = append(*b, c)
- return nil
}
-func (bp *buffer) WriteRune(r rune) error {
+func (bp *buffer) WriteRune(r rune) {
if r < utf8.RuneSelf {
*bp = append(*bp, byte(r))
- return nil
+ return
}
b := *bp
@@ -103,25 +99,29 @@ func (bp *buffer) WriteRune(r rune) error {
}
w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
*bp = b[:n+w]
- return nil
}
+// pp is used to store a printer's state and is reused with sync.Pool to avoid allocations.
type pp struct {
- n int
- panicking bool
- erroring bool // printing an error condition
- buf buffer
+ buf buffer
+
// arg holds the current item, as an interface{}.
arg interface{}
- // value holds the current item, as a reflect.Value, and will be
- // the zero Value if the item has not been reflected.
+
+ // value is used instead of arg for reflect values.
value reflect.Value
+
+ // fmt is used to format basic items such as integers or strings.
+ fmt fmt
+
// reordered records whether the format string used argument reordering.
reordered bool
// goodArgNum records whether the most recent reordering directive was valid.
goodArgNum bool
- runeBuf [utf8.UTFMax]byte
- fmt fmt
+ // panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion.
+ panicking bool
+ // erroring is set when printing an error string to guard against calling handleMethods.
+ erroring bool
}
var ppFree = sync.Pool{
@@ -139,10 +139,6 @@ func newPrinter() *pp {
// free saves used pp structs in ppFree; avoids an allocation per invocation.
func (p *pp) free() {
- // Don't hold on to pp structs with large buffers.
- if cap(p.buf) > 1024 {
- return
- }
p.buf = p.buf[:0]
p.arg = nil
p.value = reflect.Value{}
@@ -158,9 +154,9 @@ func (p *pp) Flag(b int) bool {
case '-':
return p.fmt.minus
case '+':
- return p.fmt.plus
+ return p.fmt.plus || p.fmt.plusV
case '#':
- return p.fmt.sharp
+ return p.fmt.sharp || p.fmt.sharpV
case ' ':
return p.fmt.space
case '0':
@@ -169,14 +165,11 @@ func (p *pp) Flag(b int) bool {
return false
}
-func (p *pp) add(c rune) {
- p.buf.WriteRune(c)
-}
-
// Implement Write so we can call Fprintf on a pp (through State), for
// recursive use in custom verbs.
func (p *pp) Write(b []byte) (ret int, err error) {
- return p.buf.Write(b)
+ p.buf.Write(b)
+ return len(b), nil
}
// These routines end in 'f' and take a format string.
@@ -219,7 +212,7 @@ func Errorf(format string, a ...interface{}) error {
// It returns the number of bytes written and any write error encountered.
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
- p.doPrint(a, false, false)
+ p.doPrint(a)
n, err = w.Write(p.buf)
p.free()
return
@@ -236,7 +229,7 @@ func Print(a ...interface{}) (n int, err error) {
// Spaces are added between operands when neither is a string.
func Sprint(a ...interface{}) string {
p := newPrinter()
- p.doPrint(a, false, false)
+ p.doPrint(a)
s := string(p.buf)
p.free()
return s
@@ -251,7 +244,7 @@ func Sprint(a ...interface{}) string {
// It returns the number of bytes written and any write error encountered.
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
- p.doPrint(a, true, true)
+ p.doPrintln(a)
n, err = w.Write(p.buf)
p.free()
return
@@ -268,7 +261,7 @@ func Println(a ...interface{}) (n int, err error) {
// Spaces are always added between operands and a newline is appended.
func Sprintln(a ...interface{}) string {
p := newPrinter()
- p.doPrint(a, true, true)
+ p.doPrintln(a)
s := string(p.buf)
p.free()
return s
@@ -309,7 +302,7 @@ func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
func (p *pp) unknownType(v reflect.Value) {
if !v.IsValid() {
- p.buf.Write(nilAngleBytes)
+ p.buf.WriteString(nilAngleString)
return
}
p.buf.WriteByte('?')
@@ -319,23 +312,22 @@ func (p *pp) unknownType(v reflect.Value) {
func (p *pp) badVerb(verb rune) {
p.erroring = true
- p.add('%')
- p.add('!')
- p.add(verb)
- p.add('(')
+ p.buf.WriteString(percentBangString)
+ p.buf.WriteRune(verb)
+ p.buf.WriteByte('(')
switch {
case p.arg != nil:
p.buf.WriteString(reflect.TypeOf(p.arg).String())
- p.add('=')
- p.printArg(p.arg, 'v', 0)
+ p.buf.WriteByte('=')
+ p.printArg(p.arg, 'v')
case p.value.IsValid():
p.buf.WriteString(p.value.Type().String())
- p.add('=')
+ p.buf.WriteByte('=')
p.printValue(p.value, 'v', 0)
default:
- p.buf.Write(nilAngleBytes)
+ p.buf.WriteString(nilAngleString)
}
- p.add(')')
+ p.buf.WriteByte(')')
p.erroring = false
}
@@ -348,162 +340,82 @@ func (p *pp) fmtBool(v bool, verb rune) {
}
}
-// fmtC formats a rune for the 'c' format.
-func (p *pp) fmtC(c int64) {
- r := rune(c) // Check for overflow.
- if int64(r) != c {
- r = utf8.RuneError
- }
- w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], r)
- p.fmt.pad(p.runeBuf[0:w])
-}
-
-func (p *pp) fmtInt64(v int64, verb rune) {
- switch verb {
- case 'b':
- p.fmt.integer(v, 2, signed, ldigits)
- case 'c':
- p.fmtC(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(v)
- } else {
- p.badVerb(verb)
- }
- case 'x':
- p.fmt.integer(v, 16, signed, ldigits)
- case 'U':
- p.fmtUnicode(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
// not, as requested, by temporarily setting the sharp flag.
func (p *pp) fmt0x64(v uint64, leading0x bool) {
sharp := p.fmt.sharp
p.fmt.sharp = leading0x
- p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ p.fmt.fmt_integer(v, 16, unsigned, ldigits)
p.fmt.sharp = sharp
}
-// fmtUnicode formats a uint64 in U+1234 form by
-// temporarily turning on the unicode flag and tweaking the precision.
-func (p *pp) fmtUnicode(v int64) {
- precPresent := p.fmt.precPresent
- sharp := p.fmt.sharp
- p.fmt.sharp = false
- prec := p.fmt.prec
- if !precPresent {
- // If prec is already set, leave it alone; otherwise 4 is minimum.
- p.fmt.prec = 4
- p.fmt.precPresent = true
- }
- p.fmt.unicode = true // turn on U+
- p.fmt.uniQuote = sharp
- p.fmt.integer(int64(v), 16, unsigned, udigits)
- p.fmt.unicode = false
- p.fmt.uniQuote = false
- p.fmt.prec = prec
- p.fmt.precPresent = precPresent
- 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 {
- case 'b':
- p.fmt.integer(int64(v), 2, unsigned, ldigits)
- case 'c':
- p.fmtC(int64(v))
- case 'd':
- p.fmt.integer(int64(v), 10, unsigned, ldigits)
case 'v':
- if p.fmt.sharpV {
+ if p.fmt.sharpV && !isSigned {
p.fmt0x64(v, true)
} 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':
- 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':
- if 0 <= v && v <= utf8.MaxRune {
- p.fmt.fmt_qc(int64(v))
+ if v <= utf8.MaxRune {
+ p.fmt.fmt_qc(v)
} else {
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':
- p.fmtUnicode(int64(v))
+ p.fmt.fmt_unicode(v)
default:
p.badVerb(verb)
}
}
-func (p *pp) fmtFloat32(v float32, verb rune) {
+// fmtFloat formats a float. The default precision for each verb
+// is specified as last argument in the call to fmt_float.
+func (p *pp) fmtFloat(v float64, size int, verb rune) {
switch verb {
- case 'b':
- p.fmt.fmt_fb32(v)
- case 'e':
- p.fmt.fmt_e32(v)
- case 'E':
- p.fmt.fmt_E32(v)
- case 'f', 'F':
- p.fmt.fmt_f32(v)
- case 'g', 'v':
- p.fmt.fmt_g32(v)
- case 'G':
- p.fmt.fmt_G32(v)
- default:
- p.badVerb(verb)
- }
-}
-
-func (p *pp) fmtFloat64(v float64, verb rune) {
- switch verb {
- case 'b':
- p.fmt.fmt_fb64(v)
- case 'e':
- p.fmt.fmt_e64(v)
- case 'E':
- p.fmt.fmt_E64(v)
- case 'f', 'F':
- p.fmt.fmt_f64(v)
- case 'g', 'v':
- p.fmt.fmt_g64(v)
- case 'G':
- p.fmt.fmt_G64(v)
- default:
- p.badVerb(verb)
- }
-}
-
-func (p *pp) fmtComplex64(v complex64, verb rune) {
- switch verb {
- case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
- p.fmt.fmt_c64(v, verb)
case 'v':
- p.fmt.fmt_c64(v, 'g')
+ p.fmt.fmt_float(v, size, 'g', -1)
+ case 'b', 'g', 'G':
+ p.fmt.fmt_float(v, size, verb, -1)
+ case 'f', 'e', 'E':
+ p.fmt.fmt_float(v, size, verb, 6)
+ case 'F':
+ p.fmt.fmt_float(v, size, 'f', 6)
default:
p.badVerb(verb)
}
}
-func (p *pp) fmtComplex128(v complex128, verb rune) {
+// fmtComplex formats a complex number v with
+// r = real(v) and j = imag(v) as (r+ji) using
+// fmtFloat for r and j formatting.
+func (p *pp) fmtComplex(v complex128, size int, verb rune) {
+ // Make sure any unsupported verbs are found before the
+ // calls to fmtFloat to not generate an incorrect error string.
switch verb {
- case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
- p.fmt.fmt_c128(v, verb)
- case 'v':
- p.fmt.fmt_c128(v, 'g')
+ case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E':
+ oldPlus := p.fmt.plus
+ p.buf.WriteByte('(')
+ p.fmtFloat(real(v), size/2, verb)
+ // Imaginary part always has a sign.
+ p.fmt.plus = true
+ p.fmtFloat(imag(v), size/2, verb)
+ p.buf.WriteString("i)")
+ p.fmt.plus = oldPlus
default:
p.badVerb(verb)
}
@@ -530,45 +442,33 @@ func (p *pp) fmtString(v string, verb rune) {
}
}
-func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
- if verb == 'v' || verb == 'd' {
+func (p *pp) fmtBytes(v []byte, verb rune, typeString string) {
+ switch verb {
+ case 'v', 'd':
if p.fmt.sharpV {
+ p.buf.WriteString(typeString)
if v == nil {
- if typ == nil {
- p.buf.WriteString("[]byte(nil)")
- } else {
- p.buf.WriteString(typ.String())
- p.buf.Write(nilParenBytes)
- }
+ p.buf.WriteString(nilParenString)
return
}
- if typ == nil {
- p.buf.Write(bytesBytes)
- } else {
- p.buf.WriteString(typ.String())
- p.buf.WriteByte('{')
+ p.buf.WriteByte('{')
+ for i, c := range v {
+ if i > 0 {
+ p.buf.WriteString(commaSpaceString)
+ }
+ p.fmt0x64(uint64(c), true)
}
+ p.buf.WriteByte('}')
} else {
p.buf.WriteByte('[')
- }
- for i, c := range v {
- if i > 0 {
- if p.fmt.sharpV {
- p.buf.Write(commaSpaceBytes)
- } else {
+ for i, c := range v {
+ if i > 0 {
p.buf.WriteByte(' ')
}
+ p.fmt.fmt_integer(uint64(c), 10, unsigned, ldigits)
}
- p.printArg(c, 'v', depth+1)
- }
- if p.fmt.sharpV {
- p.buf.WriteByte('}')
- } else {
p.buf.WriteByte(']')
}
- return
- }
- switch verb {
case 's':
p.fmt.fmt_s(string(v))
case 'x':
@@ -578,23 +478,11 @@ func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
case 'q':
p.fmt.fmt_q(string(v))
default:
- p.badVerb(verb)
+ p.printValue(reflect.ValueOf(v), verb, 0)
}
}
func (p *pp) fmtPointer(value reflect.Value, verb rune) {
- use0x64 := true
- switch verb {
- case 'p', 'v':
- // ok
- case 'b', 'd', 'o', 'x', 'X':
- use0x64 = false
- // ok
- default:
- p.badVerb(verb)
- return
- }
-
var u uintptr
switch value.Kind() {
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
@@ -604,40 +492,41 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune) {
return
}
- if p.fmt.sharpV {
- p.add('(')
- p.buf.WriteString(value.Type().String())
- p.add(')')
- p.add('(')
- if u == 0 {
- p.buf.Write(nilBytes)
- } else {
- p.fmt0x64(uint64(u), true)
- }
- p.add(')')
- } else if verb == 'v' && u == 0 {
- p.buf.Write(nilAngleBytes)
- } else {
- if use0x64 {
- p.fmt0x64(uint64(u), !p.fmt.sharp)
+ switch verb {
+ case 'v':
+ if p.fmt.sharpV {
+ p.buf.WriteByte('(')
+ p.buf.WriteString(value.Type().String())
+ p.buf.WriteString(")(")
+ if u == 0 {
+ p.buf.WriteString(nilString)
+ } else {
+ p.fmt0x64(uint64(u), true)
+ }
+ p.buf.WriteByte(')')
} else {
- p.fmtUint64(uint64(u), verb)
+ if u == 0 {
+ p.fmt.padString(nilAngleString)
+ } else {
+ p.fmt0x64(uint64(u), !p.fmt.sharp)
+ }
}
+ case 'p':
+ p.fmt0x64(uint64(u), !p.fmt.sharp)
+ case 'b', 'o', 'd', 'x', 'X':
+ p.fmtInteger(uint64(u), unsigned, verb)
+ default:
+ p.badVerb(verb)
}
}
-var (
- intBits = reflect.TypeOf(0).Bits()
- uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
-)
-
func (p *pp) catchPanic(arg interface{}, verb rune) {
if err := recover(); err != nil {
// If it's a nil pointer, just say "<nil>". The likeliest causes are a
// Stringer that fails to guard against nil or a nil pointer for a
// value receiver, and in either case, "<nil>" is a nice result.
if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() {
- p.buf.Write(nilAngleBytes)
+ p.buf.WriteString(nilAngleString)
return
}
// Otherwise print a concise panic message. Most of the time the panic
@@ -647,52 +536,23 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
panic(err)
}
p.fmt.clearflags() // We are done, and for this output we want default behavior.
- p.buf.Write(percentBangBytes)
- p.add(verb)
- p.buf.Write(panicBytes)
+ p.buf.WriteString(percentBangString)
+ p.buf.WriteRune(verb)
+ p.buf.WriteString(panicString)
p.panicking = true
- p.printArg(err, 'v', 0)
+ p.printArg(err, 'v')
p.panicking = false
p.buf.WriteByte(')')
}
}
-// clearSpecialFlags pushes %#v back into the regular flags and returns their old state.
-func (p *pp) clearSpecialFlags() (plusV, sharpV bool) {
- plusV = p.fmt.plusV
- if plusV {
- p.fmt.plus = true
- p.fmt.plusV = false
- }
- sharpV = p.fmt.sharpV
- if sharpV {
- p.fmt.sharp = true
- p.fmt.sharpV = false
- }
- return
-}
-
-// restoreSpecialFlags, whose argument should be a call to clearSpecialFlags,
-// restores the setting of the plusV and sharpV flags.
-func (p *pp) restoreSpecialFlags(plusV, sharpV bool) {
- if plusV {
- p.fmt.plus = false
- p.fmt.plusV = true
- }
- if sharpV {
- p.fmt.sharp = false
- p.fmt.sharpV = true
- }
-}
-
-func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
+func (p *pp) handleMethods(verb rune) (handled bool) {
if p.erroring {
return
}
// Is it a Formatter?
if formatter, ok := p.arg.(Formatter); ok {
handled = true
- defer p.restoreSpecialFlags(p.clearSpecialFlags())
defer p.catchPanic(p.arg, verb)
formatter.Format(p, verb)
return
@@ -721,13 +581,13 @@ func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
case error:
handled = true
defer p.catchPanic(p.arg, verb)
- p.printArg(v.Error(), verb, depth)
+ p.fmtString(v.Error(), verb)
return
case Stringer:
handled = true
defer p.catchPanic(p.arg, verb)
- p.printArg(v.String(), verb, depth)
+ p.fmtString(v.String(), verb)
return
}
}
@@ -735,28 +595,29 @@ func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
return false
}
-func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
+func (p *pp) printArg(arg interface{}, verb rune) {
p.arg = arg
p.value = reflect.Value{}
if arg == nil {
- if verb == 'T' || verb == 'v' {
- p.fmt.pad(nilAngleBytes)
- } else {
+ switch verb {
+ case 'T', 'v':
+ p.fmt.padString(nilAngleString)
+ default:
p.badVerb(verb)
}
- return false
+ return
}
// Special processing considerations.
// %T (the value's type) and %p (its address) are special; we always do them first.
switch verb {
case 'T':
- p.printArg(reflect.TypeOf(arg).String(), 's', 0)
- return false
+ p.fmt.fmt_s(reflect.TypeOf(arg).String())
+ return
case 'p':
- p.fmtPointer(reflect.ValueOf(arg), verb)
- return false
+ p.fmtPointer(reflect.ValueOf(arg), 'p')
+ return
}
// Some types can be done without reflection.
@@ -764,137 +625,110 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
case bool:
p.fmtBool(f, verb)
case float32:
- p.fmtFloat32(f, verb)
+ p.fmtFloat(float64(f), 32, verb)
case float64:
- p.fmtFloat64(f, verb)
+ p.fmtFloat(f, 64, verb)
case complex64:
- p.fmtComplex64(f, verb)
+ p.fmtComplex(complex128(f), 64, verb)
case complex128:
- p.fmtComplex128(f, verb)
+ p.fmtComplex(f, 128, verb)
case int:
- p.fmtInt64(int64(f), verb)
+ p.fmtInteger(uint64(f), signed, verb)
case int8:
- p.fmtInt64(int64(f), verb)
+ p.fmtInteger(uint64(f), signed, verb)
case int16:
- p.fmtInt64(int64(f), verb)
+ p.fmtInteger(uint64(f), signed, verb)
case int32:
- p.fmtInt64(int64(f), verb)
+ p.fmtInteger(uint64(f), signed, verb)
case int64:
- p.fmtInt64(f, verb)
+ p.fmtInteger(uint64(f), signed, verb)
case uint:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case uint8:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case uint16:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case uint32:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case uint64:
- p.fmtUint64(f, verb)
+ p.fmtInteger(f, unsigned, verb)
case uintptr:
- p.fmtUint64(uint64(f), verb)
+ p.fmtInteger(uint64(f), unsigned, verb)
case string:
p.fmtString(f, verb)
- wasString = verb == 's' || verb == 'v'
case []byte:
- p.fmtBytes(f, verb, nil, depth)
- wasString = verb == 's'
+ p.fmtBytes(f, verb, "[]byte")
case reflect.Value:
- return p.printReflectValue(f, verb, depth)
+ p.printValue(f, verb, 0)
default:
// If the type is not simple, it might have methods.
- if handled := p.handleMethods(verb, depth); handled {
- return false
+ if !p.handleMethods(verb) {
+ // Need to use reflection, since the type had no
+ // interface methods that could be used for formatting.
+ p.printValue(reflect.ValueOf(f), verb, 0)
}
- // Need to use reflection
- return p.printReflectValue(reflect.ValueOf(arg), verb, depth)
}
- p.arg = nil
- return
}
-// printValue is like printArg but starts with a reflect value, not an interface{} value.
-func (p *pp) printValue(value reflect.Value, verb rune, depth int) (wasString bool) {
- if !value.IsValid() {
- if verb == 'T' || verb == 'v' {
- p.buf.Write(nilAngleBytes)
- } else {
- p.badVerb(verb)
- }
- return false
- }
-
- // Special processing considerations.
- // %T (the value's type) and %p (its address) are special; we always do them first.
- switch verb {
- case 'T':
- p.printArg(value.Type().String(), 's', 0)
- return false
- case 'p':
- p.fmtPointer(value, verb)
- return false
- }
+var byteType = reflect.TypeOf(byte(0))
- // Handle values with special methods.
- // Call always, even when arg == nil, because handleMethods clears p.fmt.plus for us.
- p.arg = nil // Make sure it's cleared, for safety.
- if value.CanInterface() {
+// printValue is similar to printArg but starts with a reflect value, not an interface{} value.
+// It does not handle 'p' and 'T' verbs because these should have been already handled by printArg.
+func (p *pp) printValue(value reflect.Value, verb rune, depth int) {
+ // Handle values with special methods if not already handled by printArg (depth == 0).
+ if depth > 0 && value.IsValid() && value.CanInterface() {
p.arg = value.Interface()
+ if p.handleMethods(verb) {
+ return
+ }
}
- if handled := p.handleMethods(verb, depth); handled {
- return false
- }
-
- return p.printReflectValue(value, verb, depth)
-}
-
-var byteType = reflect.TypeOf(byte(0))
-
-// printReflectValue is the fallback for both printArg and printValue.
-// It uses reflect to print the value.
-func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasString bool) {
- oldValue := p.value
+ p.arg = nil
p.value = value
-BigSwitch:
- switch f := value; f.Kind() {
+
+ switch f := value; value.Kind() {
case reflect.Invalid:
- p.buf.WriteString("<invalid reflect.Value>")
+ if depth == 0 {
+ p.buf.WriteString(invReflectString)
+ } else {
+ switch verb {
+ case 'v':
+ p.buf.WriteString(nilAngleString)
+ default:
+ p.badVerb(verb)
+ }
+ }
case reflect.Bool:
p.fmtBool(f.Bool(), verb)
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:
- p.fmtUint64(f.Uint(), verb)
- case reflect.Float32, reflect.Float64:
- if f.Type().Size() == 4 {
- p.fmtFloat32(float32(f.Float()), verb)
- } else {
- p.fmtFloat64(f.Float(), verb)
- }
- case reflect.Complex64, reflect.Complex128:
- if f.Type().Size() == 8 {
- p.fmtComplex64(complex64(f.Complex()), verb)
- } else {
- p.fmtComplex128(f.Complex(), verb)
- }
+ p.fmtInteger(f.Uint(), unsigned, verb)
+ case reflect.Float32:
+ p.fmtFloat(f.Float(), 32, verb)
+ case reflect.Float64:
+ p.fmtFloat(f.Float(), 64, verb)
+ case reflect.Complex64:
+ p.fmtComplex(f.Complex(), 64, verb)
+ case reflect.Complex128:
+ p.fmtComplex(f.Complex(), 128, verb)
case reflect.String:
p.fmtString(f.String(), verb)
case reflect.Map:
if p.fmt.sharpV {
p.buf.WriteString(f.Type().String())
if f.IsNil() {
- p.buf.WriteString("(nil)")
- break
+ p.buf.WriteString(nilParenString)
+ return
}
p.buf.WriteByte('{')
} else {
- p.buf.Write(mapBytes)
+ p.buf.WriteString(mapString)
}
keys := f.MapKeys()
for i, key := range keys {
if i > 0 {
if p.fmt.sharpV {
- p.buf.Write(commaSpaceBytes)
+ p.buf.WriteString(commaSpaceString)
} else {
p.buf.WriteByte(' ')
}
@@ -910,26 +744,24 @@ BigSwitch:
}
case reflect.Struct:
if p.fmt.sharpV {
- p.buf.WriteString(value.Type().String())
+ p.buf.WriteString(f.Type().String())
}
- p.add('{')
- v := f
- t := v.Type()
- for i := 0; i < v.NumField(); i++ {
+ p.buf.WriteByte('{')
+ for i := 0; i < f.NumField(); i++ {
if i > 0 {
if p.fmt.sharpV {
- p.buf.Write(commaSpaceBytes)
+ p.buf.WriteString(commaSpaceString)
} else {
p.buf.WriteByte(' ')
}
}
if p.fmt.plusV || p.fmt.sharpV {
- if f := t.Field(i); f.Name != "" {
- p.buf.WriteString(f.Name)
+ if name := f.Type().Field(i).Name; name != "" {
+ p.buf.WriteString(name)
p.buf.WriteByte(':')
}
}
- p.printValue(getField(v, i), verb, depth+1)
+ p.printValue(getField(f, i), verb, depth+1)
}
p.buf.WriteByte('}')
case reflect.Interface:
@@ -937,91 +769,79 @@ BigSwitch:
if !value.IsValid() {
if p.fmt.sharpV {
p.buf.WriteString(f.Type().String())
- p.buf.Write(nilParenBytes)
+ p.buf.WriteString(nilParenString)
} else {
- p.buf.Write(nilAngleBytes)
+ p.buf.WriteString(nilAngleString)
}
} else {
- wasString = p.printValue(value, verb, depth+1)
+ p.printValue(value, verb, depth+1)
}
case reflect.Array, reflect.Slice:
- // Byte slices are special:
- // - Handle []byte (== []uint8) with fmtBytes.
- // - Handle []T, where T is a named byte type, with fmtBytes only
- // for the s, q, an x verbs. For other verbs, T might be a
- // Stringer, so we use printValue to print each element.
- if typ := f.Type(); typ.Elem().Kind() == reflect.Uint8 && (typ.Elem() == byteType || verb == 's' || verb == 'q' || verb == 'x') {
- var bytes []byte
- if f.Kind() == reflect.Slice {
- bytes = f.Bytes()
- } else if f.CanAddr() {
- bytes = f.Slice(0, f.Len()).Bytes()
- } else {
- // We have an array, but we cannot Slice() a non-addressable array,
- // so we build a slice by hand. This is a rare case but it would be nice
- // if reflection could help a little more.
- bytes = make([]byte, f.Len())
- for i := range bytes {
- bytes[i] = byte(f.Index(i).Uint())
+ switch verb {
+ case 's', 'q', 'x', 'X':
+ // Handle byte and uint8 slices and arrays special for the above verbs.
+ t := f.Type()
+ if t.Elem().Kind() == reflect.Uint8 {
+ var bytes []byte
+ if f.Kind() == reflect.Slice {
+ bytes = f.Bytes()
+ } else if f.CanAddr() {
+ bytes = f.Slice(0, f.Len()).Bytes()
+ } else {
+ // We have an array, but we cannot Slice() a non-addressable array,
+ // so we build a slice by hand. This is a rare case but it would be nice
+ // if reflection could help a little more.
+ bytes = make([]byte, f.Len())
+ for i := range bytes {
+ bytes[i] = byte(f.Index(i).Uint())
+ }
}
+ p.fmtBytes(bytes, verb, t.String())
+ return
}
- p.fmtBytes(bytes, verb, typ, depth)
- wasString = verb == 's'
- break
}
if p.fmt.sharpV {
- p.buf.WriteString(value.Type().String())
+ p.buf.WriteString(f.Type().String())
if f.Kind() == reflect.Slice && f.IsNil() {
- p.buf.WriteString("(nil)")
- break
+ p.buf.WriteString(nilParenString)
+ return
+ } else {
+ p.buf.WriteByte('{')
+ for i := 0; i < f.Len(); i++ {
+ if i > 0 {
+ p.buf.WriteString(commaSpaceString)
+ }
+ p.printValue(f.Index(i), verb, depth+1)
+ }
+ p.buf.WriteByte('}')
}
- p.buf.WriteByte('{')
} else {
p.buf.WriteByte('[')
- }
- for i := 0; i < f.Len(); i++ {
- if i > 0 {
- if p.fmt.sharpV {
- p.buf.Write(commaSpaceBytes)
- } else {
+ for i := 0; i < f.Len(); i++ {
+ if i > 0 {
p.buf.WriteByte(' ')
}
+ p.printValue(f.Index(i), verb, depth+1)
}
- p.printValue(f.Index(i), verb, depth+1)
- }
- if p.fmt.sharpV {
- p.buf.WriteByte('}')
- } else {
p.buf.WriteByte(']')
}
case reflect.Ptr:
- v := f.Pointer()
// pointer to array or slice or struct? ok at top level
// but not embedded (avoid loops)
- if v != 0 && depth == 0 {
+ if depth == 0 && f.Pointer() != 0 {
switch a := f.Elem(); a.Kind() {
- case reflect.Array, reflect.Slice:
- p.buf.WriteByte('&')
- p.printValue(a, verb, depth+1)
- break BigSwitch
- case reflect.Struct:
- p.buf.WriteByte('&')
- p.printValue(a, verb, depth+1)
- break BigSwitch
- case reflect.Map:
+ case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map:
p.buf.WriteByte('&')
p.printValue(a, verb, depth+1)
- break BigSwitch
+ return
}
}
fallthrough
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
- p.fmtPointer(value, verb)
+ p.fmtPointer(f, verb)
default:
p.unknownType(f)
}
- p.value = oldValue
- return wasString
}
// intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has integer type.
@@ -1098,11 +918,24 @@ func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum
return argNum, i + wid, ok
}
+func (p *pp) badArgNum(verb rune) {
+ p.buf.WriteString(percentBangString)
+ p.buf.WriteRune(verb)
+ p.buf.WriteString(badIndexString)
+}
+
+func (p *pp) missingArg(verb rune) {
+ p.buf.WriteString(percentBangString)
+ p.buf.WriteRune(verb)
+ p.buf.WriteString(missingString)
+}
+
func (p *pp) doPrintf(format string, a []interface{}) {
end := len(format)
argNum := 0 // we process one argument per non-trivial format
afterIndex := false // previous item in format was an index like [3].
p.reordered = false
+formatLoop:
for i := 0; i < end; {
p.goodArgNum = true
lasti := i
@@ -1122,21 +955,40 @@ func (p *pp) doPrintf(format string, a []interface{}) {
// Do we have flags?
p.fmt.clearflags()
- F:
+ simpleFormat:
for ; i < end; i++ {
- switch format[i] {
+ c := format[i]
+ switch c {
case '#':
p.fmt.sharp = true
case '0':
- p.fmt.zero = true
+ p.fmt.zero = !p.fmt.minus // Only allow zero padding to the left.
case '+':
p.fmt.plus = true
case '-':
p.fmt.minus = true
+ p.fmt.zero = false // Do not pad with zeros to the right.
case ' ':
p.fmt.space = true
default:
- break F
+ // Fast path for common case of ascii lower case simple verbs
+ // without precision or width or argument indices.
+ if 'a' <= c && c <= 'z' && argNum < len(a) {
+ if c == 'v' {
+ // Go syntax
+ p.fmt.sharpV = p.fmt.sharp
+ p.fmt.sharp = false
+ // Struct-field syntax
+ p.fmt.plusV = p.fmt.plus
+ p.fmt.plus = false
+ }
+ p.printArg(a[argNum], rune(c))
+ argNum++
+ i++
+ continue formatLoop
+ }
+ // Format is more complex than simple flags and a verb or is malformed.
+ break simpleFormat
}
}
@@ -1149,7 +1001,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
if !p.fmt.widPresent {
- p.buf.Write(badWidthBytes)
+ p.buf.WriteString(badWidthString)
}
// We have a negative width, so take its value and ensure
@@ -1157,6 +1009,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
if p.fmt.wid < 0 {
p.fmt.wid = -p.fmt.wid
p.fmt.minus = true
+ p.fmt.zero = false // Do not pad with zeros to the right.
}
afterIndex = false
} else {
@@ -1182,7 +1035,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.fmt.precPresent = false
}
if !p.fmt.precPresent {
- p.buf.Write(badPrecBytes)
+ p.buf.WriteString(badPrecString)
}
afterIndex = false
} else {
@@ -1199,80 +1052,77 @@ func (p *pp) doPrintf(format string, a []interface{}) {
}
if i >= end {
- p.buf.Write(noVerbBytes)
- continue
+ p.buf.WriteString(noVerbString)
+ break
}
- c, w := utf8.DecodeRuneInString(format[i:])
+
+ verb, w := utf8.DecodeRuneInString(format[i:])
i += w
- // percent is special - absorbs no operand
- if c == '%' {
- p.buf.WriteByte('%') // We ignore width and prec.
- continue
- }
- if !p.goodArgNum {
- p.buf.Write(percentBangBytes)
- p.add(c)
- p.buf.Write(badIndexBytes)
- continue
- } else if argNum >= len(a) { // out of operands
- p.buf.Write(percentBangBytes)
- p.add(c)
- p.buf.Write(missingBytes)
- continue
- }
- arg := a[argNum]
- argNum++
-
- if c == 'v' {
- if p.fmt.sharp {
- // Go syntax. Set the flag in the fmt and clear the sharp flag.
- p.fmt.sharp = false
- p.fmt.sharpV = true
- }
- if p.fmt.plus {
- // Struct-field syntax. Set the flag in the fmt and clear the plus flag.
- p.fmt.plus = false
- p.fmt.plusV = true
- }
+
+ switch {
+ case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
+ p.buf.WriteByte('%')
+ case !p.goodArgNum:
+ p.badArgNum(verb)
+ case argNum >= len(a): // No argument left over to print for the current verb.
+ p.missingArg(verb)
+ case verb == 'v':
+ // Go syntax
+ p.fmt.sharpV = p.fmt.sharp
+ p.fmt.sharp = false
+ // Struct-field syntax
+ p.fmt.plusV = p.fmt.plus
+ p.fmt.plus = false
+ fallthrough
+ default:
+ p.printArg(a[argNum], verb)
+ argNum++
}
- p.printArg(arg, c, 0)
}
// Check for extra arguments unless the call accessed the arguments
// out of order, in which case it's too expensive to detect if they've all
// been used and arguably OK if they're not.
if !p.reordered && argNum < len(a) {
- p.buf.Write(extraBytes)
- for ; argNum < len(a); argNum++ {
- arg := a[argNum]
- if arg != nil {
+ p.fmt.clearflags()
+ p.buf.WriteString(extraString)
+ for i, arg := range a[argNum:] {
+ if i > 0 {
+ p.buf.WriteString(commaSpaceString)
+ }
+ if arg == nil {
+ p.buf.WriteString(nilAngleString)
+ } else {
p.buf.WriteString(reflect.TypeOf(arg).String())
p.buf.WriteByte('=')
- }
- p.printArg(arg, 'v', 0)
- if argNum+1 < len(a) {
- p.buf.Write(commaSpaceBytes)
+ p.printArg(arg, 'v')
}
}
p.buf.WriteByte(')')
}
}
-func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+func (p *pp) doPrint(a []interface{}) {
prevString := false
- for argNum := 0; argNum < len(a); argNum++ {
- p.fmt.clearflags()
- // always add spaces if we're doing Println
- arg := a[argNum]
- if argNum > 0 {
- isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
- if addspace || !isString && !prevString {
- p.buf.WriteByte(' ')
- }
+ for argNum, arg := range a {
+ isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
+ // Add a space between two non-string arguments.
+ if argNum > 0 && !isString && !prevString {
+ p.buf.WriteByte(' ')
}
- prevString = p.printArg(arg, 'v', 0)
+ p.printArg(arg, 'v')
+ prevString = isString
}
- if addnewline {
- p.buf.WriteByte('\n')
+}
+
+// doPrintln is like doPrint but always adds a space between arguments
+// and a newline after the last argument.
+func (p *pp) doPrintln(a []interface{}) {
+ for argNum, arg := range a {
+ if argNum > 0 {
+ p.buf.WriteByte(' ')
+ }
+ p.printArg(arg, 'v')
}
+ p.buf.WriteByte('\n')
}
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
index 4618ed4..fdf4197 100644
--- a/libgo/go/fmt/scan.go
+++ b/libgo/go/fmt/scan.go
@@ -15,14 +15,6 @@ import (
"unicode/utf8"
)
-// runeUnreader is the interface to something that can unread runes.
-// If the object provided to Scan does not satisfy this interface,
-// a local buffer will be used to back up the input, but its contents
-// will be lost when Scan returns.
-type runeUnreader interface {
- UnreadRune() error
-}
-
// ScanState represents the scanner state passed to custom scanners.
// Scanners may do rune-at-a-time scanning or ask the ScanState
// to discover the next space-delimited token.
@@ -41,7 +33,7 @@ type ScanState interface {
// Token skips space in the input if skipSpace is true, then returns the
// run of Unicode code points c satisfying f(c). If f is nil,
// !unicode.IsSpace(c) is used; that is, the token will hold non-space
- // characters. Newlines are treated appropriately for the operation being
+ // characters. Newlines are treated appropriately for the operation being
// performed; see the package documentation for more information.
// The returned slice points to shared data that may be overwritten
// by the next call to Token, a call to a Scan function using the ScanState
@@ -58,15 +50,15 @@ type ScanState interface {
// Scanner is implemented by any value that has a Scan method, which scans
// the input for the representation of a value and stores the result in the
-// receiver, which must be a pointer to be useful. The Scan method is called
+// receiver, which must be a pointer to be useful. The Scan method is called
// for any argument to Scan, Scanf, or Scanln that implements it.
type Scanner interface {
Scan(state ScanState, verb rune) error
}
// Scan scans text read from standard input, storing successive
-// space-separated values into successive arguments. Newlines count
-// as space. It returns the number of items successfully scanned.
+// space-separated values into successive arguments. Newlines count
+// as space. It returns the number of items successfully scanned.
// If that is less than the number of arguments, err will report why.
func Scan(a ...interface{}) (n int, err error) {
return Fscan(os.Stdin, a...)
@@ -80,7 +72,7 @@ func Scanln(a ...interface{}) (n int, err error) {
// Scanf scans text read from standard input, storing successive
// space-separated values into successive arguments as determined by
-// the format. It returns the number of items successfully scanned.
+// the format. It returns the number of items successfully scanned.
// If that is less than the number of arguments, err will report why.
// Newlines in the input must match newlines in the format.
// The one exception: the verb %c always scans the next rune in the
@@ -101,8 +93,8 @@ func (r *stringReader) Read(b []byte) (n int, err error) {
}
// Sscan scans the argument string, storing successive space-separated
-// values into successive arguments. Newlines count as space. It
-// returns the number of items successfully scanned. If that is less
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
func Sscan(str string, a ...interface{}) (n int, err error) {
return Fscan((*stringReader)(&str), a...)
@@ -115,7 +107,7 @@ func Sscanln(str string, a ...interface{}) (n int, err error) {
}
// Sscanf scans the argument string, storing successive space-separated
-// values into successive arguments as determined by the format. It
+// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
// Newlines in the input must match newlines in the format.
func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
@@ -123,8 +115,8 @@ func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
}
// Fscan scans text read from r, storing successive space-separated
-// values into successive arguments. Newlines count as space. It
-// returns the number of items successfully scanned. If that is less
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
func Fscan(r io.Reader, a ...interface{}) (n int, err error) {
s, old := newScanState(r, true, false)
@@ -143,7 +135,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err error) {
}
// Fscanf scans text read from r, storing successive space-separated
-// values into successive arguments as determined by the format. It
+// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
// Newlines in the input must match newlines in the format.
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) {
@@ -163,12 +155,10 @@ const eof = -1
// ss is the internal implementation of ScanState.
type ss struct {
- rr io.RuneReader // where to read input
- buf buffer // token accumulator
- peekRune rune // one-rune lookahead
- prevRune rune // last rune returned by ReadRune
- count int // runes consumed so far.
- atEOF bool // already read EOF
+ rs io.RuneScanner // where to read input
+ buf buffer // token accumulator
+ count int // runes consumed so far.
+ atEOF bool // already read EOF
ssave
}
@@ -191,23 +181,17 @@ func (s *ss) Read(buf []byte) (n int, err error) {
}
func (s *ss) ReadRune() (r rune, size int, err error) {
- if s.peekRune >= 0 {
- s.count++
- r = s.peekRune
- size = utf8.RuneLen(r)
- s.prevRune = r
- s.peekRune = -1
- return
- }
- if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.argLimit {
+ if s.atEOF || s.count >= s.argLimit {
err = io.EOF
return
}
- r, size, err = s.rr.ReadRune()
+ r, size, err = s.rs.ReadRune()
if err == nil {
s.count++
- s.prevRune = r
+ if s.nlIsEnd && r == '\n' {
+ s.atEOF = true
+ }
} else if err == io.EOF {
s.atEOF = true
}
@@ -246,12 +230,8 @@ func (s *ss) mustReadRune() (r rune) {
}
func (s *ss) UnreadRune() error {
- if u, ok := s.rr.(runeUnreader); ok {
- u.UnreadRune()
- } else {
- s.peekRune = s.prevRune
- }
- s.prevRune = -1
+ s.rs.UnreadRune()
+ s.atEOF = false
s.count--
return nil
}
@@ -326,13 +306,14 @@ func (s *ss) SkipSpace() {
}
// readRune is a structure to enable reading UTF-8 encoded code points
-// from an io.Reader. It is used if the Reader given to the scanner does
-// not already implement io.RuneReader.
+// from an io.Reader. It is used if the Reader given to the scanner does
+// not already implement io.RuneScanner.
type readRune struct {
- reader io.Reader
- buf [utf8.UTFMax]byte // used only inside ReadRune
- pending int // number of bytes in pendBuf; only >0 for bad UTF-8
- pendBuf [utf8.UTFMax]byte // bytes left over
+ reader io.Reader
+ buf [utf8.UTFMax]byte // used only inside ReadRune
+ pending int // number of bytes in pendBuf; only >0 for bad UTF-8
+ pendBuf [utf8.UTFMax]byte // bytes left over
+ peekRune rune // if >=0 next rune; when <0 is ^(previous Rune)
}
// readByte returns the next byte from the input, which may be
@@ -344,33 +325,35 @@ func (r *readRune) readByte() (b byte, err error) {
r.pending--
return
}
- n, err := io.ReadFull(r.reader, r.pendBuf[0:1])
+ n, err := io.ReadFull(r.reader, r.pendBuf[:1])
if n != 1 {
return 0, err
}
return r.pendBuf[0], err
}
-// unread saves the bytes for the next read.
-func (r *readRune) unread(buf []byte) {
- copy(r.pendBuf[r.pending:], buf)
- r.pending += len(buf)
-}
-
// ReadRune returns the next UTF-8 encoded code point from the
// io.Reader inside r.
func (r *readRune) ReadRune() (rr rune, size int, err error) {
+ if r.peekRune >= 0 {
+ rr = r.peekRune
+ r.peekRune = ^r.peekRune
+ size = utf8.RuneLen(rr)
+ return
+ }
r.buf[0], err = r.readByte()
if err != nil {
- return 0, 0, err
+ return
}
if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
rr = rune(r.buf[0])
size = 1 // Known to be 1.
+ // Flip the bits of the rune so it's available to UnreadRune.
+ r.peekRune = ^rr
return
}
var n int
- for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+ for n = 1; !utf8.FullRune(r.buf[:n]); n++ {
r.buf[n], err = r.readByte()
if err != nil {
if err == io.EOF {
@@ -380,13 +363,25 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
return
}
}
- rr, size = utf8.DecodeRune(r.buf[0:n])
- if size < n { // an error
- r.unread(r.buf[size:n])
+ rr, size = utf8.DecodeRune(r.buf[:n])
+ if size < n { // an error, save the bytes for the next read
+ copy(r.pendBuf[r.pending:], r.buf[size:n])
+ r.pending += n - size
}
+ // Flip the bits of the rune so it's available to UnreadRune.
+ r.peekRune = ^rr
return
}
+func (r *readRune) UnreadRune() error {
+ if r.peekRune >= 0 {
+ return errors.New("fmt: scanning called UnreadRune with no rune available")
+ }
+ // Reverse bit flip of previously read rune to obtain valid >=0 state.
+ r.peekRune = ^r.peekRune
+ return nil
+}
+
var ssFree = sync.Pool{
New: func() interface{} { return new(ss) },
}
@@ -394,15 +389,13 @@ var ssFree = sync.Pool{
// newScanState allocates a new ss struct or grab a cached one.
func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
s = ssFree.Get().(*ss)
- if rr, ok := r.(io.RuneReader); ok {
- s.rr = rr
+ if rs, ok := r.(io.RuneScanner); ok {
+ s.rs = rs
} else {
- s.rr = &readRune{reader: r}
+ s.rs = &readRune{reader: r, peekRune: -1}
}
s.nlIsSpace = nlIsSpace
s.nlIsEnd = nlIsEnd
- s.prevRune = -1
- s.peekRune = -1
s.atEOF = false
s.limit = hugeWid
s.argLimit = hugeWid
@@ -424,7 +417,7 @@ func (s *ss) free(old ssave) {
return
}
s.buf = s.buf[:0]
- s.rr = nil
+ s.rs = nil
ssFree.Put(s)
}
@@ -455,8 +448,8 @@ func (s *ss) skipSpace(stopAtNewline bool) {
}
}
-// token returns the next space-delimited string from the input. It
-// skips white space. For Scanln, it stops at newlines. For Scan,
+// token returns the next space-delimited string from the input. It
+// skips white space. For Scanln, it stops at newlines. For Scan,
// newlines are treated as spaces.
func (s *ss) token(skipSpace bool, f func(rune) bool) []byte {
if skipSpace {
@@ -525,7 +518,7 @@ func (s *ss) notEOF() {
s.UnreadRune()
}
-// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
+// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
// buffer and returns true. Otherwise it return false.
func (s *ss) accept(ok string) bool {
return s.consume(ok, true)
@@ -549,7 +542,7 @@ func (s *ss) scanBool(verb rune) bool {
if !s.okVerb(verb, "tv", "boolean") {
return false
}
- // Syntax-checking a boolean is annoying. We're not fastidious about case.
+ // Syntax-checking a boolean is annoying. We're not fastidious about case.
switch s.getRune() {
case '0':
return false
@@ -643,7 +636,7 @@ func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
}
// scanInt returns the value of the integer represented by the next
-// token, checking for overflow. Any error is stored in s.err.
+// token, checking for overflow. Any error is stored in s.err.
func (s *ss) scanInt(verb rune, bitSize int) int64 {
if verb == 'c' {
return s.scanRune(bitSize)
@@ -676,7 +669,7 @@ func (s *ss) scanInt(verb rune, bitSize int) int64 {
}
// scanUint returns the value of the unsigned integer represented
-// by the next token, checking for overflow. Any error is stored in s.err.
+// by the next token, checking for overflow. Any error is stored in s.err.
func (s *ss) scanUint(verb rune, bitSize int) uint64 {
if verb == 'c' {
return uint64(s.scanRune(bitSize))
@@ -846,7 +839,7 @@ func (s *ss) quotedString() string {
return string(s.buf)
case '"':
// Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
- s.buf.WriteRune(quote)
+ s.buf.WriteByte('"')
for {
r := s.mustReadRune()
s.buf.WriteRune(r)
@@ -922,9 +915,14 @@ func (s *ss) hexString() string {
return string(s.buf)
}
-const floatVerbs = "beEfFgGv"
+const (
+ floatVerbs = "beEfFgGv"
-const hugeWid = 1 << 30
+ hugeWid = 1 << 30
+
+ intBits = 32 << (^uint(0) >> 63)
+ uintptrBits = 32 << (^uintptr(0) >> 63)
+)
// scanOne scans a single value, deriving the scanner from the type of the argument.
func (s *ss) scanOne(verb rune, arg interface{}) {
@@ -1142,7 +1140,7 @@ func (s *ss) advance(format string) (i int) {
}
// doScanf does the real work when scanning with a format string.
-// At the moment, it handles only pointers to basic types.
+// At the moment, it handles only pointers to basic types.
func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err error) {
defer errorHandler(&err)
end := len(format) - 1
@@ -1155,7 +1153,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
}
// Either we failed to advance, we have a percent character, or we ran out of input.
if format[i] != '%' {
- // Can't advance format. Why not?
+ // Can't advance format. Why not?
if w < 0 {
s.errorString("input does not match format")
}
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
index 7ac74dcb..e36b62e 100644
--- a/libgo/go/fmt/scan_test.go
+++ b/libgo/go/fmt/scan_test.go
@@ -15,6 +15,7 @@ import (
"regexp"
"strings"
"testing"
+ "testing/iotest"
"unicode/utf8"
)
@@ -78,12 +79,6 @@ var (
renamedComplex128Val renamedComplex128
)
-type FloatTest struct {
- text string
- in float64
- out float64
-}
-
// Xs accepts any non-empty run of the verb character
type Xs string
@@ -124,20 +119,6 @@ func (s *IntString) Scan(state ScanState, verb rune) error {
var intStringVal IntString
-// myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper
-// type that creates something that can read runes given only Read().
-type myStringReader struct {
- r *strings.Reader
-}
-
-func (s *myStringReader) Read(p []byte) (n int, err error) {
- return s.r.Read(p)
-}
-
-func newReader(s string) *myStringReader {
- return &myStringReader{strings.NewReader(s)}
-}
-
var scanTests = []ScanTest{
// Basic types
{"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written
@@ -369,25 +350,38 @@ var multiTests = []ScanfMultiTest{
{"%v%v", "FALSE23", args(&truth, &i), args(false, 23), ""},
}
-func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, error)) {
+var readers = []struct {
+ name string
+ f func(string) io.Reader
+}{
+ {"StringReader", func(s string) io.Reader {
+ return strings.NewReader(s)
+ }},
+ {"ReaderOnly", func(s string) io.Reader {
+ return struct{ io.Reader }{strings.NewReader(s)}
+ }},
+ {"OneByteReader", func(s string) io.Reader {
+ return iotest.OneByteReader(strings.NewReader(s))
+ }},
+ {"DataErrReader", func(s string) io.Reader {
+ return iotest.DataErrReader(strings.NewReader(s))
+ }},
+}
+
+func testScan(t *testing.T, f func(string) io.Reader, scan func(r io.Reader, a ...interface{}) (int, error)) {
for _, test := range scanTests {
- var r io.Reader
- if name == "StringReader" {
- r = strings.NewReader(test.text)
- } else {
- r = newReader(test.text)
- }
+ r := f(test.text)
n, err := scan(r, test.in)
if err != nil {
m := ""
if n > 0 {
m = Sprintf(" (%d fields ok)", n)
}
- t.Errorf("%s got error scanning %q: %s%s", name, test.text, err, m)
+ t.Errorf("got error scanning %q: %s%s", test.text, err, m)
continue
}
if n != 1 {
- t.Errorf("%s count error on entry %q: got %d", name, test.text, n)
+ t.Errorf("count error on entry %q: got %d", test.text, n)
continue
}
// The incoming value may be a pointer
@@ -397,25 +391,25 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("%s scanning %q: expected %#v got %#v, type %T", name, test.text, test.out, val, val)
+ t.Errorf("scanning %q: expected %#v got %#v, type %T", test.text, test.out, val, val)
}
}
}
func TestScan(t *testing.T) {
- testScan("StringReader", t, Fscan)
-}
-
-func TestMyReaderScan(t *testing.T) {
- testScan("myStringReader", t, Fscan)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScan(t, r.f, Fscan)
+ })
+ }
}
func TestScanln(t *testing.T) {
- testScan("StringReader", t, Fscanln)
-}
-
-func TestMyReaderScanln(t *testing.T) {
- testScan("myStringReader", t, Fscanln)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScan(t, r.f, Fscanln)
+ })
+ }
}
func TestScanf(t *testing.T) {
@@ -506,20 +500,15 @@ func TestInf(t *testing.T) {
}
}
-func testScanfMulti(name string, t *testing.T) {
+func testScanfMulti(t *testing.T, f func(string) io.Reader) {
sliceType := reflect.TypeOf(make([]interface{}, 1))
for _, test := range multiTests {
- var r io.Reader
- if name == "StringReader" {
- r = strings.NewReader(test.text)
- } else {
- r = newReader(test.text)
- }
+ r := f(test.text)
n, err := Fscanf(r, test.format, test.in...)
if err != nil {
if test.err == "" {
t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
- } else if strings.Index(err.Error(), test.err) < 0 {
+ } else if !strings.Contains(err.Error(), test.err) {
t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
}
continue
@@ -545,11 +534,11 @@ func testScanfMulti(name string, t *testing.T) {
}
func TestScanfMulti(t *testing.T) {
- testScanfMulti("StringReader", t)
-}
-
-func TestMyReaderScanfMulti(t *testing.T) {
- testScanfMulti("myStringReader", t)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScanfMulti(t, r.f)
+ })
+ }
}
func TestScanMultiple(t *testing.T) {
@@ -613,7 +602,7 @@ func TestScanNotPointer(t *testing.T) {
_, err := Fscan(r, a)
if err == nil {
t.Error("expected error scanning non-pointer")
- } else if strings.Index(err.Error(), "pointer") < 0 {
+ } else if !strings.Contains(err.Error(), "pointer") {
t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
}
}
@@ -623,7 +612,7 @@ func TestScanlnNoNewline(t *testing.T) {
_, err := Sscanln("1 x\n", &a)
if err == nil {
t.Error("expected error scanning string missing newline")
- } else if strings.Index(err.Error(), "newline") < 0 {
+ } else if !strings.Contains(err.Error(), "newline") {
t.Errorf("expected newline error scanning string missing newline, got: %s", err)
}
}
@@ -634,7 +623,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) {
_, err := Fscanln(r, &a, &b)
if err == nil {
t.Error("expected error scanning string with extra newline")
- } else if strings.Index(err.Error(), "newline") < 0 {
+ } else if !strings.Contains(err.Error(), "newline") {
t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
}
}
@@ -767,7 +756,7 @@ func TestUnreadRuneWithBufio(t *testing.T) {
type TwoLines string
-// Scan attempts to read two lines into the object. Scanln should prevent this
+// Scan attempts to read two lines into the object. Scanln should prevent this
// because it stops at newline; Scan and Scanf should be fine.
func (t *TwoLines) Scan(state ScanState, verb rune) error {
chars := make([]rune, 0, 100)
@@ -824,20 +813,10 @@ func TestMultiLine(t *testing.T) {
}
}
-// simpleReader is a strings.Reader that implements only Read, not ReadRune.
-// Good for testing readahead.
-type simpleReader struct {
- sr *strings.Reader
-}
-
-func (s *simpleReader) Read(b []byte) (n int, err error) {
- return s.sr.Read(b)
-}
-
// TestLineByLineFscanf tests that Fscanf does not read past newline. Issue
// 3481.
func TestLineByLineFscanf(t *testing.T) {
- r := &simpleReader{strings.NewReader("1\n2\n")}
+ r := struct{ io.Reader }{strings.NewReader("1\n2\n")}
var i, j int
n, err := Fscanf(r, "%v\n", &i)
if n != 1 || err != nil {
@@ -1001,6 +980,18 @@ func BenchmarkScanRecursiveInt(b *testing.B) {
}
}
+func BenchmarkScanRecursiveIntReaderWrapper(b *testing.B) {
+ b.ResetTimer()
+ ints := makeInts(intCount)
+ var r RecursiveInt
+ for i := b.N - 1; i >= 0; i-- {
+ buf := struct{ io.Reader }{strings.NewReader(string(ints))}
+ b.StartTimer()
+ Fscan(buf, &r)
+ b.StopTimer()
+ }
+}
+
// Issue 9124.
// %x on bytes couldn't handle non-space bytes terminating the scan.
func TestHexBytes(t *testing.T) {