func (c *cache) DeleteAll() map[string]Item {
	c.mu.Lock()
	items := c.items
	c.items = map[string]Item{}
	c.mu.Unlock()
	if c.onEvicted != nil {
		for k, v := range items {
			c.onEvicted(k, v.Object)
		}
	}
	return items
}
DeleteAll deletes all items from the cache and returns them.

Note that onEvicted is called on returned items.
package zcache
import (
	"errors"
	"runtime"
	"sync"
	"time"
)
const (
	NoExpiration time.Duration = -1
	DefaultExpiration time.Duration = 0
)
type Item struct {
	Object     interface{}
	Expiration int64
}
func (item Item) Expired() bool {
	if item.Expiration == 0 {
		return false
	}
	return time.Now().UnixNano() > item.Expiration
}
type Cache struct {
	*cache  
}
type cache struct {
	defaultExpiration time.Duration
	items             map[string]Item
	mu                sync.RWMutex
	onEvicted         func(string, interface{})
	janitor           *janitor
}
func (c *cache) Set(k string, v interface{}) {
	c.SetWithExpire(k, v, DefaultExpiration)
}
func (c *cache) Touch(k string) (interface{}, bool) {
	return c.TouchWithExpire(k, DefaultExpiration)
}
func (c *cache) Add(k string, v interface{}) error {
	return c.AddWithExpire(k, v, DefaultExpiration)
}
func (c *cache) Replace(k string, v interface{}) error {
	return c.ReplaceWithExpire(k, v, DefaultExpiration)
}
func (c *cache) SetWithExpire(k string, v interface{}, d time.Duration) {
	var e int64
	if d == DefaultExpiration {
		d = c.defaultExpiration
	}
	if d > 0 {
		e = time.Now().Add(d).UnixNano()
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	c.items[k] = Item{
		Object:     v,
		Expiration: e,
	}
}
func (c *cache) TouchWithExpire(k string, d time.Duration) (interface{}, bool) {
	if d == DefaultExpiration {
		d = c.defaultExpiration
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	item, ok := c.items[k]
	if !ok {
		return nil, false
	}
	item.Expiration = time.Now().Add(d).UnixNano()
	c.items[k] = item
	return item.Object, true
}
func (c *cache) set(k string, v interface{}, d time.Duration) {
	var e int64
	if d == DefaultExpiration {
		d = c.defaultExpiration
	}
	if d > 0 {
		e = time.Now().Add(d).UnixNano()
	}
	c.items[k] = Item{
		Object:     v,
		Expiration: e,
	}
}
func (c *cache) AddWithExpire(k string, v interface{}, d time.Duration) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	_, ok := c.get(k)
	if ok {
		return errors.New("zcache.Add: item " + k + "already exists")
	}
	c.set(k, v, d)
	return nil
}
func (c *cache) ReplaceWithExpire(k string, v interface{}, d time.Duration) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	_, ok := c.get(k)
	if !ok {
		return errors.New("zcache.Replace: item " + k + " doesn't exist")
	}
	c.set(k, v, d)
	return nil
}
func (c *cache) Get(k string) (interface{}, bool) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	item, ok := c.items[k]
	if !ok {
		return nil, false
	}
	if item.Expiration > 0 && time.Now().UnixNano() > item.Expiration {
		return nil, false
	}
	return item.Object, true
}
func (c *cache) GetStale(k string) (v interface{}, expired bool, ok bool) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	item, ok := c.items[k]
	if !ok {
		return nil, false, false
	}
	return item.Object,
		item.Expiration > 0 && time.Now().UnixNano() > item.Expiration,
		true
}
func (c *cache) GetWithExpire(k string) (interface{}, time.Time, bool) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	item, ok := c.items[k]
	if !ok {
		return nil, time.Time{}, false
	}
	if item.Expiration > 0 {
		if time.Now().UnixNano() > item.Expiration {
			return nil, time.Time{}, false
		}
		return item.Object, time.Unix(0, item.Expiration), true
	}
	return item.Object, time.Time{}, true
}
func (c *cache) get(k string) (interface{}, bool) {
	item, ok := c.items[k]
	if !ok {
		return nil, false
	}
	if item.Expiration > 0 && time.Now().UnixNano() > item.Expiration {
		return nil, false
	}
	return item.Object, true
}
func (c *cache) Modify(k string, f func(interface{}) interface{}) bool {
	c.mu.Lock()
	defer c.mu.Unlock()
	item, ok := c.items[k]
	if !ok {
		return false
	}
	if item.Expiration > 0 && time.Now().UnixNano() > item.Expiration {
		return false
	}
	item.Object = f(item.Object)
	c.items[k] = item
	return true
}
func (c *cache) Increment(k string, n int64) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	v, ok := c.items[k]
	if !ok || v.Expired() {
		return errors.New("zcache.Increment: item " + k + " not found")
	}
	switch v.Object.(type) {
	case int:
		v.Object = v.Object.(int) + int(n)
	case int8:
		v.Object = v.Object.(int8) + int8(n)
	case int16:
		v.Object = v.Object.(int16) + int16(n)
	case int32:
		v.Object = v.Object.(int32) + int32(n)
	case int64:
		v.Object = v.Object.(int64) + n
	case uint:
		v.Object = v.Object.(uint) + uint(n)
	case uintptr:
		v.Object = v.Object.(uintptr) + uintptr(n)
	case uint8:
		v.Object = v.Object.(uint8) + uint8(n)
	case uint16:
		v.Object = v.Object.(uint16) + uint16(n)
	case uint32:
		v.Object = v.Object.(uint32) + uint32(n)
	case uint64:
		v.Object = v.Object.(uint64) + uint64(n)
	case float32:
		v.Object = v.Object.(float32) + float32(n)
	case float64:
		v.Object = v.Object.(float64) + float64(n)
	default:
		return errors.New("zcache.Incremeny: the value for " + k + " is not an integer")
	}
	c.items[k] = v
	return nil
}
func (c *cache) Decrement(k string, n int64) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	v, ok := c.items[k]
	if !ok || v.Expired() {
		return errors.New("zcache.Decrement: item not found")
	}
	switch v.Object.(type) {
	case int:
		v.Object = v.Object.(int) - int(n)
	case int8:
		v.Object = v.Object.(int8) - int8(n)
	case int16:
		v.Object = v.Object.(int16) - int16(n)
	case int32:
		v.Object = v.Object.(int32) - int32(n)
	case int64:
		v.Object = v.Object.(int64) - n
	case uint:
		v.Object = v.Object.(uint) - uint(n)
	case uintptr:
		v.Object = v.Object.(uintptr) - uintptr(n)
	case uint8:
		v.Object = v.Object.(uint8) - uint8(n)
	case uint16:
		v.Object = v.Object.(uint16) - uint16(n)
	case uint32:
		v.Object = v.Object.(uint32) - uint32(n)
	case uint64:
		v.Object = v.Object.(uint64) - uint64(n)
	case float32:
		v.Object = v.Object.(float32) - float32(n)
	case float64:
		v.Object = v.Object.(float64) - float64(n)
	default:
		return errors.New("zcache.Decrement: the value for " + k + " is not an integer")
	}
	c.items[k] = v
	return nil
}
func (c *cache) Delete(k string) {
	c.mu.Lock()
	v, evicted := c.delete(k)
	c.mu.Unlock()
	if evicted {
		c.onEvicted(k, v)
	}
}
func (c *cache) Pop(k string) (interface{}, bool) {
	c.mu.Lock()
	item, ok := c.items[k]
	if !ok {
		c.mu.Unlock()
		return nil, false
	}
	if item.Expiration > 0 && time.Now().UnixNano() > item.Expiration {
		c.mu.Unlock()
		return nil, false
	}
	v, evicted := c.delete(k)
	c.mu.Unlock()
	if evicted {
		c.onEvicted(k, v)
	}
	return item.Object, true
}
func (c *cache) delete(k string) (interface{}, bool) {
	if c.onEvicted != nil {
		if v, ok := c.items[k]; ok {
			delete(c.items, k)
			return v.Object, true
		}
	}
	delete(c.items, k)
	return nil, false
}
type keyAndValue struct {
	key   string
	value interface{}
}
func (c *cache) DeleteExpired() {
	var evictedItems []keyAndValue
	now := time.Now().UnixNano()
	c.mu.Lock()
	for k, v := range c.items {
		if v.Expiration > 0 && now > v.Expiration {
			ov, evicted := c.delete(k)
			if evicted {
				evictedItems = append(evictedItems, keyAndValue{k, ov})
			}
		}
	}
	c.mu.Unlock()
	for _, v := range evictedItems {
		c.onEvicted(v.key, v.value)
	}
}
func (c *cache) OnEvicted(f func(string, interface{})) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.onEvicted = f
}
func (c *cache) Items() map[string]Item {
	c.mu.RLock()
	defer c.mu.RUnlock()
	m := make(map[string]Item, len(c.items))
	now := time.Now().UnixNano()
	for k, v := range c.items {
		if v.Expiration > 0 && now > v.Expiration {
			continue
		}
		m[k] = v
	}
	return m
}
func (c *cache) Keys() []string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	keys := make([]string, 0, len(c.items))
	now := time.Now().UnixNano()
	for k, v := range c.items {
		if v.Expiration > 0 && now > v.Expiration {
			continue
		}
		keys = append(keys, k)
	}
	return keys
}
func (c *cache) ItemCount() int {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return len(c.items)
}
func (c *cache) Reset() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.items = map[string]Item{}
}