package ringbuffer

// A RingBuffer is a ring buffer.
// It acts as a heap that doesn't cause any allocations.
type RingBuffer[ any] struct {
	ring             []
	headPos, tailPos int
	full             bool
}

// Init preallocates a buffer with a certain size.
func ( *RingBuffer[]) ( int) {
	.ring = make([], )
}

// Len returns the number of elements in the ring buffer.
func ( *RingBuffer[]) () int {
	if .full {
		return len(.ring)
	}
	if .tailPos >= .headPos {
		return .tailPos - .headPos
	}
	return .tailPos - .headPos + len(.ring)
}

// Empty says if the ring buffer is empty.
func ( *RingBuffer[]) () bool {
	return !.full && .headPos == .tailPos
}

// PushBack adds a new element.
// If the ring buffer is full, its capacity is increased first.
func ( *RingBuffer[]) ( ) {
	if .full || len(.ring) == 0 {
		.grow()
	}
	.ring[.tailPos] = 
	.tailPos++
	if .tailPos == len(.ring) {
		.tailPos = 0
	}
	if .tailPos == .headPos {
		.full = true
	}
}

// PopFront returns the next element.
// It must not be called when the buffer is empty, that means that
// callers might need to check if there are elements in the buffer first.
func ( *RingBuffer[]) ()  {
	if .Empty() {
		panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: pop from an empty queue")
	}
	.full = false
	 := .ring[.headPos]
	.ring[.headPos] = *new()
	.headPos++
	if .headPos == len(.ring) {
		.headPos = 0
	}
	return 
}

// PeekFront returns the next element.
// It must not be called when the buffer is empty, that means that
// callers might need to check if there are elements in the buffer first.
func ( *RingBuffer[]) ()  {
	if .Empty() {
		panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: peek from an empty queue")
	}
	return .ring[.headPos]
}

// Grow the maximum size of the queue.
// This method assume the queue is full.
func ( *RingBuffer[]) () {
	 := .ring
	 := len() * 2
	if  == 0 {
		 = 1
	}
	.ring = make([], )
	 := copy(.ring, [.headPos:])
	copy(.ring[:], [:.headPos])
	.headPos, .tailPos, .full = 0, len(), false
}

// Clear removes all elements.
func ( *RingBuffer[]) () {
	var  
	for  := range .ring {
		.ring[] = 
	}
	.headPos, .tailPos, .full = 0, 0, false
}