77 lines
2.0 KiB
Go
77 lines
2.0 KiB
Go
// Copyright (C) 2019 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package main
|
|
|
|
import (
|
|
"math/bits"
|
|
|
|
"github.com/zeebo/errs"
|
|
)
|
|
|
|
// errorBitmaskInvalidIdx is the error class to return invalid indexes for the
|
|
// the bitmask type.
|
|
var errorBitmaskInvalidIdx = errs.Class("invalid index")
|
|
|
|
// bitmask allows to track indexes in an optimal way.
|
|
type bitmask uint64
|
|
|
|
// Set tracks index in mask. It returns an error if index is negative or it's
|
|
// greater than 63.
|
|
func (mask *bitmask) Set(index int) error {
|
|
switch {
|
|
case index < 0:
|
|
return errorBitmaskInvalidIdx.New("negative value (%d)", index)
|
|
case index > 63:
|
|
return errorBitmaskInvalidIdx.New("index is greater than 63 (%d)", index)
|
|
}
|
|
|
|
bit := uint64(1) << index
|
|
*mask = bitmask(uint64(*mask) | bit)
|
|
return nil
|
|
}
|
|
|
|
// Unset removes bit from index in mask. It returns an error if index is negative or it's
|
|
// greater than 63.
|
|
func (mask *bitmask) Unset(index int) error {
|
|
switch {
|
|
case index < 0:
|
|
return errorBitmaskInvalidIdx.New("negative value (%d)", index)
|
|
case index > 63:
|
|
return errorBitmaskInvalidIdx.New("index is greater than 63 (%d)", index)
|
|
}
|
|
|
|
bit := uint64(1) << index
|
|
*mask = bitmask(uint64(*mask) ^ bit)
|
|
return nil
|
|
}
|
|
|
|
// Has returns true if the index is tracked in mask otherwise false.
|
|
// It returns an error if index is negative or it's greater than 63.
|
|
func (mask *bitmask) Has(index int) (bool, error) {
|
|
switch {
|
|
case index < 0:
|
|
return false, errorBitmaskInvalidIdx.New("negative value (%d)", index)
|
|
case index > 63:
|
|
return false, errorBitmaskInvalidIdx.New("index is greater than 63 (%d)", index)
|
|
}
|
|
|
|
bit := uint64(1) << index
|
|
bit = uint64(*mask) & bit
|
|
return bit != 0, nil
|
|
}
|
|
|
|
// Count returns the number of tracked indexes.
|
|
func (mask *bitmask) Count() int {
|
|
return bits.OnesCount64(uint64(*mask))
|
|
}
|
|
|
|
// IsSequence returns true if mask has only tracked a correlative sequence of
|
|
// indexes starting from index 0.
|
|
func (mask *bitmask) IsSequence() bool {
|
|
ones := mask.Count()
|
|
zeros := bits.LeadingZeros64(uint64(*mask))
|
|
|
|
return (zeros + ones) == 64
|
|
}
|