| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package cache provides methods for creating and using a cache. |
| package cache |
| |
| import "container/list" |
| |
| // A Key may be any value that is comparable. |
| type Key interface{} |
| |
| // Cache is the interface for cache. |
| type Cache interface { |
| // Adds a value to the cache. |
| Add(key Key, value interface{}) interface{} |
| |
| // Returns key's value from the cache. |
| Get(key Key) (interface{}, bool) |
| |
| // Checks if a key exists in cache. |
| Contains(key Key) bool |
| |
| // Removes a key from the cache. |
| Remove(key Key) interface{} |
| |
| // Returns the number of items in the cache. |
| Len() int |
| |
| // Clears all cache entries. |
| Clear() |
| } |
| |
| // LRUCache is a simple LRU cache. |
| type LRUCache struct { |
| // Size is the maximum number of entries before an item is evicted. |
| // Zero means no limit on the number of entries. |
| Size uint |
| |
| ll *list.List |
| cache map[interface{}]*list.Element |
| } |
| |
| type entry struct { |
| key Key |
| value interface{} |
| } |
| |
| // Add adds a value to the cache and updates the "recently used"-ness of the key. |
| func (c *LRUCache) Add(key Key, value interface{}) interface{} { |
| if c.cache == nil { |
| c.cache = make(map[interface{}]*list.Element) |
| c.ll = list.New() |
| } |
| if e, ok := c.cache[key]; ok { |
| c.ll.MoveToFront(e) |
| value, e.Value.(*entry).value = e.Value.(*entry).value, value |
| return value |
| } |
| e := c.ll.PushFront(&entry{key, value}) |
| c.cache[key] = e |
| if c.Size != 0 && uint(c.ll.Len()) > c.Size { |
| v := c.ll.Remove(c.ll.Back()) |
| delete(c.cache, v.(*entry).key) |
| } |
| return nil |
| } |
| |
| // Get returns key's value from the cache and updates the "recently used"-ness. |
| func (c *LRUCache) Get(key Key) (interface{}, bool) { |
| if c.cache == nil { |
| return nil, false |
| } |
| if e, ok := c.cache[key]; ok { |
| c.ll.MoveToFront(e) |
| return e.Value.(*entry).value, true |
| } |
| return nil, false |
| } |
| |
| // Contains checks if a key exists in cache without updating the recent-ness. |
| func (c *LRUCache) Contains(key Key) bool { |
| if c.cache == nil { |
| return false |
| } |
| _, ok := c.cache[key] |
| return ok |
| } |
| |
| // Remove removes a key from the cache. |
| func (c *LRUCache) Remove(key Key) interface{} { |
| if c.cache == nil { |
| return nil |
| } |
| if e, ok := c.cache[key]; ok { |
| c.ll.Remove(e) |
| delete(c.cache, key) |
| return e.Value.(*entry).value |
| } |
| return nil |
| } |
| |
| // Len returns the number of items in the cache. |
| func (c *LRUCache) Len() int { |
| if c.cache == nil { |
| return 0 |
| } |
| return c.ll.Len() |
| } |
| |
| // Clear clears all cache entries. |
| func (c *LRUCache) Clear() { |
| c.ll = nil |
| c.cache = nil |
| } |