mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-10-12 02:08:11 +08:00
85 lines
1.8 KiB
Go
85 lines
1.8 KiB
Go
package sniffer
|
|
|
|
import "math/bits"
|
|
|
|
// bitmap is a growable bitmap. Its zero value is ready for use.
|
|
type bitmap struct {
|
|
words []uint64
|
|
}
|
|
|
|
// setRange sets every bit in the half-open interval [start, end). It panics if
|
|
// start is negative or end is less than start.
|
|
func (b *bitmap) setRange(start, end int) {
|
|
if start < 0 || end < start {
|
|
panic("invalid bitmap range")
|
|
}
|
|
if start == end {
|
|
return
|
|
}
|
|
|
|
wordCount := (end-1)/64 + 1
|
|
if wordCount > len(b.words) {
|
|
newWordCount := uint(1) << bits.Len(uint(wordCount-1))
|
|
if newWordCount > ^uint(0)>>1 {
|
|
newWordCount = uint(wordCount)
|
|
}
|
|
words := make([]uint64, int(newWordCount))
|
|
copy(words, b.words)
|
|
b.words = words
|
|
}
|
|
|
|
firstWord := start / 64
|
|
lastWord := (end - 1) / 64
|
|
firstMask := ^uint64(0) << (start % 64)
|
|
lastMask := ^uint64(0)
|
|
if endBit := end % 64; endBit != 0 {
|
|
lastMask = (uint64(1) << endBit) - 1
|
|
}
|
|
if firstWord == lastWord {
|
|
b.words[firstWord] |= firstMask & lastMask
|
|
return
|
|
}
|
|
|
|
b.words[firstWord] |= firstMask
|
|
for i := firstWord + 1; i < lastWord; i++ {
|
|
b.words[i] = ^uint64(0)
|
|
}
|
|
b.words[lastWord] |= lastMask
|
|
}
|
|
|
|
// firstUnset returns the first unset bit in [start, end), or end if all bits
|
|
// in the interval are set. It panics if start is negative or end is less than
|
|
// start.
|
|
func (b bitmap) firstUnset(start, end int) int {
|
|
if start < 0 || end < start {
|
|
panic("invalid bitmap range")
|
|
}
|
|
if start == end {
|
|
return end
|
|
}
|
|
|
|
wordIndex := start / 64
|
|
if wordIndex >= len(b.words) {
|
|
return start
|
|
}
|
|
word := b.words[wordIndex] | ((uint64(1) << (start % 64)) - 1)
|
|
for {
|
|
if word != ^uint64(0) {
|
|
unset := wordIndex*64 + bits.TrailingZeros64(^word)
|
|
if unset < end {
|
|
return unset
|
|
}
|
|
return end
|
|
}
|
|
|
|
wordIndex++
|
|
if wordIndex*64 >= end {
|
|
return end
|
|
}
|
|
if wordIndex >= len(b.words) {
|
|
return wordIndex * 64
|
|
}
|
|
word = b.words[wordIndex]
|
|
}
|
|
}
|