gonna need this bit twiddling thing
parent
0645f224a9
commit
9b4075c881
@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// a bitBuffer is a buffer of raw data that is not necessarily byte-aligned,
|
||||
// for performing bitwise reads and manipulation. The bulk of this source is
|
||||
// adapted from the bitReader defined in the standard library bzip2 package.
|
||||
type bitBuffer struct {
|
||||
source []byte // the source data to be read. This slice is never modified
|
||||
index int // position of the last byte read out of source
|
||||
scratch uint64 // scratch register of bits worthy of manipulation
|
||||
bits uint // bit width of the scratch register
|
||||
err error // stored error
|
||||
}
|
||||
|
||||
func newBitBuffer(buf []byte) *bitBuffer {
|
||||
return &bitBuffer{source: buf}
|
||||
}
|
||||
|
||||
func (b *bitBuffer) readBits(bits uint) uint64 {
|
||||
for bits > b.bits {
|
||||
if b.index >= len(b.source) {
|
||||
b.err = io.ErrUnexpectedEOF
|
||||
return 0
|
||||
}
|
||||
b.scratch <<= 8
|
||||
b.scratch |= uint64(b.source[b.index])
|
||||
b.index += 1
|
||||
b.bits += 8
|
||||
}
|
||||
|
||||
// b.scratch looks like this (assuming that b.bits = 14 and bits = 6):
|
||||
// Bit: 111111
|
||||
// 5432109876543210
|
||||
//
|
||||
// (6 bits, the desired output)
|
||||
// |-----|
|
||||
// V V
|
||||
// 0101101101001110
|
||||
// ^ ^
|
||||
// |------------|
|
||||
// b.bits (num valid bits)
|
||||
//
|
||||
// This the next line right shifts the desired bits into the
|
||||
// least-significant places and masks off anything above.
|
||||
n := (b.scratch >> (b.bits - bits)) & ((1 << bits) - 1)
|
||||
b.bits -= bits
|
||||
return n
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBits(t *testing.T) {
|
||||
buf := []byte{0x00}
|
||||
bb := newBitBuffer(buf)
|
||||
for i := 0; i < 8; i++ {
|
||||
if bb.readBits(1) != 0x00 {
|
||||
t.Error("hahha what")
|
||||
}
|
||||
if bb.err != nil {
|
||||
t.Errorf("oh weird error: %v", bb.err)
|
||||
}
|
||||
}
|
||||
if bb.readBits(1) != 0x00 {
|
||||
t.Error("hahha what")
|
||||
}
|
||||
if bb.err != io.ErrUnexpectedEOF {
|
||||
t.Errorf("oh weird error: %v", bb.err)
|
||||
}
|
||||
|
||||
buf = []byte{0x10}
|
||||
bb = newBitBuffer(buf)
|
||||
if n := bb.readBits(4); n != 0x01 {
|
||||
t.Errorf("shit. wanted %v, got %v", 0x01, n)
|
||||
}
|
||||
if n := bb.readBits(4); n != 0x00 {
|
||||
t.Errorf("poop. wanted %v, got %v", 0x00, n)
|
||||
}
|
||||
if bb.err != nil {
|
||||
t.Errorf("fuck")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue