package dbUtils import "sync" type IStack[T any] interface { Push(item T) Get() T Len() int } // This queue isn't suppose to be thread safe // 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 StackSync (it's calm, never panics) type Stack[T any] struct { IStack[T] Buffer []T } func NewStack[T any]() *Stack[T] { return &Stack[T]{} } func (q *Stack[T]) Push(item T) { q.Buffer = append(q.Buffer, item) } func (q *Stack[T]) Get() T { if len(q.Buffer) < 1 { panic("Trying to get from an empty thread unsafe queue") } item := q.Buffer[len(q.Buffer)-1] q.Buffer = q.Buffer[:len(q.Buffer)-1] return item } func (q *Stack[T]) Len() int { return len(q.Buffer) } // Stack sync type StackSync[T any] struct { IStack[T] Buffer []T Mu *sync.Mutex NonEmptyCond *sync.Cond } func NewStackSync[T any]() *StackSync[T] { return &StackSync[T]{ Mu: &sync.Mutex{}, NonEmptyCond: sync.NewCond(&sync.RWMutex{}), } } func (q *StackSync[T]) Push(item T) { q.Mu.Lock() q.Buffer = append(q.Buffer, item) q.NonEmptyCond.Signal() q.Mu.Unlock() } func (q *StackSync[T]) Get() T { q.Mu.Lock() if len(q.Buffer) < 1 { q.NonEmptyCond.Wait() } item := q.Buffer[len(q.Buffer)-1] q.Buffer = q.Buffer[:len(q.Buffer)-1] q.Mu.Unlock() return item } func (q *StackSync[T]) Len() int { q.Mu.Lock() defer q.Mu.Lock() return len(q.Buffer) }