github.com/phuslu/lru@v1.0.16-0.20240421170520-46288a2fd47c/options.go (about) 1 package lru 2 3 import ( 4 "context" 5 "errors" 6 "runtime" 7 "time" 8 "unsafe" 9 ) 10 11 // Option is an interface for LRUCache and TTLCache configuration. 12 type Option[K comparable, V any] interface { 13 applyToLRUCache(*LRUCache[K, V]) 14 applyToTTLCache(*TTLCache[K, V]) 15 } 16 17 // WithShards specifies the shards count of cache. 18 func WithShards[K comparable, V any](count uint32) Option[K, V] { 19 return &shardsOption[K, V]{count: count} 20 } 21 22 type shardsOption[K comparable, V any] struct { 23 count uint32 24 } 25 26 func (o *shardsOption[K, V]) getcount(maxcount uint32) uint32 { 27 var shardcount uint32 28 if o.count == 0 { 29 shardcount = nextPowOf2(uint32(runtime.GOMAXPROCS(0) * 16)) 30 } else { 31 shardcount = nextPowOf2(o.count) 32 } 33 if shardcount > maxcount { 34 shardcount = maxcount 35 } 36 return shardcount 37 } 38 39 func (o *shardsOption[K, V]) applyToLRUCache(c *LRUCache[K, V]) { 40 c.mask = o.getcount(uint32(len(c.shards))) - 1 41 } 42 43 func (o *shardsOption[K, V]) applyToTTLCache(c *TTLCache[K, V]) { 44 c.mask = o.getcount(uint32(len(c.shards))) - 1 45 } 46 47 // WithHasher specifies the hasher function of cache. 48 func WithHasher[K comparable, V any](hasher func(key unsafe.Pointer, seed uintptr) (hash uintptr)) Option[K, V] { 49 return &hasherOption[K, V]{hasher: hasher} 50 } 51 52 type hasherOption[K comparable, V any] struct { 53 hasher func(key unsafe.Pointer, seed uintptr) (hash uintptr) 54 } 55 56 func (o *hasherOption[K, V]) applyToLRUCache(c *LRUCache[K, V]) { 57 c.hasher = o.hasher 58 } 59 60 func (o *hasherOption[K, V]) applyToTTLCache(c *TTLCache[K, V]) { 61 c.hasher = o.hasher 62 } 63 64 // WithSliding specifies that use sliding cache or not. 65 func WithSliding[K comparable, V any](sliding bool) Option[K, V] { 66 return &slidingOption[K, V]{sliding: sliding} 67 } 68 69 type slidingOption[K comparable, V any] struct { 70 sliding bool 71 } 72 73 func (o *slidingOption[K, V]) applyToLRUCache(c *LRUCache[K, V]) { 74 panic("not_supported") 75 } 76 77 func (o *slidingOption[K, V]) applyToTTLCache(c *TTLCache[K, V]) { 78 for i := uint32(0); i <= c.mask; i++ { 79 c.shards[i].sliding = o.sliding 80 } 81 } 82 83 var ErrLoaderIsNil = errors.New("loader is nil") 84 85 // WithLoader specifies that loader function of LoadingCache. 86 func WithLoader[K comparable, V any, Loader ~func(ctx context.Context, key K) (value V, err error) | ~func(ctx context.Context, key K) (value V, ttl time.Duration, err error)](loader Loader) Option[K, V] { 87 return &loaderOption[K, V]{loader: loader} 88 } 89 90 type loaderOption[K comparable, V any] struct { 91 loader any 92 } 93 94 func (o *loaderOption[K, V]) applyToLRUCache(c *LRUCache[K, V]) { 95 loader, ok := o.loader.(func(ctx context.Context, key K) (value V, err error)) 96 if !ok { 97 panic("not_supported") 98 } 99 c.loader = loader 100 c.group = singleflight_Group[K, V]{} 101 } 102 103 func (o *loaderOption[K, V]) applyToTTLCache(c *TTLCache[K, V]) { 104 loader, ok := o.loader.(func(ctx context.Context, key K) (value V, ttl time.Duration, err error)) 105 if !ok { 106 panic("not_supported") 107 } 108 c.loader = loader 109 c.group = singleflight_Group[K, V]{} 110 } 111 112 func nextPowOf2(n uint32) uint32 { 113 k := uint32(1) 114 for k < n { 115 k = k * 2 116 } 117 return k 118 } 119 120 var isamd64 = runtime.GOARCH == "amd64"