blob: dfe5cc27028ab44b21495f79b8036f23169b1a71 [file] [log] [blame]
// Package bitmap implements (thread-safe) bitmap functions and abstractions.
//
// Installation
//
// go get github.com/boljen/go-bitmap
package bitmap
import "sync"
var (
tA = [8]byte{1, 2, 4, 8, 16, 32, 64, 128}
tB = [8]byte{254, 253, 251, 247, 239, 223, 191, 127}
)
func dataOrCopy(d []byte, c bool) []byte {
if !c {
return d
}
ndata := make([]byte, len(d))
copy(ndata, d)
return ndata
}
// NewSlice creates a new byteslice with length l (in bits).
// The actual size in bits might be up to 7 bits larger because
// they are stored in a byteslice.
func NewSlice(l int) []byte {
remainder := l % 8
if remainder != 0 {
remainder = 1
}
return make([]byte, l/8+remainder)
}
// Get returns the value of bit i from map m.
// It doesn't check the bounds of the slice.
func Get(m []byte, i int) bool {
return m[i/8]&tA[i%8] != 0
}
// Set sets bit i of map m to value v.
// It doesn't check the bounds of the slice.
func Set(m []byte, i int, v bool) {
index := i / 8
bit := i % 8
if v {
m[index] = m[index] | tA[bit]
} else {
m[index] = m[index] & tB[bit]
}
}
// GetBit returns the value of bit i of byte b.
// The bit index must be between 0 and 7.
func GetBit(b byte, i int) bool {
return b&tA[i] != 0
}
// SetBit sets bit i of byte b to value v.
// The bit index must be between 0 and 7.
func SetBit(b byte, i int, v bool) byte {
if v {
return b | tA[i]
}
return b & tB[i]
}
// SetBitRef sets bit i of byte *b to value v.
func SetBitRef(b *byte, i int, v bool) {
if v {
*b = *b | tA[i]
} else {
*b = *b & tB[i]
}
}
// Len returns the length (in bits) of the provided byteslice.
// It will always be a multipile of 8 bits.
func Len(m []byte) int {
return len(m) * 8
}
// Bitmap is a byteslice with bitmap functions.
// Creating one form existing data is as simple as bitmap := Bitmap(data).
type Bitmap []byte
// New creates a new Bitmap instance with length l (in bits).
func New(l int) Bitmap {
return NewSlice(l)
}
// Len wraps around the Len function.
func (b Bitmap) Len() int {
return Len(b)
}
// Get wraps around the Get function.
func (b Bitmap) Get(i int) bool {
return Get(b, i)
}
// Set wraps around the Set function.
func (b Bitmap) Set(i int, v bool) {
Set(b, i, v)
}
// Data returns the data of the bitmap.
// If copy is false the actual underlying slice will be returned.
func (b Bitmap) Data(copy bool) []byte {
return dataOrCopy(b, copy)
}
// Threadsafe implements thread-safe read- and write locking for the bitmap.
type Threadsafe struct {
bm Bitmap
mu sync.RWMutex
}
// TSFromData creates a new Threadsafe using the provided data.
// If copy is true the actual slice will be used.
func TSFromData(data []byte, copy bool) *Threadsafe {
return &Threadsafe{
bm: Bitmap(dataOrCopy(data, copy)),
}
}
// NewTS creates a new Threadsafe instance.
func NewTS(length int) *Threadsafe {
return &Threadsafe{
bm: New(length),
}
}
// Data returns the data of the bitmap.
// If copy is false the actual underlying slice will be returned.
func (b *Threadsafe) Data(copy bool) []byte {
b.mu.RLock()
data := dataOrCopy(b.bm, copy)
b.mu.RUnlock()
return data
}
// Len wraps around the Len function.
func (b Threadsafe) Len() int {
b.mu.RLock()
l := b.bm.Len()
b.mu.RUnlock()
return l
}
// Get wraps around the Get function.
func (b Threadsafe) Get(i int) bool {
b.mu.RLock()
v := b.bm.Get(i)
b.mu.RUnlock()
return v
}
// Set wraps around the Set function.
func (b Threadsafe) Set(i int, v bool) {
b.mu.Lock()
b.bm.Set(i, v)
b.mu.Unlock()
}
// Concurrent is a bitmap implementation that achieves thread-safety
// using atomic operations along with some unsafe.
// It performs atomic operations on 32bits of data.
type Concurrent []byte
// NewConcurrent returns a concurrent bitmap.
// It will create a bitmap
func NewConcurrent(l int) Concurrent {
remainder := l % 8
if remainder != 0 {
remainder = 1
}
return make([]byte, l/8+remainder, l/8+remainder+3)
}
// Get wraps around the Get function.
func (c Concurrent) Get(b int) bool {
return Get(c, b)
}
// Set wraps around the SetAtomic function.
func (c Concurrent) Set(b int, v bool) {
SetAtomic(c, b, v)
}
// Len wraps around the Len function.
func (c Concurrent) Len() int {
return Len(c)
}
// Data returns the data of the bitmap.
// If copy is false the actual underlying slice will be returned.
func (c Concurrent) Data(copy bool) []byte {
return dataOrCopy(c, copy)
}