bit twiddling

master
Jordan Orelli 8 years ago
parent 7d589f8f62
commit 73f35ecad8

@ -51,6 +51,9 @@ func (r *Reader) ReadBits(bits uint) (n uint64) {
// ReadByte reads a single byte, regardless of alignment. // ReadByte reads a single byte, regardless of alignment.
func (r *Reader) ReadByte() (byte, error) { func (r *Reader) ReadByte() (byte, error) {
if r.bits == 0 {
return r.src.ReadByte()
}
b := byte(r.ReadBits(8)) b := byte(r.ReadBits(8))
if err := r.Err(); err != nil { if err := r.Err(); err != nil {
return 0, err return 0, err
@ -70,4 +73,27 @@ func (r *Reader) Read(buf []byte) (int, error) {
return len(buf), nil return len(buf), nil
} }
// ReadUbitVar reads a prefixed uint value. A prefix is 2 bits wide, followed
// by the 4 least-significant bits, then a variable number of most-significant
// bits based on the prefix.
//
// 00 - 0
// 01 - 4
// 10 - 8
// 11 - 28
func (r *Reader) ReadUBitVar() uint64 {
switch prefix := r.ReadBits(2); prefix {
case 0:
return r.ReadBits(4)
case 1:
return r.ReadBits(4) | r.ReadBits(4)<<4
case 2:
return r.ReadBits(4) | r.ReadBits(8)<<4
case 3:
return r.ReadBits(4) | r.ReadBits(28)<<4
default:
panic("not reached")
}
}
func (r *Reader) Err() error { return r.err } func (r *Reader) Err() error { return r.err }

@ -9,13 +9,17 @@ import (
var ( var (
// 1000 1011 1010 1101 1111 0000 0000 1101 // 1000 1011 1010 1101 1111 0000 0000 1101
badFood = []byte{0x8b, 0xad, 0xf0, 0x0d} badFood = []byte{0x8b, 0xad, 0xf0, 0x0d}
// 0000 1110 0001 1110 1110 0111 1011 1110 1110 1111
eLeetBeef = []byte{0x0e, 0x1e, 0xe7, 0xbe, 0xef}
) )
// test the bit-level reads // test the bit-level reads
func TestReadBits(t *testing.T) { func TestReadBits(t *testing.T) {
assert := assert.New(t) var (
assert = assert.New(t)
var r *Reader r *Reader
)
// aligned reading // aligned reading
r = NewBytesReader(badFood) r = NewBytesReader(badFood)
@ -44,29 +48,83 @@ func TestReadBits(t *testing.T) {
assert.Equal(uint64(0x15), r.ReadBits(5)) assert.Equal(uint64(0x15), r.ReadBits(5))
// 1000 1011 1010 1101 1111 0000 0000 1101 // 1000 1011 1010 1101 1111 0000 0000 1101
// ^---------^ // ^----+----^
assert.Equal(uint64(0x17c), r.ReadBits(9)) assert.Equal(uint64(0x17c), r.ReadBits(9))
// 1000 1011 1010 1101 1111 0000 0000 1101 // 1000 1011 1010 1101 1111 0000 0000 1101
// ^----------^ // ^----+----+^
assert.Equal(uint64(0xd), r.ReadBits(10)) assert.Equal(uint64(0xd), r.ReadBits(10))
} }
// test the Read calls, satisfying io.Reader // test the Read calls, satisfying io.Reader
func TestRead(t *testing.T) { func TestRead(t *testing.T) {
assert := assert.New(t) var (
var r *Reader assert = assert.New(t)
r *Reader
buf []byte
n int
err error
)
r = NewBytesReader(badFood)
buf = make([]byte, 4)
n, err = r.Read(buf)
assert.NoError(err)
assert.Equal(4, n)
assert.Equal(badFood, buf)
r = NewBytesReader(badFood) r = NewBytesReader(badFood)
// 1000 1011 1010 1101 1111 0000 0000 1101 // 1000 1011 1010 1101 1111 0000 0000 1101
r.ReadBits(1) r.ReadBits(1)
// 0001 0111 0101 1011 1110 0000 0001 101 // 0001 0111 0101 1011 1110 0000 0001 101
buf := make([]byte, 3) buf = make([]byte, 3)
n, err := r.Read(buf) n, err = r.Read(buf)
assert.NoError(err) assert.NoError(err)
assert.Equal(3, n) assert.Equal(3, n)
expected := []byte{0x17, 0x5b, 0xe0} expected := []byte{0x17, 0x5b, 0xe0}
assert.Equal(expected, buf) assert.Equal(expected, buf)
} }
func TestUbitVar(t *testing.T) {
var (
assert = assert.New(t)
r *Reader
u uint64
)
// 1000 1011 1010 1101 1111 0000 0000 1101
// ||^---^ : data (0101)
// ^^ : prefix (00)
r = NewBytesReader(badFood)
r.ReadBits(1)
u = r.ReadUBitVar()
assert.Equal(uint64(5), u)
r.ReadBits(2)
// 1000 1011 1010 1101 1111 0000 0000 1101
// ||| | ^--^ : most significant (1111)
// ||^---^ : least significant (0110)
// ^^ : prefix (01)
u = r.ReadUBitVar()
assert.Equal(uint64(0xf6), u)
r = NewBytesReader(badFood)
// 1000 1011 1010 1101 1111 0000 0000 1101
// ||| |^----+---^ : most significant (1110 1011)
// ||^---^ : least significant (0010)
// ^^ : prefix (10)
u = r.ReadUBitVar()
assert.Equal(uint64(0xeb2), u)
r = NewBytesReader(eLeetBeef)
r.ReadBits(4)
// 0000 1110 0001 1110 1110 0111 1011 1110 1110 1111
// ||| |^----+----+----+----+----+----+---^ : msb (0111 1011 1001 1110
// ||| | 1111 1011 1011)
// ||^---^ : lsb (1000)
// ^^ : prefix
u = r.ReadUBitVar()
assert.Equal(uint64(0x7b9efbb8), u)
}

Loading…
Cancel
Save