diff --git a/cache/cache.go b/cache/cache.go index e029eea..a97d65e 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -127,10 +127,10 @@ func (c *Cache[K, V]) Size() int64 { return c.size } -// New constructs a new empty cache with the specified settings. The store and -// limit fields must be set. -func New[K comparable, V any](limit int64, config Config[K, V]) *Cache[K, V] { - if limit <= 0 { +// New constructs a new empty cache with the specified settings. +// The store and capacity limits of config must be set or New will panic. +func New[K comparable, V any](config Config[K, V]) *Cache[K, V] { + if config.limit <= 0 { panic("cache: limit must be positive") } if config.store == nil { @@ -138,7 +138,7 @@ func New[K comparable, V any](limit int64, config Config[K, V]) *Cache[K, V] { } return &Cache[K, V]{ store: config.store, - limit: limit, + limit: config.limit, sizeOf: config.sizeFunc(), onEvict: config.onEvictFunc(), } @@ -147,12 +147,17 @@ func New[K comparable, V any](limit int64, config Config[K, V]) *Cache[K, V] { // A Config carries the settings for a cache implementation. // To set options: // +// - Use [Config.WithLimit] to set the capacity. // - Use [Config.WithStore] to set the storage implementation. // - Use [Config.WithSize] to set the size function. // - Use [Config.OnEvict] to set the eviction callback. // // A zero Config is invalid; at least the store field must be set. type Config[Key comparable, Value any] struct { + // limit is the capacity limit for the cache. + // It must be positive. The interpretation depends on sizeOf. + limit int64 + // store is the storage implementation used by the cache. // It must be non-nil. store Store[Key, Value] @@ -165,6 +170,10 @@ type Config[Key comparable, Value any] struct { onEvict func(key Key, val Value) } +// WithLimit returns a copy of c with its capacity set to n. +// The limit implementation must be positive, or [New] will panic. +func (c Config[K, V]) WithLimit(n int64) Config[K, V] { c.limit = n; return c } + // WithStore returns a copy of c with its storage implementation set to s. // The storage implementation must be set, or [New] will panic. func (c Config[K, V]) WithStore(s Store[K, V]) Config[K, V] { c.store = s; return c } diff --git a/cache/cache_test.go b/cache/cache_test.go index 47d9c89..5dc48a2 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -18,7 +18,7 @@ func TestLRU(t *testing.T) { } } - c := cache.New(25, cache.LRU[string, string](). + c := cache.New(cache.LRU[string, string](25). WithSize(cache.Length). // Record evictions so we can verify they happened in the expected order. diff --git a/cache/example_test.go b/cache/example_test.go index a5cb4f8..b08ae65 100644 --- a/cache/example_test.go +++ b/cache/example_test.go @@ -7,7 +7,7 @@ import ( ) func Example() { - c := cache.New(10, cache.LRU[string, int]()) + c := cache.New(cache.LRU[string, int](10)) for i := range 50 { c.Put(fmt.Sprint(i+1), i+1) } diff --git a/cache/lru.go b/cache/lru.go index 2e66f3e..3c09175 100644 --- a/cache/lru.go +++ b/cache/lru.go @@ -28,9 +28,9 @@ func comparePrio[Key comparable, Value any](a, b prioKey[Key, Value]) int { return cmp.Compare(a.lastAccess, b.lastAccess) // logical time order } -// LRU constructs a [Config] with a cache store that manages entries with a -// least-recently used eviction policy. -func LRU[Key comparable, Value any]() Config[Key, Value] { +// LRU constructs a [Config] with a cache store with the specified capacity +// limit that manages entries with a least-recently used eviction policy. +func LRU[Key comparable, Value any](limit int64) Config[Key, Value] { lru := &lruStore[Key, Value]{ present: make(map[Key]int), access: heapq.New(comparePrio[Key, Value]), @@ -38,7 +38,7 @@ func LRU[Key comparable, Value any]() Config[Key, Value] { lru.access.Update(func(v prioKey[Key, Value], pos int) { lru.present[v.key] = pos }) - return Config[Key, Value]{store: lru} + return Config[Key, Value]{limit: limit, store: lru} } // Check implements part of the [Store] interface.