diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
---|---|---|
committer | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
commit | 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (patch) | |
tree | 4449f2036cccf162e8417cc5841a35815b3e7ac5 /src/pkg/fmt | |
parent | c8bf49ef8a92e2337b69c14b9b88396efe498600 (diff) | |
download | golang-upstream/1.3.tar.gz |
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'src/pkg/fmt')
-rw-r--r-- | src/pkg/fmt/doc.go | 58 | ||||
-rw-r--r-- | src/pkg/fmt/fmt_test.go | 234 | ||||
-rw-r--r-- | src/pkg/fmt/format.go | 139 | ||||
-rw-r--r-- | src/pkg/fmt/print.go | 53 | ||||
-rw-r--r-- | src/pkg/fmt/scan.go | 10 |
5 files changed, 342 insertions, 152 deletions
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go index 095fd03b2..02642d6ae 100644 --- a/src/pkg/fmt/doc.go +++ b/src/pkg/fmt/doc.go @@ -37,6 +37,7 @@ %e scientific notation, e.g. -1234.456e+78 %E scientific notation, e.g. -1234.456E+78 %f decimal point but no exponent, e.g. 123.456 + %F synonym for %f %g whichever of %e or %f produces more compact output %G whichever of %E or %f produces more compact output String and slice of bytes: @@ -50,23 +51,39 @@ There is no 'u' flag. Integers are printed unsigned if they have unsigned type. Similarly, there is no need to specify the size of the operand (int8, int64). - The width and precision control formatting and are in units of Unicode - code points. (This differs from C's printf where the units are numbers + Width is specified by an optional decimal number immediately following the verb. + If absent, the width is whatever is necessary to represent the value. + Precision is specified after the (optional) width by a period followed by a + decimal number. If no period is present, a default precision is used. + A period with no following number specifies a precision of zero. + Examples: + %f: default width, default precision + %9f width 9, default precision + %.2f default width, precision 2 + %9.2f width 9, precision 2 + %9.f width 9, precision 0 + + Width and precision are measured in units of Unicode code points. + (This differs from C's printf where the units are numbers of bytes.) Either or both of the flags may be replaced with the character '*', causing their values to be obtained from the next operand, which must be of type int. - For numeric values, width sets the minimum width of the field and + For most values, width is the minimum number of characters to output, + padding the formatted form with spaces if necessary. + For strings, precision is the maximum number of characters to output, + truncating if necessary. + + 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. - For most values, width is the minimum number of characters to output, - padding the formatted form with spaces if necessary. - For strings, precision is the maximum number of characters to output, - truncating if necessary. + For complex numbers, the width and precision apply to the two + components independently and the result is parenthesized, so %f applied + to 1.2+3.4i produces (1.200000+3.400000i). Other flags: + always print a sign for numeric values; @@ -98,20 +115,33 @@ fmt.Printf("%v\n", i) will print 23. - If an operand implements interface Formatter, that interface - can be used for fine control of formatting. + Except when printed using the verbs %T and %p, special + formatting considerations apply for operands that implement + certain interfaces. In order of application: + + 1. If an operand implements the Formatter interface, it will + be invoked. Formatter provides fine control of formatting. + + 2. If the %v verb is used with the # flag (%#v) and the operand + implements the GoStringer interface, that will be invoked. If the format (which is implicitly %v for Println etc.) is valid - for a string (%s %q %v %x %X), the following two rules also apply: + for a string (%s %q %v %x %X), the following two rules apply: - 1. If an operand implements the error interface, the Error method - will be used to convert the object to a string, which will then + 3. If an operand implements the error interface, the Error method + will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any). - 2. If an operand implements method String() string, that method - will be used to convert the object to a string, which will then + 4. If an operand implements method String() string, that method + will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any). + For compound operands such as slices and structs, the format + applies to the elements of each operand, recursively, not to the + operand as a whole. Thus %q will quote each element of a slice + of strings, and %6.2f will control formatting for each element + of a floating-point array. + To avoid recursion in cases such as type X string func (x X) String() string { return Sprintf("<%s>", x) } diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go index bf50675f5..7e3d06b9f 100644 --- a/src/pkg/fmt/fmt_test.go +++ b/src/pkg/fmt/fmt_test.go @@ -220,6 +220,12 @@ var fmtTests = []struct { {"%+.3e", 0.0, "+0.000e+00"}, {"%+.3e", 1.0, "+1.000e+00"}, {"%+.3f", -1.0, "-1.000"}, + {"%+.3F", -1.0, "-1.000"}, + {"%+.3F", float32(-1.0), "-1.000"}, + {"%+07.2f", 1.0, "+001.00"}, + {"%+07.2f", -1.0, "-001.00"}, + {"%+10.2f", +1.0, " +1.00"}, + {"%+10.2f", -1.0, " -1.00"}, {"% .3E", -1.0, "-1.000E+00"}, {"% .3e", 1.0, " 1.000e+00"}, {"%+.3g", 0.0, "+0"}, @@ -239,6 +245,8 @@ var fmtTests = []struct { {"%+.3g", 1 + 2i, "(+1+2i)"}, {"%.3e", 0i, "(0.000e+00+0.000e+00i)"}, {"%.3f", 0i, "(0.000+0.000i)"}, + {"%.3F", 0i, "(0.000+0.000i)"}, + {"%.3F", complex64(0i), "(0.000+0.000i)"}, {"%.3g", 0i, "(0+0i)"}, {"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"}, {"%.3f", 1 + 2i, "(1.000+2.000i)"}, @@ -397,6 +405,8 @@ 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)"}, // slices with other formats {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`}, @@ -495,18 +505,85 @@ var fmtTests = []struct { {"%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), "-1000000000000000000000000000000000000000000000000000000000000000"}, + {"%b", int64(-1 << 63), zeroFill("-1", 63, "")}, // Used to panic. - {"%0100d", 1, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"}, - {"%0100d", -1, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"}, - {"%0.100f", 1.0, "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, - {"%0.100f", -1.0, "-1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, + {"%0100d", 1, zeroFill("", 100, "1")}, + {"%0100d", -1, zeroFill("-", 99, "1")}, + {"%0.100f", 1.0, zeroFill("1.", 100, "")}, + {"%0.100f", -1.0, zeroFill("-1.", 100, "")}, + + // Comparison of padding rules with C printf. + /* + C program: + #include <stdio.h> + + char *format[] = { + "[%.2f]", + "[% .2f]", + "[%+.2f]", + "[%7.2f]", + "[% 7.2f]", + "[%+7.2f]", + "[%07.2f]", + "[% 07.2f]", + "[%+07.2f]", + }; + + int main(void) { + int i; + for(i = 0; i < 9; i++) { + printf("%s: ", format[i]); + printf(format[i], 1.0); + printf(" "); + printf(format[i], -1.0); + printf("\n"); + } + } - // Zero padding floats used to put the minus sign in the middle. - {"%020f", -1.0, "-000000000001.000000"}, + Output: + [%.2f]: [1.00] [-1.00] + [% .2f]: [ 1.00] [-1.00] + [%+.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] + */ + {"%.2f", 1.0, "1.00"}, + {"%.2f", -1.0, "-1.00"}, + {"% .2f", 1.0, " 1.00"}, + {"% .2f", -1.0, "-1.00"}, + {"%+.2f", 1.0, "+1.00"}, + {"%+.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"}, + {"%+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"}, + + // 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"}, - {"%0100f", -1.0, "-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.000000"}, + // Make sure we can handle very large widths. + {"%0100f", -1.0, zeroFill("-", 99, "1.000000")}, // 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. @@ -515,6 +592,43 @@ 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)"}, + {"%+10.2f", +104.66 - 440.51i, "( +104.66 -440.51i)"}, + {"%+10.2f", -104.66 - 440.51i, "( -104.66 -440.51i)"}, + {"%+010.2f", +104.66 + 440.51i, "(+000104.66+000440.51i)"}, + {"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"}, + {"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"}, + {"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"}, +} + +// zeroFill generates zero-filled strings of the specified width. The length +// of the suffix (but not the prefix) is compensated for in the width calculation. +func zeroFill(prefix string, width int, suffix string) string { + return prefix + strings.Repeat("0", width-len(suffix)) + suffix } func TestSprintf(t *testing.T) { @@ -554,6 +668,50 @@ func TestSprintf(t *testing.T) { } } +// TestComplexFormatting checks that a complex always formats to the same +// thing as if done by hand with two singleton prints. +func TestComplexFormatting(t *testing.T) { + var yesNo = []bool{true, false} + var signs = []float64{1, 0, -1} + for _, plus := range yesNo { + for _, zero := range yesNo { + for _, space := range yesNo { + for _, char := range "fFeEgG" { + realFmt := "%" + if zero { + realFmt += "0" + } + if space { + realFmt += " " + } + if plus { + realFmt += "+" + } + realFmt += "10.2" + realFmt += string(char) + // Imaginary part always has a sign, so force + and ignore space. + imagFmt := "%" + if zero { + imagFmt += "0" + } + imagFmt += "+" + imagFmt += "10.2" + imagFmt += string(char) + for _, realSign := range signs { + for _, imagSign := range signs { + one := Sprintf(realFmt, complex(realSign, imagSign)) + two := Sprintf("("+realFmt+imagFmt+"i)", realSign, imagSign) + if one != two { + t.Error(f, one, two) + } + } + } + } + } + } + } +} + type SE []interface{} // slice of empty; notational compactness. var reorderTests = []struct { @@ -604,47 +762,61 @@ func TestReorder(t *testing.T) { } func BenchmarkSprintfEmpty(b *testing.B) { - for i := 0; i < b.N; i++ { - Sprintf("") - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("") + } + }) } func BenchmarkSprintfString(b *testing.B) { - for i := 0; i < b.N; i++ { - Sprintf("%s", "hello") - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%s", "hello") + } + }) } func BenchmarkSprintfInt(b *testing.B) { - for i := 0; i < b.N; i++ { - Sprintf("%d", 5) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%d", 5) + } + }) } func BenchmarkSprintfIntInt(b *testing.B) { - for i := 0; i < b.N; i++ { - Sprintf("%d %d", 5, 6) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%d %d", 5, 6) + } + }) } func BenchmarkSprintfPrefixedInt(b *testing.B) { - for i := 0; i < b.N; i++ { - Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6) + } + }) } func BenchmarkSprintfFloat(b *testing.B) { - for i := 0; i < b.N; i++ { - Sprintf("%g", 5.23184) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%g", 5.23184) + } + }) } func BenchmarkManyArgs(b *testing.B) { - var buf bytes.Buffer - for i := 0; i < b.N; i++ { - buf.Reset() - Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world") - } + b.RunParallel(func(pb *testing.PB) { + var buf bytes.Buffer + for pb.Next() { + buf.Reset() + Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world") + } + }) } var mallocBuf bytes.Buffer diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go index 2e2b0716e..a89c542cf 100644 --- a/src/pkg/fmt/format.go +++ b/src/pkg/fmt/format.go @@ -5,12 +5,15 @@ package fmt import ( + "math" "strconv" "unicode/utf8" ) const ( - nByte = 65 // %b of an int64, plus a sign. + // %b of an int64, plus a sign. + // Hex can add 0x and we handle it specially. + nByte = 65 ldigits = "0123456789abcdef" udigits = "0123456789ABCDEF" @@ -160,9 +163,16 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { } var buf []byte = f.intbuf[0:] - if f.widPresent && f.wid > nByte { - // We're going to need a bigger boat. - buf = make([]byte, f.wid) + if f.widPresent { + width := f.wid + if base == 16 && f.sharp { + // Also adds "0x". + width += 2 + } + if width > nByte { + // We're going to need a bigger boat. + buf = make([]byte, width) + } } negative := signedness == signed && a < 0 @@ -351,35 +361,48 @@ func doPrec(f *fmt, def int) int { // 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) { - // We leave one byte at the beginning of f.intbuf for a sign if needed, - // and make it a space, which we might be able to use. - f.intbuf[0] = ' ' - slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n) - // Add a plus sign or space to the floating-point string representation if missing and required. - // The formatted number starts at slice[1]. - switch slice[1] { - case '-', '+': - // If we're zero padding, want the sign before the leading zeros. - // Achieve this by writing the sign out and padding the postive number. - if f.zero && f.widPresent && f.wid > len(slice) { - f.buf.WriteByte(slice[1]) - f.wid-- - f.pad(slice[2:]) - return + // Format number, reserving space for leading + sign if needed. + num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n) + 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 } - // We're set; drop the leading space. - slice = slice[1:] - default: - // There's no sign, but we might need one. - if f.plus { - slice[0] = '+' - } else if f.space { - // space is already there - } else { - slice = slice[1:] + } + // 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-- } + 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) + return } - f.pad(slice) + // 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) { + 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. @@ -424,60 +447,46 @@ 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.buf.WriteByte('(') - r := real(v) - oldPlus := f.plus - for i := 0; ; i++ { - switch verb { - case 'b': - f.fmt_fb32(r) - case 'e': - f.fmt_e32(r) - case 'E': - f.fmt_E32(r) - case 'f': - f.fmt_f32(r) - case 'g': - f.fmt_g32(r) - case 'G': - f.fmt_G32(r) - } - if i != 0 { - break - } - f.plus = true - r = imag(v) - } - f.plus = oldPlus - f.buf.Write(irparenBytes) + 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('(') - r := real(v) oldPlus := f.plus + oldSpace := f.space + oldWid := f.wid for i := 0; ; i++ { switch verb { case 'b': - f.fmt_fb64(r) + f.formatFloat(r, 'b', 0, size) case 'e': - f.fmt_e64(r) + f.formatFloat(r, 'e', doPrec(f, 6), size) case 'E': - f.fmt_E64(r) - case 'f': - f.fmt_f64(r) + f.formatFloat(r, 'E', doPrec(f, 6), size) + case 'f', 'F': + f.formatFloat(r, 'f', doPrec(f, 6), size) case 'g': - f.fmt_g64(r) + f.formatFloat(r, 'g', doPrec(f, -1), size) case 'G': - f.fmt_G64(r) + f.formatFloat(r, 'G', doPrec(f, -1), size) } if i != 0 { break } + // Imaginary part always has a sign. f.plus = true - r = imag(v) + f.space = false + f.wid = oldWid + r = j } + f.space = oldSpace f.plus = oldPlus + f.wid = oldWid f.buf.Write(irparenBytes) } diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go index 1ea816d6d..302661f4c 100644 --- a/src/pkg/fmt/print.go +++ b/src/pkg/fmt/print.go @@ -124,45 +124,13 @@ type pp struct { fmt fmt } -// A cache holds a set of reusable objects. -// The slice is a stack (LIFO). -// If more are needed, the cache creates them by calling new. -type cache struct { - mu sync.Mutex - saved []interface{} - new func() interface{} +var ppFree = sync.Pool{ + New: func() interface{} { return new(pp) }, } -func (c *cache) put(x interface{}) { - c.mu.Lock() - if len(c.saved) < cap(c.saved) { - c.saved = append(c.saved, x) - } - c.mu.Unlock() -} - -func (c *cache) get() interface{} { - c.mu.Lock() - n := len(c.saved) - if n == 0 { - c.mu.Unlock() - return c.new() - } - x := c.saved[n-1] - c.saved = c.saved[0 : n-1] - c.mu.Unlock() - return x -} - -func newCache(f func() interface{}) *cache { - return &cache{saved: make([]interface{}, 0, 100), new: f} -} - -var ppFree = newCache(func() interface{} { return new(pp) }) - // newPrinter allocates a new pp struct or grab a cached one. func newPrinter() *pp { - p := ppFree.get().(*pp) + p := ppFree.Get().(*pp) p.panicking = false p.erroring = false p.fmt.init(&p.buf) @@ -178,7 +146,7 @@ func (p *pp) free() { p.buf = p.buf[:0] p.arg = nil p.value = reflect.Value{} - ppFree.put(p) + ppFree.Put(p) } func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent } @@ -479,7 +447,7 @@ func (p *pp) fmtFloat32(v float32, verb rune) { p.fmt.fmt_e32(v) case 'E': p.fmt.fmt_E32(v) - case 'f': + case 'f', 'F': p.fmt.fmt_f32(v) case 'g', 'v': p.fmt.fmt_g32(v) @@ -498,7 +466,7 @@ func (p *pp) fmtFloat64(v float64, verb rune) { p.fmt.fmt_e64(v) case 'E': p.fmt.fmt_E64(v) - case 'f': + case 'f', 'F': p.fmt.fmt_f64(v) case 'g', 'v': p.fmt.fmt_g64(v) @@ -555,6 +523,15 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) { func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) { if verb == 'v' || verb == 'd' { if goSyntax { + if v == nil { + if typ == nil { + p.buf.WriteString("[]byte(nil)") + } else { + p.buf.WriteString(typ.String()) + p.buf.Write(nilParenBytes) + } + return + } if typ == nil { p.buf.Write(bytesBytes) } else { diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go index 5b1be5891..8a337e479 100644 --- a/src/pkg/fmt/scan.go +++ b/src/pkg/fmt/scan.go @@ -11,6 +11,7 @@ import ( "os" "reflect" "strconv" + "sync" "unicode/utf8" ) @@ -283,7 +284,6 @@ var space = [][2]uint16{ {0x0085, 0x0085}, {0x00a0, 0x00a0}, {0x1680, 0x1680}, - {0x180e, 0x180e}, {0x2000, 0x200a}, {0x2028, 0x2029}, {0x202f, 0x202f}, @@ -380,7 +380,9 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) { return } -var ssFree = newCache(func() interface{} { return new(ss) }) +var ssFree = sync.Pool{ + New: func() interface{} { return new(ss) }, +} // newScanState allocates a new ss struct or grab a cached one. func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) { @@ -395,7 +397,7 @@ func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) { return } - s = ssFree.get().(*ss) + s = ssFree.Get().(*ss) if rr, ok := r.(io.RuneReader); ok { s.rr = rr } else { @@ -427,7 +429,7 @@ func (s *ss) free(old ssave) { } s.buf = s.buf[:0] s.rr = nil - ssFree.put(s) + ssFree.Put(s) } // skipSpace skips spaces and maybe newlines. |