Skip to content

Commit

Permalink
More convenient parsing of little-endian data (e.g.: when wanting to …
Browse files Browse the repository at this point in the history
…make a uint32 from a slice of 3 bytes.
  • Loading branch information
lemmerelassal committed Oct 21, 2019
1 parent 7a6da21 commit 801ef65
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 19 deletions.
53 changes: 46 additions & 7 deletions src/encoding/binary/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,15 @@ var BigEndian bigEndian
type littleEndian struct{}

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
// The previous implementation wouldn't allow an empty slice
switch len(b) {
case 0:
return 0
case 1:
return uint16(b[0])
default:
return uint16(b[0]) | uint16(b[1])<<8
}
}

func (littleEndian) PutUint16(b []byte, v uint16) {
Expand All @@ -60,8 +67,19 @@ func (littleEndian) PutUint16(b []byte, v uint16) {
}

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
// The previous implementation wouldn't allow for example a 3 byte slice
switch len(b) {
case 0:
return 0
case 1:
return uint32(b[0])
case 2:
return uint32(b[0]) | uint32(b[1])<<8
case 3:
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16
default:
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
}

func (littleEndian) PutUint32(b []byte, v uint32) {
Expand All @@ -73,9 +91,30 @@ 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
switch len(b) {
case 0:
return 0
case 1:
return uint64(b[0])
case 2:
return uint64(b[0]) | uint64(b[1])<<8
case 3:
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16
case 4:
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
case 5:
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32
case 6:
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40
case 7:
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
default:
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) {
Expand Down
12 changes: 0 additions & 12 deletions src/encoding/binary/binary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,15 +370,6 @@ 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
Expand All @@ -389,9 +380,6 @@ func testPutUint64SmallSliceLengthPanics() (panicked bool) {
}

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")
}
Expand Down

0 comments on commit 801ef65

Please sign in to comment.