Files
extypes/queue.go

93 lines
2.1 KiB
Go

package extypes
import (
"errors"
"sync"
)
// QueueFullErr is returned when Enqueue is called on a full queue.
var QueueFullErr = errors.New("queue full")
// QueueEmptyErr is returned when Peak or Dequeue is called on an empty queue.
var QueueEmptyErr = errors.New("queue empty")
// Queue is a fixed-size FIFO queue protected by a mutex.
type Queue[T any] struct {
size uint64
mu sync.RWMutex
queue Slice[T]
}
// CreateQueue creates a queue with the provided maximum size.
func CreateQueue[T any](size uint64) *Queue[T] {
return &Queue[T]{queue: make(Slice[T], 0, size), size: size}
}
// Len returns the current number of queued elements.
func (q *Queue[T]) Len() uint64 {
q.mu.RLock()
defer q.mu.RUnlock()
return uint64(q.queue.Len())
}
// IsEmpty reports whether the queue currently holds no elements.
func (q *Queue[T]) IsEmpty() bool { return q.Len() == 0 }
// IsFull reports whether the queue has reached its configured size.
func (q *Queue[T]) IsFull() bool { return q.Len() == q.size }
// Size returns the configured queue capacity.
func (q *Queue[T]) Size() uint64 { return q.size }
// Enqueue appends el to the queue or returns QueueFullErr.
func (q *Queue[T]) Enqueue(el T) error {
q.mu.Lock()
defer q.mu.Unlock()
if uint64(len(q.queue)) == q.size {
return QueueFullErr
}
q.queue = q.queue.Push(el)
return nil
}
// Dequeue removes and returns the head element or QueueEmptyErr.
func (q *Queue[T]) Dequeue() (T, error) {
q.mu.Lock()
defer q.mu.Unlock()
var zero T
if len(q.queue) == 0 {
return zero, QueueEmptyErr
}
el := q.queue[0]
copy(q.queue, q.queue[1:])
q.queue[len(q.queue)-1] = zero
q.queue = q.queue[:len(q.queue)-1]
return el, nil
}
// Peak returns the head element without removing it or QueueEmptyErr when the
// queue is empty.
func (q *Queue[T]) Peak() (T, error) {
q.mu.RLock()
defer q.mu.RUnlock()
var zero T
if len(q.queue) == 0 {
return zero, QueueEmptyErr
}
return q.queue[0], nil
}
// Raw returns a copy of the queue contents from head to tail.
func (q *Queue[T]) Raw() Slice[T] {
q.mu.RLock()
defer q.mu.RUnlock()
return NewSliceFrom(q.queue)
}