blob: a5edc040d6614f90c4fb63389477f97dbc6ba4ca [file] [log] [blame]
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package binary
// BitStream provides methods for reading and writing bits to a slice of bytes.
// Bits are packed in a least-significant-bit to most-significant-bit order.
type BitStream struct {
Data []byte // The byte slice containing the bits
ReadPos uint32 // The current read offset from the start of the Data slice (in bits)
WritePos uint32 // The current write offset from the start of the Data slice (in bits)
}
// ReadBit reads a single bit from the BitStream, incrementing ReadPos by one.
func (s *BitStream) ReadBit() uint32 {
ReadPos := s.ReadPos
s.ReadPos = ReadPos + 1
return (uint32(s.Data[ReadPos/8]) >> (ReadPos % 8)) & 1
}
// WriteBit writes a single bit to the BitStream, incrementing WritePos by one.
func (s *BitStream) WriteBit(bit uint32) {
WritePos := s.WritePos
b := WritePos / 8
if b == uint32(len(s.Data)) {
s.Data = append(s.Data, byte(0))
}
s.Data[b] |= byte((bit & 1) << (WritePos % 8))
s.WritePos = WritePos + 1
}
// Read reads the specified number of bits from the BitStream, increamenting the ReadPos by the
// specified number of bits and returning the bits packed into a uint32. The bits are packed into
// the uint32 from LSB to MSB.
func (s *BitStream) Read(count uint32) uint32 {
byteIdx := s.ReadPos / 8
bitIdx := s.ReadPos & 7
// Start
val := uint32(s.Data[byteIdx]) >> bitIdx
readCount := 8 - bitIdx
if count <= readCount {
s.ReadPos += count
return val & ((1 << count) - 1)
}
s.ReadPos += readCount
byteIdx++
bitIdx = 0
// Whole bytes
for ; readCount+7 < count; readCount += 8 {
val |= uint32(s.Data[byteIdx]) << readCount
byteIdx++
s.ReadPos += 8
}
// Remainder
rem := count - readCount
if rem > 0 {
val |= (uint32(s.Data[byteIdx]) & ((1 << rem) - 1)) << readCount
s.ReadPos += rem
}
return val
}
// Write writes the specified number of bits from the packed uint32, increamenting the WritePos by
// the specified number of bits. The bits are read from the uint32 from LSB to MSB.
func (s *BitStream) Write(bits, count uint32) {
// TODO: Slowest implementation ever? Quite possibly. Optimise
for i := uint32(0); i < count; i++ {
s.WriteBit(bits >> i)
}
}