1package cache
2
3import (
4	"encoding/gob"
5	"fmt"
6	"io"
7	"os"
8	"runtime"
9	"sync"
10	"time"
11)
12
13type Item struct {
14	Object     interface{}
15	Expiration int64
16}
17
18// Returns true if the item has expired.
19func (item Item) Expired() bool {
20	if item.Expiration == 0 {
21		return false
22	}
23	return time.Now().UnixNano() > item.Expiration
24}
25
26const (
27	// For use with functions that take an expiration time.
28	NoExpiration time.Duration = -1
29	// For use with functions that take an expiration time. Equivalent to
30	// passing in the same expiration duration as was given to New() or
31	// NewFrom() when the cache was created (e.g. 5 minutes.)
32	DefaultExpiration time.Duration = 0
33)
34
35type Cache struct {
36	*cache
37	// If this is confusing, see the comment at the bottom of New()
38}
39
40type cache struct {
41	defaultExpiration time.Duration
42	items             map[string]Item
43	mu                sync.RWMutex
44	onEvicted         func(string, interface{})
45	janitor           *janitor
46}
47
48// Add an item to the cache, replacing any existing item. If the duration is 0
49// (DefaultExpiration), the cache's default expiration time is used. If it is -1
50// (NoExpiration), the item never expires.
51func (c *cache) Set(k string, x interface{}, d time.Duration) {
52	// "Inlining" of set
53	var e int64
54	if d == DefaultExpiration {
55		d = c.defaultExpiration
56	}
57	if d > 0 {
58		e = time.Now().Add(d).UnixNano()
59	}
60	c.mu.Lock()
61	c.items[k] = Item{
62		Object:     x,
63		Expiration: e,
64	}
65	// TODO: Calls to mu.Unlock are currently not deferred because defer
66	// adds ~200 ns (as of go1.)
67	c.mu.Unlock()
68}
69
70func (c *cache) set(k string, x interface{}, d time.Duration) {
71	var e int64
72	if d == DefaultExpiration {
73		d = c.defaultExpiration
74	}
75	if d > 0 {
76		e = time.Now().Add(d).UnixNano()
77	}
78	c.items[k] = Item{
79		Object:     x,
80		Expiration: e,
81	}
82}
83
84// Add an item to the cache, replacing any existing item, using the default
85// expiration.
86func (c *cache) SetDefault(k string, x interface{}) {
87	c.Set(k, x, DefaultExpiration)
88}
89
90// Add an item to the cache only if an item doesn't already exist for the given
91// key, or if the existing item has expired. Returns an error otherwise.
92func (c *cache) Add(k string, x interface{}, d time.Duration) error {
93	c.mu.Lock()
94	_, found := c.get(k)
95	if found {
96		c.mu.Unlock()
97		return fmt.Errorf("Item %s already exists", k)
98	}
99	c.set(k, x, d)
100	c.mu.Unlock()
101	return nil
102}
103
104// Set a new value for the cache key only if it already exists, and the existing
105// item hasn't expired. Returns an error otherwise.
106func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
107	c.mu.Lock()
108	_, found := c.get(k)
109	if !found {
110		c.mu.Unlock()
111		return fmt.Errorf("Item %s doesn't exist", k)
112	}
113	c.set(k, x, d)
114	c.mu.Unlock()
115	return nil
116}
117
118// Get an item from the cache. Returns the item or nil, and a bool indicating
119// whether the key was found.
120func (c *cache) Get(k string) (interface{}, bool) {
121	c.mu.RLock()
122	// "Inlining" of get and Expired
123	item, found := c.items[k]
124	if !found {
125		c.mu.RUnlock()
126		return nil, false
127	}
128	if item.Expiration > 0 {
129		if time.Now().UnixNano() > item.Expiration {
130			c.mu.RUnlock()
131			return nil, false
132		}
133	}
134	c.mu.RUnlock()
135	return item.Object, true
136}
137
138// GetWithExpiration returns an item and its expiration time from the cache.
139// It returns the item or nil, the expiration time if one is set (if the item
140// never expires a zero value for time.Time is returned), and a bool indicating
141// whether the key was found.
142func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) {
143	c.mu.RLock()
144	// "Inlining" of get and Expired
145	item, found := c.items[k]
146	if !found {
147		c.mu.RUnlock()
148		return nil, time.Time{}, false
149	}
150
151	if item.Expiration > 0 {
152		if time.Now().UnixNano() > item.Expiration {
153			c.mu.RUnlock()
154			return nil, time.Time{}, false
155		}
156
157		// Return the item and the expiration time
158		c.mu.RUnlock()
159		return item.Object, time.Unix(0, item.Expiration), true
160	}
161
162	// If expiration <= 0 (i.e. no expiration time set) then return the item
163	// and a zeroed time.Time
164	c.mu.RUnlock()
165	return item.Object, time.Time{}, true
166}
167
168func (c *cache) get(k string) (interface{}, bool) {
169	item, found := c.items[k]
170	if !found {
171		return nil, false
172	}
173	// "Inlining" of Expired
174	if item.Expiration > 0 {
175		if time.Now().UnixNano() > item.Expiration {
176			return nil, false
177		}
178	}
179	return item.Object, true
180}
181
182// Increment an item of type int, int8, int16, int32, int64, uintptr, uint,
183// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
184// item's value is not an integer, if it was not found, or if it is not
185// possible to increment it by n. To retrieve the incremented value, use one
186// of the specialized methods, e.g. IncrementInt64.
187func (c *cache) Increment(k string, n int64) error {
188	c.mu.Lock()
189	v, found := c.items[k]
190	if !found || v.Expired() {
191		c.mu.Unlock()
192		return fmt.Errorf("Item %s not found", k)
193	}
194	switch v.Object.(type) {
195	case int:
196		v.Object = v.Object.(int) + int(n)
197	case int8:
198		v.Object = v.Object.(int8) + int8(n)
199	case int16:
200		v.Object = v.Object.(int16) + int16(n)
201	case int32:
202		v.Object = v.Object.(int32) + int32(n)
203	case int64:
204		v.Object = v.Object.(int64) + n
205	case uint:
206		v.Object = v.Object.(uint) + uint(n)
207	case uintptr:
208		v.Object = v.Object.(uintptr) + uintptr(n)
209	case uint8:
210		v.Object = v.Object.(uint8) + uint8(n)
211	case uint16:
212		v.Object = v.Object.(uint16) + uint16(n)
213	case uint32:
214		v.Object = v.Object.(uint32) + uint32(n)
215	case uint64:
216		v.Object = v.Object.(uint64) + uint64(n)
217	case float32:
218		v.Object = v.Object.(float32) + float32(n)
219	case float64:
220		v.Object = v.Object.(float64) + float64(n)
221	default:
222		c.mu.Unlock()
223		return fmt.Errorf("The value for %s is not an integer", k)
224	}
225	c.items[k] = v
226	c.mu.Unlock()
227	return nil
228}
229
230// Increment an item of type float32 or float64 by n. Returns an error if the
231// item's value is not floating point, if it was not found, or if it is not
232// possible to increment it by n. Pass a negative number to decrement the
233// value. To retrieve the incremented value, use one of the specialized methods,
234// e.g. IncrementFloat64.
235func (c *cache) IncrementFloat(k string, n float64) error {
236	c.mu.Lock()
237	v, found := c.items[k]
238	if !found || v.Expired() {
239		c.mu.Unlock()
240		return fmt.Errorf("Item %s not found", k)
241	}
242	switch v.Object.(type) {
243	case float32:
244		v.Object = v.Object.(float32) + float32(n)
245	case float64:
246		v.Object = v.Object.(float64) + n
247	default:
248		c.mu.Unlock()
249		return fmt.Errorf("The value for %s does not have type float32 or float64", k)
250	}
251	c.items[k] = v
252	c.mu.Unlock()
253	return nil
254}
255
256// Increment an item of type int by n. Returns an error if the item's value is
257// not an int, or if it was not found. If there is no error, the incremented
258// value is returned.
259func (c *cache) IncrementInt(k string, n int) (int, error) {
260	c.mu.Lock()
261	v, found := c.items[k]
262	if !found || v.Expired() {
263		c.mu.Unlock()
264		return 0, fmt.Errorf("Item %s not found", k)
265	}
266	rv, ok := v.Object.(int)
267	if !ok {
268		c.mu.Unlock()
269		return 0, fmt.Errorf("The value for %s is not an int", k)
270	}
271	nv := rv + n
272	v.Object = nv
273	c.items[k] = v
274	c.mu.Unlock()
275	return nv, nil
276}
277
278// Increment an item of type int8 by n. Returns an error if the item's value is
279// not an int8, or if it was not found. If there is no error, the incremented
280// value is returned.
281func (c *cache) IncrementInt8(k string, n int8) (int8, error) {
282	c.mu.Lock()
283	v, found := c.items[k]
284	if !found || v.Expired() {
285		c.mu.Unlock()
286		return 0, fmt.Errorf("Item %s not found", k)
287	}
288	rv, ok := v.Object.(int8)
289	if !ok {
290		c.mu.Unlock()
291		return 0, fmt.Errorf("The value for %s is not an int8", k)
292	}
293	nv := rv + n
294	v.Object = nv
295	c.items[k] = v
296	c.mu.Unlock()
297	return nv, nil
298}
299
300// Increment an item of type int16 by n. Returns an error if the item's value is
301// not an int16, or if it was not found. If there is no error, the incremented
302// value is returned.
303func (c *cache) IncrementInt16(k string, n int16) (int16, error) {
304	c.mu.Lock()
305	v, found := c.items[k]
306	if !found || v.Expired() {
307		c.mu.Unlock()
308		return 0, fmt.Errorf("Item %s not found", k)
309	}
310	rv, ok := v.Object.(int16)
311	if !ok {
312		c.mu.Unlock()
313		return 0, fmt.Errorf("The value for %s is not an int16", k)
314	}
315	nv := rv + n
316	v.Object = nv
317	c.items[k] = v
318	c.mu.Unlock()
319	return nv, nil
320}
321
322// Increment an item of type int32 by n. Returns an error if the item's value is
323// not an int32, or if it was not found. If there is no error, the incremented
324// value is returned.
325func (c *cache) IncrementInt32(k string, n int32) (int32, error) {
326	c.mu.Lock()
327	v, found := c.items[k]
328	if !found || v.Expired() {
329		c.mu.Unlock()
330		return 0, fmt.Errorf("Item %s not found", k)
331	}
332	rv, ok := v.Object.(int32)
333	if !ok {
334		c.mu.Unlock()
335		return 0, fmt.Errorf("The value for %s is not an int32", k)
336	}
337	nv := rv + n
338	v.Object = nv
339	c.items[k] = v
340	c.mu.Unlock()
341	return nv, nil
342}
343
344// Increment an item of type int64 by n. Returns an error if the item's value is
345// not an int64, or if it was not found. If there is no error, the incremented
346// value is returned.
347func (c *cache) IncrementInt64(k string, n int64) (int64, error) {
348	c.mu.Lock()
349	v, found := c.items[k]
350	if !found || v.Expired() {
351		c.mu.Unlock()
352		return 0, fmt.Errorf("Item %s not found", k)
353	}
354	rv, ok := v.Object.(int64)
355	if !ok {
356		c.mu.Unlock()
357		return 0, fmt.Errorf("The value for %s is not an int64", k)
358	}
359	nv := rv + n
360	v.Object = nv
361	c.items[k] = v
362	c.mu.Unlock()
363	return nv, nil
364}
365
366// Increment an item of type uint by n. Returns an error if the item's value is
367// not an uint, or if it was not found. If there is no error, the incremented
368// value is returned.
369func (c *cache) IncrementUint(k string, n uint) (uint, error) {
370	c.mu.Lock()
371	v, found := c.items[k]
372	if !found || v.Expired() {
373		c.mu.Unlock()
374		return 0, fmt.Errorf("Item %s not found", k)
375	}
376	rv, ok := v.Object.(uint)
377	if !ok {
378		c.mu.Unlock()
379		return 0, fmt.Errorf("The value for %s is not an uint", k)
380	}
381	nv := rv + n
382	v.Object = nv
383	c.items[k] = v
384	c.mu.Unlock()
385	return nv, nil
386}
387
388// Increment an item of type uintptr by n. Returns an error if the item's value
389// is not an uintptr, or if it was not found. If there is no error, the
390// incremented value is returned.
391func (c *cache) IncrementUintptr(k string, n uintptr) (uintptr, error) {
392	c.mu.Lock()
393	v, found := c.items[k]
394	if !found || v.Expired() {
395		c.mu.Unlock()
396		return 0, fmt.Errorf("Item %s not found", k)
397	}
398	rv, ok := v.Object.(uintptr)
399	if !ok {
400		c.mu.Unlock()
401		return 0, fmt.Errorf("The value for %s is not an uintptr", k)
402	}
403	nv := rv + n
404	v.Object = nv
405	c.items[k] = v
406	c.mu.Unlock()
407	return nv, nil
408}
409
410// Increment an item of type uint8 by n. Returns an error if the item's value
411// is not an uint8, or if it was not found. If there is no error, the
412// incremented value is returned.
413func (c *cache) IncrementUint8(k string, n uint8) (uint8, error) {
414	c.mu.Lock()
415	v, found := c.items[k]
416	if !found || v.Expired() {
417		c.mu.Unlock()
418		return 0, fmt.Errorf("Item %s not found", k)
419	}
420	rv, ok := v.Object.(uint8)
421	if !ok {
422		c.mu.Unlock()
423		return 0, fmt.Errorf("The value for %s is not an uint8", k)
424	}
425	nv := rv + n
426	v.Object = nv
427	c.items[k] = v
428	c.mu.Unlock()
429	return nv, nil
430}
431
432// Increment an item of type uint16 by n. Returns an error if the item's value
433// is not an uint16, or if it was not found. If there is no error, the
434// incremented value is returned.
435func (c *cache) IncrementUint16(k string, n uint16) (uint16, error) {
436	c.mu.Lock()
437	v, found := c.items[k]
438	if !found || v.Expired() {
439		c.mu.Unlock()
440		return 0, fmt.Errorf("Item %s not found", k)
441	}
442	rv, ok := v.Object.(uint16)
443	if !ok {
444		c.mu.Unlock()
445		return 0, fmt.Errorf("The value for %s is not an uint16", k)
446	}
447	nv := rv + n
448	v.Object = nv
449	c.items[k] = v
450	c.mu.Unlock()
451	return nv, nil
452}
453
454// Increment an item of type uint32 by n. Returns an error if the item's value
455// is not an uint32, or if it was not found. If there is no error, the
456// incremented value is returned.
457func (c *cache) IncrementUint32(k string, n uint32) (uint32, error) {
458	c.mu.Lock()
459	v, found := c.items[k]
460	if !found || v.Expired() {
461		c.mu.Unlock()
462		return 0, fmt.Errorf("Item %s not found", k)
463	}
464	rv, ok := v.Object.(uint32)
465	if !ok {
466		c.mu.Unlock()
467		return 0, fmt.Errorf("The value for %s is not an uint32", k)
468	}
469	nv := rv + n
470	v.Object = nv
471	c.items[k] = v
472	c.mu.Unlock()
473	return nv, nil
474}
475
476// Increment an item of type uint64 by n. Returns an error if the item's value
477// is not an uint64, or if it was not found. If there is no error, the
478// incremented value is returned.
479func (c *cache) IncrementUint64(k string, n uint64) (uint64, error) {
480	c.mu.Lock()
481	v, found := c.items[k]
482	if !found || v.Expired() {
483		c.mu.Unlock()
484		return 0, fmt.Errorf("Item %s not found", k)
485	}
486	rv, ok := v.Object.(uint64)
487	if !ok {
488		c.mu.Unlock()
489		return 0, fmt.Errorf("The value for %s is not an uint64", k)
490	}
491	nv := rv + n
492	v.Object = nv
493	c.items[k] = v
494	c.mu.Unlock()
495	return nv, nil
496}
497
498// Increment an item of type float32 by n. Returns an error if the item's value
499// is not an float32, or if it was not found. If there is no error, the
500// incremented value is returned.
501func (c *cache) IncrementFloat32(k string, n float32) (float32, error) {
502	c.mu.Lock()
503	v, found := c.items[k]
504	if !found || v.Expired() {
505		c.mu.Unlock()
506		return 0, fmt.Errorf("Item %s not found", k)
507	}
508	rv, ok := v.Object.(float32)
509	if !ok {
510		c.mu.Unlock()
511		return 0, fmt.Errorf("The value for %s is not an float32", k)
512	}
513	nv := rv + n
514	v.Object = nv
515	c.items[k] = v
516	c.mu.Unlock()
517	return nv, nil
518}
519
520// Increment an item of type float64 by n. Returns an error if the item's value
521// is not an float64, or if it was not found. If there is no error, the
522// incremented value is returned.
523func (c *cache) IncrementFloat64(k string, n float64) (float64, error) {
524	c.mu.Lock()
525	v, found := c.items[k]
526	if !found || v.Expired() {
527		c.mu.Unlock()
528		return 0, fmt.Errorf("Item %s not found", k)
529	}
530	rv, ok := v.Object.(float64)
531	if !ok {
532		c.mu.Unlock()
533		return 0, fmt.Errorf("The value for %s is not an float64", k)
534	}
535	nv := rv + n
536	v.Object = nv
537	c.items[k] = v
538	c.mu.Unlock()
539	return nv, nil
540}
541
542// Decrement an item of type int, int8, int16, int32, int64, uintptr, uint,
543// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
544// item's value is not an integer, if it was not found, or if it is not
545// possible to decrement it by n. To retrieve the decremented value, use one
546// of the specialized methods, e.g. DecrementInt64.
547func (c *cache) Decrement(k string, n int64) error {
548	// TODO: Implement Increment and Decrement more cleanly.
549	// (Cannot do Increment(k, n*-1) for uints.)
550	c.mu.Lock()
551	v, found := c.items[k]
552	if !found || v.Expired() {
553		c.mu.Unlock()
554		return fmt.Errorf("Item not found")
555	}
556	switch v.Object.(type) {
557	case int:
558		v.Object = v.Object.(int) - int(n)
559	case int8:
560		v.Object = v.Object.(int8) - int8(n)
561	case int16:
562		v.Object = v.Object.(int16) - int16(n)
563	case int32:
564		v.Object = v.Object.(int32) - int32(n)
565	case int64:
566		v.Object = v.Object.(int64) - n
567	case uint:
568		v.Object = v.Object.(uint) - uint(n)
569	case uintptr:
570		v.Object = v.Object.(uintptr) - uintptr(n)
571	case uint8:
572		v.Object = v.Object.(uint8) - uint8(n)
573	case uint16:
574		v.Object = v.Object.(uint16) - uint16(n)
575	case uint32:
576		v.Object = v.Object.(uint32) - uint32(n)
577	case uint64:
578		v.Object = v.Object.(uint64) - uint64(n)
579	case float32:
580		v.Object = v.Object.(float32) - float32(n)
581	case float64:
582		v.Object = v.Object.(float64) - float64(n)
583	default:
584		c.mu.Unlock()
585		return fmt.Errorf("The value for %s is not an integer", k)
586	}
587	c.items[k] = v
588	c.mu.Unlock()
589	return nil
590}
591
592// Decrement an item of type float32 or float64 by n. Returns an error if the
593// item's value is not floating point, if it was not found, or if it is not
594// possible to decrement it by n. Pass a negative number to decrement the
595// value. To retrieve the decremented value, use one of the specialized methods,
596// e.g. DecrementFloat64.
597func (c *cache) DecrementFloat(k string, n float64) error {
598	c.mu.Lock()
599	v, found := c.items[k]
600	if !found || v.Expired() {
601		c.mu.Unlock()
602		return fmt.Errorf("Item %s not found", k)
603	}
604	switch v.Object.(type) {
605	case float32:
606		v.Object = v.Object.(float32) - float32(n)
607	case float64:
608		v.Object = v.Object.(float64) - n
609	default:
610		c.mu.Unlock()
611		return fmt.Errorf("The value for %s does not have type float32 or float64", k)
612	}
613	c.items[k] = v
614	c.mu.Unlock()
615	return nil
616}
617
618// Decrement an item of type int by n. Returns an error if the item's value is
619// not an int, or if it was not found. If there is no error, the decremented
620// value is returned.
621func (c *cache) DecrementInt(k string, n int) (int, error) {
622	c.mu.Lock()
623	v, found := c.items[k]
624	if !found || v.Expired() {
625		c.mu.Unlock()
626		return 0, fmt.Errorf("Item %s not found", k)
627	}
628	rv, ok := v.Object.(int)
629	if !ok {
630		c.mu.Unlock()
631		return 0, fmt.Errorf("The value for %s is not an int", k)
632	}
633	nv := rv - n
634	v.Object = nv
635	c.items[k] = v
636	c.mu.Unlock()
637	return nv, nil
638}
639
640// Decrement an item of type int8 by n. Returns an error if the item's value is
641// not an int8, or if it was not found. If there is no error, the decremented
642// value is returned.
643func (c *cache) DecrementInt8(k string, n int8) (int8, error) {
644	c.mu.Lock()
645	v, found := c.items[k]
646	if !found || v.Expired() {
647		c.mu.Unlock()
648		return 0, fmt.Errorf("Item %s not found", k)
649	}
650	rv, ok := v.Object.(int8)
651	if !ok {
652		c.mu.Unlock()
653		return 0, fmt.Errorf("The value for %s is not an int8", k)
654	}
655	nv := rv - n
656	v.Object = nv
657	c.items[k] = v
658	c.mu.Unlock()
659	return nv, nil
660}
661
662// Decrement an item of type int16 by n. Returns an error if the item's value is
663// not an int16, or if it was not found. If there is no error, the decremented
664// value is returned.
665func (c *cache) DecrementInt16(k string, n int16) (int16, error) {
666	c.mu.Lock()
667	v, found := c.items[k]
668	if !found || v.Expired() {
669		c.mu.Unlock()
670		return 0, fmt.Errorf("Item %s not found", k)
671	}
672	rv, ok := v.Object.(int16)
673	if !ok {
674		c.mu.Unlock()
675		return 0, fmt.Errorf("The value for %s is not an int16", k)
676	}
677	nv := rv - n
678	v.Object = nv
679	c.items[k] = v
680	c.mu.Unlock()
681	return nv, nil
682}
683
684// Decrement an item of type int32 by n. Returns an error if the item's value is
685// not an int32, or if it was not found. If there is no error, the decremented
686// value is returned.
687func (c *cache) DecrementInt32(k string, n int32) (int32, error) {
688	c.mu.Lock()
689	v, found := c.items[k]
690	if !found || v.Expired() {
691		c.mu.Unlock()
692		return 0, fmt.Errorf("Item %s not found", k)
693	}
694	rv, ok := v.Object.(int32)
695	if !ok {
696		c.mu.Unlock()
697		return 0, fmt.Errorf("The value for %s is not an int32", k)
698	}
699	nv := rv - n
700	v.Object = nv
701	c.items[k] = v
702	c.mu.Unlock()
703	return nv, nil
704}
705
706// Decrement an item of type int64 by n. Returns an error if the item's value is
707// not an int64, or if it was not found. If there is no error, the decremented
708// value is returned.
709func (c *cache) DecrementInt64(k string, n int64) (int64, error) {
710	c.mu.Lock()
711	v, found := c.items[k]
712	if !found || v.Expired() {
713		c.mu.Unlock()
714		return 0, fmt.Errorf("Item %s not found", k)
715	}
716	rv, ok := v.Object.(int64)
717	if !ok {
718		c.mu.Unlock()
719		return 0, fmt.Errorf("The value for %s is not an int64", k)
720	}
721	nv := rv - n
722	v.Object = nv
723	c.items[k] = v
724	c.mu.Unlock()
725	return nv, nil
726}
727
728// Decrement an item of type uint by n. Returns an error if the item's value is
729// not an uint, or if it was not found. If there is no error, the decremented
730// value is returned.
731func (c *cache) DecrementUint(k string, n uint) (uint, error) {
732	c.mu.Lock()
733	v, found := c.items[k]
734	if !found || v.Expired() {
735		c.mu.Unlock()
736		return 0, fmt.Errorf("Item %s not found", k)
737	}
738	rv, ok := v.Object.(uint)
739	if !ok {
740		c.mu.Unlock()
741		return 0, fmt.Errorf("The value for %s is not an uint", k)
742	}
743	nv := rv - n
744	v.Object = nv
745	c.items[k] = v
746	c.mu.Unlock()
747	return nv, nil
748}
749
750// Decrement an item of type uintptr by n. Returns an error if the item's value
751// is not an uintptr, or if it was not found. If there is no error, the
752// decremented value is returned.
753func (c *cache) DecrementUintptr(k string, n uintptr) (uintptr, error) {
754	c.mu.Lock()
755	v, found := c.items[k]
756	if !found || v.Expired() {
757		c.mu.Unlock()
758		return 0, fmt.Errorf("Item %s not found", k)
759	}
760	rv, ok := v.Object.(uintptr)
761	if !ok {
762		c.mu.Unlock()
763		return 0, fmt.Errorf("The value for %s is not an uintptr", k)
764	}
765	nv := rv - n
766	v.Object = nv
767	c.items[k] = v
768	c.mu.Unlock()
769	return nv, nil
770}
771
772// Decrement an item of type uint8 by n. Returns an error if the item's value is
773// not an uint8, or if it was not found. If there is no error, the decremented
774// value is returned.
775func (c *cache) DecrementUint8(k string, n uint8) (uint8, error) {
776	c.mu.Lock()
777	v, found := c.items[k]
778	if !found || v.Expired() {
779		c.mu.Unlock()
780		return 0, fmt.Errorf("Item %s not found", k)
781	}
782	rv, ok := v.Object.(uint8)
783	if !ok {
784		c.mu.Unlock()
785		return 0, fmt.Errorf("The value for %s is not an uint8", k)
786	}
787	nv := rv - n
788	v.Object = nv
789	c.items[k] = v
790	c.mu.Unlock()
791	return nv, nil
792}
793
794// Decrement an item of type uint16 by n. Returns an error if the item's value
795// is not an uint16, or if it was not found. If there is no error, the
796// decremented value is returned.
797func (c *cache) DecrementUint16(k string, n uint16) (uint16, error) {
798	c.mu.Lock()
799	v, found := c.items[k]
800	if !found || v.Expired() {
801		c.mu.Unlock()
802		return 0, fmt.Errorf("Item %s not found", k)
803	}
804	rv, ok := v.Object.(uint16)
805	if !ok {
806		c.mu.Unlock()
807		return 0, fmt.Errorf("The value for %s is not an uint16", k)
808	}
809	nv := rv - n
810	v.Object = nv
811	c.items[k] = v
812	c.mu.Unlock()
813	return nv, nil
814}
815
816// Decrement an item of type uint32 by n. Returns an error if the item's value
817// is not an uint32, or if it was not found. If there is no error, the
818// decremented value is returned.
819func (c *cache) DecrementUint32(k string, n uint32) (uint32, error) {
820	c.mu.Lock()
821	v, found := c.items[k]
822	if !found || v.Expired() {
823		c.mu.Unlock()
824		return 0, fmt.Errorf("Item %s not found", k)
825	}
826	rv, ok := v.Object.(uint32)
827	if !ok {
828		c.mu.Unlock()
829		return 0, fmt.Errorf("The value for %s is not an uint32", k)
830	}
831	nv := rv - n
832	v.Object = nv
833	c.items[k] = v
834	c.mu.Unlock()
835	return nv, nil
836}
837
838// Decrement an item of type uint64 by n. Returns an error if the item's value
839// is not an uint64, or if it was not found. If there is no error, the
840// decremented value is returned.
841func (c *cache) DecrementUint64(k string, n uint64) (uint64, error) {
842	c.mu.Lock()
843	v, found := c.items[k]
844	if !found || v.Expired() {
845		c.mu.Unlock()
846		return 0, fmt.Errorf("Item %s not found", k)
847	}
848	rv, ok := v.Object.(uint64)
849	if !ok {
850		c.mu.Unlock()
851		return 0, fmt.Errorf("The value for %s is not an uint64", k)
852	}
853	nv := rv - n
854	v.Object = nv
855	c.items[k] = v
856	c.mu.Unlock()
857	return nv, nil
858}
859
860// Decrement an item of type float32 by n. Returns an error if the item's value
861// is not an float32, or if it was not found. If there is no error, the
862// decremented value is returned.
863func (c *cache) DecrementFloat32(k string, n float32) (float32, error) {
864	c.mu.Lock()
865	v, found := c.items[k]
866	if !found || v.Expired() {
867		c.mu.Unlock()
868		return 0, fmt.Errorf("Item %s not found", k)
869	}
870	rv, ok := v.Object.(float32)
871	if !ok {
872		c.mu.Unlock()
873		return 0, fmt.Errorf("The value for %s is not an float32", k)
874	}
875	nv := rv - n
876	v.Object = nv
877	c.items[k] = v
878	c.mu.Unlock()
879	return nv, nil
880}
881
882// Decrement an item of type float64 by n. Returns an error if the item's value
883// is not an float64, or if it was not found. If there is no error, the
884// decremented value is returned.
885func (c *cache) DecrementFloat64(k string, n float64) (float64, error) {
886	c.mu.Lock()
887	v, found := c.items[k]
888	if !found || v.Expired() {
889		c.mu.Unlock()
890		return 0, fmt.Errorf("Item %s not found", k)
891	}
892	rv, ok := v.Object.(float64)
893	if !ok {
894		c.mu.Unlock()
895		return 0, fmt.Errorf("The value for %s is not an float64", k)
896	}
897	nv := rv - n
898	v.Object = nv
899	c.items[k] = v
900	c.mu.Unlock()
901	return nv, nil
902}
903
904// Delete an item from the cache. Does nothing if the key is not in the cache.
905func (c *cache) Delete(k string) {
906	c.mu.Lock()
907	v, evicted := c.delete(k)
908	c.mu.Unlock()
909	if evicted {
910		c.onEvicted(k, v)
911	}
912}
913
914func (c *cache) delete(k string) (interface{}, bool) {
915	if c.onEvicted != nil {
916		if v, found := c.items[k]; found {
917			delete(c.items, k)
918			return v.Object, true
919		}
920	}
921	delete(c.items, k)
922	return nil, false
923}
924
925type keyAndValue struct {
926	key   string
927	value interface{}
928}
929
930// Delete all expired items from the cache.
931func (c *cache) DeleteExpired() {
932	var evictedItems []keyAndValue
933	now := time.Now().UnixNano()
934	c.mu.Lock()
935	for k, v := range c.items {
936		// "Inlining" of expired
937		if v.Expiration > 0 && now > v.Expiration {
938			ov, evicted := c.delete(k)
939			if evicted {
940				evictedItems = append(evictedItems, keyAndValue{k, ov})
941			}
942		}
943	}
944	c.mu.Unlock()
945	for _, v := range evictedItems {
946		c.onEvicted(v.key, v.value)
947	}
948}
949
950// Sets an (optional) function that is called with the key and value when an
951// item is evicted from the cache. (Including when it is deleted manually, but
952// not when it is overwritten.) Set to nil to disable.
953func (c *cache) OnEvicted(f func(string, interface{})) {
954	c.mu.Lock()
955	c.onEvicted = f
956	c.mu.Unlock()
957}
958
959// Write the cache's items (using Gob) to an io.Writer.
960//
961// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
962// documentation for NewFrom().)
963func (c *cache) Save(w io.Writer) (err error) {
964	enc := gob.NewEncoder(w)
965	defer func() {
966		if x := recover(); x != nil {
967			err = fmt.Errorf("Error registering item types with Gob library")
968		}
969	}()
970	c.mu.RLock()
971	defer c.mu.RUnlock()
972	for _, v := range c.items {
973		gob.Register(v.Object)
974	}
975	err = enc.Encode(&c.items)
976	return
977}
978
979// Save the cache's items to the given filename, creating the file if it
980// doesn't exist, and overwriting it if it does.
981//
982// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
983// documentation for NewFrom().)
984func (c *cache) SaveFile(fname string) error {
985	fp, err := os.Create(fname)
986	if err != nil {
987		return err
988	}
989	err = c.Save(fp)
990	if err != nil {
991		fp.Close()
992		return err
993	}
994	return fp.Close()
995}
996
997// Add (Gob-serialized) cache items from an io.Reader, excluding any items with
998// keys that already exist (and haven't expired) in the current cache.
999//
1000// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
1001// documentation for NewFrom().)
1002func (c *cache) Load(r io.Reader) error {
1003	dec := gob.NewDecoder(r)
1004	items := map[string]Item{}
1005	err := dec.Decode(&items)
1006	if err == nil {
1007		c.mu.Lock()
1008		defer c.mu.Unlock()
1009		for k, v := range items {
1010			ov, found := c.items[k]
1011			if !found || ov.Expired() {
1012				c.items[k] = v
1013			}
1014		}
1015	}
1016	return err
1017}
1018
1019// Load and add cache items from the given filename, excluding any items with
1020// keys that already exist in the current cache.
1021//
1022// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
1023// documentation for NewFrom().)
1024func (c *cache) LoadFile(fname string) error {
1025	fp, err := os.Open(fname)
1026	if err != nil {
1027		return err
1028	}
1029	err = c.Load(fp)
1030	if err != nil {
1031		fp.Close()
1032		return err
1033	}
1034	return fp.Close()
1035}
1036
1037// Copies all unexpired items in the cache into a new map and returns it.
1038func (c *cache) Items() map[string]Item {
1039	c.mu.RLock()
1040	defer c.mu.RUnlock()
1041	m := make(map[string]Item, len(c.items))
1042	now := time.Now().UnixNano()
1043	for k, v := range c.items {
1044		// "Inlining" of Expired
1045		if v.Expiration > 0 {
1046			if now > v.Expiration {
1047				continue
1048			}
1049		}
1050		m[k] = v
1051	}
1052	return m
1053}
1054
1055// Returns the number of items in the cache. This may include items that have
1056// expired, but have not yet been cleaned up.
1057func (c *cache) ItemCount() int {
1058	c.mu.RLock()
1059	n := len(c.items)
1060	c.mu.RUnlock()
1061	return n
1062}
1063
1064// Delete all items from the cache.
1065func (c *cache) Flush() {
1066	c.mu.Lock()
1067	c.items = map[string]Item{}
1068	c.mu.Unlock()
1069}
1070
1071type janitor struct {
1072	Interval time.Duration
1073	stop     chan bool
1074}
1075
1076func (j *janitor) Run(c *cache) {
1077	ticker := time.NewTicker(j.Interval)
1078	for {
1079		select {
1080		case <-ticker.C:
1081			c.DeleteExpired()
1082		case <-j.stop:
1083			ticker.Stop()
1084			return
1085		}
1086	}
1087}
1088
1089func stopJanitor(c *Cache) {
1090	c.janitor.stop <- true
1091}
1092
1093func runJanitor(c *cache, ci time.Duration) {
1094	j := &janitor{
1095		Interval: ci,
1096		stop:     make(chan bool),
1097	}
1098	c.janitor = j
1099	go j.Run(c)
1100}
1101
1102func newCache(de time.Duration, m map[string]Item) *cache {
1103	if de == 0 {
1104		de = -1
1105	}
1106	c := &cache{
1107		defaultExpiration: de,
1108		items:             m,
1109	}
1110	return c
1111}
1112
1113func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
1114	c := newCache(de, m)
1115	// This trick ensures that the janitor goroutine (which--granted it
1116	// was enabled--is running DeleteExpired on c forever) does not keep
1117	// the returned C object from being garbage collected. When it is
1118	// garbage collected, the finalizer stops the janitor goroutine, after
1119	// which c can be collected.
1120	C := &Cache{c}
1121	if ci > 0 {
1122		runJanitor(c, ci)
1123		runtime.SetFinalizer(C, stopJanitor)
1124	}
1125	return C
1126}
1127
1128// Return a new cache with a given default expiration duration and cleanup
1129// interval. If the expiration duration is less than one (or NoExpiration),
1130// the items in the cache never expire (by default), and must be deleted
1131// manually. If the cleanup interval is less than one, expired items are not
1132// deleted from the cache before calling c.DeleteExpired().
1133func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
1134	items := make(map[string]Item)
1135	return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
1136}
1137
1138// Return a new cache with a given default expiration duration and cleanup
1139// interval. If the expiration duration is less than one (or NoExpiration),
1140// the items in the cache never expire (by default), and must be deleted
1141// manually. If the cleanup interval is less than one, expired items are not
1142// deleted from the cache before calling c.DeleteExpired().
1143//
1144// NewFrom() also accepts an items map which will serve as the underlying map
1145// for the cache. This is useful for starting from a deserialized cache
1146// (serialized using e.g. gob.Encode() on c.Items()), or passing in e.g.
1147// make(map[string]Item, 500) to improve startup performance when the cache
1148// is expected to reach a certain minimum size.
1149//
1150// Only the cache's methods synchronize access to this map, so it is not
1151// recommended to keep any references to the map around after creating a cache.
1152// If need be, the map can be accessed at a later point using c.Items() (subject
1153// to the same caveat.)
1154//
1155// Note regarding serialization: When using e.g. gob, make sure to
1156// gob.Register() the individual types stored in the cache before encoding a
1157// map retrieved with c.Items(), and to register those same types before
1158// decoding a blob containing an items map.
1159func NewFrom(defaultExpiration, cleanupInterval time.Duration, items map[string]Item) *Cache {
1160	return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
1161}
1162