aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/encoding
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-01-13 05:11:45 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-01-13 05:11:45 +0000
commitdf4aa89a5e7acb315655f193e7f549e8d32367e2 (patch)
treeeb5eccc07097c5fcf940967f33ab84a7d47c96fe /libgo/go/encoding
parentf83fa0bf8f411697ec908cfa86ee6faf4cd9c476 (diff)
downloadgcc-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.go58
-rw-r--r--libgo/go/encoding/binary/varint_test.go2
-rw-r--r--libgo/go/encoding/gob/codec_test.go3
-rw-r--r--libgo/go/encoding/gob/encode.go16
-rw-r--r--libgo/go/encoding/gob/gobencdec_test.go48
-rw-r--r--libgo/go/encoding/gob/timing_test.go2
-rw-r--r--libgo/go/encoding/gob/type.go1
-rw-r--r--libgo/go/encoding/json/bench_test.go10
-rw-r--r--libgo/go/encoding/json/decode.go71
-rw-r--r--libgo/go/encoding/json/decode_test.go39
-rw-r--r--libgo/go/encoding/json/encode.go25
-rw-r--r--libgo/go/encoding/xml/marshal_test.go2
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)
}
}
}