// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved. // See the file LICENSE for licensing terms. package buffer import "errors" var ( _ Queue[struct{}] = (*boundedQueue[struct{}])(nil) errInvalidMaxSize = errors.New("maxSize must be greater than 0") ) // A FIFO queue. type Queue[T any] interface { // Pushes [elt] onto the queue. // If the queue is full, the oldest element is evicted to make space. Push(T) // Pops the oldest element from the queue. // Returns false if the queue is empty. Pop() (T, bool) // Returns the oldest element without removing it. // Returns false if the queue is empty. Peek() (T, bool) // Returns the element at the given index without removing it. // Index(0) returns the oldest element. // Index(Len() - 1) returns the newest element. // Returns false if there is no element at that index. Index(int) (T, bool) // Returns the number of elements in the queue. Len() int // Returns the queue elements from oldest to newest. // This is an O(n) operation and should be used sparingly. List() []T } // Keeps up to [maxSize] entries in an ordered buffer // and calls [onEvict] on any item that is evicted. // Not safe for concurrent use. type boundedQueue[T any] struct { deque Deque[T] maxSize int onEvict func(T) } // Returns a new bounded, non-blocking queue that holds up to [maxSize] elements. // When an element is evicted, [onEvict] is called with the evicted element. // If [onEvict] is nil, this is a no-op. // [maxSize] must be >= 1. // Not safe for concurrent use. func NewBoundedQueue[T any](maxSize int, onEvict func(T)) (Queue[T], error) { if maxSize < 1 { return nil, errInvalidMaxSize } return &boundedQueue[T]{ deque: NewUnboundedDeque[T](maxSize + 1), // +1 so we never resize maxSize: maxSize, onEvict: onEvict, }, nil } func (b *boundedQueue[T]) Push(elt T) { if b.deque.Len() == b.maxSize { evicted, _ := b.deque.PopLeft() if b.onEvict != nil { b.onEvict(evicted) } } _ = b.deque.PushRight(elt) } func (b *boundedQueue[T]) Pop() (T, bool) { return b.deque.PopLeft() } func (b *boundedQueue[T]) Peek() (T, bool) { return b.deque.PeekLeft() } func (b *boundedQueue[T]) Index(i int) (T, bool) { return b.deque.Index(i) } func (b *boundedQueue[T]) Len() int { return b.deque.Len() } func (b *boundedQueue[T]) List() []T { return b.deque.List() }