func (s *shard) Len() int {
	s.RLock()
	l := s.len()
	s.RUnlock()
	return l
}
Len returns the current length of the cache.
package cache
import (
	"errors"
	"hash/fnv"
	"sync"
)
func Hash(what []byte) uint64 {
	h := fnv.New64()
	h.Write(what)
	return h.Sum64()
}
type Cache struct {
	shards [numShards]*shard
}
type EvictFn func(*interface{}) bool
var evictAll = func(*interface{}) bool {return true}
type shard struct {
	items     map[string]*interface{}
	size      int
	evictable EvictFn
	sync.RWMutex
}
func New(size int) *Cache {
	ssize := size / numShards
	if ssize < 4 {
		ssize = 4
	}
	c := &Cache{}
	for i := 0; i < numShards; i++ {
		c.shards[i] = newShard(ssize)
	}
	return c
}
func (c *Cache) SetEvict(e EvictFn) {
	for _, s := range c.shards {
		s.evictable = e
	}
}
func keyShard(key string) uint64 {
	return Hash([]byte(key)) & (numShards - 1)
}
func (c *Cache) Add(key string, el interface{}) error {
	return c.shards[keyShard(key)].Add(key, el)
}
func (c *Cache) UpdateAdd(key string, update func(*interface{}) interface{}, add func() interface{}) interface{} {
	return c.shards[keyShard(key)].UpdateAdd(key, update, add)
}
func (c *Cache) Get(key string) (interface{}, bool) {
	return c.shards[keyShard(key)].Get(key)
}
func (c *Cache) Remove(key string) {
	c.shards[keyShard(key)].Remove(key)
}
func (c *Cache) Len() int {
	l := 0
	for _, s := range c.shards {
		l += s.Len()
	}
	return l
}
func newShard(size int) *shard {
	return &shard{
		items: make(map[string]*interface{}),
		size: size,
		evictable: evictAll,
	}
}
func (s *shard) Add(key string, el interface{}) error {
	s.Lock()
	if s.len() >= s.size && !s.evict() {
		s.Unlock()
		return errors.New("failed to add item, shard full")
	}
	s.items[key] = &el
	s.Unlock()
	return nil
}
func (s *shard) Remove(key string) {
	s.Lock()
	s.remove(key)
	s.Unlock()
}
func (s *shard) remove(key string) {
	delete(s.items, key)
}
func (s *shard) evict() bool {
	for key, item := range s.items {
		if !s.evictable(item) {
			continue
		}
		s.remove(key)
		return true
	}
	return false
}
func (s *shard) Get(key string) (interface{}, bool) {
	s.RLock()
	el, found := s.items[key]
	s.RUnlock()
	if found {
		return *el, true
	}
	return nil, false
}
func (s *shard) UpdateAdd(key string, update func(*interface{}) interface{}, add func() interface{}) interface{} {
	s.Lock()
	el, found := s.items[key]
	if found {
		resp := update(el)
		s.Unlock()
		return resp
	}
	l := len(s.items)
	if l >= s.size {
		if !s.evict() {
			return errors.New("failed to add item, shard full")
		}
	}
	newItem := add()
	s.items[key] = &newItem
	s.Unlock()
	return nil
}