2023-03-02 09:53:12 +00:00
|
|
|
// Package circ implements a circular FIFO buffer.
|
2023-03-01 04:33:22 +00:00
|
|
|
package circ
|
|
|
|
|
2023-03-02 09:53:12 +00:00
|
|
|
// B is a circular FIFO buffer.
|
2023-03-01 04:33:22 +00:00
|
|
|
type B[T any] struct {
|
|
|
|
buf []T
|
|
|
|
len int
|
|
|
|
head int
|
|
|
|
tail int
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make creates a new circular buffer.
|
|
|
|
func Make[T any](cap int) B[T] {
|
|
|
|
buf := make([]T, cap)
|
|
|
|
return B[T]{buf: buf}
|
|
|
|
}
|
|
|
|
|
|
|
|
// CanPush returns true if the buffer has space for new items.
|
|
|
|
func (b *B[T]) CanPush() bool {
|
|
|
|
return cap(b.buf)-b.len != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// CanPop returns true if the buffer has one or more items.
|
|
|
|
func (b *B[T]) CanPop() bool {
|
|
|
|
return b.len != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// PopFront returns the front-most item from the buffer.
|
|
|
|
//
|
|
|
|
// If the buffer is empty, it panics.
|
|
|
|
func (b *B[T]) PopFront() T {
|
|
|
|
if !b.CanPop() {
|
|
|
|
panic("cannot pop from empty buffer")
|
|
|
|
}
|
|
|
|
var empty T
|
|
|
|
item := b.buf[b.head]
|
|
|
|
// clear buffer slot so that we don't hold on to garbage
|
|
|
|
b.buf[b.head] = empty
|
|
|
|
b.len--
|
|
|
|
b.head++
|
|
|
|
if b.head == cap(b.buf) {
|
|
|
|
b.head = 0
|
|
|
|
}
|
|
|
|
return item
|
|
|
|
}
|
|
|
|
|
|
|
|
// PushBack adds an item to the end of the buffer.
|
|
|
|
//
|
|
|
|
// If the buffer is full, it panics.
|
|
|
|
func (b *B[T]) PushBack(value T) {
|
|
|
|
if !b.CanPush() {
|
|
|
|
panic("cannot push back to full buffer")
|
|
|
|
}
|
|
|
|
b.buf[b.tail] = value
|
|
|
|
b.len++
|
|
|
|
b.tail++
|
|
|
|
if b.tail == cap(b.buf) {
|
|
|
|
b.tail = 0
|
|
|
|
}
|
|
|
|
}
|