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) }