blob: dfe5cc27028ab44b21495f79b8036f23169b1a71 [file] [log] [blame]
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001// Package bitmap implements (thread-safe) bitmap functions and abstractions.
2//
3// Installation
4//
5// go get github.com/boljen/go-bitmap
6package bitmap
7
8import "sync"
9
10var (
11 tA = [8]byte{1, 2, 4, 8, 16, 32, 64, 128}
12 tB = [8]byte{254, 253, 251, 247, 239, 223, 191, 127}
13)
14
15func dataOrCopy(d []byte, c bool) []byte {
16 if !c {
17 return d
18 }
19 ndata := make([]byte, len(d))
20 copy(ndata, d)
21 return ndata
22}
23
24// NewSlice creates a new byteslice with length l (in bits).
25// The actual size in bits might be up to 7 bits larger because
26// they are stored in a byteslice.
27func NewSlice(l int) []byte {
28 remainder := l % 8
29 if remainder != 0 {
30 remainder = 1
31 }
32 return make([]byte, l/8+remainder)
33}
34
35// Get returns the value of bit i from map m.
36// It doesn't check the bounds of the slice.
37func Get(m []byte, i int) bool {
38 return m[i/8]&tA[i%8] != 0
39}
40
41// Set sets bit i of map m to value v.
42// It doesn't check the bounds of the slice.
43func Set(m []byte, i int, v bool) {
44 index := i / 8
45 bit := i % 8
46 if v {
47 m[index] = m[index] | tA[bit]
48 } else {
49 m[index] = m[index] & tB[bit]
50 }
51}
52
53// GetBit returns the value of bit i of byte b.
54// The bit index must be between 0 and 7.
55func GetBit(b byte, i int) bool {
56 return b&tA[i] != 0
57}
58
59// SetBit sets bit i of byte b to value v.
60// The bit index must be between 0 and 7.
61func SetBit(b byte, i int, v bool) byte {
62 if v {
63 return b | tA[i]
64 }
65 return b & tB[i]
66}
67
68// SetBitRef sets bit i of byte *b to value v.
69func SetBitRef(b *byte, i int, v bool) {
70 if v {
71 *b = *b | tA[i]
72 } else {
73 *b = *b & tB[i]
74 }
75}
76
77// Len returns the length (in bits) of the provided byteslice.
78// It will always be a multipile of 8 bits.
79func Len(m []byte) int {
80 return len(m) * 8
81}
82
83// Bitmap is a byteslice with bitmap functions.
84// Creating one form existing data is as simple as bitmap := Bitmap(data).
85type Bitmap []byte
86
87// New creates a new Bitmap instance with length l (in bits).
88func New(l int) Bitmap {
89 return NewSlice(l)
90}
91
92// Len wraps around the Len function.
93func (b Bitmap) Len() int {
94 return Len(b)
95}
96
97// Get wraps around the Get function.
98func (b Bitmap) Get(i int) bool {
99 return Get(b, i)
100}
101
102// Set wraps around the Set function.
103func (b Bitmap) Set(i int, v bool) {
104 Set(b, i, v)
105}
106
107// Data returns the data of the bitmap.
108// If copy is false the actual underlying slice will be returned.
109func (b Bitmap) Data(copy bool) []byte {
110 return dataOrCopy(b, copy)
111}
112
113// Threadsafe implements thread-safe read- and write locking for the bitmap.
114type Threadsafe struct {
115 bm Bitmap
116 mu sync.RWMutex
117}
118
119// TSFromData creates a new Threadsafe using the provided data.
120// If copy is true the actual slice will be used.
121func TSFromData(data []byte, copy bool) *Threadsafe {
122 return &Threadsafe{
123 bm: Bitmap(dataOrCopy(data, copy)),
124 }
125}
126
127// NewTS creates a new Threadsafe instance.
128func NewTS(length int) *Threadsafe {
129 return &Threadsafe{
130 bm: New(length),
131 }
132}
133
134// Data returns the data of the bitmap.
135// If copy is false the actual underlying slice will be returned.
136func (b *Threadsafe) Data(copy bool) []byte {
137 b.mu.RLock()
138 data := dataOrCopy(b.bm, copy)
139 b.mu.RUnlock()
140 return data
141}
142
143// Len wraps around the Len function.
144func (b Threadsafe) Len() int {
145 b.mu.RLock()
146 l := b.bm.Len()
147 b.mu.RUnlock()
148 return l
149}
150
151// Get wraps around the Get function.
152func (b Threadsafe) Get(i int) bool {
153 b.mu.RLock()
154 v := b.bm.Get(i)
155 b.mu.RUnlock()
156 return v
157}
158
159// Set wraps around the Set function.
160func (b Threadsafe) Set(i int, v bool) {
161 b.mu.Lock()
162 b.bm.Set(i, v)
163 b.mu.Unlock()
164}
165
166// Concurrent is a bitmap implementation that achieves thread-safety
167// using atomic operations along with some unsafe.
168// It performs atomic operations on 32bits of data.
169type Concurrent []byte
170
171// NewConcurrent returns a concurrent bitmap.
172// It will create a bitmap
173func NewConcurrent(l int) Concurrent {
174 remainder := l % 8
175 if remainder != 0 {
176 remainder = 1
177 }
178 return make([]byte, l/8+remainder, l/8+remainder+3)
179}
180
181// Get wraps around the Get function.
182func (c Concurrent) Get(b int) bool {
183 return Get(c, b)
184}
185
186// Set wraps around the SetAtomic function.
187func (c Concurrent) Set(b int, v bool) {
188 SetAtomic(c, b, v)
189}
190
191// Len wraps around the Len function.
192func (c Concurrent) Len() int {
193 return Len(c)
194}
195
196// Data returns the data of the bitmap.
197// If copy is false the actual underlying slice will be returned.
198func (c Concurrent) Data(copy bool) []byte {
199 return dataOrCopy(c, copy)
200}