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 } }