github.com/GoWebProd/gip@v0.0.0-20230623090727-b60d41d5d320/queue/queue.go (about) 1 package queue 2 3 import ( 4 "sync/atomic" 5 "unsafe" 6 ) 7 8 type node[T any] struct { 9 value *T 10 next *node[T] 11 } 12 13 type Queue[T any] struct { 14 dummy *node[T] 15 tail *node[T] 16 } 17 18 func New[T any]() Queue[T] { 19 node := &node[T]{} 20 21 return Queue[T]{ 22 dummy: node, 23 tail: node, 24 } 25 } 26 27 func (q *Queue[T]) Put(v *T) { 28 var oldTail, oldTailNext *node[T] 29 30 newNode := &node[T]{ 31 value: v, 32 } 33 newNodeAdded := false 34 35 for !newNodeAdded { 36 oldTail = q.tail 37 oldTailNext = oldTail.next 38 39 if q.tail != oldTail { 40 continue 41 } 42 43 if oldTailNext != nil { 44 atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&q.tail)), unsafe.Pointer(oldTail), unsafe.Pointer(oldTailNext)) 45 continue 46 } 47 48 newNodeAdded = atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&oldTail.next)), unsafe.Pointer(oldTailNext), unsafe.Pointer(newNode)) 49 } 50 51 atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&q.tail)), unsafe.Pointer(oldTail), unsafe.Pointer(newNode)) 52 } 53 54 func (q *Queue[T]) Take() (*T, bool) { 55 var ( 56 temp *T 57 oldDummy, oldHead *node[T] 58 ) 59 60 removed := false 61 62 for !removed { 63 oldDummy = q.dummy 64 oldHead = oldDummy.next 65 oldTail := q.tail 66 67 if q.dummy != oldDummy { 68 continue 69 } 70 71 if oldHead == nil { 72 return nil, false 73 } 74 75 if oldTail == oldDummy { 76 atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&q.tail)), unsafe.Pointer(oldTail), unsafe.Pointer(oldHead)) 77 continue 78 } 79 80 temp = oldHead.value 81 removed = atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&q.dummy)), unsafe.Pointer(oldDummy), unsafe.Pointer(oldHead)) 82 } 83 84 return temp, true 85 }