From 4a54802cc0968b2b9689776c78126d1e76a076a0 Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Mon, 15 May 2023 09:44:39 -0500 Subject: [PATCH 1/9] Define `BitArray.GetSetBits` --- bitarray/bitarray.go | 7 ++++++- bitarray/interface.go | 4 ++++ bitarray/sparse_bitarray.go | 5 +++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/bitarray/bitarray.go b/bitarray/bitarray.go index 73526c9..1124b3c 100644 --- a/bitarray/bitarray.go +++ b/bitarray/bitarray.go @@ -116,7 +116,12 @@ func (ba *bitArray) GetBit(k uint64) (bool, error) { return result, nil } -//ClearBit will unset a bit at the given index if it is set. +// GetSetBits gets the position of bits set in the array. +func (ba *bitArray) GetSetBits(_ uint64, buffer []uint64) []uint64 { + return buffer[:0] +} + +// ClearBit will unset a bit at the given index if it is set. func (ba *bitArray) ClearBit(k uint64) error { if k >= ba.Capacity() { return OutOfRangeError(k) diff --git a/bitarray/interface.go b/bitarray/interface.go index bb4057a..b3dd397 100644 --- a/bitarray/interface.go +++ b/bitarray/interface.go @@ -36,6 +36,10 @@ type BitArray interface { // function returns an error if the position is out // of range. A sparse bit array never returns an error. GetBit(k uint64) (bool, error) + // GetSetBits gets the position of bits set in the array. Will + // return as many set bits as can fit in the provided buffer + // starting from the specified position in the array. + GetSetBits(from uint64, buffer []uint64) []uint64 // ClearBit clears the bit at the given position. This // function returns an error if the position is out // of range. A sparse bit array never returns an error. diff --git a/bitarray/sparse_bitarray.go b/bitarray/sparse_bitarray.go index ca68e9f..30f2d15 100644 --- a/bitarray/sparse_bitarray.go +++ b/bitarray/sparse_bitarray.go @@ -127,6 +127,11 @@ func (sba *sparseBitArray) GetBit(k uint64) (bool, error) { return sba.blocks[i].get(position), nil } +// GetSetBits gets the position of bits set in the array. +func (sba *sparseBitArray) GetSetBits(_ uint64, buffer []uint64) []uint64 { + return buffer[:0] +} + // ToNums converts this sparse bitarray to a list of numbers contained // within it. func (sba *sparseBitArray) ToNums() []uint64 { From 42ddd6d73a3829fb5140d3837789c288c0542add Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Fri, 12 May 2023 12:39:25 -0500 Subject: [PATCH 2/9] Add test coverage for `GetSetBits` --- bitarray/bitarray_test.go | 45 ++++++++++++++++++++++++++++++++ bitarray/sparse_bitarray_test.go | 43 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/bitarray/bitarray_test.go b/bitarray/bitarray_test.go index 9172369..8c37975 100644 --- a/bitarray/bitarray_test.go +++ b/bitarray/bitarray_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestBitOperations(t *testing.T) { @@ -195,6 +196,50 @@ func BenchmarkGetBit(b *testing.B) { } } +func TestGetSetBits(t *testing.T) { + ba := newBitArray(1000) + buf := make([]uint64, 0, 5) + + require.NoError(t, ba.SetBit(1)) + require.NoError(t, ba.SetBit(4)) + require.NoError(t, ba.SetBit(8)) + require.NoError(t, ba.SetBit(63)) + require.NoError(t, ba.SetBit(64)) + require.NoError(t, ba.SetBit(200)) + require.NoError(t, ba.SetBit(1000)) + + assert.Equal(t, []uint64{1, 4, 8, 63, 64}, ba.GetSetBits(0, buf)) + assert.Equal(t, []uint64{63, 64, 200, 1000}, ba.GetSetBits(10, buf)) + assert.Equal(t, []uint64{63, 64, 200, 1000}, ba.GetSetBits(63, buf)) + assert.Equal(t, []uint64{200, 1000}, ba.GetSetBits(128, buf)) + + require.NoError(t, ba.ClearBit(4)) + require.NoError(t, ba.ClearBit(64)) + assert.Equal(t, []uint64{1, 8, 63, 200, 1000}, ba.GetSetBits(0, buf)) + assert.Empty(t, ba.GetSetBits(1001, buf)) + + ba.Reset() + assert.Empty(t, ba.GetSetBits(0, buf)) +} + +func BenchmarkGetSetBits(b *testing.B) { + numItems := uint64(168000) + + ba := newBitArray(numItems) + for i := uint64(0); i < numItems; i++ { + if i%13 == 0 || i%5 == 0 { + require.NoError(b, ba.SetBit(i)) + } + } + + buf := make([]uint64, 0, ba.Capacity()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + ba.GetSetBits(0, buf) + } +} + func TestEquality(t *testing.T) { ba := newBitArray(s + 1) other := newBitArray(s + 1) diff --git a/bitarray/sparse_bitarray_test.go b/bitarray/sparse_bitarray_test.go index 4f58d3e..712c872 100644 --- a/bitarray/sparse_bitarray_test.go +++ b/bitarray/sparse_bitarray_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGetCompressedBit(t *testing.T) { @@ -76,6 +77,48 @@ func BenchmarkSetCompressedBit(b *testing.B) { } } +func TestGetSetCompressedBits(t *testing.T) { + ba := newSparseBitArray() + buf := make([]uint64, 0, 5) + + require.NoError(t, ba.SetBit(1)) + require.NoError(t, ba.SetBit(4)) + require.NoError(t, ba.SetBit(8)) + require.NoError(t, ba.SetBit(63)) + require.NoError(t, ba.SetBit(64)) + require.NoError(t, ba.SetBit(200)) + require.NoError(t, ba.SetBit(1000)) + + assert.Equal(t, []uint64{1, 4, 8, 63, 64}, ba.GetSetBits(0, buf)) + assert.Equal(t, []uint64{63, 64, 200, 1000}, ba.GetSetBits(10, buf)) + assert.Equal(t, []uint64{63, 64, 200, 1000}, ba.GetSetBits(63, buf)) + assert.Equal(t, []uint64{200, 1000}, ba.GetSetBits(128, buf)) + + require.NoError(t, ba.ClearBit(4)) + require.NoError(t, ba.ClearBit(64)) + assert.Equal(t, []uint64{1, 8, 63, 200, 1000}, ba.GetSetBits(0, buf)) + assert.Empty(t, ba.GetSetBits(1001, buf)) + + ba.Reset() + assert.Empty(t, ba.GetSetBits(0, buf)) +} + +func BenchmarkGetSetCompressedBits(b *testing.B) { + ba := newSparseBitArray() + for i := uint64(0); i < 168000; i++ { + if i%13 == 0 || i%5 == 0 { + require.NoError(b, ba.SetBit(i)) + } + } + + buf := make([]uint64, 0, ba.Capacity()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + ba.GetSetBits(0, buf) + } +} + func TestClearCompressedBit(t *testing.T) { ba := newSparseBitArray() ba.SetBit(5) From 9eab2dfceed2df1de05c19ed6e708e5bcd1ff34e Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Tue, 16 May 2023 10:23:05 -0500 Subject: [PATCH 3/9] Implement `GetSetBits` for `bitArray` and `sparseBitArray` --- bitarray/bitarray.go | 64 +++++++++++++++++++++++++++++++++++-- bitarray/sparse_bitarray.go | 17 ++++++++-- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/bitarray/bitarray.go b/bitarray/bitarray.go index 1124b3c..cee0361 100644 --- a/bitarray/bitarray.go +++ b/bitarray/bitarray.go @@ -20,6 +20,8 @@ efficient way. This is *NOT* a threadsafe package. */ package bitarray +import "math/bits" + // bitArray is a struct that maintains state of a bit array. type bitArray struct { blocks []block @@ -117,8 +119,66 @@ func (ba *bitArray) GetBit(k uint64) (bool, error) { } // GetSetBits gets the position of bits set in the array. -func (ba *bitArray) GetSetBits(_ uint64, buffer []uint64) []uint64 { - return buffer[:0] +func (ba *bitArray) GetSetBits(from uint64, buffer []uint64) []uint64 { + fromBlockIndex, fromOffset := getIndexAndRemainder(from) + return getSetBitsInBlocks( + fromBlockIndex, + fromOffset, + ba.blocks[fromBlockIndex:], + nil, + buffer, + ) +} + +// getSetBitsInBlocks fills a buffer with positions of set bits in the provided blocks. Optionally, indices may be +// provided for sparse/non-consecutive blocks. +func getSetBitsInBlocks( + fromBlockIndex, fromOffset uint64, + blocks []block, + indices []uint64, + buffer []uint64, +) []uint64 { + bufferCapacity := cap(buffer) + results := buffer[:bufferCapacity] + resultSize := 0 + + for i, block := range blocks { + blockIndex := fromBlockIndex + uint64(i) + if indices != nil { + blockIndex = indices[i] + } + + isFirstBlock := blockIndex == fromBlockIndex + if isFirstBlock { + block >>= fromOffset + } + + for block != 0 { + trailing := bits.TrailingZeros64(uint64(block)) + + if isFirstBlock { + results[resultSize] = uint64(trailing) + (blockIndex << 6) + fromOffset + } else { + results[resultSize] = uint64(trailing) + (blockIndex << 6) + } + resultSize++ + + if resultSize == cap(results) { + return results[:resultSize] + } + + // Example of this expression: + // block 01001100 + // ^block 10110011 + // (^block) + 1 10110100 + // block & (^block) + 1 00000100 + // block ^ mask 01001000 + mask := block & ((^block) + 1) + block = block ^ mask + } + } + + return results[:resultSize] } // ClearBit will unset a bit at the given index if it is set. diff --git a/bitarray/sparse_bitarray.go b/bitarray/sparse_bitarray.go index 30f2d15..52653b0 100644 --- a/bitarray/sparse_bitarray.go +++ b/bitarray/sparse_bitarray.go @@ -128,8 +128,21 @@ func (sba *sparseBitArray) GetBit(k uint64) (bool, error) { } // GetSetBits gets the position of bits set in the array. -func (sba *sparseBitArray) GetSetBits(_ uint64, buffer []uint64) []uint64 { - return buffer[:0] +func (sba *sparseBitArray) GetSetBits(from uint64, buffer []uint64) []uint64 { + fromBlockIndex, fromOffset := getIndexAndRemainder(from) + + fromBlockLocation := sba.indices.search(fromBlockIndex) + if int(fromBlockLocation) == len(sba.indices) { + return buffer[:0] + } + + return getSetBitsInBlocks( + fromBlockIndex, + fromOffset, + sba.blocks[fromBlockLocation:], + sba.indices[fromBlockLocation:], + buffer, + ) } // ToNums converts this sparse bitarray to a list of numbers contained From d95ee5d5faa36e27a3fa32ce142a81c3d771356d Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Tue, 16 May 2023 18:03:31 -0500 Subject: [PATCH 4/9] Define `BitArray.Count` and add test coverage --- bitarray/bitarray_test.go | 22 ++++++++++++++++++++++ bitarray/interface.go | 2 ++ bitarray/sparse_bitarray_test.go | 22 ++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/bitarray/bitarray_test.go b/bitarray/bitarray_test.go index 8c37975..9364617 100644 --- a/bitarray/bitarray_test.go +++ b/bitarray/bitarray_test.go @@ -143,6 +143,28 @@ func TestIsEmpty(t *testing.T) { assert.False(t, ba.IsEmpty()) } +func TestCount(t *testing.T) { + ba := newBitArray(500) + assert.Equal(t, uint64(0), ba.Count()) + + require.NoError(t, ba.SetBit(0)) + assert.Equal(t, uint64(1), ba.Count()) + + require.NoError(t, ba.SetBit(40)) + require.NoError(t, ba.SetBit(64)) + require.NoError(t, ba.SetBit(100)) + require.NoError(t, ba.SetBit(200)) + require.NoError(t, ba.SetBit(469)) + require.NoError(t, ba.SetBit(500)) + assert.Equal(t, uint64(7), ba.Count()) + + require.NoError(t, ba.ClearBit(200)) + assert.Equal(t, uint64(6), ba.Count()) + + ba.Reset() + assert.Equal(t, uint64(0), ba.Count()) +} + func TestClear(t *testing.T) { ba := newBitArray(10) diff --git a/bitarray/interface.go b/bitarray/interface.go index b3dd397..61e30c4 100644 --- a/bitarray/interface.go +++ b/bitarray/interface.go @@ -59,6 +59,8 @@ type BitArray interface { // in the case of a dense bit array or the highest possible // seen capacity of the sparse array. Capacity() uint64 + // Count returns the number of set bits in this array. + Count() uint64 // Or will bitwise or the two bitarrays and return a new bitarray // representing the result. Or(other BitArray) BitArray diff --git a/bitarray/sparse_bitarray_test.go b/bitarray/sparse_bitarray_test.go index 712c872..48e59f2 100644 --- a/bitarray/sparse_bitarray_test.go +++ b/bitarray/sparse_bitarray_test.go @@ -119,6 +119,28 @@ func BenchmarkGetSetCompressedBits(b *testing.B) { } } +func TestCompressedCount(t *testing.T) { + ba := newSparseBitArray() + assert.Equal(t, uint64(0), ba.Count()) + + require.NoError(t, ba.SetBit(0)) + assert.Equal(t, uint64(1), ba.Count()) + + require.NoError(t, ba.SetBit(40)) + require.NoError(t, ba.SetBit(64)) + require.NoError(t, ba.SetBit(100)) + require.NoError(t, ba.SetBit(200)) + require.NoError(t, ba.SetBit(469)) + require.NoError(t, ba.SetBit(500)) + assert.Equal(t, uint64(7), ba.Count()) + + require.NoError(t, ba.ClearBit(200)) + assert.Equal(t, uint64(6), ba.Count()) + + ba.Reset() + assert.Equal(t, uint64(0), ba.Count()) +} + func TestClearCompressedBit(t *testing.T) { ba := newSparseBitArray() ba.SetBit(5) From 64dafb748cfbccc0172c6cc27a26e1764711cee2 Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Tue, 16 May 2023 18:03:46 -0500 Subject: [PATCH 5/9] Implement `Count` for `bitArray` and `sparseBitArray` --- bitarray/bitarray.go | 9 +++++++++ bitarray/sparse_bitarray.go | 14 +++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/bitarray/bitarray.go b/bitarray/bitarray.go index cee0361..d2e7ec9 100644 --- a/bitarray/bitarray.go +++ b/bitarray/bitarray.go @@ -202,6 +202,15 @@ func (ba *bitArray) ClearBit(k uint64) error { return nil } +// Count returns the number of set bits in this array. +func (ba *bitArray) Count() uint64 { + count := 0 + for _, block := range ba.blocks { + count += bits.OnesCount64(uint64(block)) + } + return uint64(count) +} + // Or will bitwise or two bit arrays and return a new bit array // representing the result. func (ba *bitArray) Or(other BitArray) BitArray { diff --git a/bitarray/sparse_bitarray.go b/bitarray/sparse_bitarray.go index 52653b0..19ec140 100644 --- a/bitarray/sparse_bitarray.go +++ b/bitarray/sparse_bitarray.go @@ -16,7 +16,10 @@ limitations under the License. package bitarray -import "sort" +import ( + "math/bits" + "sort" +) // uintSlice is an alias for a slice of ints. Len, Swap, and Less // are exported to fulfill an interface needed for the search @@ -243,6 +246,15 @@ func (sba *sparseBitArray) Equals(other BitArray) bool { return true } +// Count returns the number of set bits in this array. +func (sba *sparseBitArray) Count() uint64 { + count := 0 + for _, block := range sba.blocks { + count += bits.OnesCount64(uint64(block)) + } + return uint64(count) +} + // Or will perform a bitwise or operation with the provided bitarray and // return a new result bitarray. func (sba *sparseBitArray) Or(other BitArray) BitArray { From e309fb35d01377c2b089390dfb3ab4680241b07b Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Wed, 17 May 2023 08:39:17 -0500 Subject: [PATCH 6/9] Fix spacing for binary expression example --- bitarray/bitarray.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bitarray/bitarray.go b/bitarray/bitarray.go index d2e7ec9..4ca05b6 100644 --- a/bitarray/bitarray.go +++ b/bitarray/bitarray.go @@ -168,11 +168,11 @@ func getSetBitsInBlocks( } // Example of this expression: - // block 01001100 - // ^block 10110011 - // (^block) + 1 10110100 - // block & (^block) + 1 00000100 - // block ^ mask 01001000 + // block 01001100 + // ^block 10110011 + // (^block) + 1 10110100 + // block & (^block) + 1 00000100 + // block ^ mask 01001000 mask := block & ((^block) + 1) block = block ^ mask } From 9c88543cfcc1f8cc5941d8155cc184f545bee2c5 Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Wed, 17 May 2023 11:21:18 -0500 Subject: [PATCH 7/9] Make `BitArray.Count` return an `int` --- bitarray/bitarray.go | 4 ++-- bitarray/bitarray_test.go | 10 +++++----- bitarray/interface.go | 2 +- bitarray/sparse_bitarray.go | 4 ++-- bitarray/sparse_bitarray_test.go | 10 +++++----- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bitarray/bitarray.go b/bitarray/bitarray.go index 4ca05b6..6c28331 100644 --- a/bitarray/bitarray.go +++ b/bitarray/bitarray.go @@ -203,12 +203,12 @@ func (ba *bitArray) ClearBit(k uint64) error { } // Count returns the number of set bits in this array. -func (ba *bitArray) Count() uint64 { +func (ba *bitArray) Count() int { count := 0 for _, block := range ba.blocks { count += bits.OnesCount64(uint64(block)) } - return uint64(count) + return count } // Or will bitwise or two bit arrays and return a new bit array diff --git a/bitarray/bitarray_test.go b/bitarray/bitarray_test.go index 9364617..6f8f3dd 100644 --- a/bitarray/bitarray_test.go +++ b/bitarray/bitarray_test.go @@ -145,10 +145,10 @@ func TestIsEmpty(t *testing.T) { func TestCount(t *testing.T) { ba := newBitArray(500) - assert.Equal(t, uint64(0), ba.Count()) + assert.Equal(t, 0, ba.Count()) require.NoError(t, ba.SetBit(0)) - assert.Equal(t, uint64(1), ba.Count()) + assert.Equal(t, 1, ba.Count()) require.NoError(t, ba.SetBit(40)) require.NoError(t, ba.SetBit(64)) @@ -156,13 +156,13 @@ func TestCount(t *testing.T) { require.NoError(t, ba.SetBit(200)) require.NoError(t, ba.SetBit(469)) require.NoError(t, ba.SetBit(500)) - assert.Equal(t, uint64(7), ba.Count()) + assert.Equal(t, 7, ba.Count()) require.NoError(t, ba.ClearBit(200)) - assert.Equal(t, uint64(6), ba.Count()) + assert.Equal(t, 6, ba.Count()) ba.Reset() - assert.Equal(t, uint64(0), ba.Count()) + assert.Equal(t, 0, ba.Count()) } func TestClear(t *testing.T) { diff --git a/bitarray/interface.go b/bitarray/interface.go index 61e30c4..fb22493 100644 --- a/bitarray/interface.go +++ b/bitarray/interface.go @@ -60,7 +60,7 @@ type BitArray interface { // seen capacity of the sparse array. Capacity() uint64 // Count returns the number of set bits in this array. - Count() uint64 + Count() int // Or will bitwise or the two bitarrays and return a new bitarray // representing the result. Or(other BitArray) BitArray diff --git a/bitarray/sparse_bitarray.go b/bitarray/sparse_bitarray.go index 19ec140..b9e3dbc 100644 --- a/bitarray/sparse_bitarray.go +++ b/bitarray/sparse_bitarray.go @@ -247,12 +247,12 @@ func (sba *sparseBitArray) Equals(other BitArray) bool { } // Count returns the number of set bits in this array. -func (sba *sparseBitArray) Count() uint64 { +func (sba *sparseBitArray) Count() int { count := 0 for _, block := range sba.blocks { count += bits.OnesCount64(uint64(block)) } - return uint64(count) + return count } // Or will perform a bitwise or operation with the provided bitarray and diff --git a/bitarray/sparse_bitarray_test.go b/bitarray/sparse_bitarray_test.go index 48e59f2..8f14ecb 100644 --- a/bitarray/sparse_bitarray_test.go +++ b/bitarray/sparse_bitarray_test.go @@ -121,10 +121,10 @@ func BenchmarkGetSetCompressedBits(b *testing.B) { func TestCompressedCount(t *testing.T) { ba := newSparseBitArray() - assert.Equal(t, uint64(0), ba.Count()) + assert.Equal(t, 0, ba.Count()) require.NoError(t, ba.SetBit(0)) - assert.Equal(t, uint64(1), ba.Count()) + assert.Equal(t, 1, ba.Count()) require.NoError(t, ba.SetBit(40)) require.NoError(t, ba.SetBit(64)) @@ -132,13 +132,13 @@ func TestCompressedCount(t *testing.T) { require.NoError(t, ba.SetBit(200)) require.NoError(t, ba.SetBit(469)) require.NoError(t, ba.SetBit(500)) - assert.Equal(t, uint64(7), ba.Count()) + assert.Equal(t, 7, ba.Count()) require.NoError(t, ba.ClearBit(200)) - assert.Equal(t, uint64(6), ba.Count()) + assert.Equal(t, 6, ba.Count()) ba.Reset() - assert.Equal(t, uint64(0), ba.Count()) + assert.Equal(t, 0, ba.Count()) } func TestClearCompressedBit(t *testing.T) { From 33a45f0b71441ba16d85c53b08d8ce1ad1164236 Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Wed, 17 May 2023 16:22:04 -0500 Subject: [PATCH 8/9] Return an empty slice from `GetSetBits` for `nil`/empty buffers --- bitarray/bitarray.go | 4 ++++ bitarray/bitarray_test.go | 3 +++ bitarray/sparse_bitarray_test.go | 3 +++ 3 files changed, 10 insertions(+) diff --git a/bitarray/bitarray.go b/bitarray/bitarray.go index 6c28331..0e6e3b1 100644 --- a/bitarray/bitarray.go +++ b/bitarray/bitarray.go @@ -139,6 +139,10 @@ func getSetBitsInBlocks( buffer []uint64, ) []uint64 { bufferCapacity := cap(buffer) + if bufferCapacity == 0 { + return buffer[:0] + } + results := buffer[:bufferCapacity] resultSize := 0 diff --git a/bitarray/bitarray_test.go b/bitarray/bitarray_test.go index 6f8f3dd..b005757 100644 --- a/bitarray/bitarray_test.go +++ b/bitarray/bitarray_test.go @@ -230,6 +230,9 @@ func TestGetSetBits(t *testing.T) { require.NoError(t, ba.SetBit(200)) require.NoError(t, ba.SetBit(1000)) + assert.Equal(t, []uint64(nil), ba.GetSetBits(0, nil)) + assert.Equal(t, []uint64{}, ba.GetSetBits(0, []uint64{})) + assert.Equal(t, []uint64{1, 4, 8, 63, 64}, ba.GetSetBits(0, buf)) assert.Equal(t, []uint64{63, 64, 200, 1000}, ba.GetSetBits(10, buf)) assert.Equal(t, []uint64{63, 64, 200, 1000}, ba.GetSetBits(63, buf)) diff --git a/bitarray/sparse_bitarray_test.go b/bitarray/sparse_bitarray_test.go index 8f14ecb..0944347 100644 --- a/bitarray/sparse_bitarray_test.go +++ b/bitarray/sparse_bitarray_test.go @@ -89,6 +89,9 @@ func TestGetSetCompressedBits(t *testing.T) { require.NoError(t, ba.SetBit(200)) require.NoError(t, ba.SetBit(1000)) + assert.Equal(t, []uint64(nil), ba.GetSetBits(0, nil)) + assert.Equal(t, []uint64{}, ba.GetSetBits(0, []uint64{})) + assert.Equal(t, []uint64{1, 4, 8, 63, 64}, ba.GetSetBits(0, buf)) assert.Equal(t, []uint64{63, 64, 200, 1000}, ba.GetSetBits(10, buf)) assert.Equal(t, []uint64{63, 64, 200, 1000}, ba.GetSetBits(63, buf)) From 8f1c722b5c4c9f7d4a8e462e01a1530ea80f3c74 Mon Sep 17 00:00:00 2001 From: Daniel Way Date: Wed, 17 May 2023 16:43:45 -0500 Subject: [PATCH 9/9] Clarify purpose of bit-clearing expression --- bitarray/bitarray.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitarray/bitarray.go b/bitarray/bitarray.go index 0e6e3b1..37e49ff 100644 --- a/bitarray/bitarray.go +++ b/bitarray/bitarray.go @@ -171,7 +171,7 @@ func getSetBitsInBlocks( return results[:resultSize] } - // Example of this expression: + // Clear the bit we just added to the result, which is the last bit set in the block. Ex.: // block 01001100 // ^block 10110011 // (^block) + 1 10110100