github.com/GoWebProd/gip@v0.0.0-20230623090727-b60d41d5d320/stack/stack.go (about) 1 package stack 2 3 import ( 4 "runtime" 5 "sync/atomic" 6 "unsafe" 7 8 "github.com/GoWebProd/gip/allocator" 9 ) 10 11 type node[T any] struct { 12 next uintptr 13 data T 14 } 15 16 type Stack[T any] uintptr 17 18 func (head *Stack[T]) Init() { 19 runtime.SetFinalizer(head, func(head *Stack[T]) { 20 for { 21 _, ok := head.Pop() 22 if !ok { 23 break 24 } 25 } 26 }) 27 } 28 29 func (head *Stack[T]) Push(v T) { 30 node := allocator.AllocObject[node[T]]() 31 node.data = v 32 new := uintptr(unsafe.Pointer(node)) 33 34 for { 35 old := atomic.LoadUintptr((*uintptr)(head)) 36 node.next = old 37 38 if atomic.CompareAndSwapUintptr((*uintptr)(head), old, new) { 39 break 40 } 41 } 42 } 43 44 func (head *Stack[T]) Pop() (T, bool) { 45 var v T 46 47 for { 48 old := atomic.LoadUintptr((*uintptr)(head)) 49 if old == 0 { 50 return v, false 51 } 52 53 node := (*node[T])(unsafe.Pointer(old)) 54 next := atomic.LoadUintptr(&node.next) 55 56 if atomic.CompareAndSwapUintptr((*uintptr)(head), old, next) { 57 allocator.FreeObject(node) 58 59 return node.data, true 60 } 61 } 62 }