Skip to content

Commit 45473e1

Browse files
committed
some cleanup
1 parent 39379f7 commit 45473e1

File tree

2 files changed

+59
-34
lines changed

2 files changed

+59
-34
lines changed

ba.go

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,24 @@ const (
1616
// Bits externally represented as `bool` are stored internally as `uint64`s.
1717
// The total number of bits stored is set at creation and is immutable.
1818
type BitArray struct {
19+
// buf is a backing array that bits writes into by default when the no. of bits requested to allocate is
20+
// < 512. Only if more is asked, we'll skip buf and allocate directly into bits
21+
buf [8]Bit
1922
bits []Bit
2023
n int // no. of bits
2124
}
2225

23-
// New creates a new BitArray of `n` bits.
24-
func New(n int) BitArray {
25-
return BitArray{
26-
bits: make([]Bit, int(math.Ceil(float64(n)/64))),
27-
n: n,
26+
// New creates a new BitArray of `n` bits. If n <= 512, no allocation is done.
27+
func New(n int) (ba BitArray) {
28+
nblk := nbitsToNblks(n)
29+
ba.n = n
30+
ba.bits = ba.buf[:]
31+
if nblk <= 8 {
32+
ba.bits = ba.buf[:nblk]
33+
return
2834
}
35+
ba.bits = append(ba.bits, make([]Bit, nblk-len(ba.buf))...)
36+
return
2937
}
3038

3139
// Copy copies src into dst.
@@ -65,16 +73,8 @@ func FromUint64(u uint64) BitArray {
6573
// Size returns the no. of bits stored.
6674
func (ba *BitArray) Size() int { return ba.n }
6775

68-
func biandsi(k int) (uint64, uint64) {
69-
i := uint64(k)
70-
return i / 64, i % 64
71-
}
72-
73-
func (ba *BitArray) set1(bi, si uint64) { ba.bits[bi] |= 1 << si }
74-
func (ba *BitArray) set0(bi, si uint64) { ba.bits[bi] &= ^(1 << si) }
75-
7676
// Set sets the bit at position k.
77-
func (ba *BitArray) Set(k int) { ba.set1(biandsi(k)) }
77+
func (ba *BitArray) Set(k int) { bi, si := biandsi(k); set(&ba.bits[bi], si) }
7878

7979
// SetAll sets all the bits.
8080
func (ba *BitArray) SetAll() {
@@ -84,7 +84,7 @@ func (ba *BitArray) SetAll() {
8484
}
8585

8686
// Clr clears the bit at position k.
87-
func (ba *BitArray) Clr(k int) { ba.set0(biandsi(k)) }
87+
func (ba *BitArray) Clr(k int) { bi, si := biandsi(k); clr(&ba.bits[bi], si) }
8888

8989
// ClrAll clears all the bits.
9090
func (ba *BitArray) ClrAll() {
@@ -93,25 +93,24 @@ func (ba *BitArray) ClrAll() {
9393
}
9494
}
9595

96-
func (ba *BitArray) chk(bi, si uint64) bool { return (ba.bits[bi]>>si)&1 > 0 }
97-
9896
// ChkSet returns the value of the bit at position k before setting it.
9997
func (ba *BitArray) ChkSet(k int) (b bool) {
10098
bi, si := biandsi(k)
101-
b = ba.chk(bi, si)
99+
u := &ba.bits[bi]
100+
b = chk(*u, si) != 0
102101
if !b {
103-
ba.set1(bi, si)
102+
set(u, si)
104103
}
105104
return
106-
107105
}
108106

109107
// ChkClr returns the value of the bit at position k before clearing it.
110108
func (ba *BitArray) ChkClr(k int) (b bool) {
111109
bi, si := biandsi(k)
112-
b = ba.chk(bi, si)
110+
u := &ba.bits[bi]
111+
b = chk(*u, si) != 0
113112
if b {
114-
ba.set0(bi, si)
113+
clr(u, si)
115114
}
116115
return
117116
}
@@ -125,29 +124,33 @@ func (ba *BitArray) Tgl(k int) {
125124
// Cnt returns the number of set bits.
126125
func (ba *BitArray) Cnt() (n int) {
127126
for _, b := range ba.bits {
128-
n += bits.OnesCount64(uint64(b))
127+
n += bits.OnesCount64(b)
129128
}
130129
return
131130
}
132131

133132
// Chk returns the value of the bit at position k.
134133
func (ba *BitArray) Chk(k int) bool {
135134
bi, si := biandsi(k)
136-
return (ba.bits[bi]>>si)&1 > 0
135+
return chk(ba.bits[bi], si) != 0
137136
}
138137

139138
// Put sets the value of the bit at position k to v.
140139
func (ba *BitArray) Put(k int, v Bit) {
141140
bi, si := biandsi(k)
142-
ba.bits[bi] = (ba.bits[bi] & ^(1 << si)) | (v << si)
141+
put(&ba.bits[bi], si, v)
143142
}
144143

145144
// Swap swaps the value of bit at position k with v. On return, v contains the old value.
146-
func (ba *BitArray) Swap(k int, v *Bit) {
145+
func (ba *BitArray) Swap(k int, b *Bit) {
147146
bi, si := biandsi(k)
148-
ob := (ba.bits[bi] >> si) & 1
149-
ba.bits[bi] = (ba.bits[bi] & ^(1 << si)) | (*v << si)
150-
*v = ob
147+
t := &ba.bits[bi]
148+
ob := chk(*t, si)
149+
if ob == *b {
150+
return
151+
}
152+
put(t, si, ob)
153+
*b = ob
151154
}
152155

153156
func (ba *BitArray) String() string {
@@ -160,3 +163,15 @@ func (ba *BitArray) String() string {
160163
}
161164
return string(sb)
162165
}
166+
167+
func nbitsToNblks(n int) int { return int(math.Ceil(float64(n) / 64)) }
168+
169+
func set(u *uint64, si uint64) { *u |= 1 << si }
170+
func clr(u *uint64, si uint64) { *u &= ^(1 << si) }
171+
func chk(u uint64, si uint64) Bit { return (u >> si) & 1 }
172+
func put(u *uint64, si uint64, b Bit) { *u = (*u & ^(1 << si)) | (b << si) }
173+
174+
func biandsi(k int) (uint64, uint64) {
175+
i := uint64(k)
176+
return i / 64, i % 64
177+
}

ba_test.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ func TestNew(t *testing.T) {
2525
{65, 2},
2626
{256, 4},
2727
{257, 5},
28+
{512, 8},
29+
{768, 12},
2830
}
2931

3032
for i, tt := range tests {
@@ -269,10 +271,19 @@ func TestBitArray(t *testing.T) {
269271
}
270272

271273
func BenchmarkNew(b *testing.B) {
272-
b.ReportAllocs()
273-
for i := 0; i < b.N; i++ {
274-
New(256)
275-
}
274+
b.Run("<=512", func(b *testing.B) {
275+
b.ReportAllocs()
276+
for i := 0; i < b.N; i++ {
277+
New(512)
278+
}
279+
})
280+
281+
b.Run(">512", func(b *testing.B) {
282+
b.ReportAllocs()
283+
for i := 0; i < b.N; i++ {
284+
New(768)
285+
}
286+
})
276287
}
277288

278289
func BenchmarkBitArray(b *testing.B) {
@@ -397,7 +408,6 @@ func BenchmarkBitArray_Cnt(b *testing.B) {
397408
ba.Cnt()
398409
}
399410
})
400-
401411
}
402412

403413
func BenchmarkBiandSi(b *testing.B) {

0 commit comments

Comments
 (0)