storj/cmd/segment-reaper/bit_array.go
Ivan Fraixedes 9314092841
cmd/segment-reaper: Rename Bitmask to BitArray
Rename a test name and an error class because the bitmask was renamed to
bitArray in a previous commit, however, they weren't updated.

Change-Id: I92afcf747dec9e0a15d4c59b896e07b942f3518b
2020-05-12 15:22:30 +02:00

109 lines
2.7 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package main
import (
"math/bits"
"github.com/zeebo/errs"
)
// errorBitArrayInvalidIdx is the error class to return invalid indexes for the
// the bitArray type.
var errorBitArrayInvalidIdx = errs.Class("invalid index")
// bitArray allows easy access to bit values by indices.
type bitArray []byte
// 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
switch {
case index < 0:
return errorBitArrayInvalidIdx.New("negative value (%d)", index)
case byteIndex >= len(*bytes):
sizeToGrow := byteIndex - len(*bytes) + 1
*bytes = append(*bytes, make([]byte, sizeToGrow)...)
}
mask := byte(1) << bitIndex
(*bytes)[byteIndex] |= mask
return nil
}
// 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
switch {
case index < 0:
return errorBitArrayInvalidIdx.New("negative value (%d)", index)
case byteIndex >= len(*bytes):
return nil
}
mask := byte(1) << bitIndex
(*bytes)[byteIndex] &^= mask
return nil
}
// Has returns true if the index is tracked in mask otherwise false.
// It returns an error if index is negative.
func (bytes *bitArray) Has(index int) (bool, error) {
bitIndex, byteIndex := index%8, index/8
switch {
case index < 0:
return false, errorBitArrayInvalidIdx.New("negative value (%d)", index)
case byteIndex >= len(*bytes):
return false, nil
}
mask := byte(1) << bitIndex
result := (*bytes)[byteIndex] & mask
return result != 0, nil
}
// 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
}
// IsSequence returns true if mask has only tracked a correlative sequence of
// indexes starting from index 0.
func (bytes *bitArray) IsSequence() bool {
// 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
}
// 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
}
// Length returns the current size of the array in bits.
func (bytes *bitArray) Length() int {
return len(*bytes) * 8
}