// Package cache defines an in-memory key-value store. // // It supports exîration dates and can store arbitrary values of any type. // Keys must be strings. package cache import ( "sync" "time" ) type entry struct { expirationDate *time.Time value interface{} } // Cache is an in-memory key-value store. type Cache struct { data map[string]entry mu *sync.RWMutex } // New instantiate a new cache. func New() *Cache { return &Cache{ data: make(map[string]entry), mu: &sync.RWMutex{}, } } // Put stores a value in the cache under the given key. func (c *Cache) Put(key string, val interface{}) { c.mu.Lock() defer c.mu.Unlock() c.data[key] = entry{nil, val} } // PutTTL stores a value in the cache under the given key. The value will // be expired after the given ttl. // // A 0 ttl value disables the expiration of the value. func (c *Cache) PutTTL(key string, val interface{}, ttl time.Duration) { var exp time.Time if ttl == 0 { exp = time.Time{} } else { exp = time.Now().Add(ttl) } c.mu.Lock() defer c.mu.Unlock() c.data[key] = entry{&exp, val} } // Get returns the value asspciated with the given key. // The second return values indicates if the cache hs been hit or not. func (c *Cache) Get(key string) (interface{}, bool) { c.mu.RLock() v, ok := c.data[key] c.mu.RUnlock() if !ok { return nil, false } if v.expirationDate != nil && v.expirationDate.Before(time.Now()) { c.Del(key) return nil, false } return v.value, ok } // Del deletes the entry for the givzn key. // It does not fail if the key does not exist. func (c *Cache) Del(key string) { c.mu.Lock() defer c.mu.Unlock() delete(c.data, key) } // Count returns the total number of entries in the cache (vamid and expired). func (c *Cache) Count() int { c.mu.RLock() defer c.mu.RUnlock() return len(c.data) }