This commit is contained in:
Luke Massa 2021-12-30 13:33:29 -05:00
parent d798983798
commit 625d094b84
3 changed files with 98 additions and 18 deletions

112
cache.go
View File

@ -1,10 +1,10 @@
package cache package cache
import ( import (
// "encoding/gob" "encoding/gob"
"fmt" "fmt"
// "io" "io"
// "os" "os"
"runtime" "runtime"
"sync" "sync"
"time" "time"
@ -193,32 +193,108 @@ type Decrementable interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~float32 | ~float64 ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~float32 | ~float64
} }
func Increment[I Incrementable](c *Cache[I], k string, n I) error {
func (c *cache[T]) Increment(k string, n int64) (T, error) {
c.mu.Lock() c.mu.Lock()
var zero T
v, found := c.items[k] v, found := c.items[k]
if !found || v.Expired() { if !found || v.Expired() {
c.mu.Unlock() c.mu.Unlock()
return fmt.Errorf("Item %s not found", k) return zero, fmt.Errorf("Item %s not found", k)
} }
v.Object = v.Object + n // Generics does not (currently?) support type switching
// To workaround, we convert the value into a interface{}, and switching on that
var untypedValue interface{}
untypedValue = v.Object
switch untypedValue.(type) {
case int:
untypedValue = untypedValue.(int) + int(n)
case int8:
untypedValue = untypedValue.(int8) + int8(n)
case int16:
untypedValue = untypedValue.(int16) + int16(n)
case int32:
untypedValue= untypedValue.(int32) + int32(n)
case int64:
untypedValue = untypedValue.(int64) + n
case uint:
untypedValue = untypedValue.(uint) + uint(n)
case uintptr:
untypedValue = untypedValue.(uintptr) + uintptr(n)
case uint8:
untypedValue = untypedValue.(uint8) + uint8(n)
case uint16:
untypedValue = untypedValue.(uint16) + uint16(n)
case uint32:
untypedValue = untypedValue.(uint32) + uint32(n)
case uint64:
untypedValue = untypedValue.(uint64) + uint64(n)
case float32:
untypedValue = untypedValue.(float32) + float32(n)
case float64:
untypedValue = untypedValue.(float64) + float64(n)
default:
c.mu.Unlock()
return zero, fmt.Errorf("The value for %s is not an integer", k)
}
v.Object = untypedValue.(T)
c.items[k] = v c.items[k] = v
c.mu.Unlock() c.mu.Unlock()
return nil return zero, nil
} }
func Decrement[D Decrementable](c *Cache[D], k string, n D) error { func (c *cache[T]) Decrement(k string, n int64) (T, error) {
c.mu.Lock() c.mu.Lock()
var zero T
v, found := c.items[k] v, found := c.items[k]
if !found || v.Expired() { if !found || v.Expired() {
c.mu.Unlock() c.mu.Unlock()
return fmt.Errorf("Item %s not found", k) return zero, fmt.Errorf("Item %s not found", k)
} }
v.Object = v.Object - n // Generics does not (currently?) support type switching
// To workaround, we convert the value into a interface{}, and switching on that
var untypedValue interface{}
untypedValue = v.Object
switch untypedValue.(type) {
case int:
untypedValue = untypedValue.(int) - int(n)
case int8:
untypedValue = untypedValue.(int8) - int8(n)
case int16:
untypedValue = untypedValue.(int16) - int16(n)
case int32:
untypedValue= untypedValue.(int32) - int32(n)
case int64:
untypedValue = untypedValue.(int64) - n
case uint:
untypedValue = untypedValue.(uint) - uint(n)
case uintptr:
untypedValue = untypedValue.(uintptr) - uintptr(n)
case uint8:
untypedValue = untypedValue.(uint8) - uint8(n)
case uint16:
untypedValue = untypedValue.(uint16) - uint16(n)
case uint32:
untypedValue = untypedValue.(uint32) - uint32(n)
case uint64:
untypedValue = untypedValue.(uint64) - uint64(n)
case float32:
untypedValue = untypedValue.(float32) - float32(n)
case float64:
untypedValue = untypedValue.(float64) - float64(n)
default:
c.mu.Unlock()
return zero, fmt.Errorf("The value for %s is not an integer", k)
}
v.Object = untypedValue.(T)
c.items[k] = v c.items[k] = v
c.mu.Unlock() c.mu.Unlock()
return nil return zero, nil
} }
// Delete an item from the cache. Does nothing if the key is not in the cache. // Delete an item from the cache. Does nothing if the key is not in the cache.
func (c *cache[T]) Delete(k string) { func (c *cache[T]) Delete(k string) {
c.mu.Lock() c.mu.Lock()
@ -275,12 +351,12 @@ func (c *cache[T]) OnEvicted(f func(string, T)) {
c.mu.Unlock() c.mu.Unlock()
} }
/*
// Write the cache's items (using Gob) to an io.Writer. // Write the cache's items (using Gob) to an io.Writer.
// //
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
// documentation for NewFrom().) // documentation for NewFrom().)
func (c *cache) Save(w io.Writer) (err error) { func (c *cache[T]) Save(w io.Writer) (err error) {
enc := gob.NewEncoder(w) enc := gob.NewEncoder(w)
defer func() { defer func() {
if x := recover(); x != nil { if x := recover(); x != nil {
@ -301,7 +377,7 @@ func (c *cache) Save(w io.Writer) (err error) {
// //
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
// documentation for NewFrom().) // documentation for NewFrom().)
func (c *cache) SaveFile(fname string) error { func (c *cache[T]) SaveFile(fname string) error {
fp, err := os.Create(fname) fp, err := os.Create(fname)
if err != nil { if err != nil {
return err return err
@ -319,9 +395,9 @@ func (c *cache) SaveFile(fname string) error {
// //
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
// documentation for NewFrom().) // documentation for NewFrom().)
func (c *cache) Load(r io.Reader) error { func (c *cache[T]) Load(r io.Reader) error {
dec := gob.NewDecoder(r) dec := gob.NewDecoder(r)
items := map[string]Item{} items := map[string]Item[T]{}
err := dec.Decode(&items) err := dec.Decode(&items)
if err == nil { if err == nil {
c.mu.Lock() c.mu.Lock()
@ -341,7 +417,7 @@ func (c *cache) Load(r io.Reader) error {
// //
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
// documentation for NewFrom().) // documentation for NewFrom().)
func (c *cache) LoadFile(fname string) error { func (c *cache[T]) LoadFile(fname string) error {
fp, err := os.Open(fname) fp, err := os.Open(fname)
if err != nil { if err != nil {
return err return err
@ -353,7 +429,7 @@ func (c *cache) LoadFile(fname string) error {
} }
return fp.Close() return fp.Close()
} }
*/
// Copies all unexpired items in the cache into a new map and returns it. // Copies all unexpired items in the cache into a new map and returns it.
func (c *cache[T]) Items() map[string]Item[T] { func (c *cache[T]) Items() map[string]Item[T] {

View File

@ -1,5 +1,6 @@
package cache package cache
/*
import ( import (
"crypto/rand" "crypto/rand"
"math" "math"
@ -190,3 +191,4 @@ func unexportedNewSharded(defaultExpiration, cleanupInterval time.Duration, shar
} }
return SC return SC
} }
*/

View File

@ -1,5 +1,6 @@
package cache package cache
/*
import ( import (
"strconv" "strconv"
"sync" "sync"
@ -83,3 +84,4 @@ func benchmarkShardedCacheGetManyConcurrent(b *testing.B, exp time.Duration) {
b.StartTimer() b.StartTimer()
wg.Wait() wg.Wait()
} }
*/