Skip to content

Instantly share code, notes, and snippets.

@cvzi
Created November 19, 2019 20:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cvzi/ede59f1c37e9674630b3e62649c24cfb to your computer and use it in GitHub Desktop.
Save cvzi/ede59f1c37e9674630b3e62649c24cfb to your computer and use it in GitHub Desktop.
A LRU "least recently used" cache in golang
// A LRU "least recently used" cache
package lru
import (
"container/list"
"fmt"
"sync"
)
// Cache represents a LRU consisting of a map as an index and a list to hold data and indicate the last recently used queue.
// The zero value cannot be used.
// TODO make zero value usable
type Cache struct {
max int
index map[interface{}]*list.Element
*list.List
sync.RWMutex
}
// listData is the list payload
type listData struct {
key interface{}
value interface{}
}
// New returns an empty cache with capacity max
func New(max int) *Cache {
return &Cache{
max: max,
index: make(map[interface{}]*list.Element, max+1),
List: list.New(),
}
}
// Get returns element or nil, ok is true if the key x is present in the cache and
// sets the element as the last recently used.
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
c.RLock()
defer c.RUnlock()
listElement, ok := c.index[key]
if ok {
c.MoveToFront(listElement)
return listElement.Value.(*listData).value, true
}
return nil, false
}
// Set inserts or updates the value of key and
// sets the element as the last recently used.
func (c *Cache) Set(key interface{}, value interface{}) {
c.Lock()
defer c.Unlock()
listElement, ok := c.index[key]
if ok {
c.MoveToFront(listElement)
listElement.Value.(*listData).value = value
return
}
listElement = c.PushFront(&listData{key: key, value: value})
c.index[key] = listElement
if c.max != 0 && c.Len() > c.max {
lastElement := c.Back()
lastKey := lastElement.Value.(*listData).key
c.Remove(lastElement)
delete(c.index, lastKey)
}
}
func main() {
fmt.Println("LRU:")
x := New(3)
x.Set("test1", 0)
x.Set("test1", 1)
x.Set("test2", 2)
x.Set("test3", 3)
x.Set("test4", 4)
x.Set("test5", 5)
fmt.Println(x.Get("test1"))
fmt.Println(x.Get("test2"))
fmt.Println(x.Get("test3"))
fmt.Println(x.Get("test3"))
x.Set("test6", 6)
fmt.Printf("List:")
for temp := x.List.Front(); temp != nil; temp = temp.Next() {
fmt.Println(temp.Value)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment