initial commit

Golang implementation of the [Sieve cache algorithm][1].

[1]: https://cachemon.github.io/SIEVE-website/blog/2023/12/17/sieve-is-simpler-than-lru/
main
William Perron 10 months ago
commit 511bdc61c5
No known key found for this signature in database
GPG Key ID: D1815C43C9BA3DE1

@ -0,0 +1,3 @@
module go.wperron.io/sieve
go 1.21.0

@ -0,0 +1,98 @@
package sieve
type node struct {
value string
visited bool
prev, next *node
}
type SieveCache struct {
cap, size int
cache map[string]*node
head, tail, hand *node
}
func NewCache(cap int) *SieveCache {
return &SieveCache{
cap: cap,
size: 0,
cache: make(map[string]*node, cap),
}
}
// Access touches the item `v` in the cache
func (sc *SieveCache) Access(v string) {
if n, ok := sc.cache[v]; ok {
n.visited = true
} else {
if sc.size == sc.cap {
sc.evict()
}
newNode := &node{value: v}
sc.addToHead(newNode)
sc.cache[v] = newNode
sc.size += 1
newNode.visited = false
}
}
// Range iterates over the values in the cache, stops the iteration if the
// closure returns false.
func (sc *SieveCache) Range(f func(v string) bool) {
current := sc.head
keepGoing := true
for current != nil && keepGoing {
keepGoing = f(current.value)
current = current.next
}
}
func (sc *SieveCache) evict() {
var obj *node
if sc.hand != nil {
obj = sc.hand
} else {
obj = sc.tail
}
for obj != nil && obj.visited {
obj.visited = false
if obj.prev != nil {
obj = obj.prev
} else {
obj = sc.tail
}
}
sc.hand = obj.prev
delete(sc.cache, obj.value)
sc.removeNode(obj)
sc.size -= 1
}
func (sc *SieveCache) removeNode(n *node) {
if n.prev != nil {
n.prev.next = n.next
} else {
sc.head = n.next
}
if n.next != nil {
n.next.prev = n.prev
} else {
sc.tail = n.prev
}
}
func (sc *SieveCache) addToHead(n *node) {
n.next = sc.head
n.prev = nil
if sc.head != nil {
sc.head.prev = n
}
sc.head = n
if sc.tail == nil {
sc.tail = n
}
}

@ -0,0 +1,18 @@
package sieve
import "testing"
func TestSieveCache(t *testing.T) {
cache := NewCache(3)
cache.Access("A")
cache.Access("B")
cache.Access("C")
cache.Access("D")
cache.Access("B")
cache.Access("E")
cache.Access("A")
cache.Range(func(v string) bool {
t.Log(v)
return true
})
}
Loading…
Cancel
Save