github.com/tursom/GoCollections@v0.3.10/concurrent/collections/ConcurrentLinkedQueue.go (about) 1 /* 2 * Copyright (c) 2022 tursom. All rights reserved. 3 * Use of this source code is governed by a GPL-3 4 * license that can be found in the LICENSE file. 5 */ 6 7 package collections 8 9 import ( 10 "github.com/tursom/GoCollections/collections" 11 "github.com/tursom/GoCollections/exceptions" 12 "github.com/tursom/GoCollections/lang" 13 "github.com/tursom/GoCollections/lang/atomic" 14 ) 15 16 type ( 17 // ConcurrentLinkedQueue FIFO data struct, impl by linked list. 18 // in order to reuse ConcurrentLinkedStack, element will offer on queue's end, and poll on queue's head. 19 ConcurrentLinkedQueue[T lang.Object] struct { 20 lang.BaseObject 21 ConcurrentLinkedStack[T] 22 end *linkedStackNode[T] 23 } 24 25 linkedQueueIterator[T lang.Object] struct { 26 node *linkedStackNode[T] 27 queue *ConcurrentLinkedQueue[T] 28 } 29 ) 30 31 func (q *ConcurrentLinkedQueue[T]) String() string { 32 return collections.String[T](q) 33 } 34 35 func NewLinkedQueue[T lang.Object]() *ConcurrentLinkedQueue[T] { 36 return &ConcurrentLinkedQueue[T]{} 37 } 38 39 func (q *ConcurrentLinkedQueue[T]) Iterator() collections.Iterator[T] { 40 return q.MutableIterator() 41 } 42 43 func (q *ConcurrentLinkedQueue[T]) Offer(element T) exceptions.Exception { 44 _, err := q.offerAndGetNode(element) 45 return err 46 } 47 48 func (q *ConcurrentLinkedQueue[T]) OfferAndGetNode(element T) (collections.QueueNode[T], exceptions.Exception) { 49 newNode, err := q.offerAndGetNode(element) 50 if err != nil { 51 return nil, err 52 } 53 return &linkedQueueIterator[T]{queue: q, node: newNode}, nil 54 } 55 56 // offerAndGetNode offer an element on q.end 57 func (q *ConcurrentLinkedQueue[T]) offerAndGetNode(element T) (*linkedStackNode[T], exceptions.Exception) { 58 newNode := &linkedStackNode[T]{value: element} 59 q.size.Add(1) 60 61 var next **linkedStackNode[T] 62 ref := q.end 63 64 // bug fix 65 // buf caused by delete q.end but not update it's reference 66 for ref != nil && ref.deleted { 67 ref = ref.next 68 } 69 70 // q.end is nil when queue just created 71 switch { 72 case ref == nil: 73 next = &q.head 74 default: 75 next = &ref.next 76 } 77 for !atomic.CompareAndSwapPointer(next, nil, newNode) { 78 if ref == nil || ref.next == nil { 79 next = &q.head 80 ref = q.head 81 } else { 82 for ref.next != nil { 83 ref = ref.next 84 } 85 next = &ref.next 86 } 87 88 // bug fix 89 // q.head may be deleted on async env 90 for *next != nil { 91 next = &(*next).next 92 } 93 } 94 q.end = newNode 95 return newNode, nil 96 } 97 98 func (q *ConcurrentLinkedQueue[T]) Poll() (T, exceptions.Exception) { 99 return q.Pop() 100 } 101 102 func (q *ConcurrentLinkedQueue[T]) MutableIterator() collections.MutableIterator[T] { 103 return &linkedQueueIterator[T]{queue: q, node: q.head} 104 } 105 106 // Size size of queue 107 // it may not correct on concurrent environment, to check it's empty, use func IsEmpty 108 func (q *ConcurrentLinkedQueue[T]) Size() int { 109 return int(q.size.Load()) 110 } 111 112 func (q *ConcurrentLinkedQueue[T]) IsEmpty() bool { 113 return q.head == nil 114 } 115 116 func (q *ConcurrentLinkedQueue[T]) Contains(element T) bool { 117 return collections.Contains[T](q, element) 118 } 119 120 func (q *ConcurrentLinkedQueue[T]) ContainsAll(collection collections.Collection[T]) bool { 121 return collections.ContainsAll[T](q, collection) 122 } 123 124 func (q *ConcurrentLinkedQueue[T]) Add(element T) bool { 125 exception := q.Push(element) 126 exceptions.Print(exception) 127 return exception == nil 128 } 129 130 func (q *ConcurrentLinkedQueue[T]) Remove(element T) exceptions.Exception { 131 return collections.Remove[T](q, element) 132 } 133 134 func (q *ConcurrentLinkedQueue[T]) AddAll(collection collections.Collection[T]) bool { 135 return collections.AddAll[T](q, collection) 136 } 137 138 func (q *ConcurrentLinkedQueue[T]) RemoveAll(collection collections.Collection[T]) bool { 139 return collections.RemoveAll[T](q, collection) 140 } 141 142 func (q *ConcurrentLinkedQueue[T]) RetainAll(collection collections.Collection[T]) bool { 143 return collections.RetainAll[T](q, collection) 144 } 145 146 func (q *ConcurrentLinkedQueue[T]) Clear() { 147 q.head = nil 148 q.end = nil 149 q.size.Store(0) 150 } 151 152 func (i *linkedQueueIterator[T]) HasNext() bool { 153 for i.node != nil && i.node.deleted { 154 i.node = i.node.next 155 } 156 return i.node != nil 157 } 158 159 func (i *linkedQueueIterator[T]) Next() (T, exceptions.Exception) { 160 value, err := i.Get() 161 i.node = i.node.next 162 for i.node != nil && i.node.deleted { 163 i.node = i.node.next 164 } 165 return value, err 166 } 167 168 func (i *linkedQueueIterator[T]) Get() (T, exceptions.Exception) { 169 return i.node.value, nil 170 } 171 172 func (i *linkedQueueIterator[T]) Set(value T) exceptions.Exception { 173 i.node.value = value 174 return nil 175 } 176 177 func (i *linkedQueueIterator[T]) Remove() exceptions.Exception { 178 _, err := i.RemoveAndGet() 179 return err 180 } 181 182 func (i *linkedQueueIterator[T]) RemoveAndGet() (T, exceptions.Exception) { 183 if i.node == nil { 184 return lang.Nil[T](), nil 185 } 186 load := i.node 187 load.deleted = true 188 i.queue.size.Add(-1) 189 i.queue.deleted.Add(1) 190 i.queue.CleanDeleted() 191 i.node = load.next 192 return load.value, nil 193 }