summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go
diff options
context:
space:
mode:
authorLibravatar Terin Stock <terinjokes@gmail.com>2025-03-09 17:47:56 +0100
committerLibravatar Terin Stock <terinjokes@gmail.com>2025-03-10 01:59:49 +0100
commit3ac1ee16f377d31a0fb80c8dae28b6239ac4229e (patch)
treef61faa581feaaeaba2542b9f2b8234a590684413 /vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go
parent[chore] update URLs to forked source (diff)
downloadgotosocial-3ac1ee16f377d31a0fb80c8dae28b6239ac4229e.tar.xz
[chore] remove vendor
Diffstat (limited to 'vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go')
-rw-r--r--vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go636
1 files changed, 0 insertions, 636 deletions
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
-}