You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
1.8 KiB
108 lines
1.8 KiB
package sieve
|
|
|
|
type node struct {
|
|
key string
|
|
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) Put(k, v string) {
|
|
if n, ok := sc.cache[k]; ok {
|
|
n.visited = true
|
|
} else {
|
|
if sc.size == sc.cap {
|
|
sc.evict()
|
|
}
|
|
|
|
newNode := &node{key: k, value: v}
|
|
sc.addToHead(newNode)
|
|
sc.cache[v] = newNode
|
|
sc.size += 1
|
|
newNode.visited = false
|
|
}
|
|
}
|
|
|
|
func (sc *SieveCache) Get(k string) string {
|
|
if n, ok := sc.cache[k]; ok {
|
|
n.visited = true
|
|
return n.value
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Range iterates over the values in the cache, stops the iteration if the
|
|
// closure returns false.
|
|
func (sc *SieveCache) Range(f func(k, v string) bool) {
|
|
current := sc.head
|
|
keepGoing := true
|
|
for current != nil && keepGoing {
|
|
keepGoing = f(current.key, 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
|
|
}
|
|
}
|