package dbUtils import ( "sync" ) type IQueue[T any] interface { Push(item T) Get() T Len() int } // This queue isn't suppose to be thread safe and suppose to be used only in a single thread // If you will try to get item from an empty queue -- it will panic // (Because if u have single-threaded app and one thread will be locked // by getting an item from the queue, there will be no thread to put that item) // For multythreaded usage -- use QueueSync type Queue[T any] struct { IQueue[T] Buffer []T } func NewQueue[T any]() *Queue[T] { return &Queue[T]{} } func (q *Queue[T]) Push(item T) { q.Buffer = append(q.Buffer, item) } func (q *Queue[T]) Get() T { if len(q.Buffer) < 1 { panic("Trying to get from an empty thread unsafe queue") } item := q.Buffer[0] q.Buffer = q.Buffer[1:] return item } func (q *Queue[T]) Len() int { return len(q.Buffer) } // Queue sync type QueueSync[T any] struct { IQueue[T] Buffer []T Mu *sync.Mutex NonEmptyCond *sync.Cond } 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) }