summaryrefslogtreecommitdiff
path: root/libgo/go/encoding/binary
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/encoding/binary')
-rw-r--r--libgo/go/encoding/binary/binary.go83
-rw-r--r--libgo/go/encoding/binary/binary_test.go80
-rw-r--r--libgo/go/encoding/binary/varint.go2
3 files changed, 144 insertions, 21 deletions
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
index 1c2577b68d..3834254596 100644
--- a/libgo/go/encoding/binary/binary.go
+++ b/libgo/go/encoding/binary/binary.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -7,7 +7,7 @@
//
// Numbers are translated by reading and writing fixed-size values.
// A fixed-size value is either a fixed-size arithmetic
-// type (int8, uint8, int16, float32, complex64, ...)
+// type (bool, int8, uint8, int16, float32, complex64, ...)
// or an array or struct containing only fixed-size values.
//
// The varint functions encode and decode single integer values using
@@ -48,18 +48,24 @@ var BigEndian bigEndian
type littleEndian struct{}
-func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+func (littleEndian) Uint16(b []byte) uint16 {
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint16(b[0]) | uint16(b[1])<<8
+}
func (littleEndian) PutUint16(b []byte, v uint16) {
+ _ = b[1] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
}
func (littleEndian) Uint32(b []byte) uint32 {
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
func (littleEndian) PutUint32(b []byte, v uint32) {
+ _ = b[3] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
@@ -67,11 +73,13 @@ func (littleEndian) PutUint32(b []byte, v uint32) {
}
func (littleEndian) Uint64(b []byte) uint64 {
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}
func (littleEndian) PutUint64(b []byte, v uint64) {
+ _ = b[7] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
@@ -88,18 +96,24 @@ func (littleEndian) GoString() string { return "binary.LittleEndian" }
type bigEndian struct{}
-func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
+func (bigEndian) Uint16(b []byte) uint16 {
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint16(b[1]) | uint16(b[0])<<8
+}
func (bigEndian) PutUint16(b []byte, v uint16) {
+ _ = b[1] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 8)
b[1] = byte(v)
}
func (bigEndian) Uint32(b []byte) uint32 {
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
}
func (bigEndian) PutUint32(b []byte, v uint32) {
+ _ = b[3] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
@@ -107,11 +121,13 @@ func (bigEndian) PutUint32(b []byte, v uint32) {
}
func (bigEndian) Uint64(b []byte) uint64 {
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
func (bigEndian) PutUint64(b []byte, v uint64) {
+ _ = b[7] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 56)
b[1] = byte(v >> 48)
b[2] = byte(v >> 40)
@@ -131,6 +147,8 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// of fixed-size values.
// Bytes read from r are decoded using the specified byte order
// and written to successive fields of the data.
+// When decoding boolean values, a zero byte is decoded as false, and
+// any other non-zero byte is decoded as true.
// When reading into structs, the field data for fields with
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
@@ -153,6 +171,8 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
return err
}
switch data := data.(type) {
+ case *bool:
+ *data = b[0] != 0
case *int8:
*data = int8(b[0])
case *uint8:
@@ -169,8 +189,12 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
*data = int64(order.Uint64(bs))
case *uint64:
*data = order.Uint64(bs)
- case []int8:
+ case []bool:
for i, x := range bs { // Easier to loop over the input for 8-bit values.
+ data[i] = x != 0
+ }
+ case []int8:
+ for i, x := range bs {
data[i] = int8(x)
}
case []uint8:
@@ -227,6 +251,7 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Write writes the binary representation of data into w.
// Data must be a fixed-size value or a slice of fixed-size
// values, or a pointer to such data.
+// Boolean values encode as one byte: 1 for true, and 0 for false.
// Bytes written to w are encoded using the specified byte order
// and read from successive fields of the data.
// When writing structs, zero values are written for fields
@@ -242,6 +267,26 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
bs = b[:n]
}
switch v := data.(type) {
+ case *bool:
+ if *v {
+ b[0] = 1
+ } else {
+ b[0] = 0
+ }
+ case bool:
+ if v {
+ b[0] = 1
+ } else {
+ b[0] = 0
+ }
+ case []bool:
+ for i, x := range v {
+ if x {
+ bs[i] = 1
+ } else {
+ bs[i] = 0
+ }
+ }
case *int8:
b[0] = byte(*v)
case int8:
@@ -253,7 +298,7 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
case *uint8:
b[0] = *v
case uint8:
- b[0] = byte(v)
+ b[0] = v
case []uint8:
bs = v
case *int16:
@@ -362,7 +407,8 @@ func sizeof(t reflect.Type) int {
}
return sum
- case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ case reflect.Bool,
+ reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
return int(t.Size())
@@ -379,6 +425,21 @@ type coder struct {
type decoder coder
type encoder coder
+func (d *decoder) bool() bool {
+ x := d.buf[0]
+ d.buf = d.buf[1:]
+ return x != 0
+}
+
+func (e *encoder) bool(x bool) {
+ if x {
+ e.buf[0] = 1
+ } else {
+ e.buf[0] = 0
+ }
+ e.buf = e.buf[1:]
+}
+
func (d *decoder) uint8() uint8 {
x := d.buf[0]
d.buf = d.buf[1:]
@@ -469,6 +530,9 @@ func (d *decoder) value(v reflect.Value) {
d.value(v.Index(i))
}
+ case reflect.Bool:
+ v.SetBool(d.bool())
+
case reflect.Int8:
v.SetInt(int64(d.int8()))
case reflect.Int16:
@@ -531,6 +595,9 @@ func (e *encoder) value(v reflect.Value) {
e.value(v.Index(i))
}
+ case reflect.Bool:
+ e.bool(v.Bool())
+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch v.Type().Kind() {
case reflect.Int8:
@@ -593,7 +660,7 @@ func (e *encoder) skip(v reflect.Value) {
// It returns zero if the type cannot be implemented by the fast path in Read or Write.
func intDataSize(data interface{}) int {
switch data := data.(type) {
- case int8, uint8, *int8, *uint8:
+ case bool, int8, uint8, *bool, *int8, *uint8:
return 1
case []int8:
return len(data)
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
index 7fd36fa4ef..fc7f2765ef 100644
--- a/libgo/go/encoding/binary/binary_test.go
+++ b/libgo/go/encoding/binary/binary_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -27,6 +27,8 @@ type Struct struct {
Complex64 complex64
Complex128 complex128
Array [4]uint8
+ Bool bool
+ BoolArray [4]bool
}
type T struct {
@@ -58,6 +60,9 @@ var s = Struct{
),
[4]uint8{0x43, 0x44, 0x45, 0x46},
+
+ true,
+ [4]bool{true, false, true, false},
}
var big = []byte{
@@ -76,6 +81,9 @@ var big = []byte{
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70,
+
+ 1,
+ 1, 0, 1, 0,
}
var little = []byte{
@@ -94,6 +102,9 @@ var little = []byte{
58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
67, 68, 69, 70,
+
+ 1,
+ 1, 0, 1, 0,
}
var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
@@ -141,6 +152,25 @@ func TestWriteSlice(t *testing.T) {
checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
}
+func TestReadBool(t *testing.T) {
+ var res bool
+ var err error
+ err = Read(bytes.NewReader([]byte{0}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, false)
+ res = false
+ err = Read(bytes.NewReader([]byte{1}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, true)
+ res = false
+ err = Read(bytes.NewReader([]byte{2}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, true)
+}
+
+func TestReadBoolSlice(t *testing.T) {
+ slice := make([]bool, 4)
+ err := Read(bytes.NewReader([]byte{0, 1, 2, 255}), BigEndian, slice)
+ checkResult(t, "ReadBoolSlice", BigEndian, err, slice, []bool{false, true, true, true})
+}
+
// Addresses of arrays are easier to manipulate with reflection than are slices.
var intArrays = []interface{}{
&[100]int8{},
@@ -266,7 +296,7 @@ func TestBlankFields(t *testing.T) {
}
// An attempt to read into a struct with an unexported field will
-// panic. This is probably not the best choice, but at this point
+// panic. This is probably not the best choice, but at this point
// anything else would be an API change.
type Unexported struct {
@@ -339,6 +369,33 @@ func TestReadTruncated(t *testing.T) {
}
}
+func testUint64SmallSliceLengthPanics() (panicked bool) {
+ defer func() {
+ panicked = recover() != nil
+ }()
+ b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
+ LittleEndian.Uint64(b[:4])
+ return false
+}
+
+func testPutUint64SmallSliceLengthPanics() (panicked bool) {
+ defer func() {
+ panicked = recover() != nil
+ }()
+ b := [8]byte{}
+ LittleEndian.PutUint64(b[:4], 0x0102030405060708)
+ return false
+}
+
+func TestEarlyBoundsChecks(t *testing.T) {
+ if testUint64SmallSliceLengthPanics() != true {
+ t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't")
+ }
+ if testPutUint64SmallSliceLengthPanics() != true {
+ t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't")
+ }
+}
+
type byteSliceReader struct {
remain []byte
}
@@ -373,8 +430,8 @@ func BenchmarkReadStruct(b *testing.B) {
Read(bsr, BigEndian, &t)
}
b.StopTimer()
- if !reflect.DeepEqual(s, t) {
- b.Fatal("no match")
+ if b.N > 0 && !reflect.DeepEqual(s, t) {
+ b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t, s)
}
}
@@ -395,18 +452,17 @@ func BenchmarkReadInts(b *testing.B) {
Read(r, BigEndian, &ls.Uint32)
Read(r, BigEndian, &ls.Uint64)
}
-
+ b.StopTimer()
want := s
want.Float32 = 0
want.Float64 = 0
want.Complex64 = 0
want.Complex128 = 0
- for i := range want.Array {
- want.Array[i] = 0
- }
- b.StopTimer()
- if !reflect.DeepEqual(ls, want) {
- panic("no match")
+ want.Array = [4]uint8{0, 0, 0, 0}
+ want.Bool = false
+ want.BoolArray = [4]bool{false, false, false, false}
+ if b.N > 0 && !reflect.DeepEqual(ls, want) {
+ b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want)
}
}
@@ -427,7 +483,7 @@ func BenchmarkWriteInts(b *testing.B) {
Write(w, BigEndian, s.Uint64)
}
b.StopTimer()
- if !bytes.Equal(buf.Bytes(), big[:30]) {
+ if b.N > 0 && !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.go b/libgo/go/encoding/binary/varint.go
index 3a2dfa3c74..d7a75f99b1 100644
--- a/libgo/go/encoding/binary/varint.go
+++ b/libgo/go/encoding/binary/varint.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.