fckeuspy-go/vendor/fyne.io/fyne/v2/internal/async/queue_canvasobject.go

91 lines
2.0 KiB
Go

package async
import (
"sync/atomic"
"fyne.io/fyne/v2"
)
// CanvasObjectQueue implements lock-free FIFO freelist based queue.
//
// Reference: https://dl.acm.org/citation.cfm?doid=248052.248106
type CanvasObjectQueue struct {
head atomic.Pointer[itemCanvasObject]
tail atomic.Pointer[itemCanvasObject]
len atomic.Uint64
}
// NewCanvasObjectQueue returns a queue for caching values.
func NewCanvasObjectQueue() *CanvasObjectQueue {
head := &itemCanvasObject{}
queue := &CanvasObjectQueue{}
queue.head.Store(head)
queue.tail.Store(head)
return queue
}
type itemCanvasObject struct {
next atomic.Pointer[itemCanvasObject]
v fyne.CanvasObject
}
var itemCanvasObjectPool = Pool[*itemCanvasObject]{
New: func() *itemCanvasObject { return &itemCanvasObject{} },
}
// In puts the given value at the tail of the queue.
func (q *CanvasObjectQueue) In(v fyne.CanvasObject) {
i := itemCanvasObjectPool.Get()
i.next.Store(nil)
i.v = v
var last, lastnext *itemCanvasObject
for {
last = q.tail.Load()
lastnext = last.next.Load()
if q.tail.Load() == last {
if lastnext == nil {
if last.next.CompareAndSwap(lastnext, i) {
q.tail.CompareAndSwap(last, i)
q.len.Add(1)
return
}
} else {
q.tail.CompareAndSwap(last, lastnext)
}
}
}
}
// Out removes and returns the value at the head of the queue.
// It returns nil if the queue is empty.
func (q *CanvasObjectQueue) Out() fyne.CanvasObject {
var first, last, firstnext *itemCanvasObject
for {
first = q.head.Load()
last = q.tail.Load()
firstnext = first.next.Load()
if first == q.head.Load() {
if first == last {
if firstnext == nil {
return nil
}
q.tail.CompareAndSwap(last, firstnext)
} else {
v := firstnext.v
if q.head.CompareAndSwap(first, firstnext) {
q.len.Add(^uint64(0))
itemCanvasObjectPool.Put(first)
return v
}
}
}
}
}
// Len returns the length of the queue.
func (q *CanvasObjectQueue) Len() uint64 {
return q.len.Load()
}