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  }