golang.org/x/build@v0.0.0-20240506185731-218518f32b70/internal/lru/cache.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package lru implements an LRU cache. 6 package lru 7 8 import ( 9 "container/list" 10 "sync" 11 ) 12 13 // Cache is an LRU cache, safe for concurrent access. 14 type Cache struct { 15 maxEntries int 16 17 mu sync.Mutex 18 ll *list.List 19 cache map[interface{}]*list.Element 20 } 21 22 // *entry is the type stored in each *list.Element. 23 type entry struct { 24 key, value interface{} 25 } 26 27 // New returns a new cache with the provided maximum items. 28 func New(maxEntries int) *Cache { 29 return &Cache{ 30 maxEntries: maxEntries, 31 ll: list.New(), 32 cache: make(map[interface{}]*list.Element), 33 } 34 } 35 36 // Add adds the provided key and value to the cache, evicting 37 // an old item if necessary. 38 func (c *Cache) Add(key, value interface{}) { 39 c.mu.Lock() 40 defer c.mu.Unlock() 41 42 // Already in cache? 43 if ee, ok := c.cache[key]; ok { 44 c.ll.MoveToFront(ee) 45 ee.Value.(*entry).value = value 46 return 47 } 48 49 // Add to cache if not present 50 ele := c.ll.PushFront(&entry{key, value}) 51 c.cache[key] = ele 52 53 if c.ll.Len() > c.maxEntries { 54 c.removeOldest() 55 } 56 } 57 58 // Get fetches the key's value from the cache. 59 // The ok result will be true if the item was found. 60 func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { 61 c.mu.Lock() 62 defer c.mu.Unlock() 63 if ele, hit := c.cache[key]; hit { 64 c.ll.MoveToFront(ele) 65 return ele.Value.(*entry).value, true 66 } 67 return 68 } 69 70 // RemoveOldest removes the oldest item in the cache and returns its key and value. 71 // If the cache is empty, the empty string and nil are returned. 72 func (c *Cache) RemoveOldest() (key, value interface{}) { 73 c.mu.Lock() 74 defer c.mu.Unlock() 75 return c.removeOldest() 76 } 77 78 // note: must hold c.mu 79 func (c *Cache) removeOldest() (key, value interface{}) { 80 ele := c.ll.Back() 81 if ele == nil { 82 return 83 } 84 c.ll.Remove(ele) 85 ent := ele.Value.(*entry) 86 delete(c.cache, ent.key) 87 return ent.key, ent.value 88 89 } 90 91 // Len returns the number of items in the cache. 92 func (c *Cache) Len() int { 93 c.mu.Lock() 94 defer c.mu.Unlock() 95 return c.ll.Len() 96 }