88 lines
1.2 KiB
Go
88 lines
1.2 KiB
Go
package cache
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type Cache[K comparable, V any] interface {
|
|
Get(K) (V, bool)
|
|
Set(K, V)
|
|
Delete(K)
|
|
Clear()
|
|
}
|
|
|
|
type cacheItem[V any] struct {
|
|
exp int64
|
|
elem V
|
|
}
|
|
|
|
type inMem[K comparable, V any] struct {
|
|
sync.RWMutex
|
|
expiration time.Duration
|
|
m map[K]cacheItem[V]
|
|
}
|
|
|
|
type cacheOpts struct {
|
|
exp time.Duration
|
|
}
|
|
|
|
type Option func(*cacheOpts)
|
|
|
|
func WithExpiration(d time.Duration) Option {
|
|
return func(o *cacheOpts) {
|
|
o.exp = d
|
|
}
|
|
}
|
|
|
|
func New[K comparable, V any](opts ...Option) *inMem[K, V] {
|
|
co := cacheOpts{}
|
|
|
|
for _, o := range opts {
|
|
o(&co)
|
|
}
|
|
|
|
c := &inMem[K, V]{
|
|
m: make(map[K]cacheItem[V]),
|
|
expiration: co.exp,
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *inMem[K, V]) Get(key K) (V, bool) {
|
|
c.RLock()
|
|
defer c.RUnlock()
|
|
|
|
v, found := c.m[key]
|
|
if !found || (v.exp > 0 && time.Now().UnixNano() > v.exp) {
|
|
return v.elem, false
|
|
}
|
|
|
|
return v.elem, true
|
|
}
|
|
|
|
func (c *inMem[K, V]) Set(key K, val V) {
|
|
c.Lock()
|
|
defer c.Unlock()
|
|
|
|
var ci cacheItem[V]
|
|
ci.elem = val
|
|
if c.expiration > 0 {
|
|
ci.exp = time.Now().Add(c.expiration).UnixNano()
|
|
}
|
|
|
|
c.m[key] = ci
|
|
}
|
|
|
|
func (c *inMem[K, V]) Delete(key K) {
|
|
c.Lock()
|
|
defer c.Unlock()
|
|
delete(c.m, key)
|
|
}
|
|
|
|
func (c *inMem[K, V]) Clear() {
|
|
c.Lock()
|
|
defer c.Unlock()
|
|
clear(c.m)
|
|
}
|