76 lines
1.6 KiB
Go
76 lines
1.6 KiB
Go
package pvdata
|
|
|
|
import "io"
|
|
|
|
// BitSet is a variable-length set of bit indices, encoded on the wire as:
|
|
//
|
|
// compact-size(n_bytes) + n_bytes of little-endian bits.
|
|
//
|
|
// Bit 0 of byte 0 is field index 0, bit 1 of byte 0 is field index 1, etc.
|
|
// Used in pvData Monitor responses for "changed" and "overrun" masks.
|
|
type BitSet struct {
|
|
bits []byte
|
|
}
|
|
|
|
// NewBitSet returns an empty BitSet.
|
|
func NewBitSet() BitSet { return BitSet{} }
|
|
|
|
// Set sets bit i in the BitSet.
|
|
func (bs *BitSet) Set(i int) {
|
|
byteIdx := i / 8
|
|
for len(bs.bits) <= byteIdx {
|
|
bs.bits = append(bs.bits, 0)
|
|
}
|
|
bs.bits[byteIdx] |= 1 << (uint(i) % 8)
|
|
}
|
|
|
|
// Has reports whether bit i is set.
|
|
func (bs *BitSet) Has(i int) bool {
|
|
byteIdx := i / 8
|
|
if byteIdx >= len(bs.bits) {
|
|
return false
|
|
}
|
|
return bs.bits[byteIdx]&(1<<(uint(i)%8)) != 0
|
|
}
|
|
|
|
// ReadBitSet reads a BitSet from r.
|
|
func ReadBitSet(r io.Reader) (BitSet, error) {
|
|
n, err := ReadSize(r)
|
|
if err != nil {
|
|
return BitSet{}, err
|
|
}
|
|
if n == 0 {
|
|
return BitSet{}, nil
|
|
}
|
|
buf := make([]byte, n)
|
|
if _, err := io.ReadFull(r, buf); err != nil {
|
|
return BitSet{}, err
|
|
}
|
|
return BitSet{bits: buf}, nil
|
|
}
|
|
|
|
// WriteBitSet writes bs to w.
|
|
func WriteBitSet(w io.Writer, bs BitSet) error {
|
|
if err := WriteSize(w, int64(len(bs.bits))); err != nil {
|
|
return err
|
|
}
|
|
if len(bs.bits) == 0 {
|
|
return nil
|
|
}
|
|
_, err := w.Write(bs.bits)
|
|
return err
|
|
}
|
|
|
|
// FieldIndices returns all set bit indices in ascending order.
|
|
func (bs *BitSet) FieldIndices() []int {
|
|
var out []int
|
|
for bi, b := range bs.bits {
|
|
for bit := 0; bit < 8; bit++ {
|
|
if b&(1<<uint(bit)) != 0 {
|
|
out = append(out, bi*8+bit)
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|