nettools/data_structures/queue.go

84 lines
1.5 KiB
Go

package dsUtils
import (
"io"
"sync"
)
type IQueue[T any] interface {
Push(item T)
Get() T
Len() int
}
// Queue isn't thread safe and suppose to be used only in a single thread
// For multithreaded usage -- use QueueSync
type Queue[T any] struct {
IQueue[T]
Buffer []T
}
// NewQueue creates a new Queue instance
func NewQueue[T any]() *Queue[T] {
return &Queue[T]{}
}
func (q *Queue[T]) Push(item T) {
q.Buffer = append(q.Buffer, item)
}
// Get returns a single item from a queue. If queue is empty -- it will return io.EOF
func (q *Queue[T]) Get() (T, error) {
if len(q.Buffer) == 0 {
var out T
return out, io.EOF
}
item := q.Buffer[0]
q.Buffer = q.Buffer[1:]
return item, nil
}
func (q *Queue[T]) Len() int {
return len(q.Buffer)
}
// QueueSync is a Queue but for multi thread usage
type QueueSync[T any] struct {
IQueue[T]
Buffer []T
Mu *sync.Mutex
NonEmptyCond *sync.Cond
}
// NewQueueSync creates a new QueueSync instance
func NewQueueSync[T any]() *QueueSync[T] {
return &QueueSync[T]{
Mu: &sync.Mutex{},
NonEmptyCond: sync.NewCond(&sync.RWMutex{}),
}
}
func (q *QueueSync[T]) Push(item T) {
q.Mu.Lock()
q.Buffer = append(q.Buffer, item)
q.NonEmptyCond.Signal()
q.Mu.Unlock()
}
func (q *QueueSync[T]) Get() T {
q.Mu.Lock()
if len(q.Buffer) < 1 {
q.NonEmptyCond.Wait()
}
item := q.Buffer[0]
q.Buffer = q.Buffer[1:]
q.Mu.Unlock()
return item
}
func (q *QueueSync[T]) Len() int {
q.Mu.Lock()
defer q.Mu.Lock()
return len(q.Buffer)
}