github.com/tumi8/quic-go@v0.37.4-tum/noninternal/utils/ringbuffer/ringbuffer.go (about) 1 package ringbuffer 2 3 // A RingBuffer is a ring buffer. 4 // It acts as a heap that doesn't cause any allocations. 5 type RingBuffer[T any] struct { 6 ring []T 7 headPos, tailPos int 8 full bool 9 } 10 11 // Init preallocs a buffer with a certain size. 12 func (r *RingBuffer[T]) Init(size int) { 13 r.ring = make([]T, size) 14 } 15 16 // Len returns the number of elements in the ring buffer. 17 func (r *RingBuffer[T]) Len() int { 18 if r.full { 19 return len(r.ring) 20 } 21 if r.tailPos >= r.headPos { 22 return r.tailPos - r.headPos 23 } 24 return r.tailPos - r.headPos + len(r.ring) 25 } 26 27 // Empty says if the ring buffer is empty. 28 func (r *RingBuffer[T]) Empty() bool { 29 return !r.full && r.headPos == r.tailPos 30 } 31 32 // PushBack adds a new element. 33 // If the ring buffer is full, its capacity is increased first. 34 func (r *RingBuffer[T]) PushBack(t T) { 35 if r.full || len(r.ring) == 0 { 36 r.grow() 37 } 38 r.ring[r.tailPos] = t 39 r.tailPos++ 40 if r.tailPos == len(r.ring) { 41 r.tailPos = 0 42 } 43 if r.tailPos == r.headPos { 44 r.full = true 45 } 46 } 47 48 // PopFront returns the next element. 49 // It must not be called when the buffer is empty, that means that 50 // callers might need to check if there are elements in the buffer first. 51 func (r *RingBuffer[T]) PopFront() T { 52 if r.Empty() { 53 panic("github.com/tumi8/quic-go/noninternal/utils/ringbuffer: pop from an empty queue") 54 } 55 r.full = false 56 t := r.ring[r.headPos] 57 r.ring[r.headPos] = *new(T) 58 r.headPos++ 59 if r.headPos == len(r.ring) { 60 r.headPos = 0 61 } 62 return t 63 } 64 65 // Grow the maximum size of the queue. 66 // This method assume the queue is full. 67 func (r *RingBuffer[T]) grow() { 68 oldRing := r.ring 69 newSize := len(oldRing) * 2 70 if newSize == 0 { 71 newSize = 1 72 } 73 r.ring = make([]T, newSize) 74 headLen := copy(r.ring, oldRing[r.headPos:]) 75 copy(r.ring[headLen:], oldRing[:r.headPos]) 76 r.headPos, r.tailPos, r.full = 0, len(oldRing), false 77 } 78 79 // Clear removes all elements. 80 func (r *RingBuffer[T]) Clear() { 81 var zeroValue T 82 for i := range r.ring { 83 r.ring[i] = zeroValue 84 } 85 r.headPos, r.tailPos, r.full = 0, 0, false 86 }