nettools/data_structures/stack.go

82 lines
1.4 KiB
Go

package dsUtils
import (
"io"
"sync"
)
type IStack[T any] interface {
Push(item T)
Get() T
Len() int
}
// Stack isn't thread safe and suppose to be used only in a single thread
// For multithreaded usage -- use Stack
type Stack[T any] struct {
IStack[T]
Buffer []T
}
// NewStack creates a new Stack instance
func NewStack[T any]() *Stack[T] {
return &Stack[T]{}
}
func (s *Stack[T]) Push(item T) {
s.Buffer = append(s.Buffer, item)
}
func (s *Stack[T]) Get() (T, error) {
if len(s.Buffer) == 0 {
var out T
return out, io.EOF
}
item := s.Buffer[len(s.Buffer)-1]
s.Buffer = s.Buffer[:len(s.Buffer)-1]
return item, nil
}
func (s *Stack[T]) Len() int {
return len(s.Buffer)
}
// StackSync is a Stack but for multi thread usage
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 (s *StackSync[T]) Push(item T) {
s.Mu.Lock()
s.Buffer = append(s.Buffer, item)
s.NonEmptyCond.Signal()
s.Mu.Unlock()
}
func (s *StackSync[T]) Get() T {
s.Mu.Lock()
if len(s.Buffer) < 1 {
s.NonEmptyCond.Wait()
}
item := s.Buffer[len(s.Buffer)-1]
s.Buffer = s.Buffer[:len(s.Buffer)-1]
s.Mu.Unlock()
return item
}
func (s *StackSync[T]) Len() int {
s.Mu.Lock()
defer s.Mu.Lock()
return len(s.Buffer)
}