github.com/MetalBlockchain/metalgo@v1.11.9/utils/buffer/bounded_nonblocking_queue.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package buffer 5 6 import "errors" 7 8 var ( 9 _ Queue[struct{}] = (*boundedQueue[struct{}])(nil) 10 11 errInvalidMaxSize = errors.New("maxSize must be greater than 0") 12 ) 13 14 // A FIFO queue. 15 type Queue[T any] interface { 16 // Pushes [elt] onto the queue. 17 // If the queue is full, the oldest element is evicted to make space. 18 Push(T) 19 // Pops the oldest element from the queue. 20 // Returns false if the queue is empty. 21 Pop() (T, bool) 22 // Returns the oldest element without removing it. 23 // Returns false if the queue is empty. 24 Peek() (T, bool) 25 // Returns the element at the given index without removing it. 26 // Index(0) returns the oldest element. 27 // Index(Len() - 1) returns the newest element. 28 // Returns false if there is no element at that index. 29 Index(int) (T, bool) 30 // Returns the number of elements in the queue. 31 Len() int 32 // Returns the queue elements from oldest to newest. 33 // This is an O(n) operation and should be used sparingly. 34 List() []T 35 } 36 37 // Keeps up to [maxSize] entries in an ordered buffer 38 // and calls [onEvict] on any item that is evicted. 39 // Not safe for concurrent use. 40 type boundedQueue[T any] struct { 41 deque Deque[T] 42 maxSize int 43 onEvict func(T) 44 } 45 46 // Returns a new bounded, non-blocking queue that holds up to [maxSize] elements. 47 // When an element is evicted, [onEvict] is called with the evicted element. 48 // If [onEvict] is nil, this is a no-op. 49 // [maxSize] must be >= 1. 50 // Not safe for concurrent use. 51 func NewBoundedQueue[T any](maxSize int, onEvict func(T)) (Queue[T], error) { 52 if maxSize < 1 { 53 return nil, errInvalidMaxSize 54 } 55 return &boundedQueue[T]{ 56 deque: NewUnboundedDeque[T](maxSize + 1), // +1 so we never resize 57 maxSize: maxSize, 58 onEvict: onEvict, 59 }, nil 60 } 61 62 func (b *boundedQueue[T]) Push(elt T) { 63 if b.deque.Len() == b.maxSize { 64 evicted, _ := b.deque.PopLeft() 65 if b.onEvict != nil { 66 b.onEvict(evicted) 67 } 68 } 69 _ = b.deque.PushRight(elt) 70 } 71 72 func (b *boundedQueue[T]) Pop() (T, bool) { 73 return b.deque.PopLeft() 74 } 75 76 func (b *boundedQueue[T]) Peek() (T, bool) { 77 return b.deque.PeekLeft() 78 } 79 80 func (b *boundedQueue[T]) Index(i int) (T, bool) { 81 return b.deque.Index(i) 82 } 83 84 func (b *boundedQueue[T]) Len() int { 85 return b.deque.Len() 86 } 87 88 func (b *boundedQueue[T]) List() []T { 89 return b.deque.List() 90 }