diff --git a/collections/ArrayList.go b/collections/ArrayList.go index 933e73f..ca2a27c 100644 --- a/collections/ArrayList.go +++ b/collections/ArrayList.go @@ -27,27 +27,35 @@ func NewArrayListByCapacity[T lang.Object](cap int) *ArrayList[T] { } } -func (a ArrayList[T]) String() string { +func (a *ArrayList[T]) String() string { return String[T](a) } -func (a ArrayList[T]) Iterator() Iterator[T] { +func (a *ArrayList[T]) Iterator() Iterator[T] { return a.MutableIterator() } -func (a ArrayList[T]) Size() int { +func (a *ArrayList[T]) ListIterator() ListIterator[T] { + return a.MutableListIterator() +} + +func (a *ArrayList[T]) MutableListIterator() MutableListIterator[T] { + return &arrayListIterator[T]{a, 0} +} + +func (a *ArrayList[T]) Size() int { return lang.Len(a.array) } -func (a ArrayList[T]) IsEmpty() bool { +func (a *ArrayList[T]) IsEmpty() bool { return a.Size() == 0 } -func (a ArrayList[T]) Contains(element T) bool { +func (a *ArrayList[T]) Contains(element T) bool { return Contains[T](a, element) } -func (a ArrayList[T]) ContainsAll(c Collection[T]) bool { +func (a *ArrayList[T]) ContainsAll(c Collection[T]) bool { return ContainsAll[T](a, c) } @@ -56,7 +64,7 @@ func (a *ArrayList[T]) Add(element T) bool { return true } -func (a ArrayList[T]) IndexOf(element T) int { +func (a *ArrayList[T]) IndexOf(element T) int { for i := 0; i < a.Size(); i++ { if lang.Equals(element, a.array[i]) { return i @@ -90,7 +98,7 @@ func (a *ArrayList[T]) Clear() { a.array = []T{} } -func (a ArrayList[T]) Get(index int) (T, exceptions.Exception) { +func (a *ArrayList[T]) Get(index int) (T, exceptions.Exception) { if index >= a.Size() { return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil) } else { @@ -98,8 +106,8 @@ func (a ArrayList[T]) Get(index int) (T, exceptions.Exception) { } } -func (a ArrayList[T]) SubList(from, to int) List[T] { - return NewSubList[T](a, from, to) +func (a *ArrayList[T]) SubList(from, to int) List[T] { + return a.SubMutableList(from, to) } func (a *ArrayList[T]) Set(index int, element T) exceptions.Exception { @@ -131,7 +139,9 @@ func (a *ArrayList[T]) RemoveAt(index int) exceptions.Exception { } func (a *ArrayList[T]) SubMutableList(from, to int) MutableList[T] { - return NewMutableSubList[T](a, from, to) + return &ArrayList[T]{ + array: a.array[from:to], + } } func (a *ArrayList[T]) MutableIterator() MutableIterator[T] { @@ -164,3 +174,37 @@ func (a *arrayListIterator[T]) Remove() exceptions.Exception { a.index-- return nil } + +func (a *arrayListIterator[T]) HasPrevious() bool { + return a.index > 0 +} + +func (a *arrayListIterator[T]) Previous() (T, exceptions.Exception) { + if a.index <= 0 || a.index >= len(a.arrayList.array) { + return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil) + } + a.index-- + return a.arrayList.array[a.index], a.arrayList.RemoveAt(a.index) +} + +func (a *arrayListIterator[T]) NextIndex() int { + return a.index +} + +func (a *arrayListIterator[T]) PreviousIndex() int { + return a.index - 1 +} + +func (a *arrayListIterator[T]) Set(value T) exceptions.Exception { + if a.index <= 0 { + return exceptions.NewIndexOutOfBound("", nil) + } + a.arrayList.array[a.index-1] = value + return nil +} + +func (a *arrayListIterator[T]) Add(value T) exceptions.Exception { + a.arrayList.AddAtIndex(a.index, value) + a.index++ + return nil +} diff --git a/collections/Collection.go b/collections/Collection.go index 79108e6..b891b01 100644 --- a/collections/Collection.go +++ b/collections/Collection.go @@ -2,18 +2,19 @@ package collections import ( "fmt" + "strings" + "github.com/tursom/GoCollections/exceptions" "github.com/tursom/GoCollections/lang" - "strings" ) type ( - Collection[T any] interface { - Iterable[T] + Collection[E any] interface { + Iterable[E] Size() int IsEmpty() bool - Contains(element T) bool - ContainsAll(c Collection[T]) bool + Contains(element E) bool + ContainsAll(c Collection[E]) bool } MutableCollection[T any] interface { @@ -33,6 +34,7 @@ type ( Get(index int) (T, exceptions.Exception) SubList(from, to int) List[T] + ListIterator() ListIterator[T] } MutableList[T any] interface { @@ -43,6 +45,7 @@ type ( AddAtIndex(index int, element T) bool RemoveAt(index int) exceptions.Exception SubMutableList(from, to int) MutableList[T] + MutableListIterator() MutableListIterator[T] } ) diff --git a/collections/ConcurrentLinkedQueue.go b/collections/ConcurrentLinkedQueue.go deleted file mode 100644 index a54c37d..0000000 --- a/collections/ConcurrentLinkedQueue.go +++ /dev/null @@ -1,168 +0,0 @@ -package collections - -import ( - "github.com/tursom/GoCollections/exceptions" - "github.com/tursom/GoCollections/lang" - "github.com/tursom/GoCollections/lang/atomic" -) - -type ( - ConcurrentLinkedQueueNode[T lang.Object] interface { - Get() (T, exceptions.Exception) - Remove() exceptions.Exception - RemoveAndGet() (T, exceptions.Exception) - } - - ConcurrentLinkedQueue[T lang.Object] struct { - lang.BaseObject - ConcurrentLinkedStack[T] - end *concurrentLinkedStackNode[T] - } - - concurrentLinkedQueueIterator[T lang.Object] struct { - node *concurrentLinkedStackNode[T] - queue *ConcurrentLinkedQueue[T] - } -) - -func (q *ConcurrentLinkedQueue[T]) String() string { - return String[T](q) -} - -func NewConcurrentLinkedQueue[T lang.Object]() *ConcurrentLinkedQueue[T] { - return &ConcurrentLinkedQueue[T]{} -} - -func (q *ConcurrentLinkedQueue[T]) Iterator() Iterator[T] { - return q.MutableIterator() -} - -func (q *ConcurrentLinkedQueue[T]) Offer(element T) exceptions.Exception { - _, err := q.offerAndGetNode(element) - return err -} - -func (q *ConcurrentLinkedQueue[T]) OfferAndGetNode(element T) (ConcurrentLinkedQueueNode[T], exceptions.Exception) { - newNode, err := q.offerAndGetNode(element) - if err != nil { - return nil, err - } - return &concurrentLinkedQueueIterator[T]{queue: q, node: newNode}, nil -} - -func (q *ConcurrentLinkedQueue[T]) offerAndGetNode(element T) (*concurrentLinkedStackNode[T], exceptions.Exception) { - newNode := &concurrentLinkedStackNode[T]{value: element} - q.size.Add(1) - - var next **concurrentLinkedStackNode[T] - ref := q.end - switch { - case ref == nil: - next = &q.head - default: - next = &ref.next - } - for !atomic.CompareAndSwapPointer(next, nil, newNode) { - if ref == nil || ref.next == nil { - next = &q.head - ref = q.head - } else { - for ref.next != nil { - ref = ref.next - } - next = &ref.next - } - } - q.end = newNode - return newNode, nil -} - -func (q *ConcurrentLinkedQueue[T]) Poll() (T, exceptions.Exception) { - return q.Pop() -} - -func (q *ConcurrentLinkedQueue[T]) MutableIterator() MutableIterator[T] { - return &concurrentLinkedQueueIterator[T]{queue: q, node: q.head} -} - -func (q *ConcurrentLinkedQueue[T]) Size() int { - return int(q.size.Load()) -} - -func (q *ConcurrentLinkedQueue[T]) IsEmpty() bool { - return q.head == nil -} - -func (q *ConcurrentLinkedQueue[T]) Contains(element T) bool { - return Contains[T](q, element) -} - -func (q *ConcurrentLinkedQueue[T]) ContainsAll(collection Collection[T]) bool { - return ContainsAll[T](q, collection) -} - -func (q *ConcurrentLinkedQueue[T]) Add(element T) bool { - exception := q.Push(element) - exceptions.Print(exception) - return exception == nil -} - -func (q *ConcurrentLinkedQueue[T]) Remove(element T) exceptions.Exception { - return Remove[T](q, element) -} - -func (q *ConcurrentLinkedQueue[T]) AddAll(collection Collection[T]) bool { - return AddAll[T](q, collection) -} - -func (q *ConcurrentLinkedQueue[T]) RemoveAll(collection Collection[T]) bool { - return RemoveAll[T](q, collection) -} - -func (q *ConcurrentLinkedQueue[T]) RetainAll(collection Collection[T]) bool { - return RetainAll[T](q, collection) -} - -func (q *ConcurrentLinkedQueue[T]) Clear() { - q.head = nil - q.end = nil - q.size.Store(0) -} - -func (i *concurrentLinkedQueueIterator[T]) HasNext() bool { - for i.node != nil && i.node.deleted { - i.node = i.node.next - } - return i.node != nil -} - -func (i *concurrentLinkedQueueIterator[T]) Next() (T, exceptions.Exception) { - value, err := i.Get() - i.node = i.node.next - for i.node != nil && i.node.deleted { - i.node = i.node.next - } - return value, err -} - -func (i *concurrentLinkedQueueIterator[T]) Get() (T, exceptions.Exception) { - return (*i.node).value, nil -} - -func (i *concurrentLinkedQueueIterator[T]) Remove() exceptions.Exception { - _, err := i.RemoveAndGet() - return err -} - -func (i *concurrentLinkedQueueIterator[T]) RemoveAndGet() (T, exceptions.Exception) { - if i.node == nil { - return lang.Nil[T](), nil - } - load := i.node - load.deleted = true - i.queue.size.Add(-1) - i.queue.deleted.Add(1) - i.queue.CleanDeleted() - i.node = load.next - return load.value, nil -} diff --git a/collections/ConcurrentLinkedStack.go b/collections/ConcurrentLinkedStack.go deleted file mode 100644 index d004484..0000000 --- a/collections/ConcurrentLinkedStack.go +++ /dev/null @@ -1,148 +0,0 @@ -package collections - -import ( - "github.com/tursom/GoCollections/exceptions" - "github.com/tursom/GoCollections/lang" - "github.com/tursom/GoCollections/lang/atomic" -) - -type ( - ConcurrentLinkedStack[T lang.Object] struct { - lang.BaseObject - size atomic.Int32 - deleted atomic.Int32 - head *concurrentLinkedStackNode[T] - } - - concurrentLinkedStackNode[T any] struct { - deleted bool - next *concurrentLinkedStackNode[T] - value T - } - - concurrentLinkedStackIterator[T lang.Object] struct { - node *concurrentLinkedStackNode[T] - stack *ConcurrentLinkedStack[T] - } -) - -func (s *ConcurrentLinkedStack[T]) String() string { - return String[T](s) -} - -func NewConcurrentLinkedStack[T lang.Object]() *ConcurrentLinkedStack[T] { - return &ConcurrentLinkedStack[T]{} -} - -func (s *ConcurrentLinkedStack[T]) Iterator() Iterator[T] { - return s.MutableIterator() -} - -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 - } - s.size.Add(1) - 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 { - return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil) - } - - s.size.Add(-1) - return node.value, nil -} - -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 - } - } -} - -func (s *ConcurrentLinkedStack[T]) Size() int { - return int(s.size.Load()) -} - -func (s *ConcurrentLinkedStack[T]) IsEmpty() bool { - return s.head == nil -} - -func (s *ConcurrentLinkedStack[T]) Contains(element T) bool { - return Contains[T](s, element) -} - -func (s *ConcurrentLinkedStack[T]) ContainsAll(c Collection[T]) bool { - return ContainsAll[T](s, c) -} - -func (s *ConcurrentLinkedStack[T]) Add(element T) bool { - exception := s.Push(element) - exceptions.Print(exception) - return exception == nil -} - -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 { - return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil) - } - value := i.node.value - i.node = i.node.next - return value, nil -} - -func (i *concurrentLinkedStackIterator[T]) Remove() exceptions.Exception { - if i.node == nil { - return exceptions.NewIndexOutOfBound("", nil) - } - i.node.deleted = true - i.node = i.node.next - i.stack.size.Add(-1) - i.stack.deleted.Add(1) - i.stack.CleanDeleted() - return nil -} diff --git a/collections/Iterable.go b/collections/Iterable.go index a2e30e7..e5658e1 100644 --- a/collections/Iterable.go +++ b/collections/Iterable.go @@ -1,26 +1,58 @@ package collections -import "github.com/tursom/GoCollections/exceptions" -import "github.com/tursom/GoCollections/lang" +import ( + "github.com/tursom/GoCollections/exceptions" + "github.com/tursom/GoCollections/lang" +) -type Iterator[T any] interface { - HasNext() bool - Next() (T, exceptions.Exception) -} +type ( + // Iterator an iterator over a collection or another entity that can be represented as a sequence of elements. + // Allows to sequentially access the elements + Iterator[T any] interface { + // HasNext return true if the iterator has more elements + HasNext() bool + // Next returns the next element in the iteration + // return exceptions.IndexOutOfBound if there is no more element + Next() (T, exceptions.Exception) + } -type Iterable[T any] interface { - Iterator() Iterator[T] -} + // MutableIterator an iterator over a mutable collection. + // Provides the ability to remove elements while iterating. + MutableIterator[T any] interface { + Iterator[T] + // Remove removes from the underlying collection the last element returned by this iterator. + Remove() exceptions.Exception + } -type MutableIterator[T any] interface { - Iterator[T] - Remove() exceptions.Exception -} + // ListIterator an iterator over a collection that supports indexed access + ListIterator[T any] interface { + Iterator[T] + HasPrevious() bool + Previous() (T, exceptions.Exception) + NextIndex() int + PreviousIndex() int + } -type MutableIterable[T any] interface { - Iterable[T] - MutableIterator() MutableIterator[T] -} + // MutableListIterator an iterator over a mutable collection that supports indexed access + // Provides the ability to add, modify and remove elements while iterating. + MutableListIterator[T any] interface { + ListIterator[T] + MutableIterator[T] + Set(value T) exceptions.Exception + Add(value T) exceptions.Exception + } + + // Iterable classes that inherit from this interface can be represented as a sequence of elements that can be iterated over. + // param T + Iterable[T any] interface { + Iterator() Iterator[T] + } + + MutableIterable[T any] interface { + Iterable[T] + MutableIterator() MutableIterator[T] + } +) func Loop[T any](iterable Iterable[T], f func(element T) exceptions.Exception) exceptions.Exception { if f == nil || iterable == nil { diff --git a/collections/MutableSubList.go b/collections/MutableSubList.go deleted file mode 100644 index 942e06e..0000000 --- a/collections/MutableSubList.go +++ /dev/null @@ -1,97 +0,0 @@ -package collections - -import ( - "github.com/tursom/GoCollections/exceptions" - "github.com/tursom/GoCollections/lang" -) - -type MutableSubList[T lang.Object] struct { - lang.BaseObject - list MutableList[T] - from, to int -} - -func NewMutableSubList[T lang.Object](list MutableList[T], from, to int) *MutableSubList[T] { - return &MutableSubList[T]{lang.NewBaseObject(), list, from, to} -} - -func (s *MutableSubList[T]) Iterator() Iterator[T] { - iterator := s.list.Iterator() - for i := 0; i < s.from; i++ { - _, err := iterator.Next() - if err != nil { - return nil - } - } - return iterator -} - -func (s *MutableSubList[T]) Size() int { - return s.to - s.from -} - -func (s *MutableSubList[T]) IsEmpty() bool { - return s.Size() == 0 -} - -func (s *MutableSubList[T]) Contains(element T) bool { - return Contains[T](s, element) -} - -func (s *MutableSubList[T]) ContainsAll(c Collection[T]) bool { - return ContainsAll[T](s, c) -} - -func (s *MutableSubList[T]) Get(index int) (T, exceptions.Exception) { - return s.list.Get(index + s.from) -} - -func (s *MutableSubList[T]) SubList(from, to int) List[T] { - return NewSubList[T](s, from, to) -} - -func (s *MutableSubList[T]) MutableIterator() MutableIterator[T] { - return nil -} - -func (s *MutableSubList[T]) Add(_ T) bool { - return false -} - -func (s *MutableSubList[T]) Remove(element T) exceptions.Exception { - return nil -} - -func (s *MutableSubList[T]) AddAll(_ Collection[T]) bool { - return false -} - -func (s *MutableSubList[T]) RemoveAll(_ Collection[T]) bool { - return false -} - -func (s *MutableSubList[T]) RetainAll(_ Collection[T]) bool { - return false -} - -func (s *MutableSubList[T]) Clear() { -} - -func (s *MutableSubList[T]) Set(index int, element T) exceptions.Exception { - if index >= s.to-s.from { - return exceptions.NewIndexOutOfBound("", nil) - } - return s.list.Set(index+s.from, element) -} - -func (s *MutableSubList[T]) AddAtIndex(_ int, _ T) bool { - return false -} - -func (s *MutableSubList[T]) RemoveAt(index int) exceptions.Exception { - return exceptions.NewOperationNotSupportedException("", nil) -} - -func (s *MutableSubList[T]) SubMutableList(from, to int) MutableList[T] { - return NewMutableSubList[T](s.list, s.from+from, to) -} diff --git a/collections/Queue.go b/collections/Queue.go index fa03da5..0317674 100644 --- a/collections/Queue.go +++ b/collections/Queue.go @@ -5,9 +5,14 @@ import ( "github.com/tursom/GoCollections/lang" ) -type Queue[T lang.Object] interface { - MutableIterable[T] +type ( + Queue[T lang.Object] interface { + MutableIterable[T] - Offer(element T) exceptions.Exception - Poll() (T, exceptions.Exception) -} + Offer(element T) exceptions.Exception + OfferAndGetNode(element T) (QueueNode[T], exceptions.Exception) + Poll() (T, exceptions.Exception) + } + + QueueNode[T lang.Object] = StackNode[T] +) diff --git a/collections/Stack.go b/collections/Stack.go index b326e1c..17e2080 100644 --- a/collections/Stack.go +++ b/collections/Stack.go @@ -1,10 +1,23 @@ package collections -import "github.com/tursom/GoCollections/exceptions" +import ( + "github.com/tursom/GoCollections/exceptions" + "github.com/tursom/GoCollections/lang" +) -type Stack[T any] interface { - MutableIterable[T] +type ( + Stack[T any] interface { + MutableIterable[T] - Push(element T) exceptions.Exception - Pop() (T, exceptions.Exception) -} + Push(element T) exceptions.Exception + PushAndGetNode(element T) (StackNode[T], exceptions.Exception) + Pop() (T, exceptions.Exception) + } + + StackNode[T lang.Object] interface { + Set(value T) exceptions.Exception + Get() (T, exceptions.Exception) + Remove() exceptions.Exception + RemoveAndGet() (T, exceptions.Exception) + } +) diff --git a/collections/SubList.go b/collections/SubList.go deleted file mode 100644 index b82c2d8..0000000 --- a/collections/SubList.go +++ /dev/null @@ -1,51 +0,0 @@ -package collections - -import ( - "github.com/tursom/GoCollections/exceptions" - "github.com/tursom/GoCollections/lang" -) - -type SubList[T lang.Object] struct { - lang.BaseObject - list List[T] - from, to int -} - -func NewSubList[T lang.Object](list List[T], from, to int) *SubList[T] { - return &SubList[T]{lang.NewBaseObject(), list, from, to} -} - -func (s *SubList[T]) Iterator() Iterator[T] { - iterator := s.list.Iterator() - for i := 0; i < int(s.from); i++ { - _, err := iterator.Next() - if err != nil { - return nil - } - } - return iterator -} - -func (s *SubList[T]) Size() int { - return s.to - s.from -} - -func (s *SubList[T]) IsEmpty() bool { - return s.Size() == 0 -} - -func (s *SubList[T]) Contains(element T) bool { - return Contains[T](s, element) -} - -func (s *SubList[T]) ContainsAll(c Collection[T]) bool { - return ContainsAll[T](s, c) -} - -func (s *SubList[T]) Get(index int) (T, exceptions.Exception) { - return s.list.Get(index + s.from) -} - -func (s *SubList[T]) SubList(from, to int) List[T] { - return NewSubList[T](s, from, to) -} diff --git a/collections/GoSyncMap.go b/concurrent/GoSyncMap.go similarity index 72% rename from collections/GoSyncMap.go rename to concurrent/GoSyncMap.go index fe9db32..0eb4513 100644 --- a/collections/GoSyncMap.go +++ b/concurrent/GoSyncMap.go @@ -1,36 +1,38 @@ -package collections +package concurrent import ( - "github.com/tursom/GoCollections/concurrent" + "sync" + + "github.com/tursom/GoCollections/collections" "github.com/tursom/GoCollections/exceptions" "github.com/tursom/GoCollections/lang" - "sync" ) type ( + // GoSyncMap an map use go sync.Map to store hash slot GoSyncMap[K lang.Object, V any] struct { - NodeMap[K, V] + collections.NodeMap[K, V] m sync.Map - lock concurrent.RWLock + lock RWLock } ) func NewGoSyncMap[K lang.Object, V any]() *GoSyncMap[K, V] { m := &GoSyncMap[K, V]{lock: &sync.RWMutex{}} - m.MapNodeFinder = NewMapNodeFinderBySlot[K, V](m) + m.MapNodeFinder = collections.NewMapNodeFinderBySlot[K, V](m) return m } func (g *GoSyncMap[K, V]) ToString() lang.String { - return MapToString[K, V](g) + return collections.MapToString[K, V](g) } -func (g *GoSyncMap[K, V]) findSlot(k K) MapNode[K, V] { +func (g *GoSyncMap[K, V]) findSlot(k K) collections.MapNode[K, V] { hashCode := lang.HashCode(k) p, _ := g.m.Load(hashCode) - root := lang.Cast[*SimpleMapNode[K, V]](p) + root := lang.Cast[*collections.SimpleMapNode[K, V]](p) if root == nil { - root = &SimpleMapNode[K, V]{} + root = &collections.SimpleMapNode[K, V]{} g.m.Store(hashCode, root) } return root diff --git a/concurrent/LinkedQueue.go b/concurrent/LinkedQueue.go new file mode 100644 index 0000000..e11afe8 --- /dev/null +++ b/concurrent/LinkedQueue.go @@ -0,0 +1,168 @@ +package concurrent + +import ( + "github.com/tursom/GoCollections/collections" + "github.com/tursom/GoCollections/exceptions" + "github.com/tursom/GoCollections/lang" + "github.com/tursom/GoCollections/lang/atomic" +) + +type ( + LinkedQueue[T lang.Object] struct { + lang.BaseObject + LinkedStack[T] + end *linkedStackNode[T] + } + + linkedQueueIterator[T lang.Object] struct { + node *linkedStackNode[T] + queue *LinkedQueue[T] + } +) + +func (q *LinkedQueue[T]) String() string { + return collections.String[T](q) +} + +func NewLinkedQueue[T lang.Object]() *LinkedQueue[T] { + return &LinkedQueue[T]{} +} + +func (q *LinkedQueue[T]) Iterator() collections.Iterator[T] { + return q.MutableIterator() +} + +func (q *LinkedQueue[T]) Offer(element T) exceptions.Exception { + _, err := q.offerAndGetNode(element) + return err +} + +func (q *LinkedQueue[T]) OfferAndGetNode(element T) (collections.QueueNode[T], exceptions.Exception) { + newNode, err := q.offerAndGetNode(element) + if err != nil { + return nil, err + } + return &linkedQueueIterator[T]{queue: q, node: newNode}, nil +} + +func (q *LinkedQueue[T]) offerAndGetNode(element T) (*linkedStackNode[T], exceptions.Exception) { + newNode := &linkedStackNode[T]{value: element} + q.size.Add(1) + + var next **linkedStackNode[T] + ref := q.end + switch { + case ref == nil: + next = &q.head + default: + next = &ref.next + } + for !atomic.CompareAndSwapPointer(next, nil, newNode) { + if ref == nil || ref.next == nil { + next = &q.head + ref = q.head + } else { + for ref.next != nil { + ref = ref.next + } + next = &ref.next + } + } + q.end = newNode + return newNode, nil +} + +func (q *LinkedQueue[T]) Poll() (T, exceptions.Exception) { + return q.Pop() +} + +func (q *LinkedQueue[T]) MutableIterator() collections.MutableIterator[T] { + return &linkedQueueIterator[T]{queue: q, node: q.head} +} + +func (q *LinkedQueue[T]) Size() int { + return int(q.size.Load()) +} + +func (q *LinkedQueue[T]) IsEmpty() bool { + return q.head == nil +} + +func (q *LinkedQueue[T]) Contains(element T) bool { + return collections.Contains[T](q, element) +} + +func (q *LinkedQueue[T]) ContainsAll(collection collections.Collection[T]) bool { + return collections.ContainsAll[T](q, collection) +} + +func (q *LinkedQueue[T]) Add(element T) bool { + exception := q.Push(element) + exceptions.Print(exception) + return exception == nil +} + +func (q *LinkedQueue[T]) Remove(element T) exceptions.Exception { + return collections.Remove[T](q, element) +} + +func (q *LinkedQueue[T]) AddAll(collection collections.Collection[T]) bool { + return collections.AddAll[T](q, collection) +} + +func (q *LinkedQueue[T]) RemoveAll(collection collections.Collection[T]) bool { + return collections.RemoveAll[T](q, collection) +} + +func (q *LinkedQueue[T]) RetainAll(collection collections.Collection[T]) bool { + return collections.RetainAll[T](q, collection) +} + +func (q *LinkedQueue[T]) Clear() { + q.head = nil + q.end = nil + q.size.Store(0) +} + +func (i *linkedQueueIterator[T]) HasNext() bool { + for i.node != nil && i.node.deleted { + i.node = i.node.next + } + return i.node != nil +} + +func (i *linkedQueueIterator[T]) Next() (T, exceptions.Exception) { + value, err := i.Get() + i.node = i.node.next + for i.node != nil && i.node.deleted { + i.node = i.node.next + } + return value, err +} + +func (i *linkedQueueIterator[T]) Get() (T, exceptions.Exception) { + return i.node.value, nil +} + +func (i *linkedQueueIterator[T]) Set(value T) exceptions.Exception { + i.node.value = value + return nil +} + +func (i *linkedQueueIterator[T]) Remove() exceptions.Exception { + _, err := i.RemoveAndGet() + return err +} + +func (i *linkedQueueIterator[T]) RemoveAndGet() (T, exceptions.Exception) { + if i.node == nil { + return lang.Nil[T](), nil + } + load := i.node + load.deleted = true + i.queue.size.Add(-1) + i.queue.deleted.Add(1) + i.queue.CleanDeleted() + i.node = load.next + return load.value, nil +} diff --git a/collections/ConcurrentLinkedQueue_test.go b/concurrent/LinkedQueue_test.go similarity index 82% rename from collections/ConcurrentLinkedQueue_test.go rename to concurrent/LinkedQueue_test.go index 8259db1..0ad66c5 100644 --- a/collections/ConcurrentLinkedQueue_test.go +++ b/concurrent/LinkedQueue_test.go @@ -1,13 +1,14 @@ -package collections +package concurrent import ( "fmt" - "github.com/tursom/GoCollections/exceptions" - "github.com/tursom/GoCollections/lang" "sync" "testing" "time" "unsafe" + + "github.com/tursom/GoCollections/exceptions" + "github.com/tursom/GoCollections/lang" ) type data struct { @@ -21,12 +22,12 @@ func (d *data) String() string { } func TestConcurrentLinkedQueue_NodeSize(t *testing.T) { - fmt.Println(unsafe.Alignof(concurrentLinkedStackNode[*data]{})) - fmt.Println(unsafe.Sizeof(concurrentLinkedStackNode[*data]{})) + fmt.Println(unsafe.Alignof(linkedStackNode[*data]{})) + fmt.Println(unsafe.Sizeof(linkedStackNode[*data]{})) } func TestConcurrentLinkedQueue_Push(t *testing.T) { - queue := NewConcurrentLinkedQueue[*data]() + queue := NewLinkedQueue[*data]() cond := sync.WaitGroup{} cond.Add(1) for i := 0; i < 10; i++ { @@ -46,11 +47,11 @@ func TestConcurrentLinkedQueue_Push(t *testing.T) { func TestConcurrentLinkedQueue_ThreadSafe(t *testing.T) { times := 400000 - queue := NewConcurrentLinkedQueue[*data]() + queue := NewLinkedQueue[*data]() for i := 0; i < 100; i++ { id := i go func() { - //nodes := make([]ConcurrentLinkedQueueNode[*data], 0) + //nodes := make([]QueueNode[*data], 0) for j := 0; j < times; j++ { _ = queue.Offer(&data{id: id, index: j}) //node, _ := queue.OfferAndGetNode(&data{id: id, index: j}) @@ -81,8 +82,8 @@ func TestConcurrentLinkedQueue_ThreadSafe(t *testing.T) { } func Test_concurrentLinkedQueueIterator_Remove(t *testing.T) { - queue := NewConcurrentLinkedQueue[lang.Int]() - nodes := make([]ConcurrentLinkedQueueNode[lang.Int], 0) + queue := NewLinkedQueue[lang.Int]() + nodes := make([]QueueNode[lang.Int], 0) for i := 0; i < 1000; i++ { node, _ := queue.OfferAndGetNode(lang.Int(i)) nodes = append(nodes, node) diff --git a/concurrent/LinkedStack.go b/concurrent/LinkedStack.go new file mode 100644 index 0000000..6c5310d --- /dev/null +++ b/concurrent/LinkedStack.go @@ -0,0 +1,175 @@ +package concurrent + +import ( + "github.com/tursom/GoCollections/collections" + "github.com/tursom/GoCollections/exceptions" + "github.com/tursom/GoCollections/lang" + "github.com/tursom/GoCollections/lang/atomic" +) + +type ( + LinkedStack[T lang.Object] struct { + lang.BaseObject + size atomic.Int32 + deleted atomic.Int32 + head *linkedStackNode[T] + } + + linkedStackNode[T any] struct { + deleted bool + next *linkedStackNode[T] + value T + } + + linkedStackIterator[T lang.Object] struct { + node *linkedStackNode[T] + stack *LinkedStack[T] + } +) + +func (s *LinkedStack[T]) String() string { + return collections.String[T](s) +} + +func NewLinkedStack[T lang.Object]() *LinkedStack[T] { + return &LinkedStack[T]{} +} + +func (s *LinkedStack[T]) Iterator() collections.Iterator[T] { + return s.MutableIterator() +} + +func (s *LinkedStack[T]) Push(element T) exceptions.Exception { + s.push(element) + return nil +} + +func (s *LinkedStack[T]) PushAndGetNode(element T) collections.StackNode[T] { + return &linkedStackIterator[T]{ + node: s.push(element), + stack: s, + } +} + +func (s *LinkedStack[T]) push(element T) *linkedStackNode[T] { + newNode := &linkedStackNode[T]{value: element, next: s.head} + for !atomic.CompareAndSwapPointer(&s.head, newNode.next, newNode) { + newNode.next = s.head + } + s.size.Add(1) + return newNode +} + +func (s *LinkedStack[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 { + return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil) + } + + s.size.Add(-1) + return node.value, nil +} + +func (s *LinkedStack[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 + } + } +} + +func (s *LinkedStack[T]) Size() int { + return int(s.size.Load()) +} + +func (s *LinkedStack[T]) IsEmpty() bool { + return s.head == nil +} + +func (s *LinkedStack[T]) Contains(element T) bool { + return collections.Contains[T](s, element) +} + +func (s *LinkedStack[T]) ContainsAll(c collections.Collection[T]) bool { + return collections.ContainsAll[T](s, c) +} + +func (s *LinkedStack[T]) Add(element T) bool { + exception := s.Push(element) + exceptions.Print(exception) + return exception == nil +} + +func (s *LinkedStack[T]) Remove(element T) exceptions.Exception { + return collections.Remove[T](s, element) +} + +func (s *LinkedStack[T]) AddAll(c collections.Collection[T]) bool { + return collections.AddAll[T](s, c) +} + +func (s *LinkedStack[T]) RemoveAll(c collections.Collection[T]) bool { + return collections.RemoveAll[T](s, c) +} + +func (s *LinkedStack[T]) RetainAll(c collections.Collection[T]) bool { + return collections.RetainAll[T](s, c) +} + +func (s *LinkedStack[T]) Clear() { + s.head = nil + s.size.Store(0) +} + +func (s *LinkedStack[T]) MutableIterator() collections.MutableIterator[T] { + return &linkedStackIterator[T]{s.head, nil} +} + +func (i *linkedStackIterator[T]) HasNext() bool { + return i.node.next != nil +} + +func (i *linkedStackIterator[T]) Next() (T, exceptions.Exception) { + if i.node == nil { + return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil) + } + value := i.node.value + i.node = i.node.next + return value, nil +} + +func (i *linkedStackIterator[T]) Remove() exceptions.Exception { + if i.node == nil { + return exceptions.NewIndexOutOfBound("", nil) + } + i.node.deleted = true + i.node = i.node.next + i.stack.size.Add(-1) + i.stack.deleted.Add(1) + i.stack.CleanDeleted() + return nil +} + +func (i *linkedStackIterator[T]) Get() (T, exceptions.Exception) { + return i.node.value, nil +} + +func (i *linkedStackIterator[T]) Set(value T) exceptions.Exception { + i.node.value = value + return nil +} + +func (i *linkedStackIterator[T]) RemoveAndGet() (T, exceptions.Exception) { + i.node.deleted = true + return i.node.value, nil +} diff --git a/collections/LockedMutableList.go b/concurrent/LockedMutableList.go similarity index 73% rename from collections/LockedMutableList.go rename to concurrent/LockedMutableList.go index 56a4bc8..14104ff 100644 --- a/collections/LockedMutableList.go +++ b/concurrent/LockedMutableList.go @@ -1,24 +1,25 @@ -package collections +package concurrent import ( - "github.com/tursom/GoCollections/concurrent" + "sync" + + "github.com/tursom/GoCollections/collections" "github.com/tursom/GoCollections/exceptions" "github.com/tursom/GoCollections/lang" - "sync" ) type ( LockedMutableList[T lang.Object] struct { - list MutableList[T] - lock concurrent.RWLock + list collections.MutableList[T] + lock RWLock } lockedMutableListIterator[T lang.Object] struct { - iterator MutableIterator[T] - lock concurrent.RWLock + iterator collections.MutableIterator[T] + lock RWLock } ) -func MutableListWithLock[T lang.Object](list MutableList[T]) MutableList[T] { +func MutableListWithLock[T lang.Object](list collections.MutableList[T]) collections.MutableList[T] { return &LockedMutableList[T]{ list: list, lock: &sync.RWMutex{}, @@ -26,10 +27,10 @@ func MutableListWithLock[T lang.Object](list MutableList[T]) MutableList[T] { } func (l *LockedMutableList[T]) String() string { - return String[T](l) + return collections.String[T](l) } -func (l *LockedMutableList[T]) Iterator() Iterator[T] { +func (l *LockedMutableList[T]) Iterator() collections.Iterator[T] { return l.MutableIterator() } @@ -51,14 +52,14 @@ func (l *LockedMutableList[T]) Contains(element T) bool { return l.list.Contains(element) } -func (l *LockedMutableList[T]) ContainsAll(c Collection[T]) bool { +func (l *LockedMutableList[T]) ContainsAll(c collections.Collection[T]) bool { l.lock.RLock() defer l.lock.RUnlock() return l.list.ContainsAll(c) } -func (l *LockedMutableList[T]) MutableIterator() MutableIterator[T] { +func (l *LockedMutableList[T]) MutableIterator() collections.MutableIterator[T] { return &lockedMutableListIterator[T]{l.list.MutableIterator(), l.lock} } @@ -76,21 +77,21 @@ func (l *LockedMutableList[T]) Remove(element T) exceptions.Exception { return l.list.Remove(element) } -func (l *LockedMutableList[T]) AddAll(c Collection[T]) bool { +func (l *LockedMutableList[T]) AddAll(c collections.Collection[T]) bool { l.lock.Lock() defer l.lock.Unlock() return l.list.AddAll(c) } -func (l *LockedMutableList[T]) RemoveAll(c Collection[T]) bool { +func (l *LockedMutableList[T]) RemoveAll(c collections.Collection[T]) bool { l.lock.Lock() defer l.lock.Unlock() return l.list.RemoveAll(c) } -func (l *LockedMutableList[T]) RetainAll(c Collection[T]) bool { +func (l *LockedMutableList[T]) RetainAll(c collections.Collection[T]) bool { l.lock.Lock() defer l.lock.Unlock() @@ -111,7 +112,7 @@ func (l *LockedMutableList[T]) Get(index int) (T, exceptions.Exception) { return l.list.Get(index) } -func (l *LockedMutableList[T]) SubList(from, to int) List[T] { +func (l *LockedMutableList[T]) SubList(from, to int) collections.List[T] { return l.SubMutableList(from, to) } @@ -136,7 +137,7 @@ func (l *LockedMutableList[T]) RemoveAt(index int) exceptions.Exception { return l.list.RemoveAt(index) } -func (l *LockedMutableList[T]) SubMutableList(from, to int) MutableList[T] { +func (l *LockedMutableList[T]) SubMutableList(from, to int) collections.MutableList[T] { return &LockedMutableList[T]{l.list.SubMutableList(from, to), l.lock} } diff --git a/exceptions/Exception.go b/exceptions/Exception.go index 36ee4cf..db6d973 100644 --- a/exceptions/Exception.go +++ b/exceptions/Exception.go @@ -116,8 +116,8 @@ func PackagePanic(panic any, exceptionMessage string) Exception { } switch panic.(type) { case error: - return NewRuntimeException("", DefaultExceptionConfig().SetCause(panic)) + return NewRuntimeException(exceptionMessage, DefaultExceptionConfig().SetCause(panic)) default: - return NewRuntimeException("", DefaultExceptionConfig()) + return NewPackageException(panic, nil) } } diff --git a/exceptions/PackageException.go b/exceptions/PackageException.go index 39a3844..dd8a7af 100644 --- a/exceptions/PackageException.go +++ b/exceptions/PackageException.go @@ -33,12 +33,14 @@ func (p *PackageException) Err() any { func UnpackException(err any) any { for err != nil { - switch err.(type) { + switch e := err.(type) { case *PackageException: - err = err.(*PackageException).Err() - return err + return e.Err() case Exception: - err = err.(Exception).Cause() + err = e.Cause() + if err == nil { + return e + } default: return err }