aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/fmt
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2014-07-19 08:53:52 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2014-07-19 08:53:52 +0000
commit00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387 (patch)
treeb988e32ea14a3dc1b4718b1fdfa47bab087ae96c /libgo/go/fmt
parentbcf2fc6ee0a7edbe7de4299f28b66527c07bb0a2 (diff)
downloadgcc-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.go58
-rw-r--r--libgo/go/fmt/fmt_test.go200
-rw-r--r--libgo/go/fmt/format.go123
-rw-r--r--libgo/go/fmt/print.go13
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 {