github.com/sandwich-go/boost@v1.3.29/xchan/ringbuffer.go (about) 1 package xchan 2 3 import ( 4 "errors" 5 ) 6 7 var ErrIsEmpty = errors.New("ring buffer is empty") 8 9 // RingBuffer is a ring buffer for common types. 10 // It never is full and always grows if it will be full. 11 // It is not thread-safe(goroutine-safe) so you must use the lock-like synchronization primitive to use it in multiple writers and multiple readers. 12 type RingBuffer[T any] struct { 13 buf []T 14 initialSize int 15 size int 16 r int // read pointer 17 w int // write pointer 18 } 19 20 func NewRingBuffer[T any](initialSize int) *RingBuffer[T] { 21 if initialSize <= 0 { 22 panic("initial size must be great than zero") 23 } 24 // initial size must >= 2 25 if initialSize == 1 { 26 initialSize = 2 27 } 28 29 return &RingBuffer[T]{ 30 buf: make([]T, initialSize), 31 initialSize: initialSize, 32 size: initialSize, 33 } 34 } 35 36 func (r *RingBuffer[T]) Read() (T, error) { 37 var t T 38 if r.r == r.w { 39 return t, ErrIsEmpty 40 } 41 42 v := r.buf[r.r] 43 r.r++ 44 if r.r == r.size { 45 r.r = 0 46 } 47 48 return v, nil 49 } 50 51 func (r *RingBuffer[T]) Pop() T { 52 v, err := r.Read() 53 if errors.Is(err, ErrIsEmpty) { // Empty 54 panic(ErrIsEmpty.Error()) 55 } 56 57 return v 58 } 59 60 func (r *RingBuffer[T]) Peek() T { 61 if r.r == r.w { // Empty 62 panic(ErrIsEmpty.Error()) 63 } 64 65 v := r.buf[r.r] 66 return v 67 } 68 69 func (r *RingBuffer[T]) Write(v T) { 70 r.buf[r.w] = v 71 r.w++ 72 73 if r.w == r.size { 74 r.w = 0 75 } 76 77 if r.w == r.r { // full 78 r.grow() 79 } 80 } 81 82 func (r *RingBuffer[T]) grow() { 83 var size int 84 if r.size < 1024 { 85 size = r.size * 2 86 } else { 87 size = r.size + r.size/4 88 } 89 90 buf := make([]T, size) 91 92 copy(buf[0:], r.buf[r.r:]) 93 copy(buf[r.size-r.r:], r.buf[0:r.r]) 94 95 r.r = 0 96 r.w = r.size 97 r.size = size 98 r.buf = buf 99 } 100 101 func (r *RingBuffer[T]) IsEmpty() bool { 102 return r.r == r.w 103 } 104 105 // Capacity returns the size of the underlying buffer. 106 func (r *RingBuffer[T]) Capacity() int { 107 return r.size 108 } 109 110 func (r *RingBuffer[T]) Len() int { 111 if r.r == r.w { 112 return 0 113 } 114 115 if r.w > r.r { 116 return r.w - r.r 117 } 118 119 return r.size - r.r + r.w 120 } 121 122 func (r *RingBuffer[T]) Reset() { 123 r.r = 0 124 r.w = 0 125 r.size = r.initialSize 126 r.buf = make([]T, r.initialSize) 127 }