git.gammaspectra.live/P2Pool/consensus/v3@v3.8.0/utils/circular_buffer.go (about) 1 package utils 2 3 import ( 4 "slices" 5 "sync" 6 "sync/atomic" 7 ) 8 9 type CircularBuffer[T comparable] struct { 10 buffer []T 11 index atomic.Uint32 12 lock sync.RWMutex 13 } 14 15 func NewCircularBuffer[T comparable](size int) *CircularBuffer[T] { 16 return &CircularBuffer[T]{ 17 buffer: make([]T, size), 18 } 19 } 20 21 func (b *CircularBuffer[T]) Push(value T) { 22 b.lock.Lock() 23 defer b.lock.Unlock() 24 b.buffer[b.index.Add(1)%uint32(len(b.buffer))] = value 25 } 26 27 func (b *CircularBuffer[T]) Current() T { 28 b.lock.RLock() 29 defer b.lock.RUnlock() 30 return b.buffer[b.index.Load()%uint32(len(b.buffer))] 31 } 32 33 func (b *CircularBuffer[T]) Get(index uint32) T { 34 b.lock.RLock() 35 defer b.lock.RUnlock() 36 return b.buffer[index%uint32(len(b.buffer))] 37 } 38 39 func (b *CircularBuffer[T]) Replace(value, replace T) { 40 b.lock.Lock() 41 defer b.lock.Unlock() 42 43 for i, v := range b.buffer { 44 if value == v { 45 b.buffer[i] = replace 46 } 47 } 48 } 49 50 func (b *CircularBuffer[T]) PushUnique(value T) bool { 51 b.lock.Lock() 52 defer b.lock.Unlock() 53 54 if len(b.buffer) == 0 || slices.Contains(b.buffer, value) { 55 return false 56 } 57 58 b.buffer[b.index.Add(1)%uint32(len(b.buffer))] = value 59 60 return true 61 } 62 63 func (b *CircularBuffer[T]) Reverse() { 64 b.lock.Lock() 65 defer b.lock.Unlock() 66 67 for i, j := 0, len(b.buffer)-1; i < j; i, j = i+1, j-1 { 68 b.buffer[i], b.buffer[j] = b.buffer[j], b.buffer[i] 69 } 70 } 71 72 func (b *CircularBuffer[T]) Exists(value T) bool { 73 b.lock.RLock() 74 defer b.lock.RUnlock() 75 76 return slices.Contains(b.buffer, value) 77 } 78 79 func (b *CircularBuffer[T]) Slice() []T { 80 s := make([]T, len(b.buffer)) 81 b.lock.RLock() 82 defer b.lock.RUnlock() 83 copy(s, b.buffer) 84 return s 85 }