diff options
Diffstat (limited to 'vendor/codeberg.org/gruf/go-cache')
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/LICENSE | 9 | ||||
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/README.md | 11 | ||||
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/cache.go | 75 | ||||
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go | 454 | ||||
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go | 23 | ||||
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/ttl/schedule.go | 20 | ||||
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go | 636 |
7 files changed, 0 insertions, 1228 deletions
diff --git a/vendor/codeberg.org/gruf/go-cache/v3/LICENSE b/vendor/codeberg.org/gruf/go-cache/v3/LICENSE deleted file mode 100644 index d6f08d0ab..000000000 --- a/vendor/codeberg.org/gruf/go-cache/v3/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) gruf - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/codeberg.org/gruf/go-cache/v3/README.md b/vendor/codeberg.org/gruf/go-cache/v3/README.md deleted file mode 100644 index ffc516a70..000000000 --- a/vendor/codeberg.org/gruf/go-cache/v3/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# go-cache - -Provides access to simple, yet flexible, and performant caches (with TTL if required) via the `cache.Cache{}` and `cache.TTLCache{}` interfaces. - -## simple - -A `cache.Cache{}` implementation with much more of the inner workings exposed. Designed to be used as a base for your own customizations, or used as-is. - -## ttl - -A `cache.TTLCache{}` implementation with much more of the inner workings exposed. Designed to be used as a base for your own customizations, or used as-is. diff --git a/vendor/codeberg.org/gruf/go-cache/v3/cache.go b/vendor/codeberg.org/gruf/go-cache/v3/cache.go deleted file mode 100644 index d96971702..000000000 --- a/vendor/codeberg.org/gruf/go-cache/v3/cache.go +++ /dev/null @@ -1,75 +0,0 @@ -package cache - -import ( - "time" - - "codeberg.org/gruf/go-cache/v3/simple" - "codeberg.org/gruf/go-cache/v3/ttl" -) - -// TTLCache represents a TTL cache with customizable callbacks, it exists here to abstract away the "unsafe" methods in the case that you do not want your own implementation atop ttl.Cache{}. -type TTLCache[Key comparable, Value any] interface { - // Start will start the cache background eviction routine with given sweep frequency. If already running or a freq <= 0 provided, this is a no-op. This will block until the eviction routine has started. - Start(freq time.Duration) bool - - // Stop will stop cache background eviction routine. If not running this is a no-op. This will block until the eviction routine has stopped. - Stop() bool - - // SetTTL sets the cache item TTL. Update can be specified to force updates of existing items in the cache, this will simply add the change in TTL to their current expiry time. - SetTTL(ttl time.Duration, update bool) - - // implements base cache. - Cache[Key, Value] -} - -// Cache represents a cache with customizable callbacks, it exists here to abstract away the "unsafe" methods in the case that you do not want your own implementation atop simple.Cache{}. -type Cache[Key comparable, Value any] interface { - // SetEvictionCallback sets the eviction callback to the provided hook. - SetEvictionCallback(hook func(Key, Value)) - - // SetInvalidateCallback sets the invalidate callback to the provided hook. - SetInvalidateCallback(hook func(Key, Value)) - - // Get fetches the value with key from the cache, extending its TTL. - Get(key Key) (value Value, ok bool) - - // Add attempts to place the value at key in the cache, doing nothing if a value with this key already exists. Returned bool is success state. Calls invalidate callback on success. - Add(key Key, value Value) bool - - // Set places the value at key in the cache. This will overwrite any existing value. Existing values will have their TTL extended upon update. Always calls invalidate callback. - Set(key Key, value Value) - - // CAS will attempt to perform a CAS operation on 'key', using provided old and new values, and comparator function. Returned bool is success. - CAS(key Key, old, new Value, cmp func(Value, Value) bool) bool - - // Swap will attempt to perform a swap on 'key', replacing the value there and returning the existing value. If no value exists for key, this will set the value and return the zero value for V. - Swap(key Key, swp Value) Value - - // Has checks the cache for a value with key, this will not update TTL. - Has(key Key) bool - - // Invalidate deletes a value from the cache, calling the invalidate callback. - Invalidate(key Key) bool - - // InvalidateAll is equivalent to multiple Invalidate calls. - InvalidateAll(keys ...Key) bool - - // Clear empties the cache, calling the invalidate callback on each entry. - Clear() - - // Len returns the current length of the cache. - Len() int - - // Cap returns the maximum capacity of the cache. - Cap() int -} - -// New returns a new initialized Cache with given initial length, maximum capacity. -func New[K comparable, V any](len, cap int) Cache[K, V] { - return simple.New[K, V](len, cap) -} - -// NewTTL returns a new initialized TTLCache with given initial length, maximum capacity and TTL duration. -func NewTTL[K comparable, V any](len, cap int, _ttl time.Duration) TTLCache[K, V] { - return ttl.New[K, V](len, cap, _ttl) -} diff --git a/vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go b/vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go deleted file mode 100644 index 1452a0648..000000000 --- a/vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go +++ /dev/null @@ -1,454 +0,0 @@ -package simple - -import ( - "sync" - - "codeberg.org/gruf/go-maps" -) - -// Entry represents an item in the cache. -type Entry struct { - Key any - Value any -} - -// Cache is the underlying Cache implementation, providing both the base Cache interface and unsafe access to underlying map to allow flexibility in building your own. -type Cache[Key comparable, Value any] struct { - // Evict is the hook that is called when an item is evicted from the cache. - Evict func(Key, Value) - - // Invalid is the hook that is called when an item's data in the cache is invalidated, includes Add/Set. - Invalid func(Key, Value) - - // Cache is the underlying hashmap used for this cache. - Cache maps.LRUMap[Key, *Entry] - - // Embedded mutex. - sync.Mutex -} - -// New returns a new initialized Cache with given initial length, maximum capacity and item TTL. -func New[K comparable, V any](len, cap int) *Cache[K, V] { - c := new(Cache[K, V]) - c.Init(len, cap) - return c -} - -// Init will initialize this cache with given initial length, maximum capacity and item TTL. -func (c *Cache[K, V]) Init(len, cap int) { - c.SetEvictionCallback(nil) - c.SetInvalidateCallback(nil) - c.Cache.Init(len, cap) -} - -// SetEvictionCallback: implements cache.Cache's SetEvictionCallback(). -func (c *Cache[K, V]) SetEvictionCallback(hook func(K, V)) { - c.locked(func() { c.Evict = hook }) -} - -// SetInvalidateCallback: implements cache.Cache's SetInvalidateCallback(). -func (c *Cache[K, V]) SetInvalidateCallback(hook func(K, V)) { - c.locked(func() { c.Invalid = hook }) -} - -// Get: implements cache.Cache's Get(). -func (c *Cache[K, V]) Get(key K) (V, bool) { - var ( - // did exist in cache? - ok bool - - // cached value. - v V - ) - - c.locked(func() { - var item *Entry - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Set item value. - v = item.Value.(V) - }) - - return v, ok -} - -// Add: implements cache.Cache's Add(). -func (c *Cache[K, V]) Add(key K, value V) bool { - var ( - // did exist in cache? - ok bool - - // was entry evicted? - ev bool - - // evicted key values. - evcK K - evcV V - - // hook func ptrs. - evict func(K, V) - ) - - c.locked(func() { - // Check if in cache. - ok = c.Cache.Has(key) - if ok { - return - } - - // Alloc new entry. - new := GetEntry() - new.Key = key - new.Value = value - - // Add new entry to cache and catched any evicted item. - c.Cache.SetWithHook(key, new, func(_ K, item *Entry) { - evcK = item.Key.(K) - evcV = item.Value.(V) - ev = true - PutEntry(item) - }) - - // Set hook func ptr. - evict = c.Evict - }) - - if ev && evict != nil { - // Pass to eviction hook. - evict(evcK, evcV) - } - - return !ok -} - -// Set: implements cache.Cache's Set(). -func (c *Cache[K, V]) Set(key K, value V) { - var ( - // did exist in cache? - ok bool - - // was entry evicted? - ev bool - - // old value. - oldV V - - // evicted key values. - evcK K - evcV V - - // hook func ptrs. - invalid func(K, V) - evict func(K, V) - ) - - c.locked(func() { - var item *Entry - - // Check for item in cache - item, ok = c.Cache.Get(key) - - if ok { - // Set old value. - oldV = item.Value.(V) - - // Update the existing item. - item.Value = value - } else { - // Alloc new entry. - new := GetEntry() - new.Key = key - new.Value = value - - // Add new entry to cache and catched any evicted item. - c.Cache.SetWithHook(key, new, func(_ K, item *Entry) { - evcK = item.Key.(K) - evcV = item.Value.(V) - ev = true - PutEntry(item) - }) - } - - // Set hook func ptrs. - invalid = c.Invalid - evict = c.Evict - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - if ev && evict != nil { - // Pass to eviction hook. - evict(evcK, evcV) - } -} - -// CAS: implements cache.Cache's CAS(). -func (c *Cache[K, V]) CAS(key K, old V, new V, cmp func(V, V) bool) bool { - var ( - // did exist in cache? - ok bool - - // swapped value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Set old value. - oldV = item.Value.(V) - - // Perform the comparison - if !cmp(old, oldV) { - var zero V - oldV = zero - return - } - - // Update value. - item.Value = new - - // Set hook func ptr. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return ok -} - -// Swap: implements cache.Cache's Swap(). -func (c *Cache[K, V]) Swap(key K, swp V) V { - var ( - // did exist in cache? - ok bool - - // swapped value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Set old value. - oldV = item.Value.(V) - - // Update value. - item.Value = swp - - // Set hook func ptr. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return oldV -} - -// Has: implements cache.Cache's Has(). -func (c *Cache[K, V]) Has(key K) (ok bool) { - c.locked(func() { - ok = c.Cache.Has(key) - }) - return -} - -// Invalidate: implements cache.Cache's Invalidate(). -func (c *Cache[K, V]) Invalidate(key K) (ok bool) { - var ( - // old value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Set old value. - oldV = item.Value.(V) - - // Remove from cache map - _ = c.Cache.Delete(key) - - // Free entry - PutEntry(item) - - // Set hook func ptrs. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return -} - -// InvalidateAll: implements cache.Cache's InvalidateAll(). -func (c *Cache[K, V]) InvalidateAll(keys ...K) (ok bool) { - var ( - // deleted items. - items []*Entry - - // hook func ptrs. - invalid func(K, V) - ) - - // Allocate a slice for invalidated. - items = make([]*Entry, 0, len(keys)) - - c.locked(func() { - for x := range keys { - var item *Entry - - // Check for item in cache - item, ok = c.Cache.Get(keys[x]) - if !ok { - continue - } - - // Append this old value. - items = append(items, item) - - // Remove from cache map - _ = c.Cache.Delete(keys[x]) - } - - // Set hook func ptrs. - invalid = c.Invalid - }) - - if invalid != nil { - for x := range items { - // Pass to invalidate hook. - k := items[x].Key.(K) - v := items[x].Value.(V) - invalid(k, v) - - // Free this entry. - PutEntry(items[x]) - } - } - - return -} - -// Clear: implements cache.Cache's Clear(). -func (c *Cache[K, V]) Clear() { c.Trim(100) } - -// Trim will truncate the cache to ensure it stays within given percentage of total capacity. -func (c *Cache[K, V]) Trim(perc float64) { - var ( - // deleted items - items []*Entry - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - // Calculate number of cache items to truncate. - max := (perc / 100) * float64(c.Cache.Cap()) - diff := c.Cache.Len() - int(max) - if diff <= 0 { - return - } - - // Set hook func ptr. - invalid = c.Invalid - - // Truncate by calculated length. - items = c.truncate(diff, invalid) - }) - - if invalid != nil { - for x := range items { - // Pass to invalidate hook. - k := items[x].Key.(K) - v := items[x].Value.(V) - invalid(k, v) - - // Free this entry. - PutEntry(items[x]) - } - } -} - -// Len: implements cache.Cache's Len(). -func (c *Cache[K, V]) Len() (l int) { - c.locked(func() { l = c.Cache.Len() }) - return -} - -// Cap: implements cache.Cache's Cap(). -func (c *Cache[K, V]) Cap() (l int) { - c.locked(func() { l = c.Cache.Cap() }) - return -} - -// locked performs given function within mutex lock (NOTE: UNLOCK IS NOT DEFERRED). -func (c *Cache[K, V]) locked(fn func()) { - c.Lock() - fn() - c.Unlock() -} - -// truncate will truncate the cache by given size, returning deleted items. -func (c *Cache[K, V]) truncate(sz int, hook func(K, V)) []*Entry { - if hook == nil { - // No hook to execute, simply release all truncated entries. - c.Cache.Truncate(sz, func(_ K, item *Entry) { PutEntry(item) }) - return nil - } - - // Allocate a slice for deleted. - deleted := make([]*Entry, 0, sz) - - // Truncate and catch all deleted k-v pairs. - c.Cache.Truncate(sz, func(_ K, item *Entry) { - deleted = append(deleted, item) - }) - - return deleted -} diff --git a/vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go b/vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go deleted file mode 100644 index 34ae17546..000000000 --- a/vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go +++ /dev/null @@ -1,23 +0,0 @@ -package simple - -import "sync" - -// entryPool is a global pool for Entry -// objects, regardless of cache type. -var entryPool sync.Pool - -// GetEntry fetches an Entry from pool, or allocates new. -func GetEntry() *Entry { - v := entryPool.Get() - if v == nil { - return new(Entry) - } - return v.(*Entry) -} - -// PutEntry replaces an Entry in the pool. -func PutEntry(e *Entry) { - e.Key = nil - e.Value = nil - entryPool.Put(e) -} diff --git a/vendor/codeberg.org/gruf/go-cache/v3/ttl/schedule.go b/vendor/codeberg.org/gruf/go-cache/v3/ttl/schedule.go deleted file mode 100644 index a12b33ab9..000000000 --- a/vendor/codeberg.org/gruf/go-cache/v3/ttl/schedule.go +++ /dev/null @@ -1,20 +0,0 @@ -package ttl - -import ( - "time" - - "codeberg.org/gruf/go-sched" -) - -// scheduler is the global cache runtime -// scheduler for handling cache evictions. -var scheduler sched.Scheduler - -// schedule will given sweep routine to the global scheduler, and start global scheduler. -func schedule(sweep func(time.Time), freq time.Duration) func() { - if !scheduler.Running() { - // ensure sched running - _ = scheduler.Start(nil) - } - return scheduler.Schedule(sched.NewJob(sweep).Every(freq)) -} diff --git a/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go b/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go deleted file mode 100644 index 106d675c8..000000000 --- a/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go +++ /dev/null @@ -1,636 +0,0 @@ -package ttl - -import ( - "sync" - "time" - _ "unsafe" - - "codeberg.org/gruf/go-maps" -) - -// Entry represents an item in the cache, with it's currently calculated Expiry time. -type Entry[Key comparable, Value any] struct { - Key Key - Value Value - Expiry uint64 -} - -// Cache is the underlying TTLCache implementation, providing both the base Cache interface and unsafe access to underlying map to allow flexibility in building your own. -type Cache[Key comparable, Value any] struct { - // TTL is the cache item TTL. - TTL time.Duration - - // Evict is the hook that is called when an item is evicted from the cache. - Evict func(Key, Value) - - // Invalid is the hook that is called when an item's data in the cache is invalidated, includes Add/Set. - Invalid func(Key, Value) - - // Cache is the underlying hashmap used for this cache. - Cache maps.LRUMap[Key, *Entry[Key, Value]] - - // stop is the eviction routine cancel func. - stop func() - - // pool is a memory pool of entry objects. - pool []*Entry[Key, Value] - - // Embedded mutex. - sync.Mutex -} - -// New returns a new initialized Cache with given initial length, maximum capacity and item TTL. -func New[K comparable, V any](len, cap int, ttl time.Duration) *Cache[K, V] { - c := new(Cache[K, V]) - c.Init(len, cap, ttl) - return c -} - -// Init will initialize this cache with given initial length, maximum capacity and item TTL. -func (c *Cache[K, V]) Init(len, cap int, ttl time.Duration) { - if ttl <= 0 { - // Default duration - ttl = time.Second * 5 - } - c.TTL = ttl - c.SetEvictionCallback(nil) - c.SetInvalidateCallback(nil) - c.Cache.Init(len, cap) -} - -// Start: implements cache.Cache's Start(). -func (c *Cache[K, V]) Start(freq time.Duration) (ok bool) { - // Nothing to start - if freq <= 0 { - return false - } - - // Safely start - c.Lock() - - if ok = (c.stop == nil); ok { - // Not yet running, schedule us - c.stop = schedule(c.Sweep, freq) - } - - // Done with lock - c.Unlock() - - return -} - -// Stop: implements cache.Cache's Stop(). -func (c *Cache[K, V]) Stop() (ok bool) { - // Safely stop - c.Lock() - - if ok = (c.stop != nil); ok { - // We're running, cancel evicts - c.stop() - c.stop = nil - } - - // Done with lock - c.Unlock() - - return -} - -// Sweep attempts to evict expired items (with callback!) from cache. -func (c *Cache[K, V]) Sweep(_ time.Time) { - var ( - // evicted key-values. - kvs []kv[K, V] - - // hook func ptrs. - evict func(K, V) - - // get current nanoseconds. - now = runtime_nanotime() - ) - - c.locked(func() { - if c.TTL <= 0 { - // sweep is - // disabled - return - } - - // Sentinel value - after := -1 - - // The cache will be ordered by expiry date, we iterate until we reach the index of - // the youngest item that hsa expired, as all succeeding items will also be expired. - c.Cache.RangeIf(0, c.Cache.Len(), func(i int, _ K, item *Entry[K, V]) bool { - if now > item.Expiry { - after = i - - // evict all older items - // than this (inclusive) - return false - } - - // cont. loop. - return true - }) - - if after == -1 { - // No Truncation needed - return - } - - // Set hook func ptr. - evict = c.Evict - - // Truncate determined size. - sz := c.Cache.Len() - after - kvs = c.truncate(sz, evict) - }) - - if evict != nil { - for x := range kvs { - // Pass to eviction hook. - evict(kvs[x].K, kvs[x].V) - } - } -} - -// SetEvictionCallback: implements cache.Cache's SetEvictionCallback(). -func (c *Cache[K, V]) SetEvictionCallback(hook func(K, V)) { - c.locked(func() { - c.Evict = hook - }) -} - -// SetInvalidateCallback: implements cache.Cache's SetInvalidateCallback(). -func (c *Cache[K, V]) SetInvalidateCallback(hook func(K, V)) { - c.locked(func() { - c.Invalid = hook - }) -} - -// SetTTL: implements cache.Cache's SetTTL(). -func (c *Cache[K, V]) SetTTL(ttl time.Duration, update bool) { - c.locked(func() { - // Set updated TTL - diff := ttl - c.TTL - c.TTL = ttl - - if update { - // Update existing cache entries with new expiry time - c.Cache.Range(0, c.Cache.Len(), func(i int, _ K, item *Entry[K, V]) { - item.Expiry += uint64(diff) - }) - } - }) -} - -// Get: implements cache.Cache's Get(). -func (c *Cache[K, V]) Get(key K) (V, bool) { - var ( - // did exist in cache? - ok bool - - // cached value. - v V - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Update fetched's expiry - item.Expiry = c.expiry() - - // Set value. - v = item.Value - }) - - return v, ok -} - -// Add: implements cache.Cache's Add(). -func (c *Cache[K, V]) Add(key K, value V) bool { - var ( - // did exist in cache? - ok bool - - // was entry evicted? - ev bool - - // evicted key values. - evcK K - evcV V - - // hook func ptrs. - evict func(K, V) - ) - - c.locked(func() { - // Check if in cache. - ok = c.Cache.Has(key) - if ok { - return - } - - // Alloc new entry. - new := c.alloc() - new.Expiry = c.expiry() - new.Key = key - new.Value = value - - // Add new entry to cache and catched any evicted item. - c.Cache.SetWithHook(key, new, func(_ K, item *Entry[K, V]) { - evcK = item.Key - evcV = item.Value - ev = true - c.free(item) - }) - - // Set hook func ptr. - evict = c.Evict - }) - - if ev && evict != nil { - // Pass to eviction hook. - evict(evcK, evcV) - } - - return !ok -} - -// Set: implements cache.Cache's Set(). -func (c *Cache[K, V]) Set(key K, value V) { - var ( - // did exist in cache? - ok bool - - // was entry evicted? - ev bool - - // old value. - oldV V - - // evicted key values. - evcK K - evcV V - - // hook func ptrs. - invalid func(K, V) - evict func(K, V) - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - - if ok { - // Set old value. - oldV = item.Value - - // Update the existing item. - item.Expiry = c.expiry() - item.Value = value - } else { - // Alloc new entry. - new := c.alloc() - new.Expiry = c.expiry() - new.Key = key - new.Value = value - - // Add new entry to cache and catched any evicted item. - c.Cache.SetWithHook(key, new, func(_ K, item *Entry[K, V]) { - evcK = item.Key - evcV = item.Value - ev = true - c.free(item) - }) - } - - // Set hook func ptrs. - invalid = c.Invalid - evict = c.Evict - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - if ev && evict != nil { - // Pass to eviction hook. - evict(evcK, evcV) - } -} - -// CAS: implements cache.Cache's CAS(). -func (c *Cache[K, V]) CAS(key K, old V, new V, cmp func(V, V) bool) bool { - var ( - // did exist in cache? - ok bool - - // swapped value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Perform the comparison - if !cmp(old, item.Value) { - return - } - - // Set old value. - oldV = item.Value - - // Update value + expiry. - item.Expiry = c.expiry() - item.Value = new - - // Set hook func ptr. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return ok -} - -// Swap: implements cache.Cache's Swap(). -func (c *Cache[K, V]) Swap(key K, swp V) V { - var ( - // did exist in cache? - ok bool - - // swapped value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Set old value. - oldV = item.Value - - // Update value + expiry. - item.Expiry = c.expiry() - item.Value = swp - - // Set hook func ptr. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return oldV -} - -// Has: implements cache.Cache's Has(). -func (c *Cache[K, V]) Has(key K) (ok bool) { - c.locked(func() { - ok = c.Cache.Has(key) - }) - return -} - -// Invalidate: implements cache.Cache's Invalidate(). -func (c *Cache[K, V]) Invalidate(key K) (ok bool) { - var ( - // old value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Set old value. - oldV = item.Value - - // Remove from cache map - _ = c.Cache.Delete(key) - - // Free entry - c.free(item) - - // Set hook func ptrs. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return -} - -// InvalidateAll: implements cache.Cache's InvalidateAll(). -func (c *Cache[K, V]) InvalidateAll(keys ...K) (ok bool) { - var ( - // invalidated kvs. - kvs []kv[K, V] - - // hook func ptrs. - invalid func(K, V) - ) - - // Allocate a slice for invalidated. - kvs = make([]kv[K, V], 0, len(keys)) - - c.locked(func() { - for x := range keys { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(keys[x]) - if !ok { - continue - } - - // Append this old value to slice - kvs = append(kvs, kv[K, V]{ - K: keys[x], - V: item.Value, - }) - - // Remove from cache map - _ = c.Cache.Delete(keys[x]) - - // Free entry - c.free(item) - } - - // Set hook func ptrs. - invalid = c.Invalid - }) - - if invalid != nil { - for x := range kvs { - // Pass to invalidate hook. - invalid(kvs[x].K, kvs[x].V) - } - } - - return -} - -// Clear: implements cache.Cache's Clear(). -func (c *Cache[K, V]) Clear() { - var ( - // deleted key-values. - kvs []kv[K, V] - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - // Set hook func ptr. - invalid = c.Invalid - - // Truncate the entire cache length. - kvs = c.truncate(c.Cache.Len(), invalid) - }) - - if invalid != nil { - for x := range kvs { - // Pass to invalidate hook. - invalid(kvs[x].K, kvs[x].V) - } - } -} - -// Len: implements cache.Cache's Len(). -func (c *Cache[K, V]) Len() (l int) { - c.locked(func() { l = c.Cache.Len() }) - return -} - -// Cap: implements cache.Cache's Cap(). -func (c *Cache[K, V]) Cap() (l int) { - c.locked(func() { l = c.Cache.Cap() }) - return -} - -// locked performs given function within mutex lock (NOTE: UNLOCK IS NOT DEFERRED). -func (c *Cache[K, V]) locked(fn func()) { - c.Lock() - fn() - c.Unlock() -} - -// truncate will truncate the cache by given size, returning deleted items. -func (c *Cache[K, V]) truncate(sz int, hook func(K, V)) []kv[K, V] { - if hook == nil { - // No hook to execute, simply free all truncated entries. - c.Cache.Truncate(sz, func(_ K, e *Entry[K, V]) { c.free(e) }) - return nil - } - - // Allocate a slice for deleted k-v pairs. - deleted := make([]kv[K, V], 0, sz) - - c.Cache.Truncate(sz, func(_ K, item *Entry[K, V]) { - // Store key-value pair for later access. - deleted = append(deleted, kv[K, V]{ - K: item.Key, - V: item.Value, - }) - - // Free entry. - c.free(item) - }) - - return deleted -} - -// alloc will acquire cache entry from pool, or allocate new. -func (c *Cache[K, V]) alloc() *Entry[K, V] { - if len(c.pool) == 0 { - return &Entry[K, V]{} - } - idx := len(c.pool) - 1 - e := c.pool[idx] - c.pool = c.pool[:idx] - return e -} - -// clone allocates a new Entry and copies all info from passed Entry. -func (c *Cache[K, V]) clone(e *Entry[K, V]) *Entry[K, V] { - e2 := c.alloc() - e2.Key = e.Key - e2.Value = e.Value - e2.Expiry = e.Expiry - return e2 -} - -// free will reset entry fields and place back in pool. -func (c *Cache[K, V]) free(e *Entry[K, V]) { - var ( - zk K - zv V - ) - e.Expiry = 0 - e.Key = zk - e.Value = zv - c.pool = append(c.pool, e) -} - -//go:linkname runtime_nanotime runtime.nanotime -func runtime_nanotime() uint64 - -// expiry returns an the next expiry time to use for an entry, -// which is equivalent to time.Now().Add(ttl), or zero if disabled. -func (c *Cache[K, V]) expiry() uint64 { - if ttl := c.TTL; ttl > 0 { - return runtime_nanotime() + - uint64(c.TTL) - } - return 0 -} - -type kv[K comparable, V any] struct { - K K - V V -} |