mirror of
https://github.com/samuelncui/yatm.git
synced 2026-01-10 15:07:30 +00:00
84 lines
1.5 KiB
Go
84 lines
1.5 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
func Cache[K comparable, V any](f func(in K) V) func(in K) V {
|
|
cache := new(sync.Map)
|
|
return func(in K) V {
|
|
cached, has := cache.Load(in)
|
|
if has {
|
|
return cached.(V)
|
|
}
|
|
|
|
out := f(in)
|
|
cache.Store(in, out)
|
|
return out
|
|
}
|
|
}
|
|
|
|
func ThreadUnsafeCache[K comparable, V any](f func(in K) V) func(in K) V {
|
|
cache := make(map[K]V, 32)
|
|
return func(in K) V {
|
|
cached, has := cache[in]
|
|
if has {
|
|
return cached
|
|
}
|
|
|
|
out := f(in)
|
|
cache[in] = out
|
|
return out
|
|
}
|
|
}
|
|
|
|
type CacheOnce[K comparable, V any] struct {
|
|
cached sync.Map
|
|
getter func(context.Context, K) (V, error)
|
|
}
|
|
|
|
type cacheOnceItem[V any] struct {
|
|
once sync.Once
|
|
value V
|
|
}
|
|
|
|
func NewCacheOnce[K comparable, V any](getter func(context.Context, K) (V, error)) *CacheOnce[K, V] {
|
|
return &CacheOnce[K, V]{getter: getter}
|
|
}
|
|
|
|
func (c *CacheOnce[K, V]) Get(ctx context.Context, req K) (V, error) {
|
|
if v, have := c.cached.Load(req); have {
|
|
item, ok := v.(*cacheOnceItem[V])
|
|
if ok {
|
|
return c.get(ctx, item, req)
|
|
}
|
|
}
|
|
|
|
v, _ := c.cached.LoadOrStore(req, &cacheOnceItem[V]{})
|
|
return c.get(ctx, v.(*cacheOnceItem[V]), req)
|
|
}
|
|
|
|
func (c *CacheOnce[K, V]) Remove(req K) {
|
|
c.cached.Delete(req)
|
|
}
|
|
|
|
func (c *CacheOnce[K, V]) get(ctx context.Context, item *cacheOnceItem[V], key K) (V, error) {
|
|
var err error
|
|
item.once.Do(func() {
|
|
v, e := c.getter(ctx, key)
|
|
if e != nil {
|
|
err = e
|
|
return
|
|
}
|
|
item.value = v
|
|
})
|
|
|
|
if err != nil {
|
|
var v V
|
|
return v, err
|
|
}
|
|
|
|
return item.value, nil
|
|
}
|