Files
lafsession/replay.go
2026-09-24 11:33:28 +02:00

80 lines
1.4 KiB
Go

package lafsession
type replayWindow struct {
maxSeq uint64
size uint64
bits []uint64
}
func newReplayWindow(size uint64) *replayWindow {
if size < 64 {
size = 64
}
words := (size + 63) / 64
return &replayWindow{
size: size,
bits: make([]uint64, words),
}
}
func (w *replayWindow) accept(seq uint64) bool {
if seq+w.size <= w.maxSeq {
return false
}
if seq > w.maxSeq {
shift := seq - w.maxSeq
if shift >= w.size {
for i := range w.bits {
w.bits[i] = 0
}
} else {
w.shift(shift)
}
w.maxSeq = seq
}
idx := w.maxSeq - seq
word := idx / 64
bit := idx % 64
if word >= uint64(len(w.bits)) {
return false
}
mask := uint64(1) << bit
if w.bits[word]&mask != 0 {
return false
}
w.bits[word] |= mask
return true
}
func (w *replayWindow) shift(n uint64) {
words := n / 64
bits := n % 64
if words > 0 {
copy(w.bits[words:], w.bits)
for i := uint64(0); i < words && i < uint64(len(w.bits)); i++ {
w.bits[i] = 0
}
for i := uint64(len(w.bits)); i > words; i-- {
}
if words < uint64(len(w.bits)) {
for i := 0; i < int(words); i++ {
w.bits[i] = 0
}
} else {
for i := range w.bits {
w.bits[i] = 0
}
return
}
}
if bits == 0 {
return
}
var carry uint64
for i := len(w.bits) - 1; i >= 0; i-- {
newCarry := w.bits[i] >> (64 - bits)
w.bits[i] = (w.bits[i] << bits) | carry
carry = newCarry
}
}