Skip to content

Commit

Permalink
The 'extendMaybe' function is seemingly *not* inlined in Go. Yet it
Browse files Browse the repository at this point in the history
is systematically called when we set values, to check whether the backing
array need to be extended.

By bringing the check (the branch) in the calling function, we reduce the
number of function calls.

This leads to a ~10% performance gain in some  benchmarks.
  • Loading branch information
lemire committed Jul 21, 2022
1 parent 06a6e5e commit 8b8b79b
Showing 1 changed file with 28 additions and 25 deletions.
53 changes: 28 additions & 25 deletions bitset.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,24 +135,22 @@ func (b *BitSet) Len() uint {
return b.length
}

// extendSetMaybe adds additional words to incorporate new bits if needed
func (b *BitSet) extendSetMaybe(i uint) {
if i >= b.length { // if we need more bits, make 'em
if i >= Cap() {
panic("You are exceeding the capacity")
}
nsize := wordsNeeded(i + 1)
if b.set == nil {
b.set = make([]uint64, nsize)
} else if cap(b.set) >= nsize {
b.set = b.set[:nsize] // fast resize
} else if len(b.set) < nsize {
newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x
copy(newset, b.set)
b.set = newset
}
b.length = i + 1
// extendSet adds additional words to incorporate new bits if needed
func (b *BitSet) extendSet(i uint) {
if i >= Cap() {
panic("You are exceeding the capacity")
}
nsize := wordsNeeded(i + 1)
if b.set == nil {
b.set = make([]uint64, nsize)
} else if cap(b.set) >= nsize {
b.set = b.set[:nsize] // fast resize
} else if len(b.set) < nsize {
newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x
copy(newset, b.set)
b.set = newset
}
b.length = i + 1
}

// Test whether bit i is set.
Expand All @@ -170,7 +168,9 @@ func (b *BitSet) Test(i uint) bool {
// may lead to a memory shortage and a panic: the caller is responsible
// for providing sensible parameters in line with their memory capacity.
func (b *BitSet) Set(i uint) *BitSet {
b.extendSetMaybe(i)
if i >= b.length { // if we need more bits, make 'em
b.extendSet(i)
}
b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1))
return b
}
Expand Down Expand Up @@ -218,8 +218,9 @@ func (b *BitSet) FlipRange(start, end uint) *BitSet {
if start >= end {
return b
}

b.extendSetMaybe(end - 1)
if end-1 >= b.length { // if we need more bits, make 'em
b.extendSet(end - 1)
}
var startWord uint = start >> log2WordSize
var endWord uint = end >> log2WordSize
b.set[startWord] ^= ^(^uint64(0) << (start & (wordSize - 1)))
Expand Down Expand Up @@ -671,7 +672,9 @@ func (b *BitSet) InPlaceIntersection(compare *BitSet) {
b.set[i] = 0
}
if compare.length > 0 {
b.extendSetMaybe(compare.length - 1)
if compare.length-1 >= b.length {
b.extendSet(compare.length - 1)
}
}
}

Expand Down Expand Up @@ -710,8 +713,8 @@ func (b *BitSet) InPlaceUnion(compare *BitSet) {
if l > int(b.wordCount()) {
l = int(b.wordCount())
}
if compare.length > 0 {
b.extendSetMaybe(compare.length - 1)
if compare.length > 0 && compare.length-1 >= b.length {
b.extendSet(compare.length - 1)
}
for i := 0; i < l; i++ {
b.set[i] |= compare.set[i]
Expand Down Expand Up @@ -758,8 +761,8 @@ func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) {
if l > int(b.wordCount()) {
l = int(b.wordCount())
}
if compare.length > 0 {
b.extendSetMaybe(compare.length - 1)
if compare.length > 0 && compare.length-1 >= b.length {
b.extendSet(compare.length - 1)
}
for i := 0; i < l; i++ {
b.set[i] ^= compare.set[i]
Expand Down

0 comments on commit 8b8b79b

Please sign in to comment.