edge/pkg/storage/driver/cache/lfu/list.go
William Petit a276b92a03
All checks were successful
arcad/edge/pipeline/head This commit looks good
arcad/edge/pipeline/pr-master This commit looks good
feat: implement lfu based cache strategy
2024-01-10 13:16:52 +01:00

204 lines
3.1 KiB
Go

package lfu
import (
"sync/atomic"
)
type List[T any] struct {
root *Element[T]
len atomic.Int32
sync *Synchronizer[*Element[T]]
}
func (l *List[T]) First() *Element[T] {
if l.Len() == 0 {
return nil
}
var next *Element[T]
l.sync.ReadTx(l.root, func(upgrade func(func())) error {
next = l.root.next
return nil
})
return next
}
func (l *List[T]) Last() *Element[T] {
if l.Len() == 0 {
return nil
}
var prev *Element[T]
l.sync.ReadTx(l.root, func(upgrade func(func())) error {
prev = l.root.prev
return nil
})
return prev
}
func (l *List[T]) Prev(e *Element[T]) *Element[T] {
var prev *Element[T]
l.sync.ReadTx(e, func(upgrade func(func())) error {
prev = e.prev
return nil
})
return prev
}
func (l *List[T]) Next(e *Element[T]) *Element[T] {
var next *Element[T]
l.sync.ReadTx(e, func(upgrade func(func())) error {
next = e.next
return nil
})
return next
}
func (l *List[T]) Value(e *Element[T]) T {
var value T
l.sync.ReadTx(e, func(upgrade func(func())) error {
value = e.value
return nil
})
return value
}
func (l *List[T]) PushFront(v T) *Element[T] {
return l.InsertValueAfter(v, l.root)
}
func (l *List[T]) PushBack(v T) *Element[T] {
return l.InsertValueAfter(v, l.root)
}
func (l *List[T]) Remove(e *Element[T]) {
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] {
l.sync.ReadTx(e, func(upgrade func(fn func())) error {
var next *Element[T]
l.sync.ReadTx(at, func(upgrade func(func())) error {
next = at.next
return nil
})
upgrade(func() {
e.prev = at
e.next = next
e.list = l
})
if e.prev != nil {
l.sync.WriteTx(e.prev, func() error {
e.prev.next = e
return nil
})
}
if e.next != nil {
l.sync.WriteTx(e.next, func() error {
e.next.prev = e
return nil
})
}
return nil
})
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]) {
if e == nil && e == l.root {
return
}
l.sync.ReadTx(e, func(upgrade func(fn func())) error {
if e.prev != nil {
if e.prev == e {
upgrade(func() {
e.prev.next = e.next
})
} else {
l.sync.WriteTx(e.prev, func() error {
e.prev.next = e.next
return nil
})
}
}
if e.next != nil {
if e.next == e {
upgrade(func() {
e.next.prev = e.prev
})
} else {
l.sync.WriteTx(e.next, func() error {
e.next.prev = e.prev
return nil
})
}
}
upgrade(func() {
e.next = nil
e.prev = nil
e.list = nil
})
return nil
})
l.sync.Remove(e)
l.len.Add(-1)
}
func NewList[T any]() *List[T] {
root := NewElement(*new(T))
root.next = root
root.prev = root
list := &List[T]{
sync: NewSynchronizer[*Element[T]](),
}
root.list = list
list.root = root
return list
}
type Element[T any] struct {
prev *Element[T]
next *Element[T]
list *List[T]
value T
}
func NewElement[T any](v T) *Element[T] {
element := &Element[T]{
prev: nil,
next: nil,
list: nil,
value: v,
}
return element
}