2019-11-22 10:53:48 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math/bits"
|
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
)
|
|
|
|
|
2020-05-11 15:19:34 +01:00
|
|
|
// errorBitArrayInvalidIdx is the error class to return invalid indexes for the
|
2020-05-06 20:56:41 +01:00
|
|
|
// the bitArray type.
|
2020-05-11 15:19:34 +01:00
|
|
|
var errorBitArrayInvalidIdx = errs.Class("invalid index")
|
2019-11-22 10:53:48 +00:00
|
|
|
|
2020-05-06 20:56:41 +01:00
|
|
|
// bitArray allows easy access to bit values by indices.
|
|
|
|
type bitArray []byte
|
2019-11-22 10:53:48 +00:00
|
|
|
|
2020-05-06 20:56:41 +01:00
|
|
|
// Set tracks index in mask. It returns an error if index is negative.
|
|
|
|
// Set will resize the array if you access an index larger than its Length.
|
|
|
|
func (bytes *bitArray) Set(index int) error {
|
|
|
|
bitIndex, byteIndex := index%8, index/8
|
2019-11-22 10:53:48 +00:00
|
|
|
switch {
|
|
|
|
case index < 0:
|
2020-05-11 15:19:34 +01:00
|
|
|
return errorBitArrayInvalidIdx.New("negative value (%d)", index)
|
2020-05-06 20:56:41 +01:00
|
|
|
case byteIndex >= len(*bytes):
|
|
|
|
sizeToGrow := byteIndex - len(*bytes) + 1
|
|
|
|
*bytes = append(*bytes, make([]byte, sizeToGrow)...)
|
2019-11-22 10:53:48 +00:00
|
|
|
}
|
2020-05-06 20:56:41 +01:00
|
|
|
mask := byte(1) << bitIndex
|
|
|
|
(*bytes)[byteIndex] |= mask
|
2019-11-22 10:53:48 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-06 20:56:41 +01:00
|
|
|
// Unset removes bit from index in mask. It returns an error if index is negative.
|
|
|
|
func (bytes *bitArray) Unset(index int) error {
|
|
|
|
bitIndex, byteIndex := index%8, index/8
|
2019-12-09 11:30:52 +00:00
|
|
|
switch {
|
|
|
|
case index < 0:
|
2020-05-11 15:19:34 +01:00
|
|
|
return errorBitArrayInvalidIdx.New("negative value (%d)", index)
|
2020-05-06 20:56:41 +01:00
|
|
|
case byteIndex >= len(*bytes):
|
|
|
|
return nil
|
2019-12-09 11:30:52 +00:00
|
|
|
}
|
2020-05-06 20:56:41 +01:00
|
|
|
mask := byte(1) << bitIndex
|
|
|
|
(*bytes)[byteIndex] &^= mask
|
2019-12-09 11:30:52 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-11-22 10:53:48 +00:00
|
|
|
// Has returns true if the index is tracked in mask otherwise false.
|
2020-05-06 20:56:41 +01:00
|
|
|
// It returns an error if index is negative.
|
|
|
|
func (bytes *bitArray) Has(index int) (bool, error) {
|
|
|
|
bitIndex, byteIndex := index%8, index/8
|
2019-11-22 10:53:48 +00:00
|
|
|
switch {
|
|
|
|
case index < 0:
|
2020-05-11 15:19:34 +01:00
|
|
|
return false, errorBitArrayInvalidIdx.New("negative value (%d)", index)
|
2020-05-06 20:56:41 +01:00
|
|
|
case byteIndex >= len(*bytes):
|
|
|
|
return false, nil
|
2019-11-22 10:53:48 +00:00
|
|
|
}
|
|
|
|
|
2020-05-06 20:56:41 +01:00
|
|
|
mask := byte(1) << bitIndex
|
|
|
|
result := (*bytes)[byteIndex] & mask
|
|
|
|
return result != 0, nil
|
2019-11-22 10:53:48 +00:00
|
|
|
}
|
|
|
|
|
2020-05-06 20:56:41 +01:00
|
|
|
// Count returns the number of bits which are set.
|
|
|
|
func (bytes *bitArray) Count() int {
|
|
|
|
count := 0
|
|
|
|
for x := 0; x < len(*bytes); x++ {
|
|
|
|
count += bits.OnesCount8((*bytes)[x])
|
|
|
|
}
|
|
|
|
return count
|
2019-11-22 10:53:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsSequence returns true if mask has only tracked a correlative sequence of
|
|
|
|
// indexes starting from index 0.
|
2020-05-06 20:56:41 +01:00
|
|
|
func (bytes *bitArray) IsSequence() bool {
|
2020-05-11 15:02:31 +01:00
|
|
|
// find the last byte of the sequence that contains some one
|
|
|
|
var i int
|
|
|
|
for i = len(*bytes) - 1; i >= 0; i-- {
|
|
|
|
zeros := bits.LeadingZeros8((*bytes)[i])
|
|
|
|
if zeros == 8 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
ones := bits.OnesCount8((*bytes)[i])
|
|
|
|
if zeros+ones != 8 {
|
|
|
|
// zeros and ones in this byte aren't in sequence
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
2020-05-06 20:56:41 +01:00
|
|
|
}
|
2020-05-11 15:02:31 +01:00
|
|
|
|
|
|
|
// The rest of the bytes of the sequence must only contains ones
|
|
|
|
i--
|
|
|
|
for ; i >= 0; i-- {
|
|
|
|
if (*bytes)[i] != 255 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
2020-05-06 20:56:41 +01:00
|
|
|
}
|
2019-11-22 10:53:48 +00:00
|
|
|
|
2020-05-06 20:56:41 +01:00
|
|
|
// Length returns the current size of the array in bits.
|
|
|
|
func (bytes *bitArray) Length() int {
|
|
|
|
return len(*bytes) * 8
|
2019-11-22 10:53:48 +00:00
|
|
|
}
|