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  }