github.com/quic-go/quic-go@v0.44.0/internal/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 preallocates 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/quic-go/quic-go/internal/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 // PeekFront returns the next element. 66 // It must not be called when the buffer is empty, that means that 67 // callers might need to check if there are elements in the buffer first. 68 func (r *RingBuffer[T]) PeekFront() T { 69 if r.Empty() { 70 panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: peek from an empty queue") 71 } 72 return r.ring[r.headPos] 73 } 74 75 // Grow the maximum size of the queue. 76 // This method assume the queue is full. 77 func (r *RingBuffer[T]) grow() { 78 oldRing := r.ring 79 newSize := len(oldRing) * 2 80 if newSize == 0 { 81 newSize = 1 82 } 83 r.ring = make([]T, newSize) 84 headLen := copy(r.ring, oldRing[r.headPos:]) 85 copy(r.ring[headLen:], oldRing[:r.headPos]) 86 r.headPos, r.tailPos, r.full = 0, len(oldRing), false 87 } 88 89 // Clear removes all elements. 90 func (r *RingBuffer[T]) Clear() { 91 var zeroValue T 92 for i := range r.ring { 93 r.ring[i] = zeroValue 94 } 95 r.headPos, r.tailPos, r.full = 0, 0, false 96 }