Skip to content

Commit b7a9c44

Browse files
committed
🥇 bitset: add First and FlipFirst
1 parent ab8caea commit b7a9c44

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

bitset/bitset.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,30 @@ func (s BitSet) Count() (count uint) {
3434
return
3535
}
3636

37+
// First returns the index of the first set bit.
38+
func (s BitSet) First() (index uint, found bool) {
39+
for i, block := range s.blocks {
40+
if block == 0 {
41+
continue
42+
}
43+
return uint(i*blockBits + bits.TrailingZeros(block)), true
44+
}
45+
return 0, false
46+
}
47+
48+
// FlipFirst unsets the first set bit and returns its index.
49+
func (s BitSet) FlipFirst() (index uint, found bool) {
50+
for i, block := range s.blocks {
51+
if block == 0 {
52+
continue
53+
}
54+
bitIndex := bits.TrailingZeros(block)
55+
s.blocks[i] ^= 1 << bitIndex
56+
return uint(i*blockBits + bitIndex), true
57+
}
58+
return 0, false
59+
}
60+
3761
func (s BitSet) checkIndex(index uint) {
3862
if index >= s.capacity {
3963
panic(fmt.Sprintf("bitset: index out of range [%d] with capacity %d", index, s.capacity))

bitset/bitset_test.go

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,47 +23,53 @@ func testBitSetIndexOutOfRange(t *testing.T, s BitSet) {
2323
func assertEmptyBitSet(t *testing.T, s BitSet) {
2424
t.Helper()
2525
if count := s.Count(); count != 0 {
26-
t.Errorf("expected count to be 0, got %d", count)
26+
t.Errorf("s.Count() = %d, want 0", count)
27+
}
28+
if first, found := s.First(); first != 0 || found {
29+
t.Errorf("s.First() = (%d, %t), want (0, false)", first, found)
30+
}
31+
if index, found := s.FlipFirst(); index != 0 || found {
32+
t.Errorf("s.FlipFirst() = (%d, %t), want (0, false)", index, found)
2733
}
2834
for i := range s.Capacity() {
2935
if s.IsSet(i) {
30-
t.Errorf("bit %d is unexpectedly set", i)
36+
t.Errorf("s.IsSet(%d) = true, want false", i)
3137
}
3238
}
3339
}
3440

3541
func assertOddBitSet(t *testing.T, s BitSet) {
3642
t.Helper()
3743
if count, expectedCount := s.Count(), s.Capacity()/2; count != expectedCount {
38-
t.Errorf("expected count to be %d, got %d", expectedCount, count)
44+
t.Errorf("s.Count() = %d, want %d", count, expectedCount)
3945
}
4046
for i := range s.Capacity() {
41-
if i%2 == 0 == s.IsSet(i) {
42-
t.Errorf("unexpected bit %d", i)
47+
if got, want := s.IsSet(i), i%2 == 1; got != want {
48+
t.Errorf("s.IsSet(%d) = %t, want %t", i, got, want)
4349
}
4450
}
4551
}
4652

4753
func assertEvenBitSet(t *testing.T, s BitSet) {
4854
t.Helper()
4955
if count, expectedCount := s.Count(), (s.Capacity()+1)/2; count != expectedCount {
50-
t.Errorf("expected count to be %d, got %d", expectedCount, count)
56+
t.Errorf("s.Count() = %d, want %d", count, expectedCount)
5157
}
5258
for i := range s.Capacity() {
53-
if i%2 == 1 == s.IsSet(i) {
54-
t.Errorf("unexpected bit %d", i)
59+
if got, want := s.IsSet(i), i%2 == 0; got != want {
60+
t.Errorf("s.IsSet(%d) = %t, want %t", i, got, want)
5561
}
5662
}
5763
}
5864

5965
func assertFullBitSet(t *testing.T, s BitSet) {
6066
t.Helper()
6167
if count := s.Count(); count != s.Capacity() {
62-
t.Errorf("expected count to be %d, got %d", s.Capacity(), count)
68+
t.Errorf("s.Count() = %d, want %d", count, s.Capacity())
6369
}
6470
for i := range s.Capacity() {
6571
if !s.IsSet(i) {
66-
t.Errorf("bit %d is unexpectedly unset", i)
72+
t.Errorf("s.IsSet(%d) = false, want true", i)
6773
}
6874
}
6975
}
@@ -106,6 +112,32 @@ func fillBitSet(t *testing.T, s BitSet) {
106112
}
107113
}
108114

115+
func testBitSetFirst(t *testing.T, s BitSet) {
116+
if first, found := s.First(); first != 0 || found {
117+
t.Errorf("s.First() = (%d, %t), want (0, false)", first, found)
118+
}
119+
if index, found := s.FlipFirst(); index != 0 || found {
120+
t.Errorf("s.FlipFirst() = (%d, %t), want (0, false)", index, found)
121+
}
122+
123+
for i := s.Capacity() - 1; i < s.Capacity(); i-- {
124+
s.Set(i)
125+
if first, found := s.First(); first != i || !found {
126+
t.Errorf("s.First() = (%d, %t), want (%d, true)", first, found, i)
127+
}
128+
}
129+
130+
assertFullBitSet(t, s)
131+
132+
for i := range s.Capacity() {
133+
if index, found := s.FlipFirst(); index != i || !found {
134+
t.Errorf("s.FlipFirst() = (%d, %t), want (%d, true)", index, found, i)
135+
}
136+
}
137+
138+
assertEmptyBitSet(t, s)
139+
}
140+
109141
func testBitSetSetAll(t *testing.T, s BitSet) {
110142
clearBitSet(t, s)
111143
s.SetAll()
@@ -194,6 +226,9 @@ func TestBitSet(t *testing.T) {
194226
t.Run("IndexOutOfRange", func(t *testing.T) {
195227
testBitSetIndexOutOfRange(t, s)
196228
})
229+
t.Run("First", func(t *testing.T) {
230+
testBitSetFirst(t, s)
231+
})
197232
t.Run("SetAll", func(t *testing.T) {
198233
testBitSetSetAll(t, s)
199234
})

0 commit comments

Comments
 (0)