alifo/LIFO.go
2019-09-25 16:46:31 +03:30

81 lines
1.6 KiB
Go

package alifo
import (
"sync/atomic"
"unsafe"
)
//LIFO represnts an LIFO
type LIFO struct {
head unsafe.Pointer
count uint32
}
// Push adds a new item to end of List
func (l *LIFO) Count() uint32 {
return atomic.LoadUint32(&l.count)
}
func (l *LIFO) Push(data interface{}) uint32 {
if data == nil {
panic("LIFO: insert nil data")
}
if l == nil {
l = &LIFO{}
}
if atomic.CompareAndSwapPointer(&l.head, nil, unsafe.Pointer(&Item{Data: data})) {
return atomic.AddUint32(&l.count, 1)
}
last := (*Item)(l.head)
for atomic.CompareAndSwapPointer(&last.next, nil, unsafe.Pointer(&Item{Data: data})) == false {
last = (*Item)(last.next)
continue
}
return atomic.AddUint32(&l.count, 1)
}
//Pop removes the first item in the list
func (l *LIFO) Pop() uint32 {
if l.head == nil {
return 0
}
atomic.StorePointer(&l.head, l.Head().next)
return atomic.AddUint32(&l.count, ^uint32(0))
}
func (l *LIFO) SafePop(it *Item) (uint32, bool) {
if l.head == nil {
return 0, false
}
if atomic.CompareAndSwapPointer(&l.head, unsafe.Pointer(it), l.Head().next) {
return atomic.AddUint32(&l.count, ^uint32(0)), true
}
return l.Count(), false
}
//xxx
func (l *LIFO) Skip(data interface{}) bool {
if l.head == nil {
return false
}
if l.Head().Data == data {
l.Pop()
atomic.AddUint32(&l.count, ^uint32(0))
return true
}
pre := l.Head()
for it := l.Head().Next(); it != nil; it = it.Next() {
if it.Data == data {
pre.SkipNext()
atomic.AddUint32(&l.count, ^uint32(0))
return true
}
pre = it
}
return false
}
//Head returns the first item that
func (l *LIFO) Head() *Item {
return (*Item)(atomic.LoadPointer(&l.head))
}