func (c *Cache) Get(key interface{}) (interface{}, bool) {
	if c == nil || c.isClosed || key == nil {
		return nil, false
	}
	keyHash, conflictHash := c.keyToHash(key)
	c.getBuf.Push(keyHash)
	value, ok := c.store.Get(keyHash, conflictHash)
	if ok {
		c.Metrics.add(hit, keyHash, 1)
	} else {
		c.Metrics.add(miss, keyHash, 1)
	}
	return value, ok
}
Get returns the value (if any) and a boolean representing whether the
value was found or not. The value can be nil and the boolean can be true at
the same time.
package ristretto
import (
	"errors"
	"sync"
	"time"
	"unsafe"
	"github.com/dgraph-io/ristretto/z"
)
var (
	setBufSize = 32 * 1024
)
type itemCallback func(*Item)
const itemSize = int64(unsafe.Sizeof(storeItem{}))
type Cache struct {
	store *shardedMap
	policy *lfuPolicy
	getBuf *ringBuffer
	setBuf chan *Item
	onEvict itemCallback
	onReject itemCallback
	onExit (func(interface{}))
	keyToHash func(interface{}) (uint64, uint64)
	stop chan struct{}
	isClosed bool
	cost func(value interface{}) int64
	ignoreInternalCost bool
	cleanupTicker *time.Ticker
	Metrics *Metrics
}
type Config struct {
	NumCounters int64
	MaxCost int64
	BufferItems int64
	Metrics bool
	OnEvict func(item *Item)
	OnReject func(item *Item)
	OnExit func(val interface{})
	KeyToHash func(key interface{}) (uint64, uint64)
	ShouldUpdate func(prev, cur interface{}) bool
	Cost func(value interface{}) int64
	IgnoreInternalCost bool
}
type itemFlag byte
const (
	itemNew itemFlag = iota
	itemDelete
	itemUpdate
)
type Item struct {
	flag       itemFlag
	Key        uint64
	Conflict   uint64
	Value      interface{}
	Cost       int64
	Expiration time.Time
	wg         *sync.WaitGroup
}
func NewCache(config *Config) (*Cache, error) {
	switch {
	case config.NumCounters == 0:
		return nil, errors.New("NumCounters can't be zero")
	case config.MaxCost == 0:
		return nil, errors.New("MaxCost can't be zero")
	case config.BufferItems == 0:
		return nil, errors.New("BufferItems can't be zero")
	}
	policy := newPolicy(config.NumCounters, config.MaxCost)
	cache := &Cache{
		store:              newShardedMap(config.ShouldUpdate),
		policy:             policy,
		getBuf:             newRingBuffer(policy, config.BufferItems),
		setBuf:             make(chan *Item, setBufSize),
		keyToHash:          config.KeyToHash,
		stop:               make(chan struct{}),
		cost:               config.Cost,
		ignoreInternalCost: config.IgnoreInternalCost,
		cleanupTicker:      time.NewTicker(time.Duration(bucketDurationSecs) * time.Second / 2),
	}
	cache.onExit = func(val interface{}) {
		if config.OnExit != nil && val != nil {
			config.OnExit(val)
		}
	}
	cache.onEvict = func(item *Item) {
		if config.OnEvict != nil {
			config.OnEvict(item)
		}
		cache.onExit(item.Value)
	}
	cache.onReject = func(item *Item) {
		if config.OnReject != nil {
			config.OnReject(item)
		}
		cache.onExit(item.Value)
	}
	cache.store.shouldUpdate = func(prev, cur interface{}) bool {
		if config.ShouldUpdate != nil {
			return config.ShouldUpdate(prev, cur)
		}
		return true
	}
	if cache.keyToHash == nil {
		cache.keyToHash = z.KeyToHash
	}
	if config.Metrics {
		cache.collectMetrics()
	}
	go cache.processItems()
	return cache, nil
}
func (c *Cache) Wait() {
	if c == nil || c.isClosed {
		return
	}
	wg := &sync.WaitGroup{}
	wg.Add(1)
	c.setBuf <- &Item{wg: wg}
	wg.Wait()
}