Co-authored-by: jdl <jdl@desktop> Co-authored-by: jdl <jdl@crumpington.com> Reviewed-on: #3
77 lines
1.3 KiB
Go
77 lines
1.3 KiB
Go
package peer
|
|
|
|
type dupCheck struct {
|
|
bitSet
|
|
head int
|
|
tail int
|
|
headCounter uint64
|
|
tailCounter uint64 // Also next expected counter value.
|
|
}
|
|
|
|
func newDupCheck(headCounter uint64) *dupCheck {
|
|
return &dupCheck{
|
|
headCounter: headCounter,
|
|
tailCounter: headCounter + 1,
|
|
tail: 1,
|
|
}
|
|
}
|
|
|
|
func (dc *dupCheck) IsDup(counter uint64) bool {
|
|
|
|
// Before head => it's late, say it's a dup.
|
|
if counter < dc.headCounter {
|
|
return true
|
|
}
|
|
|
|
// It's within the counter bounds.
|
|
if counter < dc.tailCounter {
|
|
index := (int(counter-dc.headCounter) + dc.head) % bitSetSize
|
|
if dc.Get(index) {
|
|
return true
|
|
}
|
|
|
|
dc.Set(index)
|
|
return false
|
|
}
|
|
|
|
// It's more than 1 beyond the tail.
|
|
delta := counter - dc.tailCounter
|
|
|
|
// Full clear.
|
|
if delta >= bitSetSize-1 {
|
|
dc.ClearAll()
|
|
dc.Set(0)
|
|
|
|
dc.tail = 1
|
|
dc.head = 2
|
|
dc.tailCounter = counter + 1
|
|
dc.headCounter = dc.tailCounter - bitSetSize + 1
|
|
|
|
return false
|
|
}
|
|
|
|
// Clear if necessary.
|
|
for i := 0; i < int(delta); i++ {
|
|
dc.put(false)
|
|
}
|
|
|
|
dc.put(true)
|
|
return false
|
|
}
|
|
|
|
func (dc *dupCheck) put(set bool) {
|
|
if set {
|
|
dc.Set(dc.tail)
|
|
} else {
|
|
dc.Clear(dc.tail)
|
|
}
|
|
|
|
dc.tail = (dc.tail + 1) % bitSetSize
|
|
dc.tailCounter++
|
|
|
|
if dc.head == dc.tail {
|
|
dc.head = (dc.head + 1) % bitSetSize
|
|
dc.headCounter++
|
|
}
|
|
}
|