nettools/data_structures/stack.go

80 lines
1.5 KiB
Go
Raw Normal View History

2024-11-12 08:10:09 +00:00
package ds_utils
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)
}