// Package circ implements a circular FIFO buffer. package circ // B is a circular FIFO buffer. 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 } }