Skip to content

Commit b57da1e

Browse files
committed
bitset: add code and tests
1 parent 4ec8e4d commit b57da1e

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

bitset.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package bitset
2+
3+
const word = uint64(64)
4+
const logword = uint(6)
5+
6+
type BitSet struct {
7+
length uint64
8+
bits []uint64
9+
}
10+
11+
func getSize(length uint64) uint64 {
12+
return uint64((length + word - 1) / word)
13+
}
14+
15+
func New(length uint64) *BitSet {
16+
size := getSize(length)
17+
return &BitSet{length, make([]uint64, size)}
18+
}
19+
20+
func getIndex(pos uint64) (q uint64, r uint) {
21+
q = pos >> logword
22+
r = uint(pos & (word - 1))
23+
return
24+
}
25+
26+
func (b *BitSet) Length() uint64 {
27+
return b.length
28+
}
29+
30+
func (b *BitSet) Get(pos uint64) bool {
31+
q, r := getIndex(pos)
32+
bit := (b.bits[q] >> r) & 1
33+
return bit != 0
34+
}
35+
36+
func (b *BitSet) Set(pos uint64) bool {
37+
current := b.Get(pos)
38+
q, r := getIndex(pos)
39+
b.bits[q] |= (1 << r)
40+
return current
41+
}
42+
43+
func (b *BitSet) Clear(pos uint64) bool {
44+
current := b.Get(pos)
45+
q, r := getIndex(pos)
46+
b.bits[q] &= ^(1 << r)
47+
return current
48+
}
49+
50+
func (b *BitSet) Flip(pos uint64) bool {
51+
current := b.Get(pos)
52+
q, r := getIndex(pos)
53+
b.bits[q] ^= (1 << r)
54+
return current
55+
}

bitset_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package bitset
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestInit(t *testing.T) {
8+
bs := New(1000)
9+
// initially all bits should be zero
10+
for i := uint64(0); i < 1000; i++ {
11+
if bs.Get(i) {
12+
t.Errorf("Bit %d is set when it should not be", i)
13+
}
14+
}
15+
}
16+
17+
func TestGetSet(t *testing.T) {
18+
bs := New(1000)
19+
if bs.Set(0) == true {
20+
t.Error("Set on bit %d returned true when it should return false", 0)
21+
}
22+
23+
if bs.Get(0) == false {
24+
t.Errorf("Bit %d is not set when it should be", 0)
25+
}
26+
27+
if bs.Set(0) == false {
28+
t.Errorf("Set on bit %d returned false when it should return true", 0)
29+
}
30+
}
31+
32+
func TestLargeSetGet(t *testing.T) {
33+
size := uint64(1) << 35
34+
bs := New(size)
35+
36+
positions := []uint64{0, 1, 10, 1000, 1 << 32, size - 1}
37+
for _, position := range positions {
38+
if bs.Get(position) {
39+
t.Errorf("Bit %d should be false but is true", position)
40+
}
41+
42+
bs.Set(position)
43+
44+
if !bs.Get(position) {
45+
t.Errorf("Bit %d should be true but is false", position)
46+
}
47+
}
48+
}
49+
50+
func TestLength(t *testing.T) {
51+
52+
sizes := []uint64{0, 1, 10, 1000, 1 << 32, 1 << 33}
53+
for _, size := range sizes {
54+
bs := New(size)
55+
if bs.Length() != size {
56+
t.Errorf("Length should be %d", size)
57+
}
58+
}
59+
}
60+
61+
func TestClear(t *testing.T) {
62+
bs := New(1000)
63+
pos := uint64(1)
64+
bs.Set(pos)
65+
66+
if !bs.Get(pos) {
67+
t.Errorf("Bit %d should be set when it is not", pos)
68+
}
69+
70+
if !bs.Clear(pos) {
71+
t.Error("Clearing bit %d should have returned true", pos)
72+
}
73+
74+
if bs.Get(pos) {
75+
t.Errorf("Bit %d should have been cleared when it is not", pos)
76+
}
77+
}
78+
79+
func TestFlip(t *testing.T) {
80+
bs := New(1000)
81+
pos := uint64(1)
82+
83+
if bs.Get(pos) {
84+
t.Errorf("Bit %d should be clear when it is not", pos)
85+
}
86+
87+
if bs.Flip(pos) {
88+
t.Error("Flipping bit %d should have returned false, but it did not", pos)
89+
}
90+
91+
if !bs.Get(pos) {
92+
t.Errorf("Bit %d should have been set when it is not", pos)
93+
}
94+
if !bs.Flip(pos) {
95+
t.Error("Flipping bit %d should have returned true, but it did not", pos)
96+
}
97+
98+
if bs.Get(pos) {
99+
t.Errorf("Bit %d should have been clear when it is not", pos)
100+
}
101+
}

0 commit comments

Comments
 (0)