GoCollections/collections/ConcurrentLinkedStack.go

149 lines
3.4 KiB
Go
Raw Normal View History

2021-05-22 17:10:26 +08:00
package collections
import (
"github.com/tursom/GoCollections/exceptions"
2022-03-21 11:02:41 +08:00
"github.com/tursom/GoCollections/lang"
"github.com/tursom/GoCollections/lang/atomic"
2021-05-22 17:10:26 +08:00
)
type (
ConcurrentLinkedStack[T lang.Object] struct {
lang.BaseObject
size atomic.Int32
deleted atomic.Int32
head *concurrentLinkedStackNode[T]
}
2021-05-22 17:10:26 +08:00
concurrentLinkedStackNode[T any] struct {
deleted bool
next *concurrentLinkedStackNode[T]
value T
}
2021-05-22 17:10:26 +08:00
concurrentLinkedStackIterator[T lang.Object] struct {
node *concurrentLinkedStackNode[T]
stack *ConcurrentLinkedStack[T]
}
)
2021-05-22 17:10:26 +08:00
func (s *ConcurrentLinkedStack[T]) String() string {
return String[T](s)
2021-05-22 17:10:26 +08:00
}
func NewConcurrentLinkedStack[T lang.Object]() *ConcurrentLinkedStack[T] {
return &ConcurrentLinkedStack[T]{}
2021-05-22 17:10:26 +08:00
}
func (s *ConcurrentLinkedStack[T]) Iterator() Iterator[T] {
return s.MutableIterator()
2021-05-22 17:10:26 +08:00
}
func (s *ConcurrentLinkedStack[T]) Push(element T) exceptions.Exception {
newNode := &concurrentLinkedStackNode[T]{value: element, next: s.head}
for !atomic.CompareAndSwapPointer(&s.head, newNode.next, newNode) {
newNode.next = s.head
2021-05-22 17:10:26 +08:00
}
s.size.Add(1)
2021-05-22 17:10:26 +08:00
return nil
}
func (s *ConcurrentLinkedStack[T]) Pop() (T, exceptions.Exception) {
node := s.head
for node != nil && (!atomic.CompareAndSwapPointer(&s.head, node, node.next) || node.deleted) {
node = s.head
}
if node == nil {
2022-03-21 11:02:41 +08:00
return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil)
2021-05-22 17:10:26 +08:00
}
s.size.Add(-1)
return node.value, nil
}
2021-05-22 17:10:26 +08:00
func (s *ConcurrentLinkedStack[T]) CleanDeleted() {
if s.deleted.Load() <= s.size.Load() {
return
}
s.deleted.Store(0)
node := &s.head
for node != nil && *node != nil {
if (*node).deleted {
atomic.CompareAndSwapPointer(node, *node, (*node).next)
} else {
node = &(*node).next
2021-05-22 17:10:26 +08:00
}
}
}
func (s *ConcurrentLinkedStack[T]) Size() int {
return int(s.size.Load())
}
func (s *ConcurrentLinkedStack[T]) IsEmpty() bool {
return s.head == nil
}
2021-05-22 17:10:26 +08:00
func (s *ConcurrentLinkedStack[T]) Contains(element T) bool {
return Contains[T](s, element)
2021-05-22 17:10:26 +08:00
}
func (s *ConcurrentLinkedStack[T]) ContainsAll(c Collection[T]) bool {
return ContainsAll[T](s, c)
2021-05-22 17:10:26 +08:00
}
func (s *ConcurrentLinkedStack[T]) Add(element T) bool {
exception := s.Push(element)
exceptions.Print(exception)
return exception == nil
2021-05-22 17:10:26 +08:00
}
func (s *ConcurrentLinkedStack[T]) Remove(element T) exceptions.Exception {
return Remove[T](s, element)
}
func (s *ConcurrentLinkedStack[T]) AddAll(c Collection[T]) bool {
return AddAll[T](s, c)
}
func (s *ConcurrentLinkedStack[T]) RemoveAll(c Collection[T]) bool {
return RemoveAll[T](s, c)
}
func (s *ConcurrentLinkedStack[T]) RetainAll(c Collection[T]) bool {
return RetainAll[T](s, c)
}
func (s *ConcurrentLinkedStack[T]) Clear() {
s.head = nil
s.size.Store(0)
}
func (s *ConcurrentLinkedStack[T]) MutableIterator() MutableIterator[T] {
return &concurrentLinkedStackIterator[T]{s.head, nil}
}
func (i *concurrentLinkedStackIterator[T]) HasNext() bool {
return i.node.next != nil
}
func (i *concurrentLinkedStackIterator[T]) Next() (T, exceptions.Exception) {
if i.node == nil {
2022-03-21 11:02:41 +08:00
return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil)
2021-05-22 17:10:26 +08:00
}
value := i.node.value
i.node = i.node.next
return value, nil
2021-05-22 17:10:26 +08:00
}
func (i *concurrentLinkedStackIterator[T]) Remove() exceptions.Exception {
if i.node == nil {
2022-03-21 11:02:41 +08:00
return exceptions.NewIndexOutOfBound("", nil)
2021-05-22 17:10:26 +08:00
}
i.node.deleted = true
i.node = i.node.next
i.stack.size.Add(-1)
i.stack.deleted.Add(1)
i.stack.CleanDeleted()
2021-05-22 17:10:26 +08:00
return nil
}