github.com/pawelgaczynski/gain@v0.4.0-alpha.0.20230821120126-41f1e60a18da/pkg/stack/stack_lf.go (about)

     1  // Copyright 2023 Paweł Gaczyński.
     2  // Copyright 2020 The golang.design Initiative authors.
     3  // All rights reserved. Use of this source code is governed
     4  // by a MIT license that can be found in the LICENSE file.
     5  //
     6  // Original source: https://github.com/golang-design/lockfree/blob/master/stack.go
     7  
     8  package stack
     9  
    10  import (
    11  	"sync/atomic"
    12  	"unsafe"
    13  )
    14  
    15  type node[T any] struct {
    16  	value T
    17  	next  unsafe.Pointer
    18  }
    19  
    20  type Stack[T any] struct {
    21  	top unsafe.Pointer
    22  	len uint64
    23  }
    24  
    25  // NewStack creates a new lock-free queue.
    26  func NewLockFreeStack[T any]() *Stack[T] {
    27  	return &Stack[T]{}
    28  }
    29  
    30  func getZero[T any]() T {
    31  	var result T
    32  
    33  	return result
    34  }
    35  
    36  // Pop pops value from the top of the stack.
    37  func (s *Stack[T]) Pop() T {
    38  	var (
    39  		top, next unsafe.Pointer
    40  		item      *node[T]
    41  	)
    42  
    43  	for {
    44  		top = atomic.LoadPointer(&s.top)
    45  		if top == nil {
    46  			return getZero[T]()
    47  		}
    48  		item = (*node[T])(top)
    49  		next = atomic.LoadPointer(&item.next)
    50  
    51  		if atomic.CompareAndSwapPointer(&s.top, top, next) {
    52  			atomic.AddUint64(&s.len, ^uint64(0))
    53  
    54  			return item.value
    55  		}
    56  	}
    57  }
    58  
    59  // Push pushes a value on top of the stack.
    60  func (s *Stack[T]) Push(v T) {
    61  	var (
    62  		item = node[T]{value: v}
    63  		top  unsafe.Pointer
    64  	)
    65  
    66  	for {
    67  		top = atomic.LoadPointer(&s.top)
    68  		item.next = top
    69  
    70  		if atomic.CompareAndSwapPointer(&s.top, top, unsafe.Pointer(&item)) {
    71  			atomic.AddUint64(&s.len, 1)
    72  
    73  			return
    74  		}
    75  	}
    76  }