diff --git a/dataext/stack.go b/dataext/stack.go new file mode 100644 index 0000000..6211334 --- /dev/null +++ b/dataext/stack.go @@ -0,0 +1,98 @@ +package dataext + +import ( + "errors" + "gogs.mikescher.com/BlackForestBytes/goext/langext" + "sync" +) + +var ErrEmptyStack = errors.New("stack is empty") + +type Stack[T any] struct { + lock *sync.Mutex + data []T +} + +func NewStack[T any](threadsafe bool, initialCapacity int) *Stack[T] { + var lck *sync.Mutex = nil + if threadsafe { + lck = &sync.Mutex{} + } + return &Stack[T]{ + lock: lck, + data: make([]T, 0, initialCapacity), + } +} + +func (s *Stack[T]) Push(v T) { + if s.lock != nil { + s.lock.Lock() + defer s.lock.Unlock() + } + + s.data = append(s.data, v) +} + +func (s *Stack[T]) Pop() (T, error) { + if s.lock != nil { + s.lock.Lock() + defer s.lock.Unlock() + } + + l := len(s.data) + if l == 0 { + return *new(T), ErrEmptyStack + } + + result := s.data[l-1] + s.data = s.data[:l-1] + + return result, nil +} + +func (s *Stack[T]) OptPop() *T { + if s.lock != nil { + s.lock.Lock() + defer s.lock.Unlock() + } + + l := len(s.data) + if l == 0 { + return nil + } + + result := s.data[l-1] + s.data = s.data[:l-1] + + return langext.Ptr(result) +} + +func (s *Stack[T]) Peek() (T, error) { + if s.lock != nil { + s.lock.Lock() + defer s.lock.Unlock() + } + + l := len(s.data) + + if l == 0 { + return *new(T), ErrEmptyStack + } + + return s.data[l-1], nil +} + +func (s *Stack[T]) OptPeek() *T { + if s.lock != nil { + s.lock.Lock() + defer s.lock.Unlock() + } + + l := len(s.data) + + if l == 0 { + return nil + } + + return langext.Ptr(s.data[l-1]) +}