diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-19 08:53:52 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-19 08:53:52 +0000 |
commit | 00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387 (patch) | |
tree | b988e32ea14a3dc1b4718b1fdfa47bab087ae96c /libgo/go/fmt | |
parent | bcf2fc6ee0a7edbe7de4299f28b66527c07bb0a2 (diff) | |
download | gcc-00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387.zip gcc-00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387.tar.gz gcc-00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387.tar.bz2 |
libgo: Update to Go 1.3 release.
From-SVN: r212837
Diffstat (limited to 'libgo/go/fmt')
-rw-r--r-- | libgo/go/fmt/doc.go | 58 | ||||
-rw-r--r-- | libgo/go/fmt/fmt_test.go | 200 | ||||
-rw-r--r-- | libgo/go/fmt/format.go | 123 | ||||
-rw-r--r-- | libgo/go/fmt/print.go | 13 |
4 files changed, 276 insertions, 118 deletions
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go index 095fd03..02642d6 100644 --- a/libgo/go/fmt/doc.go +++ b/libgo/go/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/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index ce837ba..8e69231 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -11,7 +11,6 @@ import ( "math" "runtime" "strings" - "sync/atomic" "testing" "time" "unicode" @@ -221,8 +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"}, @@ -242,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)"}, @@ -400,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]`}, @@ -506,9 +513,76 @@ var fmtTests = []struct { {"%0.100f", 1.0, zeroFill("1.", 100, "")}, {"%0.100f", -1.0, zeroFill("-1.", 100, "")}, - // Zero padding floats used to put the minus sign in the middle. - {"%020f", -1.0, "-000000000001.000000"}, + // 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"); + } + } + + 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"}, + // 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 @@ -539,6 +613,16 @@ var fmtTests = []struct { {"%#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 @@ -584,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 { @@ -634,69 +762,63 @@ func TestReorder(t *testing.T) { } func BenchmarkSprintfEmpty(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("") + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("") + } }) } func BenchmarkSprintfString(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("%s", "hello") + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%s", "hello") + } }) } func BenchmarkSprintfInt(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("%d", 5) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%d", 5) + } }) } func BenchmarkSprintfIntInt(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("%d %d", 5, 6) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%d %d", 5, 6) + } }) } func BenchmarkSprintfPrefixedInt(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - 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) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("%g", 5.23184) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%g", 5.23184) + } }) } func BenchmarkManyArgs(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - 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") + } }) } -func benchmarkSprintf(b *testing.B, f func(buf *bytes.Buffer)) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - var buf bytes.Buffer - for atomic.AddInt32(&N, -1) >= 0 { - for g := 0; g < CallsPerSched; g++ { - f(&buf) - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } -} - var mallocBuf bytes.Buffer // gccgo numbers are different because gccgo does not have escape diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go index 3835aa9..a89c542 100644 --- a/libgo/go/fmt/format.go +++ b/libgo/go/fmt/format.go @@ -5,6 +5,7 @@ package fmt import ( + "math" "strconv" "unicode/utf8" ) @@ -360,38 +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 { - f.buf.WriteByte('+') + } + // 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(slice[1:]) - return - } else if f.space { - // space is already there - } else { - slice = slice[1:] } + f.pad(num[1:]) + return } - f.pad(slice) + // f.space says to replace a leading + with a space. + if f.space && num[0] == '+' { + num[0] = ' ' + f.pad(num) + 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) { + 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. @@ -436,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/libgo/go/fmt/print.go b/libgo/go/fmt/print.go index 2f13bcd..302661f 100644 --- a/libgo/go/fmt/print.go +++ b/libgo/go/fmt/print.go @@ -447,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) @@ -466,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) @@ -523,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 { |