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  }