edge/pkg/storage/driver/cache/lfu/list.go

163 lines
2.5 KiB
Go

package lfu
import (
"sync/atomic"
)
type List[T any] struct {
root atomic.Pointer[Element[T]]
len atomic.Int32
}
func (l *List[T]) First() *Element[T] {
if l.len.Load() == 0 {
return nil
}
root := l.root.Load()
return root.next.Load()
}
func (l *List[T]) Last() *Element[T] {
if l.len.Load() == 0 {
return nil
}
root := l.root.Load()
return root.prev.Load()
}
func (l *List[T]) PushFront(v T) *Element[T] {
root := l.root.Load()
return l.InsertValueAfter(v, root)
}
func (l *List[T]) PushBack(v T) *Element[T] {
root := l.root.Load()
return l.InsertValueAfter(v, root)
}
func (l *List[T]) Remove(e *Element[T]) {
if e.list.Load() == l {
l.remove(e)
}
}
func (l *List[T]) Len() int {
return int(l.len.Load())
}
func (l *List[T]) insertAfter(e *Element[T], at *Element[T]) *Element[T] {
e.prev.Store(at)
e.next.Store(at.next.Load())
prev := e.prev.Load()
if prev != nil {
prev.next.Store(e)
}
next := e.next.Load()
if next != nil {
next.prev.Store(e)
}
e.list.Store(l)
l.len.Add(1)
return e
}
func (l *List[T]) InsertValueAfter(v T, at *Element[T]) *Element[T] {
e := NewElement[T](v)
return l.insertAfter(e, at)
}
func (l *List[T]) remove(e *Element[T]) {
prev := e.prev.Load()
if prev != nil {
prev.next.Store(e.next.Load())
}
next := e.next.Load()
if next != nil {
next.prev.Store(e.prev.Load())
}
e.next.Store(nil)
e.prev.Store(nil)
e.list.Store(nil)
l.len.Add(-1)
}
func NewList[T any]() *List[T] {
root := NewElement(*new(T))
root.next.Store(root)
root.prev.Store(root)
list := &List[T]{}
root.list.Store(list)
atomic := atomic.Pointer[Element[T]]{}
atomic.Store(root)
list.root = atomic
return list
}
type Element[T any] struct {
prev atomic.Pointer[Element[T]]
next atomic.Pointer[Element[T]]
list atomic.Pointer[List[T]]
value atomic.Pointer[T]
}
func (e *Element[T]) Next() *Element[T] {
l := e.list.Load()
if l == nil {
return nil
}
n := e.next.Load()
r := l.root.Load()
if n == r {
return nil
}
return n
}
func (e *Element[T]) Prev() *Element[T] {
l := e.list.Load()
if l == nil {
return nil
}
p := e.prev.Load()
r := l.root.Load()
if p == r {
return nil
}
return p
}
func (e *Element[T]) Value() T {
return *e.value.Load()
}
func NewElement[T any](v T) *Element[T] {
value := atomic.Pointer[T]{}
value.Store(&v)
return &Element[T]{
value: value,
prev: atomic.Pointer[Element[T]]{},
next: atomic.Pointer[Element[T]]{},
list: atomic.Pointer[List[T]]{},
}
}