@@ -20,6 +20,8 @@ efficient way. This is *NOT* a threadsafe package.
2020*/
2121package bitarray
2222
23+ import "math/bits"
24+
2325// bitArray is a struct that maintains state of a bit array.
2426type bitArray struct {
2527 blocks []block
@@ -117,8 +119,66 @@ func (ba *bitArray) GetBit(k uint64) (bool, error) {
117119}
118120
119121// GetSetBits gets the position of bits set in the array.
120- func (ba * bitArray ) GetSetBits (_ uint64 , buffer []uint64 ) []uint64 {
121- return buffer [:0 ]
122+ func (ba * bitArray ) GetSetBits (from uint64 , buffer []uint64 ) []uint64 {
123+ fromBlockIndex , fromOffset := getIndexAndRemainder (from )
124+ return getSetBitsInBlocks (
125+ fromBlockIndex ,
126+ fromOffset ,
127+ ba .blocks [fromBlockIndex :],
128+ nil ,
129+ buffer ,
130+ )
131+ }
132+
133+ // getSetBitsInBlocks fills a buffer with positions of set bits in the provided blocks. Optionally, indices may be
134+ // provided for sparse/non-consecutive blocks.
135+ func getSetBitsInBlocks (
136+ fromBlockIndex , fromOffset uint64 ,
137+ blocks []block ,
138+ indices []uint64 ,
139+ buffer []uint64 ,
140+ ) []uint64 {
141+ bufferCapacity := cap (buffer )
142+ results := buffer [:bufferCapacity ]
143+ resultSize := 0
144+
145+ for i , block := range blocks {
146+ blockIndex := fromBlockIndex + uint64 (i )
147+ if indices != nil {
148+ blockIndex = indices [i ]
149+ }
150+
151+ isFirstBlock := blockIndex == fromBlockIndex
152+ if isFirstBlock {
153+ block >>= fromOffset
154+ }
155+
156+ for block != 0 {
157+ trailing := bits .TrailingZeros64 (uint64 (block ))
158+
159+ if isFirstBlock {
160+ results [resultSize ] = uint64 (trailing ) + (blockIndex << 6 ) + fromOffset
161+ } else {
162+ results [resultSize ] = uint64 (trailing ) + (blockIndex << 6 )
163+ }
164+ resultSize ++
165+
166+ if resultSize == cap (results ) {
167+ return results [:resultSize ]
168+ }
169+
170+ // Example of this expression:
171+ // block 01001100
172+ // ^block 10110011
173+ // (^block) + 1 10110100
174+ // block & (^block) + 1 00000100
175+ // block ^ mask 01001000
176+ mask := block & ((^ block ) + 1 )
177+ block = block ^ mask
178+ }
179+ }
180+
181+ return results [:resultSize ]
122182}
123183
124184// ClearBit will unset a bit at the given index if it is set.
0 commit comments