forked from boljen/go-bitmap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bitmap.go
164 lines (141 loc) · 3.45 KB
/
bitmap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// 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()
}