81 lines
1.6 KiB
Go
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))
|
|
}
|