audit-go/audit/utils/sequence_generator.go
2024-11-14 13:30:25 +00:00

60 lines
1.6 KiB
Go

package utils
import (
"slices"
"sync"
)
// SequenceNumberGenerator can be used to generate increasing numbers.
type SequenceNumberGenerator interface {
// Next returns the next number
Next() uint64
// Revert can be used to revert a specific number (e.g. in case of an error)
Revert(uint64)
}
// DefaultSequenceNumberGenerator is a mutex protected implementation of SequenceNumberGenerator
type DefaultSequenceNumberGenerator struct {
backlog []uint64
sequenceNumber uint64
sequenceNumberLock sync.Mutex
}
// NewDefaultSequenceNumberGenerator returns an instance of DefaultSequenceNumberGenerator as pointer
// of SequenceNumberGenerator.
func NewDefaultSequenceNumberGenerator() SequenceNumberGenerator {
var generator SequenceNumberGenerator = &DefaultSequenceNumberGenerator{
backlog: make([]uint64, 0),
sequenceNumber: 0,
sequenceNumberLock: sync.Mutex{},
}
return generator
}
// Next implements SequenceNumberGenerator.Next
func (g *DefaultSequenceNumberGenerator) Next() uint64 {
g.sequenceNumberLock.Lock()
defer g.sequenceNumberLock.Unlock()
var next uint64
if len(g.backlog) == 0 {
next = g.sequenceNumber
g.sequenceNumber += 1
} else {
next = g.backlog[0]
g.backlog = g.backlog[1:]
}
return next
}
// Revert implements SequenceNumberGenerator.Revert
func (g *DefaultSequenceNumberGenerator) Revert(value uint64) {
g.sequenceNumberLock.Lock()
defer g.sequenceNumberLock.Unlock()
if value == g.sequenceNumber-1 {
g.sequenceNumber -= 1
} else if !slices.Contains(g.backlog, value) {
g.backlog = append(g.backlog, value)
}
}