From 8b8b79b8d414e87f1119e424528549ec40119edc Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Thu, 21 Jul 2022 10:11:26 -0400 Subject: [PATCH] The 'extendMaybe' function is seemingly *not* inlined in Go. Yet it 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. --- bitset.go | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/bitset.go b/bitset.go index d688806..03db2a9 100644 --- a/bitset.go +++ b/bitset.go @@ -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. @@ -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 } @@ -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))) @@ -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) + } } } @@ -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] @@ -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]