diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-01-13 05:11:45 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-01-13 05:11:45 +0000 |
commit | df4aa89a5e7acb315655f193e7f549e8d32367e2 (patch) | |
tree | eb5eccc07097c5fcf940967f33ab84a7d47c96fe /libgo/go/encoding | |
parent | f83fa0bf8f411697ec908cfa86ee6faf4cd9c476 (diff) | |
download | gcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.zip gcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.tar.gz gcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.tar.bz2 |
libgo: Update to weekly.2011-12-22.
From-SVN: r183150
Diffstat (limited to 'libgo/go/encoding')
-rw-r--r-- | libgo/go/encoding/binary/binary_test.go | 58 | ||||
-rw-r--r-- | libgo/go/encoding/binary/varint_test.go | 2 | ||||
-rw-r--r-- | libgo/go/encoding/gob/codec_test.go | 3 | ||||
-rw-r--r-- | libgo/go/encoding/gob/encode.go | 16 | ||||
-rw-r--r-- | libgo/go/encoding/gob/gobencdec_test.go | 48 | ||||
-rw-r--r-- | libgo/go/encoding/gob/timing_test.go | 2 | ||||
-rw-r--r-- | libgo/go/encoding/gob/type.go | 1 | ||||
-rw-r--r-- | libgo/go/encoding/json/bench_test.go | 10 | ||||
-rw-r--r-- | libgo/go/encoding/json/decode.go | 71 | ||||
-rw-r--r-- | libgo/go/encoding/json/decode_test.go | 39 | ||||
-rw-r--r-- | libgo/go/encoding/json/encode.go | 25 | ||||
-rw-r--r-- | libgo/go/encoding/xml/marshal_test.go | 2 |
12 files changed, 210 insertions, 67 deletions
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go index fd4fdb0..3e7057e 100644 --- a/libgo/go/encoding/binary/binary_test.go +++ b/libgo/go/encoding/binary/binary_test.go @@ -171,11 +171,42 @@ func (br *byteSliceReader) Read(p []byte) (int, error) { return n, nil } -func BenchmarkRead(b *testing.B) { +func BenchmarkReadSlice1000Int32s(b *testing.B) { + bsr := &byteSliceReader{} + slice := make([]int32, 1000) + buf := make([]byte, len(slice)*4) + b.SetBytes(int64(len(buf))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + bsr.remain = buf + Read(bsr, BigEndian, slice) + } +} + +func BenchmarkReadStruct(b *testing.B) { + bsr := &byteSliceReader{} + var buf bytes.Buffer + Write(&buf, BigEndian, &s) + n := TotalSize(reflect.ValueOf(s)) + b.SetBytes(int64(n)) + t := s + b.ResetTimer() + for i := 0; i < b.N; i++ { + bsr.remain = buf.Bytes() + Read(bsr, BigEndian, &t) + } + b.StopTimer() + if !reflect.DeepEqual(s, t) { + b.Fatal("no match") + } +} + +func BenchmarkReadInts(b *testing.B) { var ls Struct bsr := &byteSliceReader{} var r io.Reader = bsr - + b.SetBytes(2 * (1 + 2 + 4 + 8)) + b.ResetTimer() for i := 0; i < b.N; i++ { bsr.remain = big Read(r, BigEndian, &ls.Int8) @@ -196,25 +227,19 @@ func BenchmarkRead(b *testing.B) { for i := range want.Array { want.Array[i] = 0 } + b.StopTimer() if !reflect.DeepEqual(ls, want) { panic("no match") } } -func BenchmarkWrite(b *testing.B) { +func BenchmarkWriteInts(b *testing.B) { buf := new(bytes.Buffer) var w io.Writer = buf - + b.SetBytes(2 * (1 + 2 + 4 + 8)) + b.ResetTimer() for i := 0; i < b.N; i++ { buf.Reset() - Write(w, BigEndian, &s.Int8) - Write(w, BigEndian, &s.Int16) - Write(w, BigEndian, &s.Int32) - Write(w, BigEndian, &s.Int64) - Write(w, BigEndian, &s.Uint8) - Write(w, BigEndian, &s.Uint16) - Write(w, BigEndian, &s.Uint32) - Write(w, BigEndian, &s.Uint64) Write(w, BigEndian, s.Int8) Write(w, BigEndian, s.Int16) Write(w, BigEndian, s.Int32) @@ -224,11 +249,8 @@ func BenchmarkWrite(b *testing.B) { Write(w, BigEndian, s.Uint32) Write(w, BigEndian, s.Uint64) } - - if !bytes.Equal(buf.Bytes()[:30], big[:30]) { - panic("first half doesn't match") - } - if !bytes.Equal(buf.Bytes()[30:], big[:30]) { - panic("second half doesn't match") + b.StopTimer() + if !bytes.Equal(buf.Bytes(), big[:30]) { + b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30]) } } diff --git a/libgo/go/encoding/binary/varint_test.go b/libgo/go/encoding/binary/varint_test.go index b553d6d..dc550f2 100644 --- a/libgo/go/encoding/binary/varint_test.go +++ b/libgo/go/encoding/binary/varint_test.go @@ -165,6 +165,7 @@ func TestNonCanonicalZero(t *testing.T) { func BenchmarkPutUvarint32(b *testing.B) { buf := make([]byte, MaxVarintLen32) + b.SetBytes(4) for i := 0; i < b.N; i++ { for j := uint(0); j < MaxVarintLen32; j++ { PutUvarint(buf, 1<<(j*7)) @@ -174,6 +175,7 @@ func BenchmarkPutUvarint32(b *testing.B) { func BenchmarkPutUvarint64(b *testing.B) { buf := make([]byte, MaxVarintLen64) + b.SetBytes(8) for i := 0; i < b.N; i++ { for j := uint(0); j < MaxVarintLen64; j++ { PutUvarint(buf, 1<<(j*7)) diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go index dc0e007..73844b9 100644 --- a/libgo/go/encoding/gob/codec_test.go +++ b/libgo/go/encoding/gob/codec_test.go @@ -102,12 +102,15 @@ func TestIntCodec(t *testing.T) { // The result of encoding a true boolean with field number 7 var boolResult = []byte{0x07, 0x01} + // The result of encoding a number 17 with field number 7 var signedResult = []byte{0x07, 2 * 17} var unsignedResult = []byte{0x07, 17} var floatResult = []byte{0x07, 0xFE, 0x31, 0x40} + // The result of encoding a number 17+19i with field number 7 var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40} + // The result of encoding "hello" with field number 7 var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'} diff --git a/libgo/go/encoding/gob/encode.go b/libgo/go/encoding/gob/encode.go index c7e4823..f05b17c 100644 --- a/libgo/go/encoding/gob/encode.go +++ b/libgo/go/encoding/gob/encode.go @@ -469,7 +469,14 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) { // isZero returns whether the value is the zero of its type. func isZero(val reflect.Value) bool { switch val.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + case reflect.Array: + for i := 0; i < val.Len(); i++ { + if !isZero(val.Index(i)) { + return false + } + } + return true + case reflect.Map, reflect.Slice, reflect.String: return val.Len() == 0 case reflect.Bool: return !val.Bool() @@ -483,6 +490,13 @@ func isZero(val reflect.Value) bool { return val.Float() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return val.Uint() == 0 + case reflect.Struct: + for i := 0; i < val.NumField(); i++ { + if !isZero(val.Field(i)) { + return false + } + } + return true } panic("unknown type in isZero " + val.Type().String()) } diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go index eacfd84..b8dfeeb 100644 --- a/libgo/go/encoding/gob/gobencdec_test.go +++ b/libgo/go/encoding/gob/gobencdec_test.go @@ -13,6 +13,7 @@ import ( "io" "strings" "testing" + "time" ) // Types that implement the GobEncoder/Decoder interfaces. @@ -526,3 +527,50 @@ func TestGobEncoderExtraIndirect(t *testing.T) { t.Errorf("got = %q, want %q", got, gdb) } } + +// Another bug: this caused a crash with the new Go1 Time type. +// We throw in a gob-encoding array, to test another case of isZero + +type isZeroBug struct { + T time.Time + S string + I int + A isZeroBugArray +} + +type isZeroBugArray [2]uint8 + +// Receiver is value, not pointer, to test isZero of array. +func (a isZeroBugArray) GobEncode() (b []byte, e error) { + b = append(b, a[:]...) + return b, nil +} + +func (a *isZeroBugArray) GobDecode(data []byte) error { + println("DECODE") + if len(data) != len(a) { + return io.EOF + } + a[0] = data[0] + a[1] = data[1] + return nil +} + +func TestGobEncodeIsZero(t *testing.T) { + x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}} + b := new(bytes.Buffer) + enc := NewEncoder(b) + err := enc.Encode(x) + if err != nil { + t.Fatal("encode:", err) + } + var y isZeroBug + dec := NewDecoder(b) + err = dec.Decode(&y) + if err != nil { + t.Fatal("decode:", err) + } + if x != y { + t.Fatalf("%v != %v", x, y) + } +} diff --git a/libgo/go/encoding/gob/timing_test.go b/libgo/go/encoding/gob/timing_test.go index 47437a6..1017eb7 100644 --- a/libgo/go/encoding/gob/timing_test.go +++ b/libgo/go/encoding/gob/timing_test.go @@ -39,7 +39,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) { func BenchmarkEndToEndPipe(b *testing.B) { r, w, err := os.Pipe() if err != nil { - panic("can't get pipe:" + err.Error()) + b.Fatal("can't get pipe:", err) } benchmarkEndToEnd(r, w, b) } diff --git a/libgo/go/encoding/gob/type.go b/libgo/go/encoding/gob/type.go index 1b20843..71a28be 100644 --- a/libgo/go/encoding/gob/type.go +++ b/libgo/go/encoding/gob/type.go @@ -130,6 +130,7 @@ func userType(rt reflect.Type) *userTypeInfo { } return ut } + // A typeId represents a gob Type as an integer that can be passed on the wire. // Internally, typeIds are used as keys to a map to recover the underlying type info. type typeId int32 diff --git a/libgo/go/encoding/json/bench_test.go b/libgo/go/encoding/json/bench_test.go index f0c5201..333c1c0 100644 --- a/libgo/go/encoding/json/bench_test.go +++ b/libgo/go/encoding/json/bench_test.go @@ -84,7 +84,7 @@ func BenchmarkCodeEncoder(b *testing.B) { enc := NewEncoder(ioutil.Discard) for i := 0; i < b.N; i++ { if err := enc.Encode(&codeStruct); err != nil { - panic(err) + b.Fatal("Encode:", err) } } b.SetBytes(int64(len(codeJSON))) @@ -98,7 +98,7 @@ func BenchmarkCodeMarshal(b *testing.B) { } for i := 0; i < b.N; i++ { if _, err := Marshal(&codeStruct); err != nil { - panic(err) + b.Fatal("Marshal:", err) } } b.SetBytes(int64(len(codeJSON))) @@ -120,7 +120,7 @@ func BenchmarkCodeDecoder(b *testing.B) { buf.WriteByte('\n') buf.WriteByte('\n') if err := dec.Decode(&r); err != nil { - panic(err) + b.Fatal("Decode:", err) } } b.SetBytes(int64(len(codeJSON))) @@ -135,7 +135,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) { for i := 0; i < b.N; i++ { var r codeResponse if err := Unmarshal(codeJSON, &r); err != nil { - panic(err) + b.Fatal("Unmmarshal:", err) } } b.SetBytes(int64(len(codeJSON))) @@ -150,7 +150,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) { var r codeResponse for i := 0; i < b.N; i++ { if err := Unmarshal(codeJSON, &r); err != nil { - panic(err) + b.Fatal("Unmmarshal:", err) } } b.SetBytes(int64(len(codeJSON))) diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index 0a70092..8287b33 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -228,7 +228,9 @@ func (d *decodeState) value(v reflect.Value) { // Feed in an empty string - the shortest, simplest value - // so that it knows we got to the end of the value. if d.scan.redo { - panic("redo") + // rewind. + d.scan.redo = false + d.scan.step = stateBeginValue } d.scan.step(&d.scan, '"') d.scan.step(&d.scan, '"') @@ -317,25 +319,22 @@ func (d *decodeState) array(v reflect.Value) { } v = pv - // Decoding into nil interface? Switch to non-reflect code. - iv := v - ok := iv.Kind() == reflect.Interface - if ok { - iv.Set(reflect.ValueOf(d.arrayInterface())) - return - } - // Check type of target. - av := v - if av.Kind() != reflect.Array && av.Kind() != reflect.Slice { + switch v.Kind() { + default: d.saveError(&UnmarshalTypeError{"array", v.Type()}) d.off-- d.next() return + case reflect.Interface: + // Decoding into nil interface? Switch to non-reflect code. + v.Set(reflect.ValueOf(d.arrayInterface())) + return + case reflect.Array: + case reflect.Slice: + break } - sv := v - i := 0 for { // Look ahead for ] - can only happen on first iteration. @@ -349,23 +348,25 @@ func (d *decodeState) array(v reflect.Value) { d.scan.undo(op) // Get element of array, growing if necessary. - if i >= av.Cap() && sv.IsValid() { - newcap := sv.Cap() + sv.Cap()/2 - if newcap < 4 { - newcap = 4 + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) } - newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap) - reflect.Copy(newv, sv) - sv.Set(newv) - } - if i >= av.Len() && sv.IsValid() { - // Must be slice; gave up on array during i >= av.Cap(). - sv.SetLen(i + 1) } - // Decode into element. - if i < av.Len() { - d.value(av.Index(i)) + if i < v.Len() { + // Decode into element. + d.value(v.Index(i)) } else { // Ran out of fixed array: skip. d.value(reflect.Value{}) @@ -382,19 +383,19 @@ func (d *decodeState) array(v reflect.Value) { } } - if i < av.Len() { - if !sv.IsValid() { + if i < v.Len() { + if v.Kind() == reflect.Array { // Array. Zero the rest. - z := reflect.Zero(av.Type().Elem()) - for ; i < av.Len(); i++ { - av.Index(i).Set(z) + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) } } else { - sv.SetLen(i) + v.SetLen(i) } } - if i == 0 && av.Kind() == reflect.Slice && sv.IsNil() { - sv.Set(reflect.MakeSlice(sv.Type(), 0, 0)) + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) } } diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go index bf3953e..05c8a06 100644 --- a/libgo/go/encoding/json/decode_test.go +++ b/libgo/go/encoding/json/decode_test.go @@ -6,6 +6,7 @@ package json import ( "bytes" + "fmt" "reflect" "strings" "testing" @@ -73,6 +74,12 @@ var unmarshalTests = []unmarshalTest{ // syntax errors {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}}, + {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}}, + + // array tests + {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil}, + {`[1, 2, 3]`, new([1]int), [1]int{1}, nil}, + {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil}, // composite tests {allValueIndent, new(All), allValue, nil}, @@ -242,6 +249,38 @@ func TestHTMLEscape(t *testing.T) { } } +// WrongString is a struct that's misusing the ,string modifier. +type WrongString struct { + Message string `json:"result,string"` +} + +type wrongStringTest struct { + in, err string +} + +// TODO(bradfitz): as part of Issue 2331, fix these tests' expected +// error values to be helpful, rather than the confusing messages they +// are now. +var wrongStringTests = []wrongStringTest{ + {`{"result":"x"}`, "JSON decoder out of sync - data changing underfoot?"}, + {`{"result":"foo"}`, "json: cannot unmarshal bool into Go value of type string"}, + {`{"result":"123"}`, "json: cannot unmarshal number into Go value of type string"}, +} + +// If people misuse the ,string modifier, the error message should be +// helpful, telling the user that they're doing it wrong. +func TestErrorMessageFromMisusedString(t *testing.T) { + for n, tt := range wrongStringTests { + r := strings.NewReader(tt.in) + var s WrongString + err := NewDecoder(r).Decode(&s) + got := fmt.Sprintf("%v", err) + if got != tt.err { + t.Errorf("%d. got err = %q, want %q", n, got, tt.err) + } + } +} + func noSpace(c rune) rune { if isSpace(c) { return -1 diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index ff8e80c..3d2f4fc 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -197,6 +197,7 @@ var hex = "0123456789abcdef" // An encodeState encodes JSON into a bytes.Buffer. type encodeState struct { bytes.Buffer // accumulated output + scratch [64]byte } func (e *encodeState) marshal(v interface{}) (err error) { @@ -275,14 +276,26 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) { } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - writeString(e, strconv.FormatInt(v.Int(), 10)) - + b := strconv.AppendInt(e.scratch[:0], v.Int(), 10) + if quoted { + writeString(e, string(b)) + } else { + e.Write(b) + } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - writeString(e, strconv.FormatUint(v.Uint(), 10)) - + b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10) + if quoted { + writeString(e, string(b)) + } else { + e.Write(b) + } case reflect.Float32, reflect.Float64: - writeString(e, strconv.FormatFloat(v.Float(), 'g', -1, v.Type().Bits())) - + b := strconv.AppendFloat(e.scratch[:0], v.Float(), 'g', -1, v.Type().Bits()) + if quoted { + writeString(e, string(b)) + } else { + e.Write(b) + } case reflect.String: if quoted { sb, err := Marshal(v.String()) diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index 8040765..6a24169 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -394,7 +394,7 @@ func TestUnmarshal(t *testing.T) { if err != nil { t.Errorf("#%d: unexpected error: %#v", i, err) } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) { - t.Errorf("#%d: unmarshal(%#s) = %#v, want %#v", i, test.ExpectXML, got, want) + t.Errorf("#%d: unmarshal(%q) = %#v, want %#v", i, test.ExpectXML, got, want) } } } |