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 }